diff --git a/.github/workflows/autocounterd.yml b/.github/workflows/autocounterd.yml new file mode 100644 index 00000000000..3c1812a3ba1 --- /dev/null +++ b/.github/workflows/autocounterd.yml @@ -0,0 +1,47 @@ +name: autocounterd + +on: + push: + paths: + - misc/autocounterd + - .github/workflows/autocounterd.yml + branches: + - "master" + - "misc/autocounterd" + tags: + - "v*" + +permissions: + contents: read + packages: write + +jobs: + autocounterd: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker metadata autcounterd + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }}/autcounterd + tags: | + type=raw,value=latest + type=semver,pattern=v{{version}} + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: ./misc/autocounterd + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f2d1896a61c..0b4def650c0 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -14,69 +14,71 @@ concurrency: cancel-in-progress: true jobs: - build-push: + build-main: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Build main Docker image - env: - owner: ${{ github.repository_owner }} - reponame: ${{ github.event.repository.name }} - run: | - docker build -t ghcr.io/${owner}/${reponame} . - docker tag ghcr.io/${owner}/${reponame}:latest ghcr.io/${owner}/${reponame}:${GITHUB_SHA::8} + - name: Get commit SHA + id: commit + run: echo "sha=${GITHUB_SHA::8}" >> "$GITHUB_OUTPUT" - - name: Build slim Docker images - env: - owner: ${{ github.repository_owner }} - reponame: ${{ github.event.repository.name }} - run: | - docker build --target=gnoland-slim -t ghcr.io/${owner}/${reponame}/gnoland-slim . - docker build --target=gnokey-slim -t ghcr.io/${owner}/${reponame}/gnokey-slim . - docker build --target=gno-slim -t ghcr.io/${owner}/${reponame}/gno-slim . - docker build --target=gnofaucet-slim -t ghcr.io/${owner}/${reponame}/gnofaucet-slim . - docker build --target=gnoweb-slim -t ghcr.io/${owner}/${reponame}/gnoweb-slim . + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - docker tag ghcr.io/${owner}/${reponame}/gnoland-slim:latest ghcr.io/${owner}/${reponame}/gnoland-slim:${GITHUB_SHA::8} - docker tag ghcr.io/${owner}/${reponame}/gnokey-slim:latest ghcr.io/${owner}/${reponame}/gnokey-slim:${GITHUB_SHA::8} - docker tag ghcr.io/${owner}/${reponame}/gno-slim:latest ghcr.io/${owner}/${reponame}/gno-slim:${GITHUB_SHA::8} - docker tag ghcr.io/${owner}/${reponame}/gnofaucet-slim:latest ghcr.io/${owner}/${reponame}/gnofaucet-slim:${GITHUB_SHA::8} - docker tag ghcr.io/${owner}/${reponame}/gnoweb-slim:latest ghcr.io/${owner}/${reponame}/gnoweb-slim:${GITHUB_SHA::8} - - - name: List docker images - run: | - docker images | grep ghcr - - - name: Log in to GitHub Container Registry - if: (github.event_name != 'pull_request') + - name: Login to GitHub Container Registry uses: docker/login-action@v3 + if: (github.event_name != 'pull_request') with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: | + ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest + ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ steps.commit.outputs.sha }} - - name: Publish images - if: (github.event_name != 'pull_request') - env: - owner: ${{ github.repository_owner }} - reponame: ${{ github.event.repository.name }} - run: | - docker push ghcr.io/${owner}/${reponame}:latest - docker push ghcr.io/${owner}/${reponame}:${GITHUB_SHA::8} - - docker push ghcr.io/${owner}/${reponame}/gnoland-slim:latest - docker push ghcr.io/${owner}/${reponame}/gnoland-slim:${GITHUB_SHA::8} + build-slim: + runs-on: ubuntu-latest + strategy: + matrix: + target: [gnoland-slim, gnokey-slim, gno-slim, gnofaucet-slim, gnoweb-slim] + steps: + - name: Checkout + uses: actions/checkout@v4 - docker push ghcr.io/${owner}/${reponame}/gnokey-slim:latest - docker push ghcr.io/${owner}/${reponame}/gnokey-slim:${GITHUB_SHA::8} + - name: Get commit SHA + id: commit + run: echo "sha=${GITHUB_SHA::8}" >> "$GITHUB_OUTPUT" - docker push ghcr.io/${owner}/${reponame}/gno-slim:latest - docker push ghcr.io/${owner}/${reponame}/gno-slim:${GITHUB_SHA::8} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - docker push ghcr.io/${owner}/${reponame}/gnofaucet-slim:latest - docker push ghcr.io/${owner}/${reponame}/gnofaucet-slim:${GITHUB_SHA::8} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - docker push ghcr.io/${owner}/${reponame}/gnoweb-slim:latest - docker push ghcr.io/${owner}/${reponame}/gnoweb-slim:${GITHUB_SHA::8} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + if: (github.event_name != 'pull_request') + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + platforms: linux/amd64,linux/arm64 + target: ${{ matrix.target }} + push: ${{ github.event_name != 'pull_request' }} + tags: | + ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/${{ matrix.target }}:latest + ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}/${{ matrix.target }}:${{ steps.commit.outputs.sha }} diff --git a/contribs/gnodev/go.mod b/contribs/gnodev/go.mod index 4ec6a63d59c..0f466f9dc5d 100644 --- a/contribs/gnodev/go.mod +++ b/contribs/gnodev/go.mod @@ -5,52 +5,73 @@ go 1.21 replace github.com/gnolang/gno => ../.. require ( + github.com/charmbracelet/lipgloss v0.9.1 + github.com/charmbracelet/log v0.3.1 github.com/fsnotify/fsnotify v1.7.0 github.com/gnolang/gno v0.0.0-00010101000000-000000000000 github.com/gorilla/websocket v1.5.1 + github.com/muesli/termenv v0.15.2 go.uber.org/zap v1.27.0 golang.org/x/term v0.18.0 ) require ( dario.cat/mergo v1.0.0 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect github.com/gotuna/gotuna v0.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/jaekwon/testify v1.6.1 // indirect - github.com/kr/pretty v0.2.1 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/muesli/reflow v0.3.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/ff/v3 v3.4.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.4.3 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.10.1 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect + go.opentelemetry.io/otel v1.25.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 // indirect + go.opentelemetry.io/otel/metric v1.25.0 // indirect + go.opentelemetry.io/otel/sdk v1.25.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.25.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap/exp v0.2.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.19.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contribs/gnodev/go.sum b/contribs/gnodev/go.sum index a20a723cc14..7cde4cbdb93 100644 --- a/contribs/gnodev/go.sum +++ b/contribs/gnodev/go.sum @@ -1,14 +1,16 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= +github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= @@ -26,6 +28,12 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= +github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= +github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw= +github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= @@ -38,8 +46,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -49,6 +57,13 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -63,8 +78,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= @@ -80,6 +95,8 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/ github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gotuna/gotuna v0.6.0 h1:N1lQKXEi/lwRp8u3sccTYLhzOffA4QasExz/1M5Riws= github.com/gotuna/gotuna v0.6.0/go.mod h1:F/ecRt29ChB6Ycy1AFIBpBiMNK0j7Heq+gFbLWquhjc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jaekwon/testify v1.6.1 h1:4AtAJcR9GzXN5W4DdY7ie74iCPiJV1JJUJL90t2ZUyw= github.com/jaekwon/testify v1.6.1/go.mod h1:Oun0RXIHI7osufabQ60i4Lqkj0GXLbqI1I7kgzBNm1U= @@ -89,10 +106,8 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= @@ -101,6 +116,17 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/linxGnu/grocksdb v1.6.20 h1:C0SNv12/OBr/zOdGw6reXS+mKpIdQGb/AkZWjHYnO64= github.com/linxGnu/grocksdb v1.6.20/go.mod h1:IbTMGpmWg/1pg2hcG9LlxkqyqiJymdCweaUrzsLRFmg= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= @@ -122,6 +148,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= @@ -139,6 +169,20 @@ github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfU github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 h1:hDKnobznDpcdTlNzO0S/owRB8tyVr1OoeZZhDoqY+Cs= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0/go.mod h1:kUDQaUs1h8iTIHbQTk+iJRiUvSfJYMMKTtMCaiVu7B0= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= +go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= +go.opentelemetry.io/otel/sdk/metric v1.25.0 h1:7CiHOy08LbrxMAp4vWpbiPcklunUshVpAvGBrdDRlGw= +go.opentelemetry.io/otel/sdk/metric v1.25.0/go.mod h1:LzwoKptdbBBdYfvtGCzGwk6GWMA3aUzBOwtQpR6Nz7o= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= +go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -161,8 +205,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -173,6 +217,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= @@ -188,10 +233,14 @@ golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/contribs/gnodev/main.go b/contribs/gnodev/main.go index df68bf54bec..6e6d12fcbdc 100644 --- a/contribs/gnodev/main.go +++ b/contribs/gnodev/main.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "io" + "log/slog" "net" "net/http" "os" @@ -12,27 +13,28 @@ import ( "strings" "time" + "github.com/charmbracelet/lipgloss" "github.com/fsnotify/fsnotify" "github.com/gnolang/gno/contribs/gnodev/pkg/dev" gnodev "github.com/gnolang/gno/contribs/gnodev/pkg/dev" "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" + "github.com/gnolang/gno/contribs/gnodev/pkg/logger" "github.com/gnolang/gno/contribs/gnodev/pkg/rawterm" "github.com/gnolang/gno/contribs/gnodev/pkg/watcher" "github.com/gnolang/gno/gno.land/pkg/gnoweb" - "github.com/gnolang/gno/gno.land/pkg/log" + zaplog "github.com/gnolang/gno/gno.land/pkg/log" "github.com/gnolang/gno/gnovm/pkg/gnoenv" "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/tm2/pkg/commands" osm "github.com/gnolang/gno/tm2/pkg/os" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" + "github.com/muesli/termenv" ) const ( NodeLogName = "Node" WebLogName = "GnoWeb" KeyPressLogName = "KeyPress" - EventServerLogName = "Events" + EventServerLogName = "Event" ) type devCfg struct { @@ -41,13 +43,14 @@ type devCfg struct { nodeP2PListenerAddr string nodeProxyAppListenerAddr string - minimal bool - verbose bool - hotreload bool - noWatch bool - noReplay bool - maxGas int64 - chainId string + minimal bool + verbose bool + hotreload bool + noWatch bool + noReplay bool + maxGas int64 + chainId string + serverMode bool } var defaultDevOptions = &devCfg{ @@ -105,6 +108,13 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { "do not load packages from examples directory", ) + fs.BoolVar( + &c.serverMode, + "server-mode", + defaultDevOptions.serverMode, + "disable interaction, and adjust logging for server use.", + ) + fs.BoolVar( &c.verbose, "verbose", @@ -141,7 +151,7 @@ func (c *devCfg) RegisterFlags(fs *flag.FlagSet) { ) } -func execDev(cfg *devCfg, args []string, io commands.IO) error { +func execDev(cfg *devCfg, args []string, io commands.IO) (err error) { ctx, cancel := context.WithCancelCause(context.Background()) defer cancel(nil) @@ -160,7 +170,7 @@ func execDev(cfg *devCfg, args []string, io commands.IO) error { } // Setup Raw Terminal - rt, restore, err := setupRawTerm(io) + rt, restore, err := setupRawTerm(cfg, io) if err != nil { return fmt.Errorf("unable to init raw term: %w", err) } @@ -168,25 +178,28 @@ func execDev(cfg *devCfg, args []string, io commands.IO) error { // Setup trap signal osm.TrapSignal(func() { - restore() cancel(nil) + restore() }) - zapLoggerEvents := NewZapLogger(rt.NamespacedWriter(EventServerLogName), zapcore.DebugLevel) - loggerEvents := log.ZapLoggerToSlog(zapLoggerEvents) + logger := setuplogger(cfg, rt) + loggerEvents := logger.WithGroup(EventServerLogName) emitterServer := emitter.NewServer(loggerEvents) // Setup Dev Node // XXX: find a good way to export or display node logs - devNode, err := setupDevNode(ctx, cfg, emitterServer, rt, pkgpaths) + devNode, err := setupDevNode(ctx, logger, cfg, emitterServer, pkgpaths) if err != nil { return err } defer devNode.Close() - rt.Taskf(NodeLogName, "Listener: %s\n", devNode.GetRemoteAddress()) - rt.Taskf(NodeLogName, "Default Address: %s\n", gnodev.DefaultCreator.String()) - rt.Taskf(NodeLogName, "Chain ID: %s\n", cfg.chainId) + logger.WithGroup(NodeLogName). + Info("node started", + "lisn", devNode.GetRemoteAddress(), + "addr", gnodev.DefaultCreator.String(), + "chainID", cfg.chainId, + ) // Create server mux := http.NewServeMux() @@ -197,7 +210,7 @@ func execDev(cfg *devCfg, args []string, io commands.IO) error { defer server.Close() // Setup gnoweb - webhandler := setupGnoWebServer(cfg, devNode, rt) + webhandler := setupGnoWebServer(logger.WithGroup(WebLogName), cfg, devNode) // Setup HotReload if needed if !cfg.noWatch { @@ -213,7 +226,9 @@ func execDev(cfg *devCfg, args []string, io commands.IO) error { cancel(err) }() - rt.Taskf(WebLogName, "Listener: http://%s\n", server.Addr) + logger.WithGroup(WebLogName). + Info("gnoweb started", + "lisn", fmt.Sprintf("http://%s", server.Addr)) watcher, err := watcher.NewPackageWatcher(loggerEvents, emitterServer) if err != nil { @@ -224,35 +239,28 @@ func execDev(cfg *devCfg, args []string, io commands.IO) error { // Add node pkgs to watcher watcher.AddPackages(devNode.ListPkgs()...) - // GnoDev should be ready, run event loop - rt.Taskf("[Ready]", "for commands and help, press `h`") + logger.WithGroup("--- READY").Info("for commands and help, press `h`") // Run the main event loop - return runEventLoop(ctx, cfg, rt, devNode, watcher) + return runEventLoop(ctx, logger, rt, devNode, watcher) } -// XXX: Automatize this the same way command does -func printHelper(rt *rawterm.RawTerm) { - rt.Taskf("Helper", ` -Gno Dev Helper: - H Help - display this message - R Reload - Reload all packages to take change into account. - Ctrl+R Reset - Reset application state. - Ctrl+C Exit - Exit the application -`) -} +var helper string = ` +H Help - display this message +R Reload - Reload all packages to take change into account. +Ctrl+R Reset - Reset application state. +Ctrl+C Exit - Exit the application +` func runEventLoop( ctx context.Context, - cfg *devCfg, + logger *slog.Logger, rt *rawterm.RawTerm, dnode *dev.Node, watch *watcher.PackageWatcher, ) error { - nodeOut := rt.NamespacedWriter(NodeLogName) - keyOut := rt.NamespacedWriter(KeyPressLogName) - keyPressCh := listenForKeyPress(keyOut, rt) + keyPressCh := listenForKeyPress(logger.WithGroup(KeyPressLogName), rt) for { var err error @@ -264,41 +272,54 @@ func runEventLoop( return nil } - fmt.Fprintln(nodeOut, "Loading package updates...") + // fmt.Fprintln(nodeOut, "Loading package updates...") if err = dnode.UpdatePackages(pkgs.PackagesPath()...); err != nil { return fmt.Errorf("unable to update packages: %w", err) } - fmt.Fprintln(nodeOut, "Reloading...") - err = dnode.Reload(ctx) - - checkForError(rt, err) + logger.WithGroup(NodeLogName).Info("reloading...") + if err = dnode.Reload(ctx); err != nil { + logger.WithGroup(NodeLogName). + Error("unable to reload node", "err", err) + } case key, ok := <-keyPressCh: if !ok { return nil } - if cfg.verbose { - fmt.Fprintf(keyOut, "<%s>\n", key.String()) - } + logger.WithGroup(KeyPressLogName).Debug( + fmt.Sprintf("<%s>", key.String()), + ) switch key.Upper() { case rawterm.KeyH: - printHelper(rt) + logger.Info("Gno Dev Helper", "helper", helper) case rawterm.KeyR: - fmt.Fprintln(nodeOut, "Reloading all packages...") - checkForError(nodeOut, dnode.ReloadAll(ctx)) + logger.WithGroup(NodeLogName).Info("reloading...") + if err = dnode.ReloadAll(ctx); err != nil { + logger.WithGroup(NodeLogName). + Error("unable to reload node", "err", err) + + } + case rawterm.KeyCtrlR: - fmt.Fprintln(nodeOut, "Reseting state...") - checkForError(nodeOut, dnode.Reset(ctx)) + logger.WithGroup(NodeLogName).Info("reseting node state...") + if err = dnode.Reset(ctx); err != nil { + logger.WithGroup(NodeLogName). + Error("unable to reset node state", "err", err) + } + case rawterm.KeyCtrlC: return nil + case rawterm.KeyCtrlE: + panic("NOOOO") + return nil default: } - // Listen for the next keypress - keyPressCh = listenForKeyPress(keyOut, rt) + // Reset listen for the next keypress + keyPressCh = listenForKeyPress(logger.WithGroup(KeyPressLogName), rt) } } } @@ -348,15 +369,20 @@ func runPkgsWatcher(ctx context.Context, cfg *devCfg, pkgs []gnomod.Pkg, changed } } -func setupRawTerm(io commands.IO) (rt *rawterm.RawTerm, restore func() error, err error) { - rt = rawterm.NewRawTerm() +var noopRestore = func() error { return nil } - restore, err = rt.Init() - if err != nil { - return nil, nil, err +func setupRawTerm(cfg *devCfg, io commands.IO) (*rawterm.RawTerm, func() error, error) { + rt := rawterm.NewRawTerm() + restore := noopRestore + if !cfg.serverMode { + var err error + restore, err = rt.Init() + if err != nil { + return nil, nil, err + } } - // Correctly format output for terminal + // correctly format output for terminal io.SetOut(commands.WriteNopCloser(rt)) return rt, restore, nil } @@ -364,13 +390,12 @@ func setupRawTerm(io commands.IO) (rt *rawterm.RawTerm, restore func() error, er // setupDevNode initializes and returns a new DevNode. func setupDevNode( ctx context.Context, + logger *slog.Logger, cfg *devCfg, remitter emitter.Emitter, - rt *rawterm.RawTerm, pkgspath []string, ) (*gnodev.Node, error) { - nodeOut := rt.NamespacedWriter("Node") - zapLogger := NewZapLogger(nodeOut, zapcore.ErrorLevel) + nodeLogger := logger.WithGroup(NodeLogName) gnoroot := gnoenv.RootDir() @@ -379,7 +404,6 @@ func setupDevNode( config.PackagesPathList = pkgspath config.TMConfig.RPC.ListenAddress = resolveUnixOrTCPAddr(cfg.nodeRPCListenerAddr) config.NoReplay = cfg.noReplay - config.SkipFailingGenesisTxs = true config.MaxGasPerBlock = cfg.maxGas config.ChainID = cfg.chainId @@ -387,18 +411,17 @@ func setupDevNode( config.TMConfig.P2P.ListenAddress = defaultDevOptions.nodeP2PListenerAddr config.TMConfig.ProxyApp = defaultDevOptions.nodeProxyAppListenerAddr - return gnodev.NewDevNode(ctx, log.ZapLoggerToSlog(zapLogger), remitter, config) + return gnodev.NewDevNode(ctx, nodeLogger, remitter, config) } // setupGnowebServer initializes and starts the Gnoweb server. -func setupGnoWebServer(cfg *devCfg, dnode *gnodev.Node, rt *rawterm.RawTerm) http.Handler { +func setupGnoWebServer(logger *slog.Logger, cfg *devCfg, dnode *gnodev.Node) http.Handler { webConfig := gnoweb.NewDefaultConfig() webConfig.RemoteAddr = dnode.GetRemoteAddress() webConfig.HelpRemote = dnode.GetRemoteAddress() webConfig.HelpChainID = cfg.chainId - zapLogger := NewZapLogger(rt.NamespacedWriter("GnoWeb"), zapcore.DebugLevel) - app := gnoweb.MakeApp(log.ZapLoggerToSlog(zapLogger), webConfig) + app := gnoweb.MakeApp(logger, webConfig) return app.Router } @@ -421,13 +444,13 @@ func parseArgsPackages(args []string) (paths []string, err error) { return paths, nil } -func listenForKeyPress(w io.Writer, rt *rawterm.RawTerm) <-chan rawterm.KeyPress { +func listenForKeyPress(logger *slog.Logger, rt *rawterm.RawTerm) <-chan rawterm.KeyPress { cc := make(chan rawterm.KeyPress, 1) go func() { defer close(cc) key, err := rt.ReadKeyPress() if err != nil { - fmt.Fprintf(w, "unable to read keypress: %s\n", err.Error()) + logger.Error("unable to read keypress", "err", err) return } @@ -437,15 +460,6 @@ func listenForKeyPress(w io.Writer, rt *rawterm.RawTerm) <-chan rawterm.KeyPress return cc } -func checkForError(w io.Writer, err error) { - if err != nil { - fmt.Fprintf(w, "[ERROR] - %s\n", err.Error()) - return - } - - fmt.Fprintln(w, "[DONE]") -} - func resolveUnixOrTCPAddr(in string) (out string) { var err error var addr net.Addr @@ -469,15 +483,26 @@ func resolveUnixOrTCPAddr(in string) (out string) { panic(err) } -// NewZapLogger creates a zap logger with a console encoder for development use. -func NewZapLogger(w io.Writer, level zapcore.Level) *zap.Logger { - // Build encoder config - consoleConfig := zap.NewDevelopmentEncoderConfig() - consoleConfig.TimeKey = "" - consoleConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder - consoleConfig.EncodeName = zapcore.FullNameEncoder - - // Build encoder - enc := zapcore.NewConsoleEncoder(consoleConfig) - return log.NewZapLogger(enc, w, level) +func setuplogger(cfg *devCfg, out io.Writer) *slog.Logger { + level := slog.LevelInfo + if cfg.verbose { + level = slog.LevelDebug + } + + if cfg.serverMode { + zaplogger := logger.NewZapLogger(out, level) + return zaplog.ZapLoggerToSlog(zaplogger) + } + + // Detect term color profile + colorProfile := termenv.DefaultOutput().Profile + clogger := logger.NewColumnLogger(out, level, colorProfile) + + // Register well known group color with system colors + clogger.RegisterGroupColor(NodeLogName, lipgloss.Color("3")) + clogger.RegisterGroupColor(WebLogName, lipgloss.Color("4")) + clogger.RegisterGroupColor(KeyPressLogName, lipgloss.Color("5")) + clogger.RegisterGroupColor(EventServerLogName, lipgloss.Color("6")) + + return slog.New(clogger) } diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index 5d5a4c5c5e6..02d97dff733 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "log/slog" + "strings" + "unicode" "github.com/gnolang/gno/contribs/gnodev/pkg/emitter" "github.com/gnolang/gno/contribs/gnodev/pkg/events" @@ -17,18 +19,19 @@ import ( bft "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/crypto" tm2events "github.com/gnolang/gno/tm2/pkg/events" + "github.com/gnolang/gno/tm2/pkg/log" + "github.com/gnolang/gno/tm2/pkg/sdk" "github.com/gnolang/gno/tm2/pkg/std" // backup "github.com/gnolang/tx-archive/backup/client" // restore "github.com/gnolang/tx-archive/restore/client" ) type NodeConfig struct { - PackagesPathList []string - TMConfig *tmcfg.Config - SkipFailingGenesisTxs bool - NoReplay bool - MaxGasPerBlock int64 - ChainID string + PackagesPathList []string + TMConfig *tmcfg.Config + NoReplay bool + MaxGasPerBlock int64 + ChainID string } func DefaultNodeConfig(rootdir string) *NodeConfig { @@ -36,11 +39,10 @@ func DefaultNodeConfig(rootdir string) *NodeConfig { tmc.Consensus.SkipTimeoutCommit = false // avoid time drifting, see issue #1507 return &NodeConfig{ - ChainID: tmc.ChainID(), - PackagesPathList: []string{}, - TMConfig: tmc, - SkipFailingGenesisTxs: true, - MaxGasPerBlock: 10_000_000_000, + ChainID: tmc.ChainID(), + PackagesPathList: []string{}, + TMConfig: tmc, + MaxGasPerBlock: 10_000_000_000, } } @@ -80,6 +82,8 @@ func NewDevNode(ctx context.Context, logger *slog.Logger, emitter emitter.Emitte return nil, fmt.Errorf("unable to load genesis packages: %w", err) } + logger.Info("pkgs loaded", "path", cfg.PackagesPathList) + // generate genesis state genesis := gnoland.GnoGenesisState{ Balances: DefaultBalance, @@ -125,6 +129,7 @@ func (d *Node) GetRemoteAddress() string { // UpdatePackages updates the currently known packages. It will be taken into // consideration in the next reload of the node. func (d *Node) UpdatePackages(paths ...string) error { + var n int for _, path := range paths { // List all packages from target path pkgslist, err := gnomod.ListPkgs(path) @@ -135,9 +140,13 @@ func (d *Node) UpdatePackages(paths ...string) error { // Update or add package in the current known list. for _, pkg := range pkgslist { d.pkgs[pkg.Dir] = pkg + d.logger.Debug("pkgs update", "name", pkg.Name, "path", pkg.Dir) } + + n += len(pkgslist) } + d.logger.Info(fmt.Sprintf("updated %d pacakges", n)) return nil } @@ -230,6 +239,36 @@ func (d *Node) Reload(ctx context.Context) error { return nil } +func (d *Node) genesisTxHandler(ctx sdk.Context, tx std.Tx, res sdk.Result) { + if res.IsErr() { + // XXX: for now, this is only way to catch the error + before, after, found := strings.Cut(res.Log, "\n") + if !found { + d.logger.Error("unable to send tx", "err", res.Error, "log", res.Log) + return + } + + var attrs []slog.Attr + + // Add error + attrs = append(attrs, slog.Any("err", res.Error)) + + // Fetch first line as error message + msg := strings.TrimFunc(before, func(r rune) bool { + return unicode.IsSpace(r) || r == ':' + }) + attrs = append(attrs, slog.String("err", msg)) + + // If debug is enable, also append stack + if d.logger.Enabled(context.Background(), slog.LevelDebug) { + attrs = append(attrs, slog.String("stack", after)) + + } + + d.logger.LogAttrs(context.Background(), slog.LevelError, "unable to deliver tx", attrs...) + } +} + // GetBlockTransactions returns the transactions contained // within the specified block, if any func (d *Node) GetBlockTransactions(blockNum uint64) ([]std.Tx, error) { @@ -322,30 +361,30 @@ func (n *Node) stopIfRunning() error { return nil } -func (n *Node) reset(ctx context.Context, genesis gnoland.GnoGenesisState) error { +func (n *Node) reset(ctx context.Context, genesis gnoland.GnoGenesisState) (err error) { // Setup node config nodeConfig := newNodeConfig(n.config.TMConfig, n.config.ChainID, genesis) - nodeConfig.SkipFailingGenesisTxs = n.config.SkipFailingGenesisTxs + nodeConfig.GenesisTxHandler = n.genesisTxHandler nodeConfig.Genesis.ConsensusParams.Block.MaxGas = n.config.MaxGasPerBlock - var recoverErr error - // recoverFromError handles panics and converts them to errors. recoverFromError := func() { if r := recover(); r != nil { - var ok bool - if recoverErr, ok = r.(error); !ok { - panic(r) // Re-panic if not an error. + switch val := r.(type) { + case error: + err = val + case string: + err = fmt.Errorf("error: %s", val) + default: + err = fmt.Errorf("unknown error: %#v", val) } } } // Execute node creation and handle any errors. defer recoverFromError() + node, nodeErr := buildNode(n.logger, n.emitter, nodeConfig) - if recoverErr != nil { // First check for recover error in case of panic - return fmt.Errorf("recovered from a node panic: %w", recoverErr) - } if nodeErr != nil { // Then for any node error return fmt.Errorf("unable to build the node: %w", nodeErr) } @@ -361,8 +400,11 @@ func (n *Node) reset(ctx context.Context, genesis gnoland.GnoGenesisState) error return nil } +var noopLogger = log.NewNoopLogger() + func buildNode(logger *slog.Logger, emitter emitter.Emitter, cfg *gnoland.InMemoryNodeConfig) (*node.Node, error) { - node, err := gnoland.NewInMemoryNode(logger, cfg) + // XXX(TODO): Redirect the node log somewhere else + node, err := gnoland.NewInMemoryNode(noopLogger, cfg) if err != nil { return nil, fmt.Errorf("unable to create a new node: %w", err) } @@ -371,8 +413,9 @@ func buildNode(logger *slog.Logger, emitter emitter.Emitter, cfg *gnoland.InMemo switch data := evt.(type) { case bft.EventTx: resEvt := events.TxResult{ - Height: data.Result.Height, - Index: data.Result.Index, + Height: data.Result.Height, + Index: data.Result.Index, + // XXX: Update this to split error for stack Response: data.Result.Response, } @@ -410,8 +453,9 @@ func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesi } return &gnoland.InMemoryNodeConfig{ - PrivValidator: pv, - TMConfig: tmc, - Genesis: genesis, + PrivValidator: pv, + TMConfig: tmc, + Genesis: genesis, + GenesisMaxVMCycles: 10_000_000, } } diff --git a/contribs/gnodev/pkg/logger/colors.go b/contribs/gnodev/pkg/logger/colors.go new file mode 100644 index 00000000000..b0499e01722 --- /dev/null +++ b/contribs/gnodev/pkg/logger/colors.go @@ -0,0 +1,60 @@ +package logger + +import ( + "fmt" + "hash/fnv" + "math" + + "github.com/charmbracelet/lipgloss" +) + +func colorFromString(s string, saturation, lightness float64) lipgloss.Color { + hue := float64(hash32a(s) % 360) + + r, g, b := hslToRGB(float64(hue), saturation, lightness) + hex := rgbToHex(r, g, b) + return lipgloss.Color(hex) +} + +func hash32a(s string) uint32 { + h := fnv.New32a() + h.Write([]byte(s)) + return h.Sum32() +} + +// from: https://www.rapidtables.com/convert/color/hsl-to-rgb.html +// hslToRGB converts an HSL triple to an RGB triple. +func hslToRGB(h, s, l float64) (r, g, b uint8) { + if h < 0 || h >= 360 || s < 0 || s > 1 || l < 0 || l > 1 { + return 0, 0, 0 + } + + C := (1 - math.Abs((2*l)-1)) * s + X := C * (1 - math.Abs(math.Mod(h/60, 2)-1)) + m := l - (C / 2) + + var rNot, gNot, bNot float64 + switch { + case 0 <= h && h < 60: + rNot, gNot, bNot = C, X, 0 + case 60 <= h && h < 120: + rNot, gNot, bNot = X, C, 0 + case 120 <= h && h < 180: + rNot, gNot, bNot = 0, C, X + case 180 <= h && h < 240: + rNot, gNot, bNot = 0, X, C + case 240 <= h && h < 300: + rNot, gNot, bNot = X, 0, C + case 300 <= h && h < 360: + rNot, gNot, bNot = C, 0, X + } + + r = uint8(math.Round((rNot + m) * 255)) + g = uint8(math.Round((gNot + m) * 255)) + b = uint8(math.Round((bNot + m) * 255)) + return r, g, b +} + +func rgbToHex(r, g, b uint8) string { + return fmt.Sprintf("#%02X%02X%02X", r, g, b) +} diff --git a/contribs/gnodev/pkg/logger/log_column.go b/contribs/gnodev/pkg/logger/log_column.go new file mode 100644 index 00000000000..8e145e89175 --- /dev/null +++ b/contribs/gnodev/pkg/logger/log_column.go @@ -0,0 +1,199 @@ +package logger + +import ( + "bytes" + "fmt" + "io" + "log/slog" + "strings" + "sync" + + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/log" + "github.com/muesli/termenv" +) + +func NewColumnLogger(w io.Writer, level slog.Level, profile termenv.Profile) *ColumnLogger { + charmLogger := log.NewWithOptions(w, log.Options{ + ReportTimestamp: false, + ReportCaller: false, + Prefix: "", + }) + + // Default column output + defaultOutput := newColumeWriter(lipgloss.NewStyle(), "", w) + charmLogger.SetOutput(defaultOutput) + charmLogger.SetStyles(defaultStyles()) + charmLogger.SetColorProfile(profile) + charmLogger.SetReportCaller(false) + switch level { + case slog.LevelDebug: + charmLogger.SetLevel(log.DebugLevel) + case slog.LevelError: + charmLogger.SetLevel(log.ErrorLevel) + case slog.LevelInfo: + charmLogger.SetLevel(log.InfoLevel) + case slog.LevelWarn: + charmLogger.SetLevel(log.WarnLevel) + default: + panic("invalid slog level") + } + + return &ColumnLogger{ + Logger: charmLogger, + writer: w, + prefix: charmLogger.GetPrefix(), + colors: map[string]lipgloss.Color{}, + } +} + +type ColumnLogger struct { + *log.Logger + + prefix string + writer io.Writer + colorProfile termenv.Profile + + colors map[string]lipgloss.Color + muColors sync.RWMutex +} + +func (cl *ColumnLogger) WithGroup(group string) slog.Handler { + cl.muColors.RLock() + defer cl.muColors.RUnlock() + + if cl.prefix != "" { + group = fmt.Sprintf("%.1s.%s", cl.prefix, group) + } + + // check if we already know this group + fg, ok := cl.colors[group] + if !ok { + // generate bright color based on the group name + fg = colorFromString(group, 0.5, 0.6) + } + baseStyle := lipgloss.NewStyle().Foreground(fg) + + nlog := cl.Logger.With() // clone logger + nlog.SetOutput(newColumeWriter(baseStyle, group, cl.writer)) + nlog.SetColorProfile(cl.colorProfile) + return &ColumnLogger{ + Logger: nlog, + prefix: group, + writer: cl.writer, + } +} + +func (cl *ColumnLogger) RegisterGroupColor(group string, color lipgloss.Color) { + cl.muColors.Lock() + cl.colors[group] = color + cl.muColors.Unlock() +} + +var lf = []byte{'\n'} + +type columnWriter struct { + inline bool + style lipgloss.Style + prefix string + writer io.Writer +} + +func newColumeWriter(baseStyle lipgloss.Style, prefix string, writer io.Writer) *columnWriter { + const width = 12 + + style := baseStyle. + Border(lipgloss.ThickBorder(), false, true, false, false). + BorderForeground(baseStyle.GetForeground()). + Bold(true). + Width(width) + + if len(prefix) >= width { + prefix = prefix[:width-3] + "..." + } + + return &columnWriter{style: style, prefix: prefix, writer: writer} +} + +func (cl *columnWriter) Write(buf []byte) (n int, err error) { + for line := 0; len(buf) > 0; line++ { + i := bytes.IndexByte(buf, '\n') + todo := len(buf) + if i >= 0 { + todo = i + } + + if !cl.inline { + var prefix string + if line == 0 { + prefix = cl.prefix + } + + fmt.Fprint(cl.writer, cl.style.Render(prefix)+" ") + } + + var nn int + nn, err = cl.writer.Write(buf[:todo]) + n += nn + if err != nil { + return n, err + } + buf = buf[todo:] + + if cl.inline = i < 0; !cl.inline { + if _, err = cl.writer.Write([]byte(lf)); err != nil { + return n, err + } + n++ + buf = buf[1:] + } + } + + return n, nil +} + +// defaultStyles returns the default lipgloss styles for column logger +func defaultStyles() *log.Styles { + style := log.DefaultStyles() + style.Levels = map[log.Level]lipgloss.Style{ + log.DebugLevel: lipgloss.NewStyle(). + SetString(strings.ToUpper(log.DebugLevel.String())). + Bold(true). + MaxWidth(1). + Foreground(lipgloss.Color("63")), + log.InfoLevel: lipgloss.NewStyle(). + SetString(strings.ToUpper(log.InfoLevel.String())). + MaxWidth(1). + Foreground(lipgloss.Color("12")), + + log.WarnLevel: lipgloss.NewStyle(). + SetString(strings.ToUpper(log.WarnLevel.String())). + Bold(true). + MaxWidth(1). + Foreground(lipgloss.Color("192")), + log.ErrorLevel: lipgloss.NewStyle(). + SetString(strings.ToUpper(log.ErrorLevel.String())). + Bold(true). + MaxWidth(1). + Foreground(lipgloss.Color("204")), + log.FatalLevel: lipgloss.NewStyle(). + SetString(strings.ToUpper(log.FatalLevel.String())). + Bold(true). + MaxWidth(1). + Foreground(lipgloss.Color("134")), + } + style.Keys = map[string]lipgloss.Style{ + "err": lipgloss.NewStyle(). + Foreground(lipgloss.Color("204")), + "error": lipgloss.NewStyle(). + Foreground(lipgloss.Color("204")), + } + style.Values = map[string]lipgloss.Style{ + "err": lipgloss.NewStyle(). + Foreground(lipgloss.Color("204")), + "error": lipgloss.NewStyle(). + Foreground(lipgloss.Color("204")), + } + + return style +} diff --git a/contribs/gnodev/pkg/logger/log_zap.go b/contribs/gnodev/pkg/logger/log_zap.go new file mode 100644 index 00000000000..b7e5b34cc4e --- /dev/null +++ b/contribs/gnodev/pkg/logger/log_zap.go @@ -0,0 +1,38 @@ +package logger + +import ( + "io" + "log/slog" + + "github.com/gnolang/gno/gno.land/pkg/log" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func NewZapLogger(w io.Writer, slevel slog.Level) *zap.Logger { + // Build encoder config + consoleConfig := zap.NewDevelopmentEncoderConfig() + consoleConfig.EncodeCaller = zapcore.FullCallerEncoder + consoleConfig.EncodeTime = zapcore.RFC3339TimeEncoder + consoleConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + consoleConfig.EncodeName = zapcore.FullNameEncoder + + // Build encoder + enc := zapcore.NewConsoleEncoder(consoleConfig) + + var level zapcore.Level + switch slevel { + case slog.LevelDebug: + level = zapcore.DebugLevel + case slog.LevelError: + level = zapcore.ErrorLevel + case slog.LevelInfo: + level = zapcore.InfoLevel + case slog.LevelWarn: + level = zapcore.WarnLevel + default: + panic("invalid slog level") + } + + return log.NewZapLogger(enc, w, level) +} diff --git a/contribs/gnodev/pkg/rawterm/rawterm.go b/contribs/gnodev/pkg/rawterm/rawterm.go index f6d6e7534e2..58b8dde1530 100644 --- a/contribs/gnodev/pkg/rawterm/rawterm.go +++ b/contribs/gnodev/pkg/rawterm/rawterm.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "os" - "strings" "sync" "golang.org/x/term" @@ -17,16 +16,16 @@ var CRLF = []byte{'\r', '\n'} type RawTerm struct { syncWriter sync.Mutex - fsin *os.File - reader io.Reader - taskWriter TaskWriter + fsin *os.File + reader io.Reader + writer io.Writer } func NewRawTerm() *RawTerm { return &RawTerm{ - fsin: os.Stdin, - reader: os.Stdin, - taskWriter: &rawTaskWriter{os.Stdout}, + fsin: os.Stdin, + reader: os.Stdin, + writer: os.Stdout, } } @@ -38,38 +37,16 @@ func (rt *RawTerm) Init() (restore func() error, err error) { } rt.reader = rt.fsin - rt.taskWriter = &columnTaskWriter{os.Stdout} return func() error { return term.Restore(fd, oldstate) }, nil } -func (rt *RawTerm) Taskf(task string, format string, args ...interface{}) (n int, err error) { - format = strings.TrimSpace(format) - if len(args) > 0 { - str := fmt.Sprintf(format, args...) - return rt.taskWriter.WriteTask(task, []byte(str+"\n")) - } - - return rt.taskWriter.WriteTask(task, []byte(format+"\n")) -} - func (rt *RawTerm) Write(buf []byte) (n int, err error) { rt.syncWriter.Lock() defer rt.syncWriter.Unlock() - return rt.taskWriter.Write(buf) -} - -func (rt *RawTerm) WriteTask(name string, buf []byte) (n int, err error) { - rt.syncWriter.Lock() - defer rt.syncWriter.Unlock() - - return rt.taskWriter.WriteTask(name, buf) -} - -func (rt *RawTerm) NamespacedWriter(namepsace string) io.Writer { - return &namespaceWriter{namepsace, rt} + return writeWithCRLF(rt.writer, buf) } func (rt *RawTerm) read(buf []byte) (n int, err error) { @@ -85,31 +62,9 @@ func (rt *RawTerm) ReadKeyPress() (KeyPress, error) { return KeyPress(buf[0]), nil } -type namespaceWriter struct { - namespace string - writer TaskWriter -} - -func (r *namespaceWriter) Write(buf []byte) (n int, err error) { - return r.writer.WriteTask(r.namespace, buf) -} - -type TaskWriter interface { - io.Writer - WriteTask(task string, buf []byte) (n int, err error) -} - -type columnTaskWriter struct { - writer io.Writer -} - -func (r *columnTaskWriter) Write(buf []byte) (n int, err error) { - return r.WriteTask("", buf) -} - -func (r *columnTaskWriter) WriteTask(left string, buf []byte) (n int, err error) { - var nline int - for nline = 0; len(buf) > 0; nline++ { +// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n. +func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { + for len(buf) > 0 { i := bytes.IndexByte(buf, '\n') todo := len(buf) if i >= 0 { @@ -117,23 +72,15 @@ func (r *columnTaskWriter) WriteTask(left string, buf []byte) (n int, err error) } var nn int - switch { - case nline == 0, left == "": // first line or left side is empty - nn, err = r.writeColumnLine(left, buf[:todo]) - case i < 0 || i+1 == len(buf): // last line - nn, err = r.writeColumnLine(" └─", buf[:todo]) - default: // middle lines - nn, err = r.writeColumnLine(" │", buf[:todo]) - } - + nn, err = w.Write(buf[:todo]) n += nn if err != nil { return n, err } buf = buf[todo:] - if i >= 0 { // always jump a line on the last line - if _, err = r.writer.Write(CRLF); err != nil { + if i >= 0 { + if _, err = w.Write(CRLF); err != nil { return n, err } n++ @@ -141,38 +88,5 @@ func (r *columnTaskWriter) WriteTask(left string, buf []byte) (n int, err error) } } - return -} - -func (r *columnTaskWriter) writeColumnLine(left string, line []byte) (n int, err error) { - // Write left column - if n, err = fmt.Fprintf(r.writer, "%-15s | ", left); err != nil { - return n, err - } - - // Write left line - var nn int - nn, err = r.writer.Write(line) - n += nn - - return -} - -type rawTaskWriter struct { - writer io.Writer -} - -func (r *rawTaskWriter) Write(buf []byte) (n int, err error) { - return r.writer.Write(buf) -} - -func (r *rawTaskWriter) WriteTask(task string, buf []byte) (n int, err error) { - if task != "" { - n, err = r.writer.Write([]byte(task + ": ")) - } - - var nn int - nn, err = r.writer.Write(buf) - n += nn - return + return n, nil } diff --git a/contribs/gnokeykc/go.mod b/contribs/gnokeykc/go.mod index 66a3c750633..0a4965e4a5d 100644 --- a/contribs/gnokeykc/go.mod +++ b/contribs/gnokeykc/go.mod @@ -11,19 +11,22 @@ require ( require ( github.com/alessio/shellescape v1.4.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gorilla/websocket v1.5.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/jaekwon/testify v1.6.1 // indirect - github.com/kr/pretty v0.1.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/ff/v3 v3.4.0 // indirect @@ -33,15 +36,23 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect + go.opentelemetry.io/otel v1.25.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 // indirect + go.opentelemetry.io/otel/metric v1.25.0 // indirect + go.opentelemetry.io/otel/sdk v1.25.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.25.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/proto/otlp v1.1.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contribs/gnokeykc/go.sum b/contribs/gnokeykc/go.sum index 1bc8ea08a57..d19ce65d8d7 100644 --- a/contribs/gnokeykc/go.sum +++ b/contribs/gnokeykc/go.sum @@ -9,8 +9,8 @@ github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7 github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= +github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= @@ -28,6 +28,8 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= @@ -40,8 +42,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -50,6 +52,11 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -66,13 +73,15 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jaekwon/testify v1.6.1 h1:4AtAJcR9GzXN5W4DdY7ie74iCPiJV1JJUJL90t2ZUyw= github.com/jaekwon/testify v1.6.1/go.mod h1:Oun0RXIHI7osufabQ60i4Lqkj0GXLbqI1I7kgzBNm1U= @@ -82,11 +91,10 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/linxGnu/grocksdb v1.6.20 h1:C0SNv12/OBr/zOdGw6reXS+mKpIdQGb/AkZWjHYnO64= @@ -112,6 +120,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -131,6 +141,20 @@ github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfU github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 h1:hDKnobznDpcdTlNzO0S/owRB8tyVr1OoeZZhDoqY+Cs= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0/go.mod h1:kUDQaUs1h8iTIHbQTk+iJRiUvSfJYMMKTtMCaiVu7B0= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= +go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= +go.opentelemetry.io/otel/sdk/metric v1.25.0 h1:7CiHOy08LbrxMAp4vWpbiPcklunUshVpAvGBrdDRlGw= +go.opentelemetry.io/otel/sdk/metric v1.25.0/go.mod h1:LzwoKptdbBBdYfvtGCzGwk6GWMA3aUzBOwtQpR6Nz7o= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= +go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -145,8 +169,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -170,10 +194,14 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/docs/concepts/effective-gno.md b/docs/concepts/effective-gno.md index 72f3081556d..17e4ba28de6 100644 --- a/docs/concepts/effective-gno.md +++ b/docs/concepts/effective-gno.md @@ -612,7 +612,7 @@ For example, if you're creating a coin for cross-chain transfers, Coins are your best bet. They're IBC-ready and their strict rules offer top-notch security. -Read about how to use the Banker module [here](../concepts/standard-library/banker). +Read about how to use the Banker module [here](stdlibs/banker). #### GRC20 tokens diff --git a/docs/concepts/gno-test.md b/docs/concepts/gno-test.md index e05d2db7ed5..754dfad43c8 100644 --- a/docs/concepts/gno-test.md +++ b/docs/concepts/gno-test.md @@ -88,4 +88,4 @@ Internally, a GnoVM instance is initialized to run the test, and, at that moment a blockchain-related context is injected into the GnoVM. Utilizing this context, the transaction sender, coins, block height, etc. can be mocked. -For detailed information on these functions, refer to their [reference page](../reference/standard-library/std/testing.md). +For detailed information on these functions, refer to their [reference page](../reference/stdlibs/std/testing.md). diff --git a/docs/concepts/portal-loop.md b/docs/concepts/portal-loop.md index f335013034d..10772cc5126 100644 --- a/docs/concepts/portal-loop.md +++ b/docs/concepts/portal-loop.md @@ -8,7 +8,7 @@ Portal Loop is an always-up-to-date staging testnet that allows for using the latest version of Gno, Gno.land, and TM2. By utilizing the power of Docker & the [tx-archive](https://github.com/gnolang/tx-archive) tool, the Portal Loop can run the latest code from the master branch on the [Gno monorepo](https://github.com/gnolang/gno), -while preserving most/all the previous the transaction data. +while preserving most/all of the previous transaction data. The Portal Loop allows for quick iteration on the latest version of Gno - without having to make a hard/soft fork. diff --git a/docs/concepts/standard-library/banker.md b/docs/concepts/stdlibs/banker.md similarity index 93% rename from docs/concepts/standard-library/banker.md rename to docs/concepts/stdlibs/banker.md index a4a1104859c..873fac7c418 100644 --- a/docs/concepts/standard-library/banker.md +++ b/docs/concepts/stdlibs/banker.md @@ -15,4 +15,4 @@ The Banker module can be cast into 4 subtypes of bankers that expose different f 3. `BankerTypeRealmSend` - full access to coins that the realm itself owns, including the ones sent with the transaction 4. `BankerTypeRealmIssue` - able to issue new coins -The Banker API can be found under the `std` package [reference](../../reference/standard-library/std/banker.md). +The Banker API can be found under the `std` package [reference](../../reference/stdlibs/std/banker.md). diff --git a/docs/concepts/standard-library/coin.md b/docs/concepts/stdlibs/coin.md similarity index 95% rename from docs/concepts/standard-library/coin.md rename to docs/concepts/stdlibs/coin.md index db1618ef3f7..7a610866fd2 100644 --- a/docs/concepts/standard-library/coin.md +++ b/docs/concepts/stdlibs/coin.md @@ -33,4 +33,4 @@ which can manipulate them depending on access rights. [//]: # (TODO ADD LINK TO Effective GNO) Read more about coins in the [Effective Gno](https://docs.gno.land/concepts/effective-gno/#native-tokens) section. -The Coin(s) API can be found in under the `std` package [reference](../../reference/standard-library/std/coin.md). +The Coin(s) API can be found in under the `std` package [reference](../../reference/stdlibs/std/coin.md). diff --git a/docs/concepts/standard-library/gnopher-hole.md b/docs/concepts/stdlibs/gnopher-hole.md similarity index 100% rename from docs/concepts/standard-library/gnopher-hole.md rename to docs/concepts/stdlibs/gnopher-hole.md diff --git a/docs/concepts/standard-library/overview.md b/docs/concepts/stdlibs/stdlibs.md similarity index 96% rename from docs/concepts/standard-library/overview.md rename to docs/concepts/stdlibs/stdlibs.md index 6068de83f0f..ae0bb5b55bb 100644 --- a/docs/concepts/standard-library/overview.md +++ b/docs/concepts/stdlibs/stdlibs.md @@ -1,21 +1,20 @@ --- -id: overview +id: stdlibs --- -# Overview +# Standard Libraries Gno comes with a set of standard libraries which are included to ease development and provide extended functionality to the language. These include: - standard libraries as we know them in classic Go, i.e. `encoding/binary`, `strings`, `testing`, etc. - a special `std` package, which contains types, interfaces, and APIs created to handle blockchain-related functionality. - Standard libraries differ from on-chain packages in terms of their import path structure. Unlike on-chain [packages](../packages.md), standard libraries do not incorporate a domain-like format at the beginning of their import path. For example: - `import "encoding/binary"` refers to a standard library - `import "gno.land/p/demo/avl"` refers to an on-chain package. -To see concrete implementation details & API references, see the [reference](../../reference/standard-library/overview.md) section. +To see concrete implementation details & API references, see the [reference](../../reference/stdlibs/stdlibs.md) section. ## Accessing documentation diff --git a/docs/how-to-guides/simple-library.md b/docs/how-to-guides/simple-library.md index 2846117df45..1ae231251d0 100644 --- a/docs/how-to-guides/simple-library.md +++ b/docs/how-to-guides/simple-library.md @@ -141,7 +141,7 @@ There are a few things happening here, so let's dissect them: - We defined the logic of our library into a package called `tapas`. - The package imports `std`, which -is the [Gno standard library](../concepts/standard-library/overview.md) +is the [Gno standard library](../concepts/stdlibs/stdlibs.md) - We use the imported package inside of `GetTapaSuggestion` to generate a random index value for a tapa diff --git a/docs/how-to-guides/testing-gno.md b/docs/how-to-guides/testing-gno.md index d517a8c9e24..3ba734abba4 100644 --- a/docs/how-to-guides/testing-gno.md +++ b/docs/how-to-guides/testing-gno.md @@ -177,7 +177,7 @@ Luckily, the Gno standard library provides ample support for functionality such time, such as the request caller address, or the calling package address. You can learn more about these methods, that are importable using the `std` import declaration, -in the [Standard Library](../concepts/standard-library/overview.md) reference section. +in the [Standard Library](../concepts/stdlibs/stdlibs.md) reference section. ## Conclusion diff --git a/docs/reference/gnoclient/client.md b/docs/reference/gnoclient/client.md index c4d9affffd5..3f258fa683e 100644 --- a/docs/reference/gnoclient/client.md +++ b/docs/reference/gnoclient/client.md @@ -17,7 +17,15 @@ type Client struct { } ``` -### func \(\*Client\) [Call]() +### func \(\*Client\) [AddPackage]() + +```go +func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...MsgAddPackage) (*ctypes.ResultBroadcastTxCommit, error) +``` + +`AddPackage` executes one or more [AddPackage](#type-msgaddpackage) calls on the blockchain. + +### func \(\*Client\) [Call]() ```go func (c *Client) Call(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTxCommit, error) @@ -25,7 +33,7 @@ func (c *Client) Call(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTx `Call` executes a one or more [MsgCall](#type-msgcall) calls on the blockchain. -### func \(\*Client\) [Send]() +### func \(\*Client\) [Send]() ```go func (c *Client) Send(cfg BaseTxCfg, msgs ...MsgSend) (*ctypes.ResultBroadcastTxCommit, error) @@ -33,7 +41,7 @@ func (c *Client) Send(cfg BaseTxCfg, msgs ...MsgSend) (*ctypes.ResultBroadcastTx `Send` executes one or more [MsgSend](#type-msgsend) calls on the blockchain. -### func \(\*Client\) [Run]() +### func \(\*Client\) [Run]() ```go func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCommit, error) @@ -41,7 +49,7 @@ func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCo `Run` executes a one or more MsgRun calls on the blockchain. -### func \(*Client\) [QEval]() +### func \(\*Client\) [QEval]() ```go func (c *Client) QEval(pkgPath string, expression string) (string, *ctypes.ResultABCIQuery, error) @@ -101,6 +109,17 @@ type BaseTxCfg struct { } ``` +## type [MsgAddPackage]() + +`MsgAddPackage` \- syntax sugar for `vm.MsgAddPackage`. + +```go +type MsgAddPackage struct { + Package *std.MemPackage // Package to add + Deposit string // Coin deposit +} +``` + ## type [MsgCall]() `MsgCall` \- syntax sugar for `vm.MsgCall`. diff --git a/docs/reference/standard-library/std/address.md b/docs/reference/stdlibs/std/address.md similarity index 100% rename from docs/reference/standard-library/std/address.md rename to docs/reference/stdlibs/std/address.md diff --git a/docs/reference/standard-library/std/banker.md b/docs/reference/stdlibs/std/banker.md similarity index 96% rename from docs/reference/standard-library/std/banker.md rename to docs/reference/stdlibs/std/banker.md index 621a447ab84..71eb3709ea2 100644 --- a/docs/reference/standard-library/std/banker.md +++ b/docs/reference/stdlibs/std/banker.md @@ -3,7 +3,7 @@ id: banker --- # Banker -View concept page [here](../../../concepts/standard-library/banker.md). +View concept page [here](../../../concepts/stdlibs/banker.md). ```go type BankerType uint8 diff --git a/docs/reference/standard-library/std/chain.md b/docs/reference/stdlibs/std/chain.md similarity index 100% rename from docs/reference/standard-library/std/chain.md rename to docs/reference/stdlibs/std/chain.md diff --git a/docs/reference/standard-library/std/coin.md b/docs/reference/stdlibs/std/coin.md similarity index 91% rename from docs/reference/standard-library/std/coin.md rename to docs/reference/stdlibs/std/coin.md index a59e0781724..f2e1cf694b4 100644 --- a/docs/reference/standard-library/std/coin.md +++ b/docs/reference/stdlibs/std/coin.md @@ -3,7 +3,7 @@ id: coin --- # Coin -View concept page [here](../../../concepts/standard-library/coin.md). +View concept page [here](../../../concepts/stdlibs/coin.md). ```go type Coin struct { diff --git a/docs/reference/standard-library/std/coins.md b/docs/reference/stdlibs/std/coins.md similarity index 100% rename from docs/reference/standard-library/std/coins.md rename to docs/reference/stdlibs/std/coins.md diff --git a/docs/reference/standard-library/std/testing.md b/docs/reference/stdlibs/std/testing.md similarity index 100% rename from docs/reference/standard-library/std/testing.md rename to docs/reference/stdlibs/std/testing.md diff --git a/docs/reference/standard-library/overview.md b/docs/reference/stdlibs/stdlibs.md similarity index 92% rename from docs/reference/standard-library/overview.md rename to docs/reference/stdlibs/stdlibs.md index ddf921e74a0..edcd9b7b7be 100644 --- a/docs/reference/standard-library/overview.md +++ b/docs/reference/stdlibs/stdlibs.md @@ -1,8 +1,8 @@ --- -id: overview +id: stdlibs --- -# Overview +# Standard Libraries This section serves as a reference to the standard libraries available in Gno. diff --git a/examples/gno.land/p/demo/todolist/gno.mod b/examples/gno.land/p/demo/todolist/gno.mod new file mode 100644 index 00000000000..a51528b9500 --- /dev/null +++ b/examples/gno.land/p/demo/todolist/gno.mod @@ -0,0 +1,3 @@ +module gno.land/p/demo/todolist + +require gno.land/p/demo/avl v0.0.0-latest diff --git a/examples/gno.land/p/demo/todolist/todolist.gno b/examples/gno.land/p/demo/todolist/todolist.gno new file mode 100644 index 00000000000..a675344655f --- /dev/null +++ b/examples/gno.land/p/demo/todolist/todolist.gno @@ -0,0 +1,63 @@ +package todolist + +import ( + "std" + "strconv" + + "gno.land/p/demo/avl" +) + +type TodoList struct { + Title string + Tasks *avl.Tree + Owner std.Address +} + +type Task struct { + Title string + Done bool +} + +func NewTodoList(title string) *TodoList { + return &TodoList{ + Title: title, + Tasks: avl.NewTree(), + Owner: std.GetOrigCaller(), + } +} + +func NewTask(title string) *Task { + return &Task{ + Title: title, + Done: false, + } +} + +func (tl *TodoList) AddTask(id int, task *Task) { + tl.Tasks.Set(strconv.Itoa(id), task) +} + +func ToggleTaskStatus(task *Task) { + task.Done = !task.Done +} + +func (tl *TodoList) RemoveTask(taskId string) { + tl.Tasks.Remove(taskId) +} + +func (tl *TodoList) GetTasks() []*Task { + tasks := make([]*Task, 0, tl.Tasks.Size()) + tl.Tasks.Iterate("", "", func(key string, value interface{}) bool { + tasks = append(tasks, value.(*Task)) + return false + }) + return tasks +} + +func (tl *TodoList) GetTodolistOwner() std.Address { + return tl.Owner +} + +func (tl *TodoList) GetTodolistTitle() string { + return tl.Title +} diff --git a/examples/gno.land/p/demo/todolist/todolist_test.gno b/examples/gno.land/p/demo/todolist/todolist_test.gno new file mode 100644 index 00000000000..5b2bb361881 --- /dev/null +++ b/examples/gno.land/p/demo/todolist/todolist_test.gno @@ -0,0 +1,81 @@ +package todolist + +import ( + "std" + "testing" +) + +func TestNewTodoList(t *testing.T) { + title := "My Todo List" + todoList := NewTodoList(title) + + if todoList.GetTodolistTitle() != title { + t.Errorf("Expected title %q, got %q", title, todoList.GetTodolistTitle()) + } + + if len(todoList.GetTasks()) != 0 { + t.Errorf("Expected 0 tasks, got %d", len(todoList.GetTasks())) + } + + if todoList.GetTodolistOwner() != std.GetOrigCaller() { + t.Errorf("Expected owner %v, got %v", std.GetOrigCaller(), todoList.GetTodolistOwner()) + } +} + +func TestNewTask(t *testing.T) { + title := "My Task" + task := NewTask(title) + + if task.Title != title { + t.Errorf("Expected title %q, got %q", title, task.Title) + } + + if task.Done { + t.Errorf("Expected task to be not done, but it is done") + } +} + +func TestAddTask(t *testing.T) { + todoList := NewTodoList("My Todo List") + task := NewTask("My Task") + + todoList.AddTask(1, task) + + tasks := todoList.GetTasks() + if len(tasks) != 1 { + t.Errorf("Expected 1 task, got %d", len(tasks)) + } + + if tasks[0] != task { + t.Errorf("Expected task %v, got %v", task, tasks[0]) + } +} + +func TestToggleTaskStatus(t *testing.T) { + task := NewTask("My Task") + + ToggleTaskStatus(task) + + if !task.Done { + t.Errorf("Expected task to be done, but it is not done") + } + + ToggleTaskStatus(task) + + if task.Done { + t.Errorf("Expected task to be not done, but it is done") + } +} + +func TestRemoveTask(t *testing.T) { + todoList := NewTodoList("My Todo List") + task := NewTask("My Task") + todoList.AddTask(1, task) + + todoList.RemoveTask("1") + + tasks := todoList.GetTasks() + if len(tasks) != 0 { + t.Errorf("Expected 0 tasks, got %d", len(tasks)) + } +} diff --git a/examples/gno.land/r/demo/todolist/gno.mod b/examples/gno.land/r/demo/todolist/gno.mod new file mode 100644 index 00000000000..563bab74ad5 --- /dev/null +++ b/examples/gno.land/r/demo/todolist/gno.mod @@ -0,0 +1,8 @@ +module gno.land/r/demo/todolist + +require ( + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/seqid v0.0.0-latest + gno.land/p/demo/todolist v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest +) diff --git a/examples/gno.land/r/demo/todolist/todolist.gno b/examples/gno.land/r/demo/todolist/todolist.gno new file mode 100644 index 00000000000..5790aac630a --- /dev/null +++ b/examples/gno.land/r/demo/todolist/todolist.gno @@ -0,0 +1,176 @@ +package todolistrealm + +import ( + "bytes" + "strconv" + + "gno.land/p/demo/avl" + "gno.land/p/demo/seqid" + "gno.land/p/demo/todolist" + "gno.land/p/demo/ufmt" +) + +// State variables +var ( + todolistTree *avl.Tree + tlid seqid.ID +) + +// Constructor +func init() { + todolistTree = avl.NewTree() +} + +func NewTodoList(title string) (int, string) { + // Create new Todolist + tl := todolist.NewTodoList(title) + // Update AVL tree with new state + tlid.Next() + todolistTree.Set(strconv.Itoa(int(tlid)), tl) + return int(tlid), "created successfully" +} + +func AddTask(todolistID int, title string) string { + // Get Todolist from AVL tree + tl, ok := todolistTree.Get(strconv.Itoa(todolistID)) + if !ok { + panic("Todolist not found") + } + + // get the number of tasks in the todolist + id := tl.(*todolist.TodoList).Tasks.Size() + + // create the task + task := todolist.NewTask(title) + + // Cast raw data from tree into Todolist struct + tl.(*todolist.TodoList).AddTask(id, task) + + return "task added successfully" +} + +func ToggleTaskStatus(todolistID int, taskID int) string { + // Get Todolist from AVL tree + tl, ok := todolistTree.Get(strconv.Itoa(todolistID)) + if !ok { + panic("Todolist not found") + } + + // Get the task from the todolist + task, found := tl.(*todolist.TodoList).Tasks.Get(strconv.Itoa(taskID)) + if !found { + panic("Task not found") + } + + // Change the status of the task + todolist.ToggleTaskStatus(task.(*todolist.Task)) + + return "task status changed successfully" +} + +func RemoveTask(todolistID int, taskID int) string { + // Get Todolist from AVL tree + tl, ok := todolistTree.Get(strconv.Itoa(todolistID)) + if !ok { + panic("Todolist not found") + } + + // Get the task from the todolist + _, ok = tl.(*todolist.TodoList).Tasks.Get(strconv.Itoa(taskID)) + if !ok { + panic("Task not found") + } + + // Change the status of the task + tl.(*todolist.TodoList).RemoveTask(strconv.Itoa(taskID)) + + return "task status changed successfully" +} + +func RemoveTodoList(todolistID int) string { + // Get Todolist from AVL tree + _, ok := todolistTree.Get(strconv.Itoa(todolistID)) + if !ok { + panic("Todolist not found") + } + + // Remove the todolist + todolistTree.Remove(strconv.Itoa(todolistID)) + + return "Todolist removed successfully" +} + +func Render(path string) string { + if path == "" { + return renderHomepage() + } + + return "unknown page" +} + +func renderHomepage() string { + // Define empty buffer + var b bytes.Buffer + + b.WriteString("# Welcome to ToDolist\n\n") + + // If no todolists have been created + if todolistTree.Size() == 0 { + b.WriteString("### No todolists available currently!") + return b.String() + } + + // Iterate through AVL tree + todolistTree.Iterate("", "", func(key string, value interface{}) bool { + // cast raw data from tree into Todolist struct + tl := value.(*todolist.TodoList) + + // Add Todolist name + b.WriteString( + ufmt.Sprintf( + "## Todolist #%s: %s\n", + key, // Todolist ID + tl.GetTodolistTitle(), + ), + ) + + // Add Todolist owner + b.WriteString( + ufmt.Sprintf( + "#### Todolist owner : %s\n", + tl.GetTodolistOwner(), + ), + ) + + // List all todos that are currently Todolisted + if todos := tl.GetTasks(); len(todos) > 0 { + b.WriteString( + ufmt.Sprintf("Currently Todo tasks: %d\n\n", len(todos)), + ) + + for index, todo := range todos { + b.WriteString( + ufmt.Sprintf("#%d - %s ", index, todo.Title), + ) + // displays a checked box if task is marked as done, an empty box if not + if todo.Done { + b.WriteString( + "☑\n\n", + ) + continue + } + + b.WriteString( + "☐\n\n", + ) + } + } else { + b.WriteString("No tasks in this list currently\n") + } + + b.WriteString("\n") + return false + }) + + return b.String() +} diff --git a/examples/gno.land/r/demo/todolist/todolist_test.gno b/examples/gno.land/r/demo/todolist/todolist_test.gno new file mode 100644 index 00000000000..db55110851e --- /dev/null +++ b/examples/gno.land/r/demo/todolist/todolist_test.gno @@ -0,0 +1,86 @@ +package todolistrealm + +import ( + "std" + "strconv" + "testing" + + "gno.land/p/demo/todolist" +) + +var ( + node interface{} + tdl *todolist.TodoList +) + +func TestNewTodoList(t *testing.T) { + title := "My Todo List" + tlid, _ := NewTodoList(title) + if tlid != 1 { + t.Errorf("Expected tlid to be 1, but got %d", tlid) + } + + // get the todolist node from the tree + node, _ = todolistTree.Get(strconv.Itoa(tlid)) + // convert the node to a TodoList struct + tdl = node.(*todolist.TodoList) + + if tdl.Title != title { + t.Errorf("Expected title to be %s, but got %s", title, tdl.Title) + } + if tdl.Owner != std.GetOrigCaller() { + t.Errorf("Expected owner to be %s, but got %s", std.GetOrigCaller(), tdl.Owner) + } + if len(tdl.GetTasks()) != 0 { + t.Errorf("Expected no tasks in the todo list, but got %d tasks", len(tdl.GetTasks())) + } +} + +func TestAddTask(t *testing.T) { + AddTask(1, "Task 1") + + tasks := tdl.GetTasks() + if len(tasks) != 1 { + t.Errorf("Expected 1 task in the todo list, but got %d tasks", len(tasks)) + } + + if tasks[0].Title != "Task 1" { + t.Errorf("Expected task title to be 'Task 1', but got '%s'", tasks[0].Title) + } + + if tasks[0].Done { + t.Errorf("Expected task to be not done, but it is marked as done") + } +} + +func TestToggleTaskStatus(t *testing.T) { + ToggleTaskStatus(1, 0) + task := tdl.GetTasks()[0] + + if !task.Done { + t.Errorf("Expected task to be done, but it is not marked as done") + } + + ToggleTaskStatus(1, 0) + + if task.Done { + t.Errorf("Expected task to be not done, but it is marked as done") + } +} + +func TestRemoveTask(t *testing.T) { + RemoveTask(1, 0) + tasks := tdl.GetTasks() + + if len(tasks) != 0 { + t.Errorf("Expected no tasks in the todo list, but got %d tasks", len(tasks)) + } +} + +func TestRemoveTodoList(t *testing.T) { + RemoveTodoList(1) + + if todolistTree.Size() != 0 { + t.Errorf("Expected no tasks in the todo list, but got %d tasks", todolistTree.Size()) + } +} diff --git a/gno.land/cmd/gnoland/start.go b/gno.land/cmd/gnoland/start.go index 7fa7de32e5c..921fcc89640 100644 --- a/gno.land/cmd/gnoland/start.go +++ b/gno.land/cmd/gnoland/start.go @@ -5,6 +5,7 @@ import ( "errors" "flag" "fmt" + "os" "path/filepath" "strings" "time" @@ -12,6 +13,7 @@ import ( "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/gno.land/pkg/log" "github.com/gnolang/gno/gnovm/pkg/gnoenv" + "github.com/gnolang/gno/telemetry" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" "github.com/gnolang/gno/tm2/pkg/bft/config" "github.com/gnolang/gno/tm2/pkg/bft/node" @@ -36,6 +38,7 @@ type startCfg struct { chainID string genesisRemote string dataDir string + genesisMaxVMCycles int64 config string txEventStoreType string @@ -124,6 +127,13 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) { "replacement for '%%REMOTE%%' in genesis", ) + fs.Int64Var( + &c.genesisMaxVMCycles, + "genesis-max-vm-cycles", + 10_000_000, + "set maximum allowed vm cycles per operation. Zero means no limit.", + ) + fs.StringVar( &c.config, flagConfigFlag, @@ -192,6 +202,12 @@ func execStart(c *startCfg, io commands.IO) error { loadCfgErr error ) + // Attempt to initialize telemetry. If the environment variables required to initialize + // telemetry are not set, then the initialization will do nothing. + if err := initTelemetry(); err != nil { + return fmt.Errorf("error initializing telemetry: %w", err) + } + // Set the node configuration if c.nodeConfigPath != "" { // Load the node configuration @@ -246,7 +262,7 @@ func execStart(c *startCfg, io commands.IO) error { cfg.TxEventStore = txEventStoreCfg // Create application and node. - gnoApp, err := gnoland.NewApp(dataDir, c.skipFailingGenesisTxs, logger) + gnoApp, err := gnoland.NewApp(dataDir, c.skipFailingGenesisTxs, logger, c.genesisMaxVMCycles) if err != nil { return fmt.Errorf("error in creating new app: %w", err) } @@ -364,3 +380,19 @@ func getTxEventStoreConfig(c *startCfg) (*eventstorecfg.Config, error) { return cfg, nil } + +func initTelemetry() error { + var options []telemetry.Option + + if os.Getenv("TELEM_METRICS_ENABLED") == "true" { + options = append(options, telemetry.WithOptionMetricsEnabled()) + } + + // The string options can be added by default. Their absence would yield the same result + // as if the option were excluded altogether. + options = append(options, telemetry.WithOptionMeterName(os.Getenv("TELEM_METER_NAME"))) + options = append(options, telemetry.WithOptionExporterEndpoint(os.Getenv("TELEM_EXPORTER_ENDPOINT"))) + options = append(options, telemetry.WithOptionServiceName(os.Getenv("TELEM_SERVICE_NAME"))) + + return telemetry.Init(options...) +} diff --git a/gno.land/pkg/gnoclient/client_test.go b/gno.land/pkg/gnoclient/client_test.go index 044919173e8..d68a209dd26 100644 --- a/gno.land/pkg/gnoclient/client_test.go +++ b/gno.land/pkg/gnoclient/client_test.go @@ -888,3 +888,194 @@ func TestRunErrors(t *testing.T) { }) } } + +// AddPackage tests +func TestAddPackageErrors(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + client Client + cfg BaseTxCfg + msgs []MsgAddPackage + expectedError error + }{ + { + name: "Invalid Signer", + client: Client{ + Signer: nil, + RPCClient: &mockRPCClient{}, + }, + cfg: BaseTxCfg{ + GasWanted: 100000, + GasFee: "10000ugnot", + AccountNumber: 1, + SequenceNumber: 1, + Memo: "Test memo", + }, + msgs: []MsgAddPackage{ + { + Package: &std.MemPackage{ + Name: "", + Path: "", + Files: []*std.MemFile{ + { + Name: "file1.gno", + Body: "", + }, + }, + }, + Deposit: "", + }, + }, + expectedError: ErrMissingSigner, + }, + { + name: "Invalid RPCClient", + client: Client{ + &mockSigner{}, + nil, + }, + cfg: BaseTxCfg{ + GasWanted: 100000, + GasFee: "10000ugnot", + AccountNumber: 1, + SequenceNumber: 1, + Memo: "Test memo", + }, + msgs: []MsgAddPackage{}, + expectedError: ErrMissingRPCClient, + }, + { + name: "Invalid Gas Fee", + client: Client{ + Signer: &mockSigner{}, + RPCClient: &mockRPCClient{}, + }, + cfg: BaseTxCfg{ + GasWanted: 100000, + GasFee: "", + AccountNumber: 1, + SequenceNumber: 1, + Memo: "Test memo", + }, + msgs: []MsgAddPackage{ + { + Package: &std.MemPackage{ + Name: "", + Path: "", + Files: []*std.MemFile{ + { + Name: "file1.gno", + Body: "", + }, + }, + }, + Deposit: "", + }, + }, + expectedError: ErrInvalidGasFee, + }, + { + name: "Negative Gas Wanted", + client: Client{ + Signer: &mockSigner{}, + RPCClient: &mockRPCClient{}, + }, + cfg: BaseTxCfg{ + GasWanted: -1, + GasFee: "10000ugnot", + AccountNumber: 1, + SequenceNumber: 1, + Memo: "Test memo", + }, + msgs: []MsgAddPackage{ + { + Package: &std.MemPackage{ + Name: "", + Path: "", + Files: []*std.MemFile{ + { + Name: "file1.gno", + Body: "", + }, + }, + }, + Deposit: "", + }, + }, + expectedError: ErrInvalidGasWanted, + }, + { + name: "0 Gas Wanted", + client: Client{ + Signer: &mockSigner{}, + RPCClient: &mockRPCClient{}, + }, + cfg: BaseTxCfg{ + GasWanted: 0, + GasFee: "10000ugnot", + AccountNumber: 1, + SequenceNumber: 1, + Memo: "Test memo", + }, + msgs: []MsgAddPackage{ + { + Package: &std.MemPackage{ + Name: "", + Path: "", + Files: []*std.MemFile{ + { + Name: "file1.gno", + Body: "", + }, + }, + }, + Deposit: "", + }, + }, + expectedError: ErrInvalidGasWanted, + }, + { + name: "Invalid Empty Package", + client: Client{ + Signer: &mockSigner{ + info: func() keys.Info { + return &mockKeysInfo{ + getAddress: func() crypto.Address { + adr, _ := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") + return adr + }, + } + }, + }, + RPCClient: &mockRPCClient{}, + }, + cfg: BaseTxCfg{ + GasWanted: 100000, + GasFee: "10000ugnot", + AccountNumber: 1, + SequenceNumber: 1, + Memo: "Test memo", + }, + msgs: []MsgAddPackage{ + { + Package: nil, + Deposit: "", + }, + }, + expectedError: ErrEmptyPackage, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + res, err := tc.client.AddPackage(tc.cfg, tc.msgs...) + assert.Nil(t, res) + assert.ErrorIs(t, err, tc.expectedError) + }) + } +} diff --git a/gno.land/pkg/gnoclient/client_txs.go b/gno.land/pkg/gnoclient/client_txs.go index eda34c82b07..a61fa9a892d 100644 --- a/gno.land/pkg/gnoclient/client_txs.go +++ b/gno.land/pkg/gnoclient/client_txs.go @@ -23,7 +23,7 @@ var ( ErrInvalidSendAmount = errors.New("invalid send amount") ) -// BaseTxCfg defines the base transaction configuration, shared by all message types. +// BaseTxCfg defines the base transaction configuration, shared by all message types type BaseTxCfg struct { GasFee string // Gas fee GasWanted int64 // Gas wanted @@ -32,7 +32,7 @@ type BaseTxCfg struct { Memo string // Memo } -// MsgCall - syntax sugar for vm.MsgCall. +// MsgCall - syntax sugar for vm.MsgCall type MsgCall struct { PkgPath string // Package path FuncName string // Function name @@ -40,19 +40,25 @@ type MsgCall struct { Send string // Send amount } -// MsgSend - syntax sugar for bank.MsgSend. +// MsgSend - syntax sugar for bank.MsgSend type MsgSend struct { ToAddress crypto.Address // Send to address Send string // Send amount } -// MsgRun - syntax sugar for vm.MsgRun. +// MsgRun - syntax sugar for vm.MsgRun type MsgRun struct { Package *std.MemPackage // Package to run Send string // Send amount } -// Call executes a one or more MsgCall calls on the blockchain. +// MsgAddPackage - syntax sugar for vm.MsgAddPackage +type MsgAddPackage struct { + Package *std.MemPackage // Package to add + Deposit string // Coin deposit +} + +// Call executes one or more MsgCall calls on the blockchain func (c *Client) Call(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. if err := c.validateSigner(); err != nil { @@ -108,7 +114,7 @@ func (c *Client) Call(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTx return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } -// Run executes a one or more MsgRun calls on the blockchain. +// Run executes one or more MsgRun calls on the blockchain func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. if err := c.validateSigner(); err != nil { @@ -172,7 +178,7 @@ func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCo return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } -// Send executes one or more MsgSend calls on the blockchain. +// Send executes one or more MsgSend calls on the blockchain func (c *Client) Send(cfg BaseTxCfg, msgs ...MsgSend) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. if err := c.validateSigner(); err != nil { @@ -226,7 +232,68 @@ func (c *Client) Send(cfg BaseTxCfg, msgs ...MsgSend) (*ctypes.ResultBroadcastTx return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } -// signAndBroadcastTxCommit signs a transaction and broadcasts it, returning the result. +// AddPackage executes one or more AddPackage calls on the blockchain +func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...MsgAddPackage) (*ctypes.ResultBroadcastTxCommit, error) { + // Validate required client fields. + if err := c.validateSigner(); err != nil { + return nil, err + } + if err := c.validateRPCClient(); err != nil { + return nil, err + } + + // Validate base transaction config + if err := cfg.validateBaseTxConfig(); err != nil { + return nil, err + } + + // Parse MsgRun slice + vmMsgs := make([]std.Msg, 0, len(msgs)) + for _, msg := range msgs { + // Validate MsgCall fields + if err := msg.validateMsgAddPackage(); err != nil { + return nil, err + } + + // Parse deposit coins + deposit, err := std.ParseCoins(msg.Deposit) + if err != nil { + return nil, err + } + + caller := c.Signer.Info().GetAddress() + + // Transpile and validate Gno syntax + if err = transpiler.TranspileAndCheckMempkg(msg.Package); err != nil { + return nil, err + } + + // Unwrap syntax sugar to vm.MsgCall slice + vmMsgs = append(vmMsgs, std.Msg(vm.MsgAddPackage{ + Creator: caller, + Package: msg.Package, + Deposit: deposit, + })) + } + + // Parse gas fee + gasFeeCoins, err := std.ParseCoin(cfg.GasFee) + if err != nil { + return nil, err + } + + // Pack transaction + tx := std.Tx{ + Msgs: vmMsgs, + Fee: std.NewFee(cfg.GasWanted, gasFeeCoins), + Signatures: nil, + Memo: cfg.Memo, + } + + return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) +} + +// signAndBroadcastTxCommit signs a transaction and broadcasts it, returning the result func (c *Client) signAndBroadcastTxCommit(tx std.Tx, accountNumber, sequenceNumber uint64) (*ctypes.ResultBroadcastTxCommit, error) { caller := c.Signer.Info().GetAddress() diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index 554cba8ecf2..3244b32af3f 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -3,6 +3,8 @@ package gnoclient import ( "testing" + "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/gno.land/pkg/integration" @@ -351,6 +353,179 @@ func main() { assert.Equal(t, expected, string(res.DeliverTx.Data)) } +func TestAddPackageSingle_Integration(t *testing.T) { + // Set up in-memory node + config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) + node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNoopLogger(), config) + defer node.Stop() + + // Init Signer & RPCClient + signer := newInMemorySigner(t, "tendermint_test") + rpcClient := rpcclient.NewHTTP(remoteAddr, "/websocket") + + // Setup Client + client := Client{ + Signer: signer, + RPCClient: rpcClient, + } + + // Make Tx config + baseCfg := BaseTxCfg{ + GasFee: "10000ugnot", + GasWanted: 8000000, + AccountNumber: 0, + SequenceNumber: 0, + Memo: "", + } + + body := `package echo + +func Echo(str string) string { + return str +}` + + fileName := "echo.gno" + deploymentPath := "gno.land/p/demo/integration/test/echo" + deposit := "100ugnot" + + // Make Msg config + msg := MsgAddPackage{ + Package: &std.MemPackage{ + Name: "echo", + Path: deploymentPath, + Files: []*std.MemFile{ + { + Name: fileName, + Body: body, + }, + }, + }, + Deposit: deposit, + } + + // Execute AddPackage + _, err := client.AddPackage(baseCfg, msg) + assert.Nil(t, err) + + // Check for deployed file on the node + query, err := client.Query(QueryCfg{ + Path: "vm/qfile", + Data: []byte(deploymentPath), + }) + require.NoError(t, err) + assert.Equal(t, string(query.Response.Data), fileName) + + // Query balance to validate deposit + baseAcc, _, err := client.QueryAccount(gnolang.DerivePkgAddr(deploymentPath)) + require.NoError(t, err) + assert.Equal(t, baseAcc.GetCoins().String(), deposit) +} + +func TestAddPackageMultiple_Integration(t *testing.T) { + // Set up in-memory node + config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) + node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNoopLogger(), config) + defer node.Stop() + + // Init Signer & RPCClient + signer := newInMemorySigner(t, "tendermint_test") + rpcClient := rpcclient.NewHTTP(remoteAddr, "/websocket") + + // Setup Client + client := Client{ + Signer: signer, + RPCClient: rpcClient, + } + + // Make Tx config + baseCfg := BaseTxCfg{ + GasFee: "10000ugnot", + GasWanted: 8000000, + AccountNumber: 0, + SequenceNumber: 0, + Memo: "", + } + + deposit := "100ugnot" + deploymentPath1 := "gno.land/p/demo/integration/test/echo" + + body1 := `package echo + +func Echo(str string) string { + return str +}` + + deploymentPath2 := "gno.land/p/demo/integration/test/hello" + body2 := `package hello + +func Hello(str string) string { + return "Hello " + str + "!" +}` + + msg1 := MsgAddPackage{ + Package: &std.MemPackage{ + Name: "echo", + Path: deploymentPath1, + Files: []*std.MemFile{ + { + Name: "echo.gno", + Body: body1, + }, + }, + }, + Deposit: "", + } + + msg2 := MsgAddPackage{ + Package: &std.MemPackage{ + Name: "hello", + Path: deploymentPath2, + Files: []*std.MemFile{ + { + Name: "gno.mod", + Body: "module gno.land/p/demo/integration/test/hello", + }, + { + Name: "hello.gno", + Body: body2, + }, + }, + }, + Deposit: deposit, + } + + // Execute AddPackage + _, err := client.AddPackage(baseCfg, msg1, msg2) + assert.Nil(t, err) + + // Check Package #1 + query, err := client.Query(QueryCfg{ + Path: "vm/qfile", + Data: []byte(deploymentPath1), + }) + require.NoError(t, err) + assert.Equal(t, string(query.Response.Data), "echo.gno") + + // Query balance to validate deposit + baseAcc, _, err := client.QueryAccount(gnolang.DerivePkgAddr(deploymentPath1)) + require.NoError(t, err) + assert.Equal(t, baseAcc.GetCoins().String(), "") + + // Check Package #2 + query, err = client.Query(QueryCfg{ + Path: "vm/qfile", + Data: []byte(deploymentPath2), + }) + require.NoError(t, err) + assert.Contains(t, string(query.Response.Data), "hello.gno") + assert.Contains(t, string(query.Response.Data), "gno.mod") + + // Query balance to validate deposit + baseAcc, _, err = client.QueryAccount(gnolang.DerivePkgAddr(deploymentPath2)) + require.NoError(t, err) + assert.Equal(t, baseAcc.GetCoins().String(), deposit) +} + // todo add more integration tests: // MsgCall with Send field populated (single/multiple) // MsgRun with Send field populated (single/multiple) diff --git a/gno.land/pkg/gnoclient/util.go b/gno.land/pkg/gnoclient/util.go index 9860d567f1e..177e6d92906 100644 --- a/gno.land/pkg/gnoclient/util.go +++ b/gno.land/pkg/gnoclient/util.go @@ -20,6 +20,7 @@ func (msg MsgCall) validateMsgCall() error { if msg.FuncName == "" { return ErrEmptyFuncName } + return nil } @@ -31,13 +32,22 @@ func (msg MsgSend) validateMsgSend() error { if err != nil { return ErrInvalidSendAmount } + return nil } func (msg MsgRun) validateMsgRun() error { - // todo replace with msg.ValidateBasic() after PR #1646 is merged. if msg.Package == nil || len(msg.Package.Files) == 0 { return ErrEmptyPackage } + + return nil +} + +func (msg MsgAddPackage) validateMsgAddPackage() error { + if msg.Package == nil || len(msg.Package.Files) == 0 { + return ErrEmptyPackage + } + return nil } diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index 86fb6321386..f67b86fd735 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -28,16 +28,18 @@ type AppOptions struct { DB dbm.DB // `gnoRootDir` should point to the local location of the gno repository. // It serves as the gno equivalent of GOROOT. - GnoRootDir string - SkipFailingGenesisTxs bool - Logger *slog.Logger + GnoRootDir string + GenesisTxHandler GenesisTxHandler + Logger *slog.Logger + MaxCycles int64 } func NewAppOptions() *AppOptions { return &AppOptions{ - Logger: log.NewNoopLogger(), - DB: memdb.NewMemDB(), - GnoRootDir: gnoenv.RootDir(), + GenesisTxHandler: PanicOnFailingTxHandler, + Logger: log.NewNoopLogger(), + DB: memdb.NewMemDB(), + GnoRootDir: gnoenv.RootDir(), } } @@ -77,10 +79,10 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { // XXX: Embed this ? stdlibsDir := filepath.Join(cfg.GnoRootDir, "gnovm", "stdlibs") - vmKpr := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, stdlibsDir) + vmKpr := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, stdlibsDir, cfg.MaxCycles) // Set InitChainer - baseApp.SetInitChainer(InitChainer(baseApp, acctKpr, bankKpr, cfg.SkipFailingGenesisTxs)) + baseApp.SetInitChainer(InitChainer(baseApp, acctKpr, bankKpr, cfg.GenesisTxHandler)) // Set AnteHandler authOptions := auth.AnteOptions{ @@ -122,11 +124,13 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { } // NewApp creates the GnoLand application. -func NewApp(dataRootDir string, skipFailingGenesisTxs bool, logger *slog.Logger) (abci.Application, error) { +func NewApp(dataRootDir string, skipFailingGenesisTxs bool, logger *slog.Logger, maxCycles int64) (abci.Application, error) { var err error cfg := NewAppOptions() - cfg.SkipFailingGenesisTxs = skipFailingGenesisTxs + if skipFailingGenesisTxs { + cfg.GenesisTxHandler = NoopGenesisTxHandler + } // Get main DB. cfg.DB, err = dbm.NewDB("gnolang", dbm.GoLevelDBBackend, filepath.Join(dataRootDir, "data")) @@ -139,8 +143,18 @@ func NewApp(dataRootDir string, skipFailingGenesisTxs bool, logger *slog.Logger) return NewAppWithOptions(cfg) } +type GenesisTxHandler func(ctx sdk.Context, tx std.Tx, res sdk.Result) + +func NoopGenesisTxHandler(ctx sdk.Context, tx std.Tx, res sdk.Result) {} + +func PanicOnFailingTxHandler(ctx sdk.Context, tx std.Tx, res sdk.Result) { + if res.IsErr() { + panic(res.Log) + } +} + // InitChainer returns a function that can initialize the chain with genesis. -func InitChainer(baseApp *sdk.BaseApp, acctKpr auth.AccountKeeperI, bankKpr bank.BankKeeperI, skipFailingGenesisTxs bool) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain { +func InitChainer(baseApp *sdk.BaseApp, acctKpr auth.AccountKeeperI, bankKpr bank.BankKeeperI, resHandler GenesisTxHandler) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { // Get genesis state. genState := req.AppState.(GnoGenesisState) @@ -153,21 +167,20 @@ func InitChainer(baseApp *sdk.BaseApp, acctKpr auth.AccountKeeperI, bankKpr bank panic(err) } } + // Run genesis txs. for i, tx := range genState.Txs { res := baseApp.Deliver(tx) if res.IsErr() { ctx.Logger().Error("LOG", "log", res.Log) ctx.Logger().Error(fmt.Sprintf("#%d", i), "value", string(amino.MustMarshalJSON(tx))) - - // NOTE: comment out to ignore. - if !skipFailingGenesisTxs { - panic(res.Log) - } } else { ctx.Logger().Info("SUCCESS:", "value", string(amino.MustMarshalJSON(tx))) } + + resHandler(ctx, tx, res) } + // Done! return abci.ResponseInitChain{ Validators: req.Validators, diff --git a/gno.land/pkg/gnoland/node_inmemory.go b/gno.land/pkg/gnoland/node_inmemory.go index d8dc3caa485..d48d0e2ab47 100644 --- a/gno.land/pkg/gnoland/node_inmemory.go +++ b/gno.land/pkg/gnoland/node_inmemory.go @@ -21,10 +21,11 @@ import ( ) type InMemoryNodeConfig struct { - PrivValidator bft.PrivValidator // identity of the validator - Genesis *bft.GenesisDoc - TMConfig *tmcfg.Config - SkipFailingGenesisTxs bool + PrivValidator bft.PrivValidator // identity of the validator + Genesis *bft.GenesisDoc + TMConfig *tmcfg.Config + GenesisTxHandler GenesisTxHandler + GenesisMaxVMCycles int64 } // NewMockedPrivValidator generate a new key @@ -78,9 +79,11 @@ func NewDefaultInMemoryNodeConfig(rootdir string) *InMemoryNodeConfig { } return &InMemoryNodeConfig{ - PrivValidator: pv, - TMConfig: tm, - Genesis: genesis, + PrivValidator: pv, + TMConfig: tm, + Genesis: genesis, + GenesisTxHandler: PanicOnFailingTxHandler, + GenesisMaxVMCycles: 10_000_000, } } @@ -97,6 +100,10 @@ func (cfg *InMemoryNodeConfig) validate() error { return fmt.Errorf("`TMConfig.RootDir` is required to locate `stdlibs` directory") } + if cfg.GenesisTxHandler == nil { + return fmt.Errorf("`GenesisTxHandler` is required but not provided") + } + return nil } @@ -110,10 +117,11 @@ func NewInMemoryNode(logger *slog.Logger, cfg *InMemoryNodeConfig) (*node.Node, // Initialize the application with the provided options gnoApp, err := NewAppWithOptions(&AppOptions{ - Logger: logger, - GnoRootDir: cfg.TMConfig.RootDir, - SkipFailingGenesisTxs: cfg.SkipFailingGenesisTxs, - DB: memdb.NewMemDB(), + Logger: logger, + GnoRootDir: cfg.TMConfig.RootDir, + GenesisTxHandler: cfg.GenesisTxHandler, + MaxCycles: cfg.GenesisMaxVMCycles, + DB: memdb.NewMemDB(), }) if err != nil { return nil, fmt.Errorf("error initializing new app: %w", err) diff --git a/gno.land/pkg/integration/testing_node.go b/gno.land/pkg/integration/testing_node.go index 106c5b14bb8..16b23b6565c 100644 --- a/gno.land/pkg/integration/testing_node.go +++ b/gno.land/pkg/integration/testing_node.go @@ -71,9 +71,10 @@ func TestingMinimalNodeConfig(t TestingTS, gnoroot string) *gnoland.InMemoryNode genesis := DefaultTestingGenesisConfig(t, gnoroot, pv.GetPubKey(), tmconfig) return &gnoland.InMemoryNodeConfig{ - PrivValidator: pv, - Genesis: genesis, - TMConfig: tmconfig, + PrivValidator: pv, + Genesis: genesis, + TMConfig: tmconfig, + GenesisTxHandler: gnoland.PanicOnFailingTxHandler, } } diff --git a/gno.land/pkg/sdk/vm/common_test.go b/gno.land/pkg/sdk/vm/common_test.go index ec14ae8515b..b65757da403 100644 --- a/gno.land/pkg/sdk/vm/common_test.go +++ b/gno.land/pkg/sdk/vm/common_test.go @@ -39,7 +39,7 @@ func setupTestEnv() testEnv { acck := authm.NewAccountKeeper(iavlCapKey, std.ProtoBaseAccount) bank := bankm.NewBankKeeper(acck) stdlibsDir := filepath.Join("..", "..", "..", "..", "gnovm", "stdlibs") - vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, stdlibsDir) + vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, stdlibsDir, 10_000_000) vmk.Initialize(ms.MultiCacheWrap()) diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index af794fb9b1f..67710be620c 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -22,11 +22,6 @@ import ( const ( maxAllocTx = 500 * 1000 * 1000 maxAllocQuery = 1500 * 1000 * 1000 // higher limit for queries - - // maxVMCycles is the maximum number of cycles allowed while executing a single VM - // message. Ideally this should not be needed, as execution should halt when out of - // gas. The worst case scenario is that this value is used as a fallback. - maxVMCycles = 10_000_000 ) // vm.VMKeeperI defines a module interface that supports Gno @@ -60,6 +55,7 @@ func NewVMKeeper( acck auth.AccountKeeper, bank bank.BankKeeper, stdlibsDir string, + maxCycles int64, ) *VMKeeper { // TODO: create an Options struct to avoid too many constructor parameters vmk := &VMKeeper{ @@ -68,7 +64,7 @@ func NewVMKeeper( acck: acck, bank: bank, stdlibsDir: stdlibsDir, - maxCycles: maxVMCycles, + maxCycles: maxCycles, } return vmk } diff --git a/gnovm/pkg/gnolang/gno_test.go b/gnovm/pkg/gnolang/gno_test.go index e67d4a7024d..7881ddd1601 100644 --- a/gnovm/pkg/gnolang/gno_test.go +++ b/gnovm/pkg/gnolang/gno_test.go @@ -17,6 +17,92 @@ import ( "github.com/jaekwon/testify/require" ) +func TestRunInvalidLabels(t *testing.T) { + tests := []struct { + code string + output string + }{ + { + code: ` + package test + func main(){} + func invalidLabel() { + FirstLoop: + for i := 0; i < 10; i++ { + } + for i := 0; i < 10; i++ { + break FirstLoop + } + } +`, + output: `cannot find branch label "FirstLoop"`, + }, + { + code: ` + package test + func main(){} + + func undefinedLabel() { + for i := 0; i < 10; i++ { + break UndefinedLabel + } + } +`, + output: `label UndefinedLabel undefined`, + }, + { + code: ` + package test + func main(){} + + func labelOutsideScope() { + for i := 0; i < 10; i++ { + continue FirstLoop + } + FirstLoop: + for i := 0; i < 10; i++ { + } + } +`, + output: `cannot find branch label "FirstLoop"`, + }, + { + code: ` + package test + func main(){} + + func invalidLabelStatement() { + if true { + break InvalidLabel + } + } +`, + output: `label InvalidLabel undefined`, + }, + } + + for n, s := range tests { + n := n + t.Run(fmt.Sprintf("%v\n", n), func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + es := fmt.Sprintf("%v\n", r) + if !strings.Contains(es, s.output) { + t.Fatalf("invalid label test: `%v` missing expected error: %+v got: %v\n", n, s.output, es) + } + } else { + t.Fatalf("invalid label test: `%v` should have failed but didn't\n", n) + } + }() + + m := NewMachine("test", nil) + nn := MustParseFile("main.go", s.code) + m.RunFiles(nn) + m.RunMain() + }) + } +} + func TestBuiltinIdentifiersShadowing(t *testing.T) { t.Parallel() tests := map[string]string{} diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 4cd39858300..f73a5c58962 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -129,7 +129,7 @@ func (ds *defaultStore) Go2GnoType(rt reflect.Type) (t Type) { // for methods with ptr receivers, // whereas gno methods are all // declared on the *DeclaredType. - prt = reflect.PtrTo(rt) + prt = reflect.PointerTo(rt) } nm := prt.NumMethod() mtvs = make([]TypedValue, nm) @@ -825,7 +825,7 @@ func gno2GoType(t Type) reflect.Type { } case *PointerType: et := gno2GoType(ct.Elem()) - return reflect.PtrTo(et) + return reflect.PointerTo(et) case *ArrayType: ne := ct.Len et := gno2GoType(ct.Elem()) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 8f2c5054a8a..5d430a8bcde 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -158,6 +158,23 @@ type Attributes struct { data map[interface{}]interface{} // not persisted } +func (attr *Attributes) Copy() Attributes { + if attr == nil { + return Attributes{} + } + + data := make(map[interface{}]interface{}) + for k, v := range attr.data { + data[k] = v + } + + return Attributes{ + Line: attr.Line, + Label: attr.Label, + data: data, + } +} + func (attr *Attributes) GetLine() int { return attr.Line } @@ -1614,7 +1631,7 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath { bp = bp.GetParentNode(store) gen++ if 0xff < gen { - panic("value path depth overflow") + panic("GetPathForName: value path depth overflow") } } } diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index 9162a710d7d..99b56c18a06 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -475,7 +475,13 @@ func isEql(store Store, lv, rv *TypedValue) bool { rfv.GetClosure(store) } case PointerKind: - // TODO: assumes runtime instance normalization. + if lv.V != nil && rv.V != nil { + lpv := lv.V.(PointerValue) + rpv := rv.V.(PointerValue) + if lpv.TV.T == DataByteType && rpv.TV.T == DataByteType { + return *(lpv.TV) == *(rpv.TV) && lpv.Base == rpv.Base && lpv.Index == rpv.Index && lpv.Key == rpv.Key + } + } return lv.V == rv.V default: panic(fmt.Sprintf( diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index b3bf240aea1..2efcc41fdce 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -147,7 +147,7 @@ func (m *Machine) doOpStar() { case *PointerType: pv := xv.V.(PointerValue) if pv.TV.T == DataByteType { - tv := TypedValue{T: xv.T.(*PointerType).Elt} + tv := TypedValue{T: bt.Elt} dbv := pv.TV.V.(DataByteValue) tv.SetUint8(dbv.GetByte()) m.PushValue(tv) @@ -163,7 +163,7 @@ func (m *Machine) doOpStar() { t := xv.GetType() var pt Type if nt, ok := t.(*NativeType); ok { - pt = &NativeType{Type: reflect.PtrTo(nt.Type)} + pt = &NativeType{Type: reflect.PointerTo(nt.Type)} } else { pt = &PointerType{Elt: t} } diff --git a/gnovm/pkg/gnolang/op_types.go b/gnovm/pkg/gnolang/op_types.go index a38010bac4e..904b74fd1a9 100644 --- a/gnovm/pkg/gnolang/op_types.go +++ b/gnovm/pkg/gnolang/op_types.go @@ -405,7 +405,7 @@ func (m *Machine) doOpStaticTypeOf() { "VPNative access on pointer to non-native value %v", pt.Elt)) } dxt = &NativeType{ - Type: reflect.PtrTo(net.Type), + Type: reflect.PointerTo(net.Type), } } // switch on type and maybe match field. @@ -431,10 +431,10 @@ func (m *Machine) doOpStaticTypeOf() { return } // make rt ptr. - rt = reflect.PtrTo(rt) + rt = reflect.PointerTo(rt) } else { // make rt ptr. - rt = reflect.PtrTo(rt) + rt = reflect.PointerTo(rt) } // match method. rmt, ok := rt.MethodByName(string(x.Sel)) @@ -467,7 +467,7 @@ func (m *Machine) doOpStaticTypeOf() { m.PushOp(OpStaticTypeOf) m.Run() // XXX replace xt := m.ReapValues(start)[0].V.(TypeValue).Type - if pt, ok := xt.(*PointerType); ok { + if pt, ok := baseOf(xt).(*PointerType); ok { m.PushValue(asValue(&SliceType{ Elt: pt.Elt.Elem(), })) @@ -485,7 +485,7 @@ func (m *Machine) doOpStaticTypeOf() { m.PushOp(OpStaticTypeOf) m.Run() // XXX replace xt := m.ReapValues(start)[0].GetType() - if pt, ok := xt.(*PointerType); ok { + if pt, ok := baseOf(xt).(*PointerType); ok { m.PushValue(asValue(pt.Elt)) } else if _, ok := xt.(*TypeType); ok { m.PushValue(asValue(gTypeType)) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index dcb1b0856ca..029641f2507 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -13,11 +13,21 @@ import ( // Anything predefined or preprocessed here get skipped during the Preprocess // phase. func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { + for _, fn := range fset.Files { + decls, err := sortValueDeps(fn.Decls) + if err != nil { + panic(err) + } + + fn.Decls = decls + } + // First, initialize all file nodes and connect to package node. for _, fn := range fset.Files { SetNodeLocations(pn.PkgPath, string(fn.Name), fn) fn.InitStaticBlock(fn, pn) } + // NOTE: much of what follows is duplicated for a single *FileNode // in the main Preprocess translation function. Keep synced. @@ -29,11 +39,7 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { d := fn.Decls[i] switch d.(type) { case *ImportDecl: - if d.GetAttribute(ATTR_PREDEFINED) == true { - // skip declarations already predefined - // (e.g. through recursion for a - // dependent) - } else { + if d.GetAttribute(ATTR_PREDEFINED) != true { // recursively predefine dependencies. d2, _ := predefineNow(store, fn, d) fn.Decls[i] = d2 @@ -41,17 +47,14 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { } } } + // Predefine all type decls decls. for _, fn := range fset.Files { for i := 0; i < len(fn.Decls); i++ { d := fn.Decls[i] switch d.(type) { case *TypeDecl: - if d.GetAttribute(ATTR_PREDEFINED) == true { - // skip declarations already predefined - // (e.g. through recursion for a - // dependent) - } else { + if d.GetAttribute(ATTR_PREDEFINED) != true { // recursively predefine dependencies. d2, _ := predefineNow(store, fn, d) fn.Decls[i] = d2 @@ -65,11 +68,7 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { d := fn.Decls[i] switch d.(type) { case *FuncDecl: - if d.GetAttribute(ATTR_PREDEFINED) == true { - // skip declarations already predefined - // (e.g. through recursion for a - // dependent) - } else { + if d.GetAttribute(ATTR_PREDEFINED) != true { // recursively predefine dependencies. d2, _ := predefineNow(store, fn, d) fn.Decls[i] = d2 @@ -77,15 +76,13 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { } } } + // Finally, predefine other decls and // preprocess ValueDecls.. for _, fn := range fset.Files { for i := 0; i < len(fn.Decls); i++ { d := fn.Decls[i] - if d.GetAttribute(ATTR_PREDEFINED) == true { - // skip declarations already predefined (e.g. - // through recursion for a dependent) - } else { + if d.GetAttribute(ATTR_PREDEFINED) != true { // recursively predefine dependencies. d2, _ := predefineNow(store, fn, d) fn.Decls[i] = d2 @@ -492,7 +489,14 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { last.Define(Name(rn), anyValue(rf.Type)) } } - + // functions that don't return a value do not need termination analysis + // functions that are externally defined or builtin implemented in the vm can't be analysed + if len(ft.Results) > 0 && lastpn.PkgPath != uversePkgPath && n.Body != nil { + errs := Analyze(n) + if len(errs) > 0 { + panic(fmt.Sprintf("%+v\n", errs)) + } + } // TRANS_BLOCK ----------------------- case *FileNode: // only for imports. @@ -1659,7 +1663,14 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { case *BranchStmt: switch n.Op { case BREAK: + if !isSwitchLabel(ns, n.Label) { + findBranchLabel(last, n.Label) + } case CONTINUE: + if isSwitchLabel(ns, n.Label) { + panic(fmt.Sprintf("invalid continue label %q\n", n.Label)) + } + findBranchLabel(last, n.Label) case GOTO: _, depth, index := findGotoLabel(last, n.Label) n.Depth = depth @@ -1977,6 +1988,23 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { return nn } +func isSwitchLabel(ns []Node, label Name) bool { + for { + swch := lastSwitch(ns) + if swch == nil { + break + } + + if swch.GetLabel() == label && label != "" { + return true + } + + ns = ns[:len(ns)-1] + } + + return false +} + func pushInitBlock(bn BlockNode, last *BlockNode, stack *[]BlockNode) { if !bn.IsInitialized() { bn.InitStaticBlock(bn, *last) @@ -2245,6 +2273,46 @@ func funcOf(last BlockNode) (BlockNode, *FuncTypeExpr) { } } +func findBranchLabel(last BlockNode, label Name) ( + bn BlockNode, depth uint8, bodyIdx int, +) { + for { + switch cbn := last.(type) { + case *BlockStmt, *ForStmt, *IfCaseStmt, *RangeStmt, *SelectCaseStmt, *SwitchClauseStmt, *SwitchStmt: + lbl := cbn.GetLabel() + if label == lbl { + bn = cbn + return + } + last = cbn.GetParentNode(nil) + depth += 1 + case *IfStmt: + // These are faux blocks -- shouldn't happen. + panic("unexpected faux blocknode") + case *FileNode: + panic("unexpected file blocknode") + case *PackageNode: + panic("unexpected package blocknode") + case *FuncLitExpr: + body := cbn.GetBody() + _, bodyIdx = body.GetLabeledStmt(label) + if bodyIdx != -1 { + bn = cbn + return + } + panic(fmt.Sprintf( + "cannot find branch label %q", + label)) + case *FuncDecl: + panic(fmt.Sprintf( + "cannot find branch label %q", + label)) + default: + panic("unexpected block node") + } + } +} + func findGotoLabel(last BlockNode, label Name) ( bn BlockNode, depth uint8, bodyIdx int, ) { @@ -2453,7 +2521,7 @@ func checkType(xt Type, dt Type, autoNative bool) { nidt.String())) } // if xt has native base, do the naive native. - if reflect.PtrTo(nxt.Type).AssignableTo(nidt) { + if reflect.PointerTo(nxt.Type).AssignableTo(nidt) { return // ok } else { panic(fmt.Sprintf( @@ -2474,11 +2542,11 @@ func checkType(xt Type, dt Type, autoNative bool) { // Special case if xt or dt is *PointerType to *NativeType, // convert to *NativeType of pointer kind. if pxt, ok := xt.(*PointerType); ok { - // *gonative{x} is gonative{*x} + // *gonative{x} is(to) gonative{*x} //nolint:misspell if enxt, ok := pxt.Elt.(*NativeType); ok { xt = &NativeType{ - Type: reflect.PtrTo(enxt.Type), + Type: reflect.PointerTo(enxt.Type), } } } @@ -2486,7 +2554,7 @@ func checkType(xt Type, dt Type, autoNative bool) { // *gonative{x} is gonative{*x} if endt, ok := pdt.Elt.(*NativeType); ok { dt = &NativeType{ - Type: reflect.PtrTo(endt.Type), + Type: reflect.PointerTo(endt.Type), } } } @@ -2957,11 +3025,32 @@ func predefineNow2(store Store, last BlockNode, d Decl, m map[Name]struct{}) (De ft := evalStaticType(store, last, &cd.Type).(*FuncType) ft = ft.UnboundType(rft) dt := (*DeclaredType)(nil) + + // check base type of receiver type, should not be pointer type or interface type + assertValidReceiverType := func(t Type) { + if _, ok := t.(*PointerType); ok { + panic(fmt.Sprintf("invalid receiver type %v (base type is pointer type)\n", rt)) + } + if _, ok := t.(*InterfaceType); ok { + panic(fmt.Sprintf("invalid receiver type %v (base type is interface type)\n", rt)) + } + } + if pt, ok := rt.(*PointerType); ok { - dt = pt.Elem().(*DeclaredType) + assertValidReceiverType(pt.Elem()) + if ddt, ok := pt.Elem().(*DeclaredType); ok { + assertValidReceiverType(baseOf(ddt)) + dt = ddt + } else { + panic("should not happen") + } + } else if ddt, ok := rt.(*DeclaredType); ok { + assertValidReceiverType(baseOf(ddt)) + dt = ddt } else { - dt = rt.(*DeclaredType) + panic("should not happen") } + if !dt.TryDefineMethod(&FuncValue{ Type: ft, IsMethod: true, @@ -3100,6 +3189,8 @@ func tryPredefine(store Store, last BlockNode, d Decl) (un Name) { t = &MapType{} case *StructTypeExpr: t = &StructType{} + case *StarExpr: + t = &PointerType{} case *NameExpr: if tv := last.GetValueRef(store, tx.Name); tv != nil { // (file) block name diff --git a/gnovm/pkg/gnolang/static_analysis.go b/gnovm/pkg/gnolang/static_analysis.go new file mode 100644 index 00000000000..311a0d42feb --- /dev/null +++ b/gnovm/pkg/gnolang/static_analysis.go @@ -0,0 +1,230 @@ +package gnolang + +import ( + "fmt" +) + +type staticAnalysis struct { + // contexts for switch, for, functions, and lambdas + contexts []interface{} + + // here we accumulate errors + // from lambdas defined in the function declaration + errs []error +} + +func newStaticAnalysis() *staticAnalysis { + return &staticAnalysis{ + contexts: make([]interface{}, 0), + errs: make([]error, 0), + } +} + +func Analyze(f *FuncDecl) []error { + s := newStaticAnalysis() + s.push(&FuncDeclContext{ + hasRet: false, + f: f, + }) + term := s.staticAnalysisBlockStmt(f.Body) + + errs := make([]error, 0) + if !term { + errs = append(errs, fmt.Errorf("function %q does not terminate", f.Name)) + } + + errs = append(errs, s.errs...) + + return errs +} + +func (s *staticAnalysis) push(ctx interface{}) { + s.contexts = append(s.contexts, ctx) +} + +func (s *staticAnalysis) pop() interface{} { + if len(s.contexts) == 0 { + return nil + } + last := s.contexts[len(s.contexts)-1] + s.contexts = s.contexts[:len(s.contexts)-1] + return last +} + +// findCtxByLabel returns the last context if the label is empty +// otherwise it returns the context that matches the label +// if it doesn't exist, it returns nil +func (s *staticAnalysis) findCtxByLabel(label string) interface{} { + if len(label) == 0 { + if len(s.contexts) > 0 { + return s.contexts[len(s.contexts)-1] + } + return nil + } + + for i := len(s.contexts) - 1; i >= 0; i-- { + if ctx, ok := s.contexts[i].(contextLabeler); ok && ctx.label() == label { + return s.contexts[i] + } + } + + return nil +} + +func (s *staticAnalysis) staticAnalysisBlockStmt(stmts []Stmt) bool { + if len(stmts) == 0 { + return false + } + return s.staticAnalysisStmt(stmts[len(stmts)-1]) +} + +func (s *staticAnalysis) staticAnalysisExpr(expr Expr) bool { + switch n := expr.(type) { + case *CallExpr: + for _, arg := range n.Args { + term := s.staticAnalysisExpr(arg) + if !term { + return false + } + } + case *FuncLitExpr: + s.push(&FuncLitContext{ + hasRet: false, + f: n, + }) + term := s.staticAnalysisBlockStmt(n.Body) + if !term { + ctx := s.pop().(*FuncLitContext) + s.errs = append(s.errs, fmt.Errorf("lambda at %v does not terminate", ctx.f.Loc)) + } + return false + case *NameExpr: + return false + } + return false +} + +// staticAnalysisStmt returns a boolean value, +// indicating whether a statement is terminating or not +func (s *staticAnalysis) staticAnalysisStmt(stmt Stmt) bool { + switch n := stmt.(type) { + case *BranchStmt: + switch n.Op { + case BREAK: + ctx := s.findCtxByLabel(string(n.Label)) + if ctx != nil { + if c, ok := ctx.(breakPusher); ok { + c.pushBreak(n) + } + } + case CONTINUE: + // + case DEFAULT: + // + case FALLTHROUGH: + return true + } + case *IfStmt: + terminates := s.staticAnalysisBlockStmt(n.Then.Body) + + var elseTerminates bool + if len(n.Else.Body) > 0 { + elseTerminates = s.staticAnalysisBlockStmt(n.Else.Body) + } + + return terminates && elseTerminates + case *ForStmt: + s.push(&ForContext{forstmt: n}) + _ = s.staticAnalysisBlockStmt(n.Body) + ctx := s.pop().(*ForContext) + // there are no "break" statements referring to the "for" statement + hasNoBreaks := len(ctx.breakstmts) == 0 + // the loop condition is absent + hasNoCond := n.Cond == nil + terminates := hasNoBreaks && hasNoCond + return terminates + case *ReturnStmt: + return true + case *AssignStmt: + for _, rh := range n.Rhs { + term := s.staticAnalysisExpr(rh) + if !term { + return false + } + } + return false + case *SwitchStmt: + // there is a default case, and + var hasDefault bool + for _, clause := range n.Clauses { + // nil case means default + if clause.Cases == nil { + hasDefault = true + break + } + } + s.push(&SwitchContext{switchStmt: n}) + + // the statement lists in each case, + // including the default + // end in a terminating statement, + // or a possibly labeled "fallthrough" statement. + casesTerm := true + for _, clause := range n.Clauses { + ct := s.staticAnalysisBlockStmt(clause.Body) + casesTerm = ct + } + ctx := s.pop().(*SwitchContext) + // there are no "break" statements referring to the "switch" statement + hasNoBreaks := len(ctx.breakstmts) == 0 + terminates := hasNoBreaks && hasDefault && casesTerm + return terminates + case *PanicStmt: + return true + } + return false +} + +type contextLabeler interface { + label() string +} + +type breakPusher interface { + pushBreak(breakstmt *BranchStmt) +} + +type FuncLitContext struct { + hasRet bool + f *FuncLitExpr +} + +type FuncDeclContext struct { + hasRet bool + f *FuncDecl +} + +type ForContext struct { + forstmt *ForStmt + breakstmts []*BranchStmt +} + +func (fc *ForContext) label() string { + return string(fc.forstmt.Label) +} + +func (fc *ForContext) pushBreak(breakstmt *BranchStmt) { + fc.breakstmts = append(fc.breakstmts, breakstmt) +} + +type SwitchContext struct { + switchStmt *SwitchStmt + breakstmts []*BranchStmt +} + +func (sc *SwitchContext) label() string { + return string(sc.switchStmt.Label) +} + +func (sc *SwitchContext) pushBreak(breakstmt *BranchStmt) { + sc.breakstmts = append(sc.breakstmts, breakstmt) +} diff --git a/gnovm/pkg/gnolang/static_analysis_test.go b/gnovm/pkg/gnolang/static_analysis_test.go new file mode 100644 index 00000000000..00c3d4febc6 --- /dev/null +++ b/gnovm/pkg/gnolang/static_analysis_test.go @@ -0,0 +1,417 @@ +package gnolang + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestStaticAnalysisShouldPanic(t *testing.T) { + cases := []struct { + name string + code string + }{ + { + name: "Test Case 1", + code: `package test + func main() { + invalidSwitch() + } + func invalidSwitch() int { + mockVar := map[string]int{ + "apple": 10, + "banana": 20, + "orange": 30, + "mango": 5, + "watermelon": 15, + } + + for k, v := range mockVar { + switch k { + case "apple": + if v < 50 { + return v + } else { + return 50 + } + case "banana": + if v > 10 { + return v + } else { + return 10 + } + case "orange": + if v > 30 { + } else { + return 30 + } + case "mango": + if v == 5 { + return v + } else { + return 5 + } + case "watermelon": + if v == 15 { + return v + } else { + return 15 + } + default: + return 0 + } + } + } + `, + }, + { + name: "Test Case 2", + code: `package test + func main() { + + } + + func invalidLabel() int{ + Outer: + for { + for { + break Outer + } + } + } + `, + }, + { + name: "Test Case 3", + code: `package test + func main() { + oddOrEven(3) + } + + func oddOrEven(x int) bool { + for i := 0; i < x; i++ { + if x%2 == 0 { + + } else { + return false + } + } + } + `, + }, + { + name: "Test Case 4", + code: `package test + func main() { + sumArr([]int{1,1,1}) + } + + func sumArr(x []int) int { + sum := 0 + for _, s := range x { + sum = sum + s + } + } + `, + }, + { + name: "Test Case 5", + code: `package test + func main() { + invalidSwitch(3) + } + + func invalidSwitch(x int) int { + switch x { + case 1: + return 1 + case 2: + return 2 + } + } + `, + }, + { + name: "Test Case 6", + code: `package test + func main() { + invalidCompareBool(4,5) + } + + func invalidCompareBool(a, b int) bool { + if a > b { + return true + } else { + } + } + `, + }, + { + name: "Test Case 7", + code: `package test + func main() { + invalidIfStatement(6) + } + + func invalidIfStatement(x int) int { + if x > 5 { + + } else { + return x + } + } + `, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + testFunc := func() { + m := NewMachine("test", nil) + + n := MustParseFile("main.go", tc.code) + m.RunFiles(n) + m.RunMain() + } + + assert.Panics(t, testFunc, "The code did not panic") + }) + } +} + +func TestStaticAnalysisShouldPass(t *testing.T) { + testCases := []struct { + name string + code string + }{ + { + name: "Test Case 1", + code: `package test + func main() { + first := a() + } + + func a() int { + x := 9 + return 9 + } + `, + }, + { + name: "Test Case 2", + code: `package test + func main() { + validLabel() + } + + func validLabel() int{ + OuterLoop: + for i := 0; i < 10; i++ { + for j := 0; j < 10; j++ { + break OuterLoop + } + } + return 0 + } + `, + }, + { + name: "Test Case 3", + code: `package test + func main() { + fruitStall() + + } + + func fruitStall() int { + mockVar := map[string]int{ + "apple": 10, + "banana": 20, + "orange": 30, + "mango": 5, + "watermelon": 15, + } + + for k, v := range mockVar { + switch k { + case "apple": + if v < 50 { + return(v) + } else { + return(50) + } + case "banana": + if v > 10 { + return(v) + } else { + return(10) + } + case "orange": + if v > 30 { + return(v) + } else { + return(30) + } + case "mango": + if v == 5 { + return(v) + } else { + return(5) + } + case "watermelon": + if v == 15 { + return(v) + } else { + return(15) + } + default: + return 0 + } + } + return 0 + } + `, + }, + { + name: "Test Case 4", + code: ` + package test + func main() { + whichDay() + } + func whichDay() string{ + dayOfWeek := 3 + + switch dayOfWeek { + + case 1: + return "Sunday" + + case 2: + return "Monday" + + case 3: + return "Tuesday" + + case 4: + return "Wednesday" + + case 5: + return "Thursday" + + case 6: + return "Friday" + + case 7: + return "Saturday" + + default: + return "Invalid day" + } + return "Not a day" + } + + `, + }, + { + name: "Test Case 5", + code: `package test + func main() { + switchLabel() + } + + func switchLabel() int{ + SwitchStatement: + switch 1 { + case 1: + return 1 + for i := 0; i < 10; i++ { + break SwitchStatement + } + return 2 + } + return 3 + } + `, + }, + { + name: "Test Case 6", + code: ` + package test + func main() { + add(1,1) + } + func add(a, b int) int { + return a + b + }`, + }, + { + name: "Test Case 7", + code: `package test + func main() { + z := y() + } + + func y() int{ + x := 9 + return 9 + } + `, + }, + { + name: "Test Case 8", + code: `package test + func main() { + isEqual(2,2) + } + func isEqual(a, b int) bool { + if a == b { + return true + } + return false + } + `, + }, + { + name: "Test Case 9", + code: ` + package test + func main() { + f(2) + } + func f(a int) int { + switch a { + case 1: + return 1 + default: + return 0 + } + } + `, + }, + { + name: "Test Case 10", + code: ` + package test + func main() { + f(0) + } + func f(a int) int { + if a > 0 { + return 1 + } else { + return 0 + } + } + `, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + m := NewMachine("test", nil) + n := MustParseFile("main.go", tc.code) + m.RunFiles(n) + m.RunMain() + }) + } +} diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index 34565b7a1b6..e1814e8f243 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -696,7 +696,7 @@ func (pt *PointerType) FindEmbeddedFieldType(callerPath string, n Name, m map[Ty } case *NativeType: npt := &NativeType{ - Type: reflect.PtrTo(cet.Type), + Type: reflect.PointerTo(cet.Type), } return npt.FindEmbeddedFieldType(n, m) default: diff --git a/gnovm/pkg/gnolang/value_decl_dep_graph.go b/gnovm/pkg/gnolang/value_decl_dep_graph.go new file mode 100644 index 00000000000..fe130dbf43a --- /dev/null +++ b/gnovm/pkg/gnolang/value_decl_dep_graph.go @@ -0,0 +1,245 @@ +package gnolang + +import ( + "fmt" + "slices" + "strings" +) + +// sortValueDeps creates a new topologically sorted +// decl slice ready for processing in order +func sortValueDeps(decls Decls) (Decls, error) { + graph := &graph{ + edges: make(map[string][]string), + vertices: make([]string, 0), + } + + otherDecls := make(Decls, 0) + + for i := 0; i < len(decls); i++ { + d := decls[i] + vd, ok := d.(*ValueDecl) + + if !ok { + otherDecls = append(otherDecls, d) + continue + } + + if isTuple(vd) { + _, ok := vd.Values[0].(*CallExpr) + if ok { + graph.addVertex(vd.NameExprs.String()) + continue + } + } + + for j := 0; j < len(vd.NameExprs); j++ { + graph.addVertex(string(vd.NameExprs[j].Name)) + } + } + + for i := 0; i < len(decls); i++ { + d := decls[i] + vd, ok := d.(*ValueDecl) + + if !ok { + continue + } + + if isTuple(vd) { + ce, ok := vd.Values[0].(*CallExpr) + if ok { + addDepFromExpr(graph, vd.NameExprs.String(), ce) + continue + } + } + + for j := 0; j < len(vd.NameExprs); j++ { + if len(vd.Values) > j { + addDepFromExpr(graph, string(vd.NameExprs[j].Name), vd.Values[j]) + } + } + } + + sorted := make(Decls, 0) + + for _, node := range graph.topologicalSort() { + var dd Decl + + for _, decl := range decls { + vd, ok := decl.(*ValueDecl) + + if !ok { + continue + } + + if isCompoundNode(node) { + dd = processCompound(node, vd, decl) + break + } + + for i, nameExpr := range vd.NameExprs { + if string(nameExpr.Name) == node { + if len(vd.Values) > i { + dd = &ValueDecl{ + Attributes: vd.Attributes.Copy(), + NameExprs: []NameExpr{nameExpr}, + Type: vd.Type, + Values: []Expr{vd.Values[i]}, + Const: vd.Const, + } + break + } else { + dd = vd + break + } + } + } + } + + if dd == nil { + continue + } + + sorted = append(sorted, dd) + } + + slices.Reverse(sorted) + + otherDecls = append(otherDecls, sorted...) + + return otherDecls, nil +} + +func addDepFromExpr(dg *graph, fromNode string, expr Expr) { + switch e := expr.(type) { + case *FuncLitExpr: + for _, stmt := range e.Body { + addDepFromExprStmt(dg, fromNode, stmt) + } + case *CallExpr: + addDepFromExpr(dg, fromNode, e.Func) + + for _, arg := range e.Args { + addDepFromExpr(dg, fromNode, arg) + } + case *NameExpr: + if isUverseName(e.Name) { + break + } + + toNode := string(e.Name) + dg.addEdge(fromNode, toNode) + } +} + +func addDepFromExprStmt(dg *graph, fromNode string, stmt Stmt) { + switch e := stmt.(type) { + case *ExprStmt: + addDepFromExpr(dg, fromNode, e.X) + case *IfStmt: + addDepFromExprStmt(dg, fromNode, e.Init) + addDepFromExpr(dg, fromNode, e.Cond) + + for _, stm := range e.Then.Body { + addDepFromExprStmt(dg, fromNode, stm) + } + for _, stm := range e.Else.Body { + addDepFromExprStmt(dg, fromNode, stm) + } + case *ReturnStmt: + for _, stm := range e.Results { + addDepFromExpr(dg, fromNode, stm) + } + case *AssignStmt: + for _, stm := range e.Rhs { + addDepFromExpr(dg, fromNode, stm) + } + case *SwitchStmt: + addDepFromExpr(dg, fromNode, e.X) + for _, clause := range e.Clauses { + addDepFromExpr(dg, fromNode, clause.bodyStmt.Cond) + for _, s := range clause.bodyStmt.Body { + addDepFromExprStmt(dg, fromNode, s) + } + } + case *ForStmt: + addDepFromExpr(dg, fromNode, e.Cond) + for _, s := range e.bodyStmt.Body { + addDepFromExprStmt(dg, fromNode, s) + } + case *BlockStmt: + for _, s := range e.Block.bodyStmt.Body { + addDepFromExprStmt(dg, fromNode, s) + } + } +} + +type graph struct { + edges map[string][]string + vertices []string +} + +func (g *graph) addEdge(u, v string) { + g.edges[u] = append(g.edges[u], v) +} + +func (g *graph) addVertex(v string) { + g.vertices = append(g.vertices, v) +} + +func (g *graph) topologicalSortUtil(v string, visited map[string]bool, stack *[]string) { + visited[v] = true + + for _, u := range g.edges[v] { + if !visited[u] { + g.topologicalSortUtil(u, visited, stack) + } + } + + *stack = append([]string{v}, *stack...) +} + +func (g *graph) topologicalSort() []string { + stack := make([]string, 0) + visited := make(map[string]bool) + + for _, v := range g.vertices { + if !visited[v] { + g.topologicalSortUtil(v, visited, &stack) + } + } + + return stack +} + +func isTuple(vd *ValueDecl) bool { + return len(vd.NameExprs) > len(vd.Values) && len(vd.Values) > 0 +} + +func isCompoundNode(node string) bool { + return strings.Contains(node, ", ") +} + +func processCompound(node string, vd *ValueDecl, decl Decl) Decl { + names := strings.Split(node, ", ") + + if len(names) != len(vd.NameExprs) { + panic("should not happen") + } + + equal := true + + for i, name := range names { + if vd.NameExprs[i].String() != name { + equal = false + break + } + } + + if !equal { + panic(fmt.Sprintf("names: %+v != nameExprs: %+v\n", names, vd.NameExprs)) + } + + return decl +} diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 85e6562eca6..ae5ac7fd40b 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -361,7 +361,7 @@ func (av *ArrayValue) GetPointerAtIndexInt2(store Store, ii int, et Type) Pointe Index: ii, } } - bv := &TypedValue{ // heap alloc + bv := &TypedValue{ // heap alloc, so need to compare value rather than pointer T: DataByteType, V: DataByteValue{ Base: av, @@ -369,6 +369,7 @@ func (av *ArrayValue) GetPointerAtIndexInt2(store Store, ii int, et Type) Pointe ElemType: et, }, } + return PointerValue{ TV: bv, Base: av, diff --git a/gnovm/pkg/gnolang/values_string.go b/gnovm/pkg/gnolang/values_string.go index 34187e32879..b334addc1c3 100644 --- a/gnovm/pkg/gnolang/values_string.go +++ b/gnovm/pkg/gnolang/values_string.go @@ -11,7 +11,7 @@ type protectedStringer interface { ProtectedString(*seenValues) string } -// This indicates the maximum ancticipated depth of the stack when printing a Value type. +// This indicates the maximum anticipated depth of the stack when printing a Value type. const defaultSeenValuesSize = 32 type seenValues struct { @@ -322,6 +322,8 @@ func (tv *TypedValue) ProtectedSprint(seen *seenValues, considerDeclaredType boo return fmt.Sprintf("%d", tv.GetUint()) case Uint8Type: return fmt.Sprintf("%d", tv.GetUint8()) + case DataByteType: + return fmt.Sprintf("%d", tv.GetDataByte()) case Uint16Type: return fmt.Sprintf("%d", tv.GetUint16()) case Uint32Type: diff --git a/gnovm/stdlibs/crypto/ed25519/ed25519.gno b/gnovm/stdlibs/crypto/ed25519/ed25519.gno index 80c9d24085b..baeda5ba359 100644 --- a/gnovm/stdlibs/crypto/ed25519/ed25519.gno +++ b/gnovm/stdlibs/crypto/ed25519/ed25519.gno @@ -1,8 +1,8 @@ package ed25519 // Verify returns true if the signature is valid for the message and public key. -func Verify(publicKey []byte, message []byte, signature []byte) bool { - return verify(publicKey, message, signature) +func VerifyED25519(publicKey []byte, message []byte, signature []byte) bool { + return verifyED25519(publicKey, message, signature) } -func verify(publicKey []byte, message []byte, signature []byte) bool // injected +func verifyED25519(publicKey []byte, message []byte, signature []byte) bool // injected diff --git a/gnovm/stdlibs/crypto/ed25519/ed25519.go b/gnovm/stdlibs/crypto/ed25519/ed25519.go index b19e6870312..51bad2e83c2 100644 --- a/gnovm/stdlibs/crypto/ed25519/ed25519.go +++ b/gnovm/stdlibs/crypto/ed25519/ed25519.go @@ -4,6 +4,6 @@ import ( "crypto/ed25519" ) -func X_verify(publicKey []byte, message []byte, signature []byte) bool { +func X_verifyED25519(publicKey []byte, message []byte, signature []byte) bool { return ed25519.Verify(publicKey, message, signature) } diff --git a/gnovm/stdlibs/crypto/ed25519/ed25519_test.gno b/gnovm/stdlibs/crypto/ed25519/ed25519_test.gno index e170658b7fc..33f29715a2f 100644 --- a/gnovm/stdlibs/crypto/ed25519/ed25519_test.gno +++ b/gnovm/stdlibs/crypto/ed25519/ed25519_test.gno @@ -7,10 +7,10 @@ import ( "testing" ) -func TestED25519Verify(t *testing.T) { +func TestVerifyED25519(t *testing.T) { publicKey, _ := hex.DecodeString("0D853FA898A07EB91F618BB3E8B738B0E45BE9B3053799A2C42F8204F5FA3505") signature, _ := hex.DecodeString("2B39638983858715AD2FA059665ADFE267936B8F20C4DA01E9650958E0CA65C0255C75164360F468087FE8385140E48EE3471E332472A50AEE599F9D0EADD106") - if !ed25519.Verify(publicKey, []byte("hello gno.land"), signature) { + if !ed25519.VerifyED25519(publicKey, []byte("hello gno.land"), signature) { t.Error("verify failed") } } diff --git a/gnovm/stdlibs/io/io.gno b/gnovm/stdlibs/io/io.gno index 6ee52cfe293..e1c8de731b6 100644 --- a/gnovm/stdlibs/io/io.gno +++ b/gnovm/stdlibs/io/io.gno @@ -488,7 +488,7 @@ func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader { // Assume we can read up to an offset of `1<<63 - 1` bytes in this case. remaining = maxInt64 } - return &SectionReader{r, off, off, off + n} + return &SectionReader{r, off, off, remaining} } // SectionReader implements Read, Seek, and ReadAt on a section diff --git a/gnovm/stdlibs/native.go b/gnovm/stdlibs/native.go index 0b56eeb7399..f105875fa89 100644 --- a/gnovm/stdlibs/native.go +++ b/gnovm/stdlibs/native.go @@ -27,7 +27,7 @@ type nativeFunc struct { var nativeFuncs = [...]nativeFunc{ { "crypto/ed25519", - "verify", + "verifyED25519", []gno.FieldTypeExpr{ {Name: gno.N("p0"), Type: gno.X("[]byte")}, {Name: gno.N("p1"), Type: gno.X("[]byte")}, @@ -51,7 +51,7 @@ var nativeFuncs = [...]nativeFunc{ gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 2, "")).TV, rp2) - r0 := libs_crypto_ed25519.X_verify(p0, p1, p2) + r0 := libs_crypto_ed25519.X_verifyED25519(p0, p1, p2) m.PushValue(gno.Go2GnoValue( m.Alloc, diff --git a/gnovm/tests/files/a47.gno b/gnovm/tests/files/a47.gno index 2775547a3e8..1749968eac1 100644 --- a/gnovm/tests/files/a47.gno +++ b/gnovm/tests/files/a47.gno @@ -20,7 +20,9 @@ func main() { println(newArr[0].i, newArr[1].i) // The struct should have been copied, not referenced. - println(&sArr[2] != &newArr[1]) + println(&sArr[2] == &newArr[1]) + // share same underlying array, and same index + println(&sArr[1] == &newArr[1]) } // Output: @@ -29,4 +31,5 @@ func main() { // 2 3 3 // true // 2 3 +// false // true diff --git a/gnovm/tests/files/a47a.gno b/gnovm/tests/files/a47a.gno new file mode 100644 index 00000000000..a613482efda --- /dev/null +++ b/gnovm/tests/files/a47a.gno @@ -0,0 +1,24 @@ +package main + +type S struct { + i int +} + +func main() { + sArr := make([]S, 0, 4) + sArr = append(sArr, S{1}, S{2}, S{3}) + + newArr := append(sArr[:0], sArr[0:]...) + + // share same underlying array + println(&sArr[0] == &newArr[0]) + + println(&sArr[1] == &newArr[1]) + + println(&sArr[2] == &newArr[2]) +} + +// Output: +// true +// true +// true diff --git a/gnovm/tests/files/a47b.gno b/gnovm/tests/files/a47b.gno new file mode 100644 index 00000000000..89385a6f562 --- /dev/null +++ b/gnovm/tests/files/a47b.gno @@ -0,0 +1,13 @@ +package main + +func main() { + s1 := []int{1, 2} + i0 := &s1[0] + // new array allocated, so they have different base array + s1 = append(s1, 3) + ii0 := &s1[0] + println(i0 == ii0) +} + +// Output: +// false diff --git a/gnovm/tests/files/a48.gno b/gnovm/tests/files/a48.gno new file mode 100644 index 00000000000..be6e9c064ce --- /dev/null +++ b/gnovm/tests/files/a48.gno @@ -0,0 +1,31 @@ +package main + +func main() { + { + b := []byte("ABCDEFGHIJKL") + a := b + println(&b[0] == &a[0], b[0], a[0]) + + // modifying the underlying array modifies both a[0] and b[0], + // as it should + a[0] = 11 + println(a[0], b[0]) + } + + { + b := []byte{1, 2, 3} + a := b + println(&b[0] == &a[0], b[0], a[0]) + + // modifying the underlying array modifies both a[0] and b[0], + // as it should + a[0] = 11 + println(a[0], b[0]) + } +} + +// Output: +// true 65 65 +// 11 11 +// true 1 1 +// 11 11 diff --git a/gnovm/tests/files/a48a.gno b/gnovm/tests/files/a48a.gno new file mode 100644 index 00000000000..b17fdff515d --- /dev/null +++ b/gnovm/tests/files/a48a.gno @@ -0,0 +1,12 @@ +package main + +func main() { + { + b := []byte("ABCDEFGHIJKL") + a := b + println(&a[0] == &a[0]) + } +} + +// Output: +// true diff --git a/gnovm/tests/files/a49.gno b/gnovm/tests/files/a49.gno new file mode 100644 index 00000000000..ee39a484eb7 --- /dev/null +++ b/gnovm/tests/files/a49.gno @@ -0,0 +1,12 @@ +package main + +func main() { + c := []byte{'A'} + a := c + println(&c[0]) + println(&c[0] == &a[0]) +} + +// Output: +// &(65 uint8) +// true diff --git a/gnovm/tests/files/type33.gno b/gnovm/tests/files/type33.gno new file mode 100644 index 00000000000..62d6696fafa --- /dev/null +++ b/gnovm/tests/files/type33.gno @@ -0,0 +1,28 @@ +package main + +import "fmt" + +// Define a base type +type Base int + +// Declare a new type that is a pointer to the base type +type PtrToBase *Base + +func main() { + var b Base = 42 // Initialize a variable of the base type + var p PtrToBase = &b // Initialize a variable of the new pointer type with the address of b + + fmt.Printf("The value of b is: %d\n", b) + + // Using the new pointer type + fmt.Printf("The value pointed to by p is: %d\n", *p) + + // Modifying the value pointed to by p + *p = 100 + fmt.Printf("The new value of b after modification through p is: %d\n", b) +} + +// Output: +// The value of b is: 42 +// The value pointed to by p is: 42 +// The new value of b after modification through p is: 100 diff --git a/gnovm/tests/files/type34.gno b/gnovm/tests/files/type34.gno new file mode 100644 index 00000000000..20f53b78cd6 --- /dev/null +++ b/gnovm/tests/files/type34.gno @@ -0,0 +1,12 @@ +package main + +type BytePtr *byte + +func main() { + bs := []byte("hello") + var p BytePtr = &bs[0] + println(*p) +} + +// Output: +// 104 diff --git a/gnovm/tests/files/type35.gno b/gnovm/tests/files/type35.gno new file mode 100644 index 00000000000..9ade96ee9c8 --- /dev/null +++ b/gnovm/tests/files/type35.gno @@ -0,0 +1,15 @@ +package main + +type IntPtr *int + +func main() { + var a, b int + a = 1 // Set a to 104 + s := []IntPtr{} + s = append(s, &a) + s = append(s, &b) + println(*s[0]) +} + +// Output: +// 1 diff --git a/gnovm/tests/files/type36.gno b/gnovm/tests/files/type36.gno new file mode 100644 index 00000000000..8bb64118036 --- /dev/null +++ b/gnovm/tests/files/type36.gno @@ -0,0 +1,17 @@ +package main + +type Arr [2]int +type Ptr *Arr + +func main() { + var arr Arr + arr[0] = 0 + arr[1] = 1 + + p := Ptr(&arr) + + println(p[:]) +} + +// Output: +// slice[(0 int),(1 int)] diff --git a/gnovm/tests/files/type37.gno b/gnovm/tests/files/type37.gno new file mode 100644 index 00000000000..1bc157b44ff --- /dev/null +++ b/gnovm/tests/files/type37.gno @@ -0,0 +1,20 @@ +package main + +import "fmt" + +type IntArray []int +type Arr *IntArray + +func (a Arr) Add(x int) { // receiver is val, not ptr + *a = append(*a, x) +} + +func main() { + a := new(IntArray) + Arr(a).Add(4) + + fmt.Println(*a) +} + +// Error: +// main/files/type37.gno:8: invalid receiver type main.Arr (base type is pointer type) diff --git a/gnovm/tests/files/type37a.gno b/gnovm/tests/files/type37a.gno new file mode 100644 index 00000000000..16db1cc4dc2 --- /dev/null +++ b/gnovm/tests/files/type37a.gno @@ -0,0 +1,19 @@ +package main + +import "fmt" + +type IntArray []int + +func (a *IntArray) Add(x int) { // receiver is val, not ptr + *a = append(*a, x) +} + +func main() { + a := new(IntArray) + a.Add(4) + + fmt.Println(*a) +} + +// Output: +// [4] diff --git a/gnovm/tests/files/type37b.gno b/gnovm/tests/files/type37b.gno new file mode 100644 index 00000000000..aea1b445ca1 --- /dev/null +++ b/gnovm/tests/files/type37b.gno @@ -0,0 +1,22 @@ +package main + +import "fmt" + +type Integer int + +func (i **Integer) Add(x int) { + **i += Integer(x) // Dereference twice to get to the actual Integer value and modify it +} + +func main() { + a := new(Integer) // a is a pointer to Integer + b := &a // b is a pointer to a pointer to Integer + + // Since Add is defined on **Integer, you need to pass b + b.Add(4) // Adds 4 to the value **b points to + + fmt.Println(**b) // Should print 4, as **b is the same as *a +} + +// Error: +// main/files/type37b.gno:7: invalid receiver type **main.Integer (base type is pointer type) diff --git a/gnovm/tests/files/type37c.gno b/gnovm/tests/files/type37c.gno new file mode 100644 index 00000000000..7cd8ac7367e --- /dev/null +++ b/gnovm/tests/files/type37c.gno @@ -0,0 +1,20 @@ +package main + +import "fmt" + +type Integer int + +func (i *Integer) Add(x int) { // receiver is val, not ptr + println(int(*i) + x) +} + +func main() { + a := new(Integer) + a.Add(4) + + fmt.Println(*a) +} + +// Output: +// 4 +// 0 diff --git a/gnovm/tests/files/type37d.gno b/gnovm/tests/files/type37d.gno new file mode 100644 index 00000000000..ada9541e64e --- /dev/null +++ b/gnovm/tests/files/type37d.gno @@ -0,0 +1,16 @@ +package main + +type IntPtr *int + +var ip IntPtr = new(int) + +func (p IntPtr) Int() int { + return *p +} + +func main() { + println(ip.Int()) +} + +// Error: +// main/files/type37d.gno:7: invalid receiver type main.IntPtr (base type is pointer type) diff --git a/gnovm/tests/files/type37e.gno b/gnovm/tests/files/type37e.gno new file mode 100644 index 00000000000..a2537c9cb8d --- /dev/null +++ b/gnovm/tests/files/type37e.gno @@ -0,0 +1,17 @@ +package main + +type IntPtr *int +type Int2 IntPtr + +var ip IntPtr = new(int) + +func (i2 Int2) Int() int { + return *i2 +} + +func main() { + println(Int2(ip).Int()) +} + +// Error: +// main/files/type37e.gno:8: invalid receiver type main.Int2 (base type is pointer type) diff --git a/gnovm/tests/files/type37f.gno b/gnovm/tests/files/type37f.gno new file mode 100644 index 00000000000..7bffa748314 --- /dev/null +++ b/gnovm/tests/files/type37f.gno @@ -0,0 +1,16 @@ +package main + +type IntPtr *int + +var ip IntPtr = new(int) + +func (p *IntPtr) Int() int { + return **p +} + +func main() { + println((&ip).Int()) +} + +// Error: +// main/files/type37f.gno:7: invalid receiver type *main.IntPtr (base type is pointer type) diff --git a/gnovm/tests/files/type38.gno b/gnovm/tests/files/type38.gno new file mode 100644 index 00000000000..a3a03f1e248 --- /dev/null +++ b/gnovm/tests/files/type38.gno @@ -0,0 +1,26 @@ +package main + +import "fmt" + +type IntArray []int +type Arr *IntArray + +func add(arr Arr) { // receiver is val, not ptr + *arr = append(*arr, 1) +} + +func main() { + a := new(IntArray) + add(a) + + fmt.Println(a) + fmt.Println(*a) + fmt.Println(len(*a)) + fmt.Println((*a)[0]) +} + +// Output: +// &[1] +// [1] +// 1 +// 1 diff --git a/gnovm/tests/files/type39.gno b/gnovm/tests/files/type39.gno new file mode 100644 index 00000000000..aebcc226385 --- /dev/null +++ b/gnovm/tests/files/type39.gno @@ -0,0 +1,22 @@ +package main + +type foo interface { + say() +} + +func (f foo) echo() int { + return 1 +} + +type Bar struct{} + +func (b *Bar) say() {} + +func main() { + var f foo + f = &Bar{} + println(f.echo()) +} + +// Error: +// main/files/type39.gno:7: invalid receiver type main.foo (base type is interface type) diff --git a/gnovm/tests/files/type39a.gno b/gnovm/tests/files/type39a.gno new file mode 100644 index 00000000000..06f41897f93 --- /dev/null +++ b/gnovm/tests/files/type39a.gno @@ -0,0 +1,24 @@ +package main + +type foo interface { + say() +} + +type FF foo + +func (f FF) echo() int { + return 1 +} + +type Bar struct{} + +func (b *Bar) say() {} + +func main() { + var f foo + f = &Bar{} + println(f.echo()) +} + +// Error: +// main/files/type39a.gno:9: invalid receiver type main.FF (base type is interface type) diff --git a/gnovm/tests/files/type39b.gno b/gnovm/tests/files/type39b.gno new file mode 100644 index 00000000000..dbf5312a825 --- /dev/null +++ b/gnovm/tests/files/type39b.gno @@ -0,0 +1,22 @@ +package main + +type foo interface { + say() +} + +func (f *foo) echo() int { + return 1 +} + +type Bar struct{} + +func (b *Bar) say() {} + +func main() { + var f *foo + *f = &Bar{} + println(f.echo()) +} + +// Error: +// main/files/type39b.gno:7: invalid receiver type *main.foo (base type is interface type) diff --git a/gnovm/tests/files/var18.gno b/gnovm/tests/files/var18.gno new file mode 100644 index 00000000000..619aedef779 --- /dev/null +++ b/gnovm/tests/files/var18.gno @@ -0,0 +1,14 @@ +package main + +func main() { + println(a) + println(b) +} + +func r2() (int, int) { return 1, 2 } + +var a, b int = r2() + +// Output: +// 1 +// 2 diff --git a/gnovm/tests/files/var19.gno b/gnovm/tests/files/var19.gno new file mode 100644 index 00000000000..f26c230de0d --- /dev/null +++ b/gnovm/tests/files/var19.gno @@ -0,0 +1,14 @@ +package main + +func main() { + println(a) + println(b) + println(c) +} + +var a, b, c = 1, a + 1, b + 1 + +// Output: +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/var20.gno b/gnovm/tests/files/var20.gno new file mode 100644 index 00000000000..1aec4792fcb --- /dev/null +++ b/gnovm/tests/files/var20.gno @@ -0,0 +1,17 @@ +package main + +func main() { + println(a) + println(b) + println(c) + println(d) +} + +var a, b, c = 1, a + d, 3 +var d = a + +// Output: +// 1 +// 2 +// 3 +// 1 diff --git a/gnovm/tests/files/var21.gno b/gnovm/tests/files/var21.gno new file mode 100644 index 00000000000..7ec32e1ebfa --- /dev/null +++ b/gnovm/tests/files/var21.gno @@ -0,0 +1,17 @@ +package main + +func main() { + myDep = "123" + myVar() +} + +func hello(s string) { + println(s) +} + +var myVar = func() { hello(myDep) } + +var myDep string + +// Output: +// 123 diff --git a/go.mod b/go.mod index c6983d10b4f..e2d8baf6e74 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,10 @@ require ( github.com/cockroachdb/apd/v3 v3.2.1 github.com/cosmos/ledger-cosmos-go v0.13.3 github.com/davecgh/go-spew v1.1.1 - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/fortytw2/leaktest v1.3.0 github.com/gdamore/tcell/v2 v2.7.4 - github.com/gnolang/faucet v0.1.3 + github.com/gnolang/faucet v0.2.0 github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 github.com/golang/protobuf v1.5.4 github.com/google/gofuzz v1.2.0 @@ -31,13 +31,18 @@ require ( github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 go.etcd.io/bbolt v1.3.9 + go.opentelemetry.io/otel v1.25.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 + go.opentelemetry.io/otel/metric v1.25.0 + go.opentelemetry.io/otel/sdk v1.25.0 + go.opentelemetry.io/otel/sdk/metric v1.25.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 go.uber.org/zap/exp v0.2.0 golang.org/x/crypto v0.21.0 golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 golang.org/x/mod v0.16.0 - golang.org/x/net v0.22.0 + golang.org/x/net v0.23.0 golang.org/x/term v0.18.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.19.0 @@ -46,7 +51,17 @@ require ( ) require ( - github.com/btcsuite/btcd/btcec/v2 v2.3.2 + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/proto/otlp v1.1.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect +) + +require ( + github.com/btcsuite/btcd/btcec/v2 v2.3.3 github.com/gdamore/encoding v1.0.0 // indirect github.com/go-chi/chi/v5 v5.0.12 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -58,10 +73,9 @@ require ( github.com/rivo/uniseg v0.4.3 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - golang.org/x/sync v0.6.0 // indirect + golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect - google.golang.org/grpc v1.58.3 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.0 // indirect ) diff --git a/go.sum b/go.sum index b71747f5d32..c7c81d86bd1 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7 github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= +github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= @@ -26,6 +26,8 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= @@ -38,8 +40,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -57,12 +59,17 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= -github.com/gnolang/faucet v0.1.3 h1:eg3S4rGkW6LYWo7nhc4AhWrPmHsaEFy6R8fyef/KgK4= -github.com/gnolang/faucet v0.1.3/go.mod h1:+91pqgE+pyX8FO9eoe2MGiwgTpYY0bITYsHO/4Zg+CY= +github.com/gnolang/faucet v0.2.0 h1:ynUgJ/z5F6to/4j5F9v7tpPth4b9ZUvLseGKd+tiL/g= +github.com/gnolang/faucet v0.2.0/go.mod h1:E7Nxsgmx4JbXWlBXE8teSj7IZf/BSwCfB2pO9hGY02E= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8= github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -77,8 +84,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= @@ -94,6 +101,8 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/ github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gotuna/gotuna v0.6.0 h1:N1lQKXEi/lwRp8u3sccTYLhzOffA4QasExz/1M5Riws= github.com/gotuna/gotuna v0.6.0/go.mod h1:F/ecRt29ChB6Ycy1AFIBpBiMNK0j7Heq+gFbLWquhjc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jaekwon/testify v1.6.1 h1:4AtAJcR9GzXN5W4DdY7ie74iCPiJV1JJUJL90t2ZUyw= github.com/jaekwon/testify v1.6.1/go.mod h1:Oun0RXIHI7osufabQ60i4Lqkj0GXLbqI1I7kgzBNm1U= @@ -103,10 +112,8 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= @@ -162,6 +169,20 @@ github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfU github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0 h1:hDKnobznDpcdTlNzO0S/owRB8tyVr1OoeZZhDoqY+Cs= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.25.0/go.mod h1:kUDQaUs1h8iTIHbQTk+iJRiUvSfJYMMKTtMCaiVu7B0= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= +go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= +go.opentelemetry.io/otel/sdk/metric v1.25.0 h1:7CiHOy08LbrxMAp4vWpbiPcklunUshVpAvGBrdDRlGw= +go.opentelemetry.io/otel/sdk/metric v1.25.0/go.mod h1:LzwoKptdbBBdYfvtGCzGwk6GWMA3aUzBOwtQpR6Nz7o= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= +go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -191,14 +212,14 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -242,10 +263,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/misc/autocounterd/Dockerfile b/misc/autocounterd/Dockerfile new file mode 100644 index 00000000000..d860fc5f37f --- /dev/null +++ b/misc/autocounterd/Dockerfile @@ -0,0 +1,16 @@ +FROM golang:alpine AS builder + +COPY . /go/src/github.com/gnolang/gno/misc/autocounterd + +WORKDIR /go/src/github.com/gnolang/gno/misc/autocounterd + +RUN go build -o /build/autocounterd ./cmd + +# Final image for autocounterd +FROM alpine AS autocounterd + +COPY --from=builder /build/autocounterd /usr/bin/autocounterd + +ENTRYPOINT [ "/usr/bin/autocounterd" ] +CMD [ "start" ] + diff --git a/misc/autocounterd/README.md b/misc/autocounterd/README.md new file mode 100644 index 00000000000..28b44312f25 --- /dev/null +++ b/misc/autocounterd/README.md @@ -0,0 +1,13 @@ +# Autocounterd + +## What is it? + +`autcounterd` is a simple binary that increments a simple counter every x seconds to analyse and test a network. + +## How to use + +Start it with: + +``` sh +$ docker compose up -d +``` diff --git a/misc/autocounterd/cmd/cmd_start.go b/misc/autocounterd/cmd/cmd_start.go new file mode 100644 index 00000000000..2e120b1c86d --- /dev/null +++ b/misc/autocounterd/cmd/cmd_start.go @@ -0,0 +1,100 @@ +package main + +import ( + "context" + "flag" + "fmt" + "time" + + "github.com/gnolang/gno/gno.land/pkg/gnoclient" + rpcclient "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" + "github.com/gnolang/gno/tm2/pkg/commands" +) + +type startCfg struct { + rpcURL string + chainID string + mnemonic string + realmPath string + incrementInterval time.Duration +} + +func (cfg *startCfg) Validate() error { + switch { + case cfg.rpcURL == "": + return fmt.Errorf("rpc url cannot be empty") + case cfg.chainID == "": + return fmt.Errorf("chainID cannot be empty") + case cfg.mnemonic == "": + return fmt.Errorf("mnemonic cannot be empty") + case cfg.realmPath == "": + return fmt.Errorf("realmPath cannot be empty") + case cfg.incrementInterval == 0: + return fmt.Errorf("interval cannot be empty") + } + + return nil +} + +func NewStartCmd(io commands.IO) *commands.Command { + cfg := &startCfg{} + + return commands.NewCommand( + commands.Metadata{ + Name: "start", + ShortUsage: "start [flags]", + ShortHelp: "Runs the linter for the specified packages", + }, + cfg, + func(_ context.Context, args []string) error { + return execStart(cfg, args, io) + }, + ) +} + +func (c *startCfg) RegisterFlags(fs *flag.FlagSet) { + fs.StringVar(&c.rpcURL, "rpc", "127.0.0.1:26657", "rpc url endpoint") + fs.StringVar(&c.chainID, "chain-id", "dev", "chain-id") + fs.StringVar(&c.mnemonic, "mnemonic", "", "mnemonic") + fs.StringVar(&c.realmPath, "realm", "gno.land/r/portal/counter", "realm path") + fs.DurationVar(&c.incrementInterval, "interval", 15*time.Second, "Increment counter interval") +} + +func execStart(cfg *startCfg, args []string, io commands.IO) error { + if err := cfg.Validate(); err != nil { + return err + } + + signer, err := gnoclient.SignerFromBip39(cfg.mnemonic, cfg.chainID, "", uint32(0), uint32(0)) + if err != nil { + return err + } + if err := signer.Validate(); err != nil { + return err + } + + rpcClient := rpcclient.NewHTTP(cfg.rpcURL, "/websocket") + + client := gnoclient.Client{ + Signer: signer, + RPCClient: rpcClient, + } + + for { + res, err := client.Call(gnoclient.CallCfg{ + PkgPath: cfg.realmPath, + FuncName: "Incr", + GasFee: "10000000ugnot", + GasWanted: 800000, + Args: nil, + }) + _ = res + + if err != nil { + fmt.Printf("[ERROR] Failed to call Incr on %s, %+v\n", cfg.realmPath, err.Error()) + } else { + fmt.Println("[INFO] Counter incremented with success") + } + time.Sleep(cfg.incrementInterval) + } +} diff --git a/misc/autocounterd/cmd/main.go b/misc/autocounterd/cmd/main.go new file mode 100644 index 00000000000..74c78ff8fdd --- /dev/null +++ b/misc/autocounterd/cmd/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "context" + "os" + + "github.com/gnolang/gno/tm2/pkg/commands" +) + +func main() { + cmd := NewStartCmd(commands.NewDefaultIO()) + + cmd.Execute(context.Background(), os.Args[1:]) +} diff --git a/misc/autocounterd/docker-compose.yml b/misc/autocounterd/docker-compose.yml new file mode 100644 index 00000000000..d71e6997b51 --- /dev/null +++ b/misc/autocounterd/docker-compose.yml @@ -0,0 +1,13 @@ +version: "3" +services: + autocounterd: + image: ghcr.io/gnolang/gno/autocounterd + build: + context: . + restart: unless-stopped + environment: + COUNTER_MNEMONIC: "source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast" + COUNTER_RPC: "http://127.0.0.1:26657" + COUNTER_CHAIN_ID: "dev" + COUNTER_INTERVAL: "5s" + COUNTER_REALM: "gno.land/r/portal/counter" diff --git a/misc/autocounterd/go.mod b/misc/autocounterd/go.mod new file mode 100644 index 00000000000..d9d26eab37a --- /dev/null +++ b/misc/autocounterd/go.mod @@ -0,0 +1,52 @@ +module loop + +go 1.21 + +require github.com/gnolang/gno v0.0.0-20240125181217-b6193518e278 + +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/btcutil v1.1.3 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/dgraph-io/badger/v3 v3.2103.5 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/gnolang/goleveldb v0.0.9 // indirect + github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect + github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/flatbuffers v1.12.1 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/jaekwon/testify v1.6.1 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/klauspost/compress v1.12.3 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/linxGnu/grocksdb v1.8.11 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/peterbourgon/ff/v3 v3.4.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rs/cors v1.10.1 // indirect + github.com/stretchr/testify v1.8.4 // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + go.etcd.io/bbolt v1.3.8 // indirect + go.opencensus.io v0.22.5 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/tools v0.17.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/misc/autocounterd/go.sum b/misc/autocounterd/go.sum new file mode 100644 index 00000000000..905c884857e --- /dev/null +++ b/misc/autocounterd/go.sum @@ -0,0 +1,314 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.0 h1:V2/ZgjfDFIygAX3ZapeigkVBoVUtOJKSwrhZdlpSvaA= +github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= +github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= +github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gnolang/gno v0.0.0-20240125181217-b6193518e278 h1:CxF7gG3iqSeYVygTSYsB7Beg+Fpvka06TuTI2a0p+6s= +github.com/gnolang/gno v0.0.0-20240125181217-b6193518e278/go.mod h1:mOhpUTFaKk5CQj90qmjWfI9po2eapqziEu4D+fAtisc= +github.com/gnolang/goleveldb v0.0.9 h1:Q7rGko9oXMKtQA+Apeeed5a3sjba/mcDhzJGoTVLCKE= +github.com/gnolang/goleveldb v0.0.9/go.mod h1:Dz6p9bmpy/FBESTgduiThZt5mToVDipcHGzj/zUOo8E= +github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk= +github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jaekwon/testify v1.6.1 h1:4AtAJcR9GzXN5W4DdY7ie74iCPiJV1JJUJL90t2ZUyw= +github.com/jaekwon/testify v1.6.1/go.mod h1:Oun0RXIHI7osufabQ60i4Lqkj0GXLbqI1I7kgzBNm1U= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/linxGnu/grocksdb v1.8.11 h1:BGol9e5gB1BrsTvOxloC88pe70TCqgrfLNwkyWW0kD8= +github.com/linxGnu/grocksdb v1.8.11/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= +github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap/exp v0.1.0 h1:Ol9zQNvAEAgFHSBiR5LlwS9Xq8u5QF+7HBwNHUB8rcI= +go.uber.org/zap/exp v0.1.0/go.mod h1:z/0T3As39ttolxZGOsvk1OEvQfwwfTZpmV9YTp+VAkc= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/misc/autocounterd/r/autocounterd/autocounder.gno b/misc/autocounterd/r/autocounterd/autocounder.gno new file mode 100644 index 00000000000..8bdf15736d0 --- /dev/null +++ b/misc/autocounterd/r/autocounterd/autocounder.gno @@ -0,0 +1,17 @@ +package counter + +import "gno.land/p/demo/ufmt" + +var counter int = 0 + +func Incr() { + counter += 1 +} + +func Reset() { + counter = 0 +} + +func Render() string { + return ufmt.Sprintf("Counter: %d", counter) +} diff --git a/misc/docusaurus/sidebars.js b/misc/docusaurus/sidebars.js index f4858e22755..5a2533d7a44 100644 --- a/misc/docusaurus/sidebars.js +++ b/misc/docusaurus/sidebars.js @@ -11,7 +11,7 @@ const sidebars = { items: [ 'getting-started/playground-start', { - type: "category", + type: 'category', label: 'Local Setup', items: [ 'getting-started/local-setup/local-setup', @@ -48,11 +48,11 @@ const sidebars = { { type: 'category', label: 'Standard Libraries', + link: {type: 'doc', id: 'concepts/stdlibs/stdlibs'}, items: [ - 'concepts/standard-library/overview', - 'concepts/standard-library/banker', - 'concepts/standard-library/coin', - 'concepts/standard-library/gnopher-hole-stdlib', + 'concepts/stdlibs/banker', + 'concepts/stdlibs/coin', + 'concepts/stdlibs/gnopher-hole-stdlib', ] }, 'concepts/gnovm', @@ -96,18 +96,18 @@ const sidebars = { { type: 'category', label: 'Standard Libraries', + link: {type: 'doc', id: 'reference/stdlibs/stdlibs'}, items: [ - 'reference/standard-library/overview', { type: 'category', label: 'std', items: [ - 'reference/standard-library/std/address', - 'reference/standard-library/std/banker', - 'reference/standard-library/std/coin', - 'reference/standard-library/std/coins', - 'reference/standard-library/std/chain', - 'reference/standard-library/std/testing', + 'reference/stdlibs/std/address', + 'reference/stdlibs/std/banker', + 'reference/stdlibs/std/coin', + 'reference/stdlibs/std/coins', + 'reference/stdlibs/std/chain', + 'reference/stdlibs/std/testing', ] } ] diff --git a/telemetry/README.md b/telemetry/README.md new file mode 100644 index 00000000000..f0cbf26c5e4 --- /dev/null +++ b/telemetry/README.md @@ -0,0 +1,43 @@ +# Telemetry + +The purpose of this package is to provide a way to easily integrate OpenTelemetry Protocol (OTLP) metrics collection into our codebase. + +## Configure environment variables +Metrics can be enabled using environment variables. The following variables are supported: +- `TELEM_METRICS_ENABLED`: setting to `true` will enable metrics collection +- `TELEM_METER_NAME`: optionally set the meter name; the default is `gno.land` +- `TELEM_SERVICE_NAME`: optionally set the service name; the default is `gno.land` +- `TELEM_EXPORTER_ENDPOINT`: required; this is the endpoint to export metrics to, like a local OTEL collector + +## OTEL configuration +There are many ways configure the OTEL pipeline for exporting metrics. Here is an example of how a local OTEL collector can be configured to send metrics to Grafana Cloud. This is an optional step and can be highly customized. + +### OTEL collector +The latest collector releases can be found [here](https://github.com/open-telemetry/opentelemetry-collector-releases/releases). This is an example of the config that can be used to receive metrics from gno.land and publish them to Grafana Cloud. +```yaml +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 # should be the same as the TELEM_EXPORTER_ENDPOINT variable + +processors: + batch: + +exporters: + otlphttp: + endpoint: https://otlp-gateway-prod-us-east-0.grafana.net/otlp + +service: + pipelines: + metrics: + receivers: [otlp] + processors: [batch] + exporters: [otlphttp] +``` + +Collector exporter environment variables, including those for authentication, can be found [here](https://opentelemetry.io/docs/specs/otel/protocol/exporter/). + +## Resources +- https://opentelemetry.io/docs/collector/ +- https://grafana.com/docs/grafana-cloud/monitor-applications/application-observability/setup/collector/ \ No newline at end of file diff --git a/telemetry/exporter/error.go b/telemetry/exporter/error.go new file mode 100644 index 00000000000..5df14f0dba3 --- /dev/null +++ b/telemetry/exporter/error.go @@ -0,0 +1,5 @@ +package exporter + +import "errors" + +var ErrEndpointNotSet = errors.New("telemetry exporter endpoint not set") diff --git a/telemetry/init.go b/telemetry/init.go new file mode 100644 index 00000000000..30ea3ede66f --- /dev/null +++ b/telemetry/init.go @@ -0,0 +1,40 @@ +package telemetry + +// Inspired by the example here: +// https://github.com/open-telemetry/opentelemetry-go/blob/main/example/prometheus/main.go + +import ( + "github.com/gnolang/gno/telemetry/metrics" + "github.com/gnolang/gno/telemetry/options" +) + +const ( + defaultMeterName = "gno.land" + defaultServiceName = "gno.land" +) + +var config options.Config + +// MetricsEnabled returns true if metrics have been initialized. +func MetricsEnabled() bool { + return config.MetricsEnabled +} + +// Init will initialize metrics with the options provided. This function may also initialize tracing when +// this is something that we want to support. +func Init(options ...Option) error { + config.MeterName = defaultMeterName + config.ServiceName = defaultServiceName + for _, opt := range options { + opt(&config) + } + + // Initialize metrics to be collected. + if config.MetricsEnabled { + if err := metrics.Init(config); err != nil { + return err + } + } + + return nil +} diff --git a/telemetry/metrics/init.go b/telemetry/metrics/init.go new file mode 100644 index 00000000000..41903f88d77 --- /dev/null +++ b/telemetry/metrics/init.go @@ -0,0 +1,69 @@ +package metrics + +import ( + "context" + + "github.com/gnolang/gno/telemetry/exporter" + "github.com/gnolang/gno/telemetry/options" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/metric" + sdkMetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/resource" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" +) + +var ( + // Metrics. + BroadcastTxTimer metric.Int64Histogram + BuildBlockTimer metric.Int64Histogram +) + +func Init(config options.Config) error { + if config.ExporterEndpoint == "" { + return exporter.ErrEndpointNotSet + } + + // Use oltp metric exporter. + exporter, err := otlpmetricgrpc.New( + context.Background(), + otlpmetricgrpc.WithEndpoint(config.ExporterEndpoint), + otlpmetricgrpc.WithInsecure(), // TODO: enable security + ) + if err != nil { + return err + } + + provider := sdkMetric.NewMeterProvider( + // Default period is 1m. + sdkMetric.WithReader(sdkMetric.NewPeriodicReader(exporter)), + sdkMetric.WithResource( + resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String(config.ServiceName), + semconv.ServiceVersionKey.String("1.0.0"), + semconv.ServiceInstanceIDKey.String("gno-node-1"), + ), + ), + ) + otel.SetMeterProvider(provider) + meter := provider.Meter(config.MeterName) + + if BroadcastTxTimer, err = meter.Int64Histogram( + "broadcast_tx_hist", + metric.WithDescription("broadcast tx duration"), + metric.WithUnit("ms"), + ); err != nil { + return err + } + + if BuildBlockTimer, err = meter.Int64Histogram( + "build_block_hist", + metric.WithDescription("block build duration"), + metric.WithUnit("ms"), + ); err != nil { + return err + } + + return nil +} diff --git a/telemetry/options.go b/telemetry/options.go new file mode 100644 index 00000000000..1d299261caf --- /dev/null +++ b/telemetry/options.go @@ -0,0 +1,35 @@ +package telemetry + +import "github.com/gnolang/gno/telemetry/options" + +type Option func(*options.Config) + +func WithOptionMetricsEnabled() Option { + return func(c *options.Config) { + c.MetricsEnabled = true + } +} + +func WithOptionMeterName(meterName string) Option { + return func(c *options.Config) { + if meterName != "" { + c.MeterName = meterName + } + } +} + +func WithOptionExporterEndpoint(exporterEndpoint string) Option { + return func(c *options.Config) { + if exporterEndpoint != "" { + c.ExporterEndpoint = exporterEndpoint + } + } +} + +func WithOptionServiceName(serviceName string) Option { + return func(c *options.Config) { + if serviceName != "" { + c.ServiceName = serviceName + } + } +} diff --git a/telemetry/options/config.go b/telemetry/options/config.go new file mode 100644 index 00000000000..80d07e588aa --- /dev/null +++ b/telemetry/options/config.go @@ -0,0 +1,8 @@ +package options + +type Config struct { + MetricsEnabled bool + MeterName string + ServiceName string + ExporterEndpoint string +} diff --git a/tm2/pkg/amino/codec.go b/tm2/pkg/amino/codec.go index 602c7090d91..3fa7634e3ad 100644 --- a/tm2/pkg/amino/codec.go +++ b/tm2/pkg/amino/codec.go @@ -594,7 +594,7 @@ func (cdc *Codec) newTypeInfoUnregisteredWLocked(rt reflect.Type) *TypeInfo { cdc.typeInfos[rt] = info info.Type = rt - info.PtrToType = reflect.PtrTo(rt) + info.PtrToType = reflect.PointerTo(rt) info.ZeroValue = reflect.Zero(rt) var isAminoMarshaler bool var reprType reflect.Type @@ -602,7 +602,7 @@ func (cdc *Codec) newTypeInfoUnregisteredWLocked(rt reflect.Type) *TypeInfo { isAminoMarshaler = true reprType = marshalAminoReprType(rm) } - if rm, ok := reflect.PtrTo(rt).MethodByName("UnmarshalAmino"); ok { + if rm, ok := reflect.PointerTo(rt).MethodByName("UnmarshalAmino"); ok { if !isAminoMarshaler { panic("Must implement both (o).MarshalAmino and (*o).UnmarshalAmino") } diff --git a/tm2/pkg/bft/consensus/state.go b/tm2/pkg/bft/consensus/state.go index fcacb57e229..4e64418f6ac 100644 --- a/tm2/pkg/bft/consensus/state.go +++ b/tm2/pkg/bft/consensus/state.go @@ -2,6 +2,7 @@ package consensus import ( "bytes" + "context" goerrors "errors" "fmt" "log/slog" @@ -10,6 +11,8 @@ import ( "sync" "time" + "github.com/gnolang/gno/telemetry" + "github.com/gnolang/gno/telemetry/metrics" "github.com/gnolang/gno/tm2/pkg/amino" cnscfg "github.com/gnolang/gno/tm2/pkg/bft/consensus/config" cstypes "github.com/gnolang/gno/tm2/pkg/bft/consensus/types" @@ -987,6 +990,13 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts return } + if telemetry.MetricsEnabled() { + startTime := time.Now() + defer func(t time.Time) { + metrics.BuildBlockTimer.Record(context.Background(), time.Since(t).Milliseconds()) + }(startTime) + } + proposerAddr := cs.privValidator.GetPubKey().Address() return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr) } diff --git a/tm2/pkg/p2p/switch.go b/tm2/pkg/p2p/switch.go index 368de659fb1..9d013b42ad1 100644 --- a/tm2/pkg/p2p/switch.go +++ b/tm2/pkg/p2p/switch.go @@ -1,11 +1,14 @@ package p2p import ( + "context" "fmt" "math" "sync" "time" + "github.com/gnolang/gno/telemetry" + "github.com/gnolang/gno/telemetry/metrics" "github.com/gnolang/gno/tm2/pkg/cmap" "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/p2p/config" @@ -242,6 +245,7 @@ func (sw *Switch) OnStop() { // // NOTE: Broadcast uses goroutines, so order of broadcast may not be preserved. func (sw *Switch) Broadcast(chID byte, msgBytes []byte) chan bool { + startTime := time.Now() sw.Logger.Debug("Broadcast", "channel", chID, "msgBytes", fmt.Sprintf("%X", msgBytes)) peers := sw.peers.List() @@ -260,6 +264,9 @@ func (sw *Switch) Broadcast(chID byte, msgBytes []byte) chan bool { go func() { wg.Wait() close(successChan) + if telemetry.MetricsEnabled() { + metrics.BroadcastTxTimer.Record(context.Background(), time.Since(startTime).Milliseconds()) + } }() return successChan