forked from cerc-io/laconicd-deprecated
Compare commits
3 Commits
main
...
aleem/25-w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34812d5e27 | ||
|
|
290c9fbf0c | ||
|
|
1cb6e7acbc |
7
.github/workflows/dependencies.yml
vendored
7
.github/workflows/dependencies.yml
vendored
@ -23,7 +23,6 @@ jobs:
|
||||
- name: "Dependency Review"
|
||||
uses: actions/dependency-review-action@v3
|
||||
if: env.GIT_DIFF
|
||||
# TODO: https://git.vdb.to/cerc-io/laconicd/issues/115
|
||||
# - name: "Go vulnerability check"
|
||||
# run: make vulncheck
|
||||
# if: env.GIT_DIFF
|
||||
- name: "Go vulnerability check"
|
||||
run: make vulncheck
|
||||
if: env.GIT_DIFF
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@ -39,7 +39,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: cachix/install-nix-action@v20
|
||||
- uses: cachix/install-nix-action@v18
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: ethermint
|
||||
|
||||
21
.github/workflows/stale.yml
vendored
Normal file
21
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: "Close stale issues & pull requests"
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v6
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-pr-message: "This pull request has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed in 7 days-before-close if no further activity occurs."
|
||||
stale-issue-message: "This issue is stale because it has been open 45 days with no activity. Remove `Status: Stale` label or comment or this will be closed in 7 days."
|
||||
days-before-stale: 45
|
||||
days-before-close: 7
|
||||
exempt-issue-labels: "Status: Blocked, Type: Bug, pinned, automerge"
|
||||
exempt-pr-labels: "Status: Blocked, Type: Bug, pinned, automerge"
|
||||
stale-pr-label: "Status: Stale"
|
||||
stale-issue-label: "Status: Stale"
|
||||
@ -6,14 +6,14 @@ run:
|
||||
linters:
|
||||
enable:
|
||||
- bodyclose
|
||||
# - depguard # 20231120 disable until https://github.com/golangci/golangci-lint/issues/3906 is released
|
||||
- depguard
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- goconst
|
||||
- gocritic
|
||||
- gofumpt
|
||||
# - revive # 20231120 overly sensitive unused detection
|
||||
- revive
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
|
||||
@ -19,9 +19,6 @@ test/
|
||||
tests/
|
||||
*_test.go
|
||||
|
||||
# false positive; TODO: https://github.com/cerc-io/laconicd/issues/104
|
||||
testutil/network/network.go
|
||||
|
||||
# Semgrep rules folder
|
||||
.semgrep
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@ -237,7 +237,7 @@ endif
|
||||
|
||||
ifeq (, $(shell which go-bindata))
|
||||
@echo "Installing go-bindata..."
|
||||
@go get github.com/kevinburke/go-bindata/go-bindata@v3
|
||||
@go get github.com/kevinburke/go-bindata/go-bindata
|
||||
else
|
||||
@echo "go-bindata already installed; skipping..."
|
||||
endif
|
||||
|
||||
28
go.mod
28
go.mod
@ -27,8 +27,10 @@ require (
|
||||
github.com/holiman/uint256 v1.2.1
|
||||
github.com/improbable-eng/grpc-web v0.15.0
|
||||
github.com/ipfs/go-cid v0.3.2
|
||||
github.com/ipld/go-ipld-prime v0.19.0
|
||||
github.com/ipfs/go-ipld-cbor v0.0.6
|
||||
github.com/ipld/go-ipld-prime v0.18.0
|
||||
github.com/miguelmota/go-ethereum-hdwallet v0.1.1
|
||||
github.com/multiformats/go-multihash v0.2.0
|
||||
github.com/onsi/ginkgo/v2 v2.5.1
|
||||
github.com/onsi/gomega v1.24.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
@ -43,8 +45,8 @@ require (
|
||||
github.com/tendermint/tm-db v0.6.7
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
github.com/vektah/gqlparser/v2 v2.5.1
|
||||
golang.org/x/net v0.7.0
|
||||
golang.org/x/text v0.7.0
|
||||
golang.org/x/net v0.4.0
|
||||
golang.org/x/text v0.5.0
|
||||
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8
|
||||
@ -65,7 +67,7 @@ require (
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||
github.com/Workiva/go-datastructures v1.0.53 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.122 // indirect
|
||||
github.com/aws/aws-sdk-go v1.40.45 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
@ -121,7 +123,7 @@ require (
|
||||
github.com/gtank/merlin v0.1.1 // indirect
|
||||
github.com/gtank/ristretto255 v0.1.2 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.0 // indirect
|
||||
github.com/hashicorp/go-getter v1.6.1 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
@ -131,10 +133,12 @@ require (
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/huin/goupnp v1.0.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/ipfs/go-block-format v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipfs-util v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipld-format v0.0.1 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||
github.com/kevinburke/go-bindata v3.24.0+incompatible // indirect
|
||||
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect
|
||||
github.com/klauspost/compress v1.15.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
@ -150,14 +154,13 @@ require (
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/mtibben/percent v0.2.1 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.3 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.0.3 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.1 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
@ -188,17 +191,18 @@ require (
|
||||
github.com/tendermint/go-amino v0.16.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/ulikunitz/xz v0.5.8 // indirect
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 // indirect
|
||||
github.com/zondax/hid v0.9.1 // indirect
|
||||
github.com/zondax/ledger-go v0.14.0 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/oauth2 v0.1.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/term v0.3.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.103.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
|
||||
433
go.sum
433
go.sum
@ -19,177 +19,36 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
|
||||
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
|
||||
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
|
||||
cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
|
||||
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
|
||||
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
|
||||
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
|
||||
cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
|
||||
cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
|
||||
cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
|
||||
cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
|
||||
cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
|
||||
cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
|
||||
cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
|
||||
cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
|
||||
cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
|
||||
cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
|
||||
cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
|
||||
cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
|
||||
cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
|
||||
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
||||
cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
|
||||
cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
|
||||
cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
|
||||
cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
|
||||
cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
|
||||
cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
|
||||
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
|
||||
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||
cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
|
||||
cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU=
|
||||
cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE=
|
||||
cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48=
|
||||
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||
cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
|
||||
cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
|
||||
cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
|
||||
cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
|
||||
cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
|
||||
cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
|
||||
cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
|
||||
cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=
|
||||
cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
|
||||
cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=
|
||||
cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=
|
||||
cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=
|
||||
cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
|
||||
cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
|
||||
cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
|
||||
cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
|
||||
cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
|
||||
cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=
|
||||
cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=
|
||||
cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
|
||||
cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
|
||||
cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
|
||||
cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
|
||||
cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
|
||||
cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
|
||||
cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
|
||||
cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
|
||||
cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=
|
||||
cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=
|
||||
cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
|
||||
cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
|
||||
cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
|
||||
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
|
||||
cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk=
|
||||
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
|
||||
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
|
||||
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
|
||||
cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
|
||||
cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
|
||||
cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
|
||||
cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
|
||||
cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
|
||||
cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
|
||||
cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=
|
||||
cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=
|
||||
cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=
|
||||
cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
|
||||
cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
|
||||
cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
|
||||
cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
|
||||
cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
|
||||
cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
|
||||
cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=
|
||||
cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=
|
||||
cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=
|
||||
cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=
|
||||
cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=
|
||||
cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=
|
||||
cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
|
||||
cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=
|
||||
cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
|
||||
cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
|
||||
cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=
|
||||
cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=
|
||||
cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=
|
||||
cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=
|
||||
cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=
|
||||
cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=
|
||||
cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
|
||||
cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
|
||||
cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
|
||||
cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
|
||||
cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
|
||||
cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
|
||||
cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
|
||||
cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
|
||||
cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
|
||||
cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
|
||||
cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
|
||||
cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
|
||||
cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ=
|
||||
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
|
||||
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
|
||||
cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
|
||||
cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
|
||||
cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
|
||||
cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=
|
||||
cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=
|
||||
cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=
|
||||
cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
|
||||
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
|
||||
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
|
||||
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w=
|
||||
cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE=
|
||||
@ -274,9 +133,10 @@ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo=
|
||||
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go v1.40.45 h1:QN1nsY27ssD/JmW4s83qmSb+uL6DG4GmCDzjmJB4xUI=
|
||||
github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=
|
||||
@ -353,12 +213,6 @@ github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3h
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E=
|
||||
github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
@ -476,10 +330,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
|
||||
github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=
|
||||
@ -590,9 +440,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -609,7 +457,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
@ -634,9 +481,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.3/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
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/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
@ -648,7 +492,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us=
|
||||
github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
@ -661,11 +504,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@ -674,22 +512,12 @@ github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
@ -723,6 +551,8 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
|
||||
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
|
||||
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
|
||||
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
|
||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@ -732,8 +562,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.7.0 h1:bzrYP+qu/gMrL1au7/aDvkoOVGUJpeKBgbqRHACAFDY=
|
||||
github.com/hashicorp/go-getter v1.7.0/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-getter v1.6.1 h1:NASsgP4q6tL94WH6nJxKWj8As2H/2kop/bB1d8JMyRY=
|
||||
github.com/hashicorp/go-getter v1.6.1/go.mod h1:IZCrswsZPeWv9IkVnLElzRU/gz/QPi6pZHn4tv6vbwA=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
@ -748,6 +578,7 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
@ -796,10 +627,20 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y
|
||||
github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE=
|
||||
github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0=
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po=
|
||||
github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE=
|
||||
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
|
||||
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
|
||||
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
|
||||
github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
|
||||
github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
|
||||
github.com/ipld/go-ipld-prime v0.19.0 h1:5axC7rJmPc17Emw6TelxGwnzALk0PdupZ2oj2roDj04=
|
||||
github.com/ipld/go-ipld-prime v0.19.0/go.mod h1:Q9j3BaVXwaA3o5JUDNvptDDr/x8+F7FG6XJ8WI3ILg4=
|
||||
github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50=
|
||||
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
|
||||
github.com/ipfs/go-ipld-cbor v0.0.6 h1:pYuWHyvSpIsOOLw4Jy7NbBkCyzLDcl64Bf/LZW7eBQ0=
|
||||
github.com/ipfs/go-ipld-cbor v0.0.6/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA=
|
||||
github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80=
|
||||
github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms=
|
||||
github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo=
|
||||
github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
@ -807,6 +648,7 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1C
|
||||
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/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b h1:izTof8BKh/nE1wrKOrloNA5q4odOarjf+Xpe+4qow98=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
@ -828,6 +670,7 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
@ -836,12 +679,6 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||
github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||
github.com/kevinburke/go-bindata v1.1.0 h1:JZ8XIdxtkAszuYkgf17qwQzcU/RgsGSVLSULJdN+5bU=
|
||||
github.com/kevinburke/go-bindata v1.1.0/go.mod h1:UJ72WTOoRKzbz+vwtKgARJwsy+1ZGUukVBUCc197TJo=
|
||||
github.com/kevinburke/go-bindata v3.22.0+incompatible h1:/JmqEhIWQ7GRScV0WjX/0tqBrC5D21ALg0H0U/KZ/ts=
|
||||
github.com/kevinburke/go-bindata v3.22.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi30bslSp9YqD9pysLxunQDdb2CPM=
|
||||
github.com/kevinburke/go-bindata v3.24.0+incompatible h1:qajFA3D0pH94OTLU4zcCCKCDgR+Zr2cZK/RPJHDdFoY=
|
||||
github.com/kevinburke/go-bindata v3.24.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi30bslSp9YqD9pysLxunQDdb2CPM=
|
||||
github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
|
||||
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM=
|
||||
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc=
|
||||
@ -850,6 +687,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
|
||||
@ -932,17 +770,19 @@ github.com/miguelmota/go-ethereum-hdwallet v0.1.1/go.mod h1:f9m9uXokAHA6WNoYOPjj
|
||||
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
|
||||
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94=
|
||||
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
||||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
@ -962,6 +802,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
@ -971,11 +812,14 @@ github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
|
||||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
|
||||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
|
||||
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
|
||||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
|
||||
github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE=
|
||||
github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108=
|
||||
github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
|
||||
github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs=
|
||||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
|
||||
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.2.0 h1:oytJb9ZA1OUW0r0f9ea18GiaPOo4SXyc7p2movyUuo4=
|
||||
github.com/multiformats/go-multihash v0.2.0/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
|
||||
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
|
||||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
@ -1057,6 +901,7 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
|
||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
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/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls=
|
||||
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
@ -1149,6 +994,7 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
@ -1239,8 +1085,8 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
|
||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
@ -1254,7 +1100,10 @@ github.com/vektah/gqlparser/v2 v2.5.1 h1:ZGu+bquAY23jsxDRcYpWjttRZrUz07LbiY77gUO
|
||||
github.com/vektah/gqlparser/v2 v2.5.1/go.mod h1:mPgqFBu/woKTVYWyNk8cO3kh4S/f4aRFZrvOnp3hmCs=
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 h1:WXhVOwj2USAXB5oMDwRl3piOux2XMV9TANaYxXHdkoE=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
@ -1285,10 +1134,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
@ -1302,10 +1149,12 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/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-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -1353,7 +1202,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
@ -1416,27 +1264,17 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -1446,23 +1284,10 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk=
|
||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
|
||||
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
|
||||
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -1474,9 +1299,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -1490,6 +1313,7 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/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-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -1542,60 +1366,37 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -1606,9 +1407,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -1674,10 +1474,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
@ -1686,9 +1482,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
@ -1717,35 +1510,6 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
|
||||
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
|
||||
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
|
||||
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
||||
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||
google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||
google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
|
||||
google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||
google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||
google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
|
||||
google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
|
||||
google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ=
|
||||
google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
@ -1800,73 +1564,7 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
|
||||
google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
|
||||
google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||
google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
|
||||
google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
|
||||
google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||
google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
|
||||
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
|
||||
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
|
||||
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c h1:S34D59DS2GWOEwWNt4fYmTcFrtlOgukG2k9WsomZ7tg=
|
||||
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
@ -1893,27 +1591,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
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=
|
||||
@ -1926,9 +1605,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk=
|
||||
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
|
||||
163
init.sh
163
init.sh
@ -10,111 +10,104 @@ LOGLEVEL="info"
|
||||
TRACE="--trace"
|
||||
# TRACE=""
|
||||
|
||||
if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
|
||||
# validate dependencies are installed
|
||||
command -v jq > /dev/null 2>&1 || { echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"; exit 1; }
|
||||
# validate dependencies are installed
|
||||
command -v jq > /dev/null 2>&1 || { echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"; exit 1; }
|
||||
|
||||
# remove existing daemon and client
|
||||
rm -rf $HOME/.laconicd/*
|
||||
rm -rf $HOME/.laconic/*
|
||||
# remove existing daemon and client
|
||||
rm -rf ~/.laconic*
|
||||
|
||||
if [ -n "`which make`" ]; then
|
||||
make install
|
||||
fi
|
||||
make install
|
||||
|
||||
laconicd config keyring-backend $KEYRING
|
||||
laconicd config chain-id $CHAINID
|
||||
laconicd config keyring-backend $KEYRING
|
||||
laconicd config chain-id $CHAINID
|
||||
|
||||
# if $KEY exists it should be deleted
|
||||
laconicd keys add $KEY --keyring-backend $KEYRING --algo $KEYALGO
|
||||
# if $KEY exists it should be deleted
|
||||
laconicd keys add $KEY --keyring-backend $KEYRING --algo $KEYALGO
|
||||
|
||||
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
|
||||
laconicd init $MONIKER --chain-id $CHAINID
|
||||
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
|
||||
laconicd init $MONIKER --chain-id $CHAINID
|
||||
|
||||
# Change parameter token denominations to aphoton
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["staking"]["params"]["bond_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["crisis"]["constant_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
# Custom modules
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
# Change parameter token denominations to aphoton
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["staking"]["params"]["bond_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["crisis"]["constant_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
# Custom modules
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commit_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveal_fee"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_minimum_bid"]["denom"]="aphoton"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
|
||||
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
|
||||
echo "Setting timers for expiry tests."
|
||||
if [[ "$TEST_REGISTRY_EXPIRY" == "true" ]]; then
|
||||
echo "Setting timers for expiry tests."
|
||||
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
fi
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["record_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
fi
|
||||
|
||||
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
|
||||
echo "Enabling auction and setting timers."
|
||||
if [[ "$TEST_AUCTION_ENABLED" == "true" ]]; then
|
||||
echo "Enabling auction and setting timers."
|
||||
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_enabled"]=true' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="300s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
fi
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_enabled"]=true' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_rent_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_grace_period"]="300s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_commits_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.app_state["registry"]["params"]["authority_auction_reveals_duration"]="60s"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
fi
|
||||
|
||||
# increase block time (?)
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="1000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
# increase block time (?)
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="1000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
|
||||
# Set gas limit in genesis
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="10000000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
# Set gas limit in genesis
|
||||
cat $HOME/.laconicd/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="10000000"' > $HOME/.laconicd/config/tmp_genesis.json && mv $HOME/.laconicd/config/tmp_genesis.json $HOME/.laconicd/config/genesis.json
|
||||
|
||||
# disable produce empty block
|
||||
# disable produce empty block
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
|
||||
else
|
||||
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
|
||||
fi
|
||||
|
||||
if [[ $1 == "pending" ]]; then
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
|
||||
else
|
||||
sed -i 's/create_empty_blocks = true/create_empty_blocks = false/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
else
|
||||
sed -i 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $1 == "pending" ]]; then
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i '' 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
else
|
||||
sed -i 's/create_empty_blocks_interval = "0s"/create_empty_blocks_interval = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_propose = "3s"/timeout_propose = "30s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_prevote = "1s"/timeout_prevote = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_precommit = "1s"/timeout_precommit = "10s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "5s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_commit = "5s"/timeout_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
sed -i 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "150s"/g' $HOME/.laconicd/config/config.toml
|
||||
fi
|
||||
fi
|
||||
# Allocate genesis accounts (cosmos formatted addresses)
|
||||
laconicd add-genesis-account $KEY 100000000000000000000000000aphoton --keyring-backend $KEYRING
|
||||
|
||||
# Allocate genesis accounts (cosmos formatted addresses)
|
||||
laconicd add-genesis-account $KEY 100000000000000000000000000aphoton --keyring-backend $KEYRING
|
||||
# Sign genesis transaction
|
||||
laconicd gentx $KEY 1000000000000000000000aphoton --keyring-backend $KEYRING --chain-id $CHAINID
|
||||
|
||||
# Sign genesis transaction
|
||||
laconicd gentx $KEY 1000000000000000000000aphoton --keyring-backend $KEYRING --chain-id $CHAINID
|
||||
# Collect genesis tx
|
||||
laconicd collect-gentxs
|
||||
|
||||
# Collect genesis tx
|
||||
laconicd collect-gentxs
|
||||
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||
laconicd validate-genesis
|
||||
|
||||
# Run this to ensure everything worked and that the genesis file is setup correctly
|
||||
laconicd validate-genesis
|
||||
|
||||
if [[ $1 == "pending" ]]; then
|
||||
echo "pending mode is on, please wait for the first block committed."
|
||||
fi
|
||||
else
|
||||
echo "Using existing database at $HOME/.laconicd. To replace, run '`basename $0` clean'"
|
||||
if [[ $1 == "pending" ]]; then
|
||||
echo "pending mode is on, please wait for the first block committed."
|
||||
fi
|
||||
|
||||
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
|
||||
|
||||
@ -30,102 +30,4 @@ message WebsiteRegistrationRecord {
|
||||
string tls_cert_cid = 4 [(gogoproto.moretags) = "json:\"TLSCertCID\" yaml:\"TLSCertCID\""];
|
||||
string type = 5 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string version = 6 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
}
|
||||
|
||||
message ApplicationRecord {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string name = 2 [(gogoproto.moretags) = "json:\"name\" yaml:\"name\""];
|
||||
string description = 3 [(gogoproto.moretags) = "json:\"description\" yaml:\"description\""];
|
||||
string version = 4 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string homepage = 5 [(gogoproto.moretags) = "json:\"homepage\" yaml:\"homepage\""];
|
||||
string license = 6 [(gogoproto.moretags) = "json:\"license\" yaml:\"license\""];
|
||||
string author = 7 [(gogoproto.moretags) = "json:\"author\" yaml:\"author\""];
|
||||
repeated string repository = 8 [(gogoproto.moretags) = "json:\"repository\" yaml:\"repository\""];
|
||||
string repository_ref = 9 [(gogoproto.moretags) = "json:\"repositoryRef\" yaml:\"repositoryRef\""];
|
||||
string app_version = 10 [(gogoproto.moretags) = "json:\"appVersion\" yaml:\"appVersion\""];
|
||||
string app_type = 11 [(gogoproto.moretags) = "json:\"appType\" yaml:\"appType\""];
|
||||
string engines = 12 [(gogoproto.moretags) = "json:\"engines\" yaml:\"engines\""];
|
||||
repeated string os = 13 [(gogoproto.moretags) = "json:\"os\" yaml:\"os\""];
|
||||
repeated string cpu = 14 [(gogoproto.moretags) = "json:\"cpu\" yaml:\"cpu\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
|
||||
message ApplicationArtifact {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string name = 2 [(gogoproto.moretags) = "json:\"name\" yaml:\"name\""];
|
||||
string description = 4 [(gogoproto.moretags) = "json:\"description\" yaml:\"description\""];
|
||||
string version = 5 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string application = 6 [(gogoproto.moretags) = "json:\"application\" yaml:\"application\""];
|
||||
string content_type = 7 [(gogoproto.moretags) = "json:\"contentType\" yaml:\"contentType\""];
|
||||
string os = 8 [(gogoproto.moretags) = "json:\"os\" yaml:\"os\""];
|
||||
string cpu = 9 [(gogoproto.moretags) = "json:\"cpu\" yaml:\"cpu\""];
|
||||
repeated string uri = 10 [(gogoproto.moretags) = "json:\"uri\" yaml:\"uri\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
|
||||
message DnsRecord {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string name = 2 [(gogoproto.moretags) = "json:\"name\" yaml:\"name\""];
|
||||
string version = 3 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string resource_type = 4 [(gogoproto.moretags) = "json:\"resourceType\" yaml:\"resourceType\""];
|
||||
string value = 5 [(gogoproto.moretags) = "json:\"value\" yaml:\"value\""];
|
||||
string request = 6 [(gogoproto.moretags) = "json:\"request\" yaml:\"request\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
|
||||
message ApplicationDeploymentRequest {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string name = 2 [(gogoproto.moretags) = "json:\"name\" yaml:\"name\""];
|
||||
string version = 3 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string application = 4 [(gogoproto.moretags) = "json:\"application\" yaml:\"application\""];
|
||||
string dns = 5 [(gogoproto.moretags) = "json:\"dns\" yaml:\"dns\""];
|
||||
string config = 6 [(gogoproto.moretags) = "json:\"config\" yaml:\"config\""];
|
||||
string deployment = 7 [(gogoproto.moretags) = "json:\"deployment\" yaml:\"deployment\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
|
||||
message ApplicationDeploymentRecord {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string name = 2 [(gogoproto.moretags) = "json:\"name\" yaml:\"name\""];
|
||||
string description = 3 [(gogoproto.moretags) = "json:\"description\" yaml:\"description\""];
|
||||
string version = 4 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string application = 5 [(gogoproto.moretags) = "json:\"application\" yaml:\"application\""];
|
||||
string url = 6 [(gogoproto.moretags) = "json:\"url\" yaml:\"url\""];
|
||||
string dns = 7 [(gogoproto.moretags) = "json:\"dns\" yaml:\"dns\""];
|
||||
string request = 8 [(gogoproto.moretags) = "json:\"request\" yaml:\"request\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
|
||||
message ApplicationDeploymentRemovalRequest {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string version = 2 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string deployment = 3 [(gogoproto.moretags) = "json:\"deployment\" yaml:\"deployment\""];
|
||||
string request = 4 [(gogoproto.moretags) = "json:\"request\" yaml:\"request\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
|
||||
message ApplicationDeploymentRemovalRecord {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string version = 2 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string deployment = 3 [(gogoproto.moretags) = "json:\"deployment\" yaml:\"deployment\""];
|
||||
string request = 4 [(gogoproto.moretags) = "json:\"request\" yaml:\"request\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
|
||||
message GeneralRecord {
|
||||
string type = 1 [(gogoproto.moretags) = "json:\"type\" yaml:\"type\""];
|
||||
string name = 2 [(gogoproto.moretags) = "json:\"name\" yaml:\"name\""];
|
||||
string description = 3 [(gogoproto.moretags) = "json:\"description\" yaml:\"description\""];
|
||||
string version = 4 [(gogoproto.moretags) = "json:\"version\" yaml:\"version\""];
|
||||
string category = 5 [(gogoproto.moretags) = "json:\"category\" yaml:\"category\""];
|
||||
string value = 6 [(gogoproto.moretags) = "json:\"value\" yaml:\"value\""];
|
||||
string meta = 20 [(gogoproto.moretags) = "json:\"meta\" yaml:\"meta\""];
|
||||
repeated string tags = 21 [(gogoproto.moretags) = "json:\"tags\" yaml:\"tags\""];
|
||||
}
|
||||
}
|
||||
109
proto/wasm/v1/authz.proto
Normal file
109
proto/wasm/v1/authz.proto
Normal file
@ -0,0 +1,109 @@
|
||||
syntax = "proto3";
|
||||
package cosmwasm.wasm.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "cosmos_proto/cosmos.proto";
|
||||
import "cosmos/base/v1beta1/coin.proto";
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
option go_package = "github.com/cerc-io/laconicd/x/wasm/types";
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
|
||||
// ContractExecutionAuthorization defines authorization for wasm execute.
|
||||
// Since: wasmd 0.30
|
||||
message ContractExecutionAuthorization {
|
||||
option (cosmos_proto.implements_interface) = "Authorization";
|
||||
|
||||
// Grants for contract executions
|
||||
repeated ContractGrant grants = 1 [ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// ContractMigrationAuthorization defines authorization for wasm contract
|
||||
// migration. Since: wasmd 0.30
|
||||
message ContractMigrationAuthorization {
|
||||
option (cosmos_proto.implements_interface) = "Authorization";
|
||||
|
||||
// Grants for contract migrations
|
||||
repeated ContractGrant grants = 1 [ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// ContractGrant a granted permission for a single contract
|
||||
// Since: wasmd 0.30
|
||||
message ContractGrant {
|
||||
// Contract is the bech32 address of the smart contract
|
||||
string contract = 1;
|
||||
|
||||
// Limit defines execution limits that are enforced and updated when the grant
|
||||
// is applied. When the limit lapsed the grant is removed.
|
||||
google.protobuf.Any limit = 2
|
||||
[ (cosmos_proto.accepts_interface) = "ContractAuthzLimitX" ];
|
||||
|
||||
// Filter define more fine-grained control on the message payload passed
|
||||
// to the contract in the operation. When no filter applies on execution, the
|
||||
// operation is prohibited.
|
||||
google.protobuf.Any filter = 3
|
||||
[ (cosmos_proto.accepts_interface) = "ContractAuthzFilterX" ];
|
||||
}
|
||||
|
||||
// MaxCallsLimit limited number of calls to the contract. No funds transferable.
|
||||
// Since: wasmd 0.30
|
||||
message MaxCallsLimit {
|
||||
option (cosmos_proto.implements_interface) = "ContractAuthzLimitX";
|
||||
|
||||
// Remaining number that is decremented on each execution
|
||||
uint64 remaining = 1;
|
||||
}
|
||||
|
||||
// MaxFundsLimit defines the maximal amounts that can be sent to the contract.
|
||||
// Since: wasmd 0.30
|
||||
message MaxFundsLimit {
|
||||
option (cosmos_proto.implements_interface) = "ContractAuthzLimitX";
|
||||
|
||||
// Amounts is the maximal amount of tokens transferable to the contract.
|
||||
repeated cosmos.base.v1beta1.Coin amounts = 1 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
}
|
||||
|
||||
// CombinedLimit defines the maximal amounts that can be sent to a contract and
|
||||
// the maximal number of calls executable. Both need to remain >0 to be valid.
|
||||
// Since: wasmd 0.30
|
||||
message CombinedLimit {
|
||||
option (cosmos_proto.implements_interface) = "ContractAuthzLimitX";
|
||||
|
||||
// Remaining number that is decremented on each execution
|
||||
uint64 calls_remaining = 1;
|
||||
// Amounts is the maximal amount of tokens transferable to the contract.
|
||||
repeated cosmos.base.v1beta1.Coin amounts = 2 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
}
|
||||
|
||||
// AllowAllMessagesFilter is a wildcard to allow any type of contract payload
|
||||
// message.
|
||||
// Since: wasmd 0.30
|
||||
message AllowAllMessagesFilter {
|
||||
option (cosmos_proto.implements_interface) = "ContractAuthzFilterX";
|
||||
}
|
||||
|
||||
// AcceptedMessageKeysFilter accept only the specific contract message keys in
|
||||
// the json object to be executed.
|
||||
// Since: wasmd 0.30
|
||||
message AcceptedMessageKeysFilter {
|
||||
option (cosmos_proto.implements_interface) = "ContractAuthzFilterX";
|
||||
|
||||
// Messages is the list of unique keys
|
||||
repeated string keys = 1;
|
||||
}
|
||||
|
||||
// AcceptedMessagesFilter accept only the specific raw contract messages to be
|
||||
// executed.
|
||||
// Since: wasmd 0.30
|
||||
message AcceptedMessagesFilter {
|
||||
option (cosmos_proto.implements_interface) = "ContractAuthzFilterX";
|
||||
|
||||
// Messages is the list of raw contract messages
|
||||
repeated bytes messages = 1 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
}
|
||||
46
proto/wasm/v1/genesis.proto
Normal file
46
proto/wasm/v1/genesis.proto
Normal file
@ -0,0 +1,46 @@
|
||||
syntax = "proto3";
|
||||
package cosmwasm.wasm.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "wasm/v1/types.proto";
|
||||
|
||||
option go_package = "github.com/cerc-io/laconicd/x/wasm/types";
|
||||
|
||||
// GenesisState - genesis state of x/wasm
|
||||
message GenesisState {
|
||||
Params params = 1 [ (gogoproto.nullable) = false ];
|
||||
repeated Code codes = 2
|
||||
[ (gogoproto.nullable) = false, (gogoproto.jsontag) = "codes,omitempty" ];
|
||||
repeated Contract contracts = 3 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.jsontag) = "contracts,omitempty"
|
||||
];
|
||||
repeated Sequence sequences = 4 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.jsontag) = "sequences,omitempty"
|
||||
];
|
||||
}
|
||||
|
||||
// Code struct encompasses CodeInfo and CodeBytes
|
||||
message Code {
|
||||
uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ];
|
||||
CodeInfo code_info = 2 [ (gogoproto.nullable) = false ];
|
||||
bytes code_bytes = 3;
|
||||
// Pinned to wasmvm cache
|
||||
bool pinned = 4;
|
||||
}
|
||||
|
||||
// Contract struct encompasses ContractAddress, ContractInfo, and ContractState
|
||||
message Contract {
|
||||
string contract_address = 1;
|
||||
ContractInfo contract_info = 2 [ (gogoproto.nullable) = false ];
|
||||
repeated Model contract_state = 3 [ (gogoproto.nullable) = false ];
|
||||
repeated ContractCodeHistoryEntry contract_code_history = 4
|
||||
[ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// Sequence key and value of an id generation counter
|
||||
message Sequence {
|
||||
bytes id_key = 1 [ (gogoproto.customname) = "IDKey" ];
|
||||
uint64 value = 2;
|
||||
}
|
||||
31
proto/wasm/v1/ibc.proto
Normal file
31
proto/wasm/v1/ibc.proto
Normal file
@ -0,0 +1,31 @@
|
||||
syntax = "proto3";
|
||||
package cosmwasm.wasm.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
|
||||
option go_package = "github.com/cerc-io/laconicd/x/wasm/types";
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
|
||||
// MsgIBCSend
|
||||
message MsgIBCSend {
|
||||
// the channel by which the packet will be sent
|
||||
string channel = 2 [ (gogoproto.moretags) = "yaml:\"source_channel\"" ];
|
||||
|
||||
// Timeout height relative to the current block height.
|
||||
// The timeout is disabled when set to 0.
|
||||
uint64 timeout_height = 4
|
||||
[ (gogoproto.moretags) = "yaml:\"timeout_height\"" ];
|
||||
// Timeout timestamp (in nanoseconds) relative to the current block timestamp.
|
||||
// The timeout is disabled when set to 0.
|
||||
uint64 timeout_timestamp = 5
|
||||
[ (gogoproto.moretags) = "yaml:\"timeout_timestamp\"" ];
|
||||
|
||||
// Data is the payload to transfer. We must not make assumption what format or
|
||||
// content is in here.
|
||||
bytes data = 6;
|
||||
}
|
||||
|
||||
// MsgIBCCloseChannel port and channel need to be owned by the contract
|
||||
message MsgIBCCloseChannel {
|
||||
string channel = 2 [ (gogoproto.moretags) = "yaml:\"source_channel\"" ];
|
||||
}
|
||||
272
proto/wasm/v1/proposal.proto
Normal file
272
proto/wasm/v1/proposal.proto
Normal file
@ -0,0 +1,272 @@
|
||||
syntax = "proto3";
|
||||
package cosmwasm.wasm.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "cosmos_proto/cosmos.proto";
|
||||
import "cosmos/base/v1beta1/coin.proto";
|
||||
import "wasm/v1/types.proto";
|
||||
|
||||
option go_package = "github.com/cerc-io/laconicd/x/wasm/types";
|
||||
option (gogoproto.goproto_stringer_all) = false;
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
option (gogoproto.equal_all) = true;
|
||||
|
||||
// StoreCodeProposal gov proposal content type to submit WASM code to the system
|
||||
message StoreCodeProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// RunAs is the address that is passed to the contract's environment as sender
|
||||
string run_as = 3;
|
||||
// WASMByteCode can be raw or gzip compressed
|
||||
bytes wasm_byte_code = 4 [ (gogoproto.customname) = "WASMByteCode" ];
|
||||
// Used in v1beta1
|
||||
reserved 5, 6;
|
||||
// InstantiatePermission to apply on contract creation, optional
|
||||
AccessConfig instantiate_permission = 7;
|
||||
// UnpinCode code on upload, optional
|
||||
bool unpin_code = 8;
|
||||
// Source is the URL where the code is hosted
|
||||
string source = 9;
|
||||
// Builder is the docker image used to build the code deterministically, used
|
||||
// for smart contract verification
|
||||
string builder = 10;
|
||||
// CodeHash is the SHA256 sum of the code outputted by builder, used for smart
|
||||
// contract verification
|
||||
bytes code_hash = 11;
|
||||
}
|
||||
|
||||
// InstantiateContractProposal gov proposal content type to instantiate a
|
||||
// contract.
|
||||
message InstantiateContractProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// RunAs is the address that is passed to the contract's environment as sender
|
||||
string run_as = 3;
|
||||
// Admin is an optional address that can execute migrations
|
||||
string admin = 4;
|
||||
// CodeID is the reference to the stored WASM code
|
||||
uint64 code_id = 5 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Label is optional metadata to be stored with a constract instance.
|
||||
string label = 6;
|
||||
// Msg json encoded message to be passed to the contract on instantiation
|
||||
bytes msg = 7 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
// Funds coins that are transferred to the contract on instantiation
|
||||
repeated cosmos.base.v1beta1.Coin funds = 8 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
}
|
||||
|
||||
// InstantiateContract2Proposal gov proposal content type to instantiate
|
||||
// contract 2
|
||||
message InstantiateContract2Proposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// RunAs is the address that is passed to the contract's enviroment as sender
|
||||
string run_as = 3;
|
||||
// Admin is an optional address that can execute migrations
|
||||
string admin = 4;
|
||||
// CodeID is the reference to the stored WASM code
|
||||
uint64 code_id = 5 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Label is optional metadata to be stored with a constract instance.
|
||||
string label = 6;
|
||||
// Msg json encode message to be passed to the contract on instantiation
|
||||
bytes msg = 7 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
// Funds coins that are transferred to the contract on instantiation
|
||||
repeated cosmos.base.v1beta1.Coin funds = 8 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
// Salt is an arbitrary value provided by the sender. Size can be 1 to 64.
|
||||
bytes salt = 9;
|
||||
// FixMsg include the msg value into the hash for the predictable address.
|
||||
// Default is false
|
||||
bool fix_msg = 10;
|
||||
}
|
||||
|
||||
// MigrateContractProposal gov proposal content type to migrate a contract.
|
||||
message MigrateContractProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// Note: skipping 3 as this was previously used for unneeded run_as
|
||||
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 4;
|
||||
// CodeID references the new WASM code
|
||||
uint64 code_id = 5 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Msg json encoded message to be passed to the contract on migration
|
||||
bytes msg = 6 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
}
|
||||
|
||||
// SudoContractProposal gov proposal content type to call sudo on a contract.
|
||||
message SudoContractProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 3;
|
||||
// Msg json encoded message to be passed to the contract as sudo
|
||||
bytes msg = 4 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
}
|
||||
|
||||
// ExecuteContractProposal gov proposal content type to call execute on a
|
||||
// contract.
|
||||
message ExecuteContractProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// RunAs is the address that is passed to the contract's environment as sender
|
||||
string run_as = 3;
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 4;
|
||||
// Msg json encoded message to be passed to the contract as execute
|
||||
bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
// Funds coins that are transferred to the contract on instantiation
|
||||
repeated cosmos.base.v1beta1.Coin funds = 6 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
}
|
||||
|
||||
// UpdateAdminProposal gov proposal content type to set an admin for a contract.
|
||||
message UpdateAdminProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// NewAdmin address to be set
|
||||
string new_admin = 3 [ (gogoproto.moretags) = "yaml:\"new_admin\"" ];
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 4;
|
||||
}
|
||||
|
||||
// ClearAdminProposal gov proposal content type to clear the admin of a
|
||||
// contract.
|
||||
message ClearAdminProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 3;
|
||||
}
|
||||
|
||||
// PinCodesProposal gov proposal content type to pin a set of code ids in the
|
||||
// wasmvm cache.
|
||||
message PinCodesProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ];
|
||||
// Description is a human readable text
|
||||
string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ];
|
||||
// CodeIDs references the new WASM codes
|
||||
repeated uint64 code_ids = 3 [
|
||||
(gogoproto.customname) = "CodeIDs",
|
||||
(gogoproto.moretags) = "yaml:\"code_ids\""
|
||||
];
|
||||
}
|
||||
|
||||
// UnpinCodesProposal gov proposal content type to unpin a set of code ids in
|
||||
// the wasmvm cache.
|
||||
message UnpinCodesProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ];
|
||||
// Description is a human readable text
|
||||
string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ];
|
||||
// CodeIDs references the WASM codes
|
||||
repeated uint64 code_ids = 3 [
|
||||
(gogoproto.customname) = "CodeIDs",
|
||||
(gogoproto.moretags) = "yaml:\"code_ids\""
|
||||
];
|
||||
}
|
||||
|
||||
// AccessConfigUpdate contains the code id and the access config to be
|
||||
// applied.
|
||||
message AccessConfigUpdate {
|
||||
// CodeID is the reference to the stored WASM code to be updated
|
||||
uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ];
|
||||
// InstantiatePermission to apply to the set of code ids
|
||||
AccessConfig instantiate_permission = 2 [ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// UpdateInstantiateConfigProposal gov proposal content type to update
|
||||
// instantiate config to a set of code ids.
|
||||
message UpdateInstantiateConfigProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ];
|
||||
// Description is a human readable text
|
||||
string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ];
|
||||
// AccessConfigUpdate contains the list of code ids and the access config
|
||||
// to be applied.
|
||||
repeated AccessConfigUpdate access_config_updates = 3
|
||||
[ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// StoreAndInstantiateContractProposal gov proposal content type to store
|
||||
// and instantiate the contract.
|
||||
message StoreAndInstantiateContractProposal {
|
||||
option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content";
|
||||
|
||||
// Title is a short summary
|
||||
string title = 1;
|
||||
// Description is a human readable text
|
||||
string description = 2;
|
||||
// RunAs is the address that is passed to the contract's environment as sender
|
||||
string run_as = 3;
|
||||
// WASMByteCode can be raw or gzip compressed
|
||||
bytes wasm_byte_code = 4 [ (gogoproto.customname) = "WASMByteCode" ];
|
||||
// InstantiatePermission to apply on contract creation, optional
|
||||
AccessConfig instantiate_permission = 5;
|
||||
// UnpinCode code on upload, optional
|
||||
bool unpin_code = 6;
|
||||
// Admin is an optional address that can execute migrations
|
||||
string admin = 7;
|
||||
// Label is optional metadata to be stored with a constract instance.
|
||||
string label = 8;
|
||||
// Msg json encoded message to be passed to the contract on instantiation
|
||||
bytes msg = 9 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
// Funds coins that are transferred to the contract on instantiation
|
||||
repeated cosmos.base.v1beta1.Coin funds = 10 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
// Source is the URL where the code is hosted
|
||||
string source = 11;
|
||||
// Builder is the docker image used to build the code deterministically, used
|
||||
// for smart contract verification
|
||||
string builder = 12;
|
||||
// CodeHash is the SHA256 sum of the code outputted by builder, used for smart
|
||||
// contract verification
|
||||
bytes code_hash = 13;
|
||||
}
|
||||
263
proto/wasm/v1/query.proto
Normal file
263
proto/wasm/v1/query.proto
Normal file
@ -0,0 +1,263 @@
|
||||
syntax = "proto3";
|
||||
package cosmwasm.wasm.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "wasm/v1/types.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "cosmos/base/query/v1beta1/pagination.proto";
|
||||
|
||||
option go_package = "github.com/cerc-io/laconicd/x/wasm/types";
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
option (gogoproto.equal_all) = false;
|
||||
|
||||
// Query provides defines the gRPC querier service
|
||||
service Query {
|
||||
// ContractInfo gets the contract meta data
|
||||
rpc ContractInfo(QueryContractInfoRequest)
|
||||
returns (QueryContractInfoResponse) {
|
||||
option (google.api.http).get = "/cosmwasm/wasm/v1/contract/{address}";
|
||||
}
|
||||
// ContractHistory gets the contract code history
|
||||
rpc ContractHistory(QueryContractHistoryRequest)
|
||||
returns (QueryContractHistoryResponse) {
|
||||
option (google.api.http).get =
|
||||
"/cosmwasm/wasm/v1/contract/{address}/history";
|
||||
}
|
||||
// ContractsByCode lists all smart contracts for a code id
|
||||
rpc ContractsByCode(QueryContractsByCodeRequest)
|
||||
returns (QueryContractsByCodeResponse) {
|
||||
option (google.api.http).get = "/cosmwasm/wasm/v1/code/{code_id}/contracts";
|
||||
}
|
||||
// AllContractState gets all raw store data for a single contract
|
||||
rpc AllContractState(QueryAllContractStateRequest)
|
||||
returns (QueryAllContractStateResponse) {
|
||||
option (google.api.http).get = "/cosmwasm/wasm/v1/contract/{address}/state";
|
||||
}
|
||||
// RawContractState gets single key from the raw store data of a contract
|
||||
rpc RawContractState(QueryRawContractStateRequest)
|
||||
returns (QueryRawContractStateResponse) {
|
||||
option (google.api.http).get =
|
||||
"/cosmwasm/wasm/v1/contract/{address}/raw/{query_data}";
|
||||
}
|
||||
// SmartContractState get smart query result from the contract
|
||||
rpc SmartContractState(QuerySmartContractStateRequest)
|
||||
returns (QuerySmartContractStateResponse) {
|
||||
option (google.api.http).get =
|
||||
"/cosmwasm/wasm/v1/contract/{address}/smart/{query_data}";
|
||||
}
|
||||
// Code gets the binary code and metadata for a singe wasm code
|
||||
rpc Code(QueryCodeRequest) returns (QueryCodeResponse) {
|
||||
option (google.api.http).get = "/cosmwasm/wasm/v1/code/{code_id}";
|
||||
}
|
||||
// Codes gets the metadata for all stored wasm codes
|
||||
rpc Codes(QueryCodesRequest) returns (QueryCodesResponse) {
|
||||
option (google.api.http).get = "/cosmwasm/wasm/v1/code";
|
||||
}
|
||||
|
||||
// PinnedCodes gets the pinned code ids
|
||||
rpc PinnedCodes(QueryPinnedCodesRequest) returns (QueryPinnedCodesResponse) {
|
||||
option (google.api.http).get = "/cosmwasm/wasm/v1/codes/pinned";
|
||||
}
|
||||
|
||||
// Params gets the module params
|
||||
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
|
||||
option (google.api.http).get = "/cosmwasm/wasm/v1/codes/params";
|
||||
}
|
||||
|
||||
// ContractsByCreator gets the contracts by creator
|
||||
rpc ContractsByCreator(QueryContractsByCreatorRequest)
|
||||
returns (QueryContractsByCreatorResponse) {
|
||||
option (google.api.http).get =
|
||||
"/cosmwasm/wasm/v1/contracts/creator/{creator_address}";
|
||||
}
|
||||
}
|
||||
|
||||
// QueryContractInfoRequest is the request type for the Query/ContractInfo RPC
|
||||
// method
|
||||
message QueryContractInfoRequest {
|
||||
// address is the address of the contract to query
|
||||
string address = 1;
|
||||
}
|
||||
// QueryContractInfoResponse is the response type for the Query/ContractInfo RPC
|
||||
// method
|
||||
message QueryContractInfoResponse {
|
||||
option (gogoproto.equal) = true;
|
||||
|
||||
// address is the address of the contract
|
||||
string address = 1;
|
||||
ContractInfo contract_info = 2 [
|
||||
(gogoproto.embed) = true,
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.jsontag) = ""
|
||||
];
|
||||
}
|
||||
|
||||
// QueryContractHistoryRequest is the request type for the Query/ContractHistory
|
||||
// RPC method
|
||||
message QueryContractHistoryRequest {
|
||||
// address is the address of the contract to query
|
||||
string address = 1;
|
||||
// pagination defines an optional pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 2;
|
||||
}
|
||||
|
||||
// QueryContractHistoryResponse is the response type for the
|
||||
// Query/ContractHistory RPC method
|
||||
message QueryContractHistoryResponse {
|
||||
repeated ContractCodeHistoryEntry entries = 1
|
||||
[ (gogoproto.nullable) = false ];
|
||||
// pagination defines the pagination in the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
|
||||
// QueryContractsByCodeRequest is the request type for the Query/ContractsByCode
|
||||
// RPC method
|
||||
message QueryContractsByCodeRequest {
|
||||
uint64 code_id = 1; // grpc-gateway_out does not support Go style CodID
|
||||
// pagination defines an optional pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 2;
|
||||
}
|
||||
|
||||
// QueryContractsByCodeResponse is the response type for the
|
||||
// Query/ContractsByCode RPC method
|
||||
message QueryContractsByCodeResponse {
|
||||
// contracts are a set of contract addresses
|
||||
repeated string contracts = 1;
|
||||
|
||||
// pagination defines the pagination in the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
|
||||
// QueryAllContractStateRequest is the request type for the
|
||||
// Query/AllContractState RPC method
|
||||
message QueryAllContractStateRequest {
|
||||
// address is the address of the contract
|
||||
string address = 1;
|
||||
// pagination defines an optional pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 2;
|
||||
}
|
||||
|
||||
// QueryAllContractStateResponse is the response type for the
|
||||
// Query/AllContractState RPC method
|
||||
message QueryAllContractStateResponse {
|
||||
repeated Model models = 1 [ (gogoproto.nullable) = false ];
|
||||
// pagination defines the pagination in the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
|
||||
// QueryRawContractStateRequest is the request type for the
|
||||
// Query/RawContractState RPC method
|
||||
message QueryRawContractStateRequest {
|
||||
// address is the address of the contract
|
||||
string address = 1;
|
||||
bytes query_data = 2;
|
||||
}
|
||||
|
||||
// QueryRawContractStateResponse is the response type for the
|
||||
// Query/RawContractState RPC method
|
||||
message QueryRawContractStateResponse {
|
||||
// Data contains the raw store data
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
// QuerySmartContractStateRequest is the request type for the
|
||||
// Query/SmartContractState RPC method
|
||||
message QuerySmartContractStateRequest {
|
||||
// address is the address of the contract
|
||||
string address = 1;
|
||||
// QueryData contains the query data passed to the contract
|
||||
bytes query_data = 2 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
}
|
||||
|
||||
// QuerySmartContractStateResponse is the response type for the
|
||||
// Query/SmartContractState RPC method
|
||||
message QuerySmartContractStateResponse {
|
||||
// Data contains the json data returned from the smart contract
|
||||
bytes data = 1 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
}
|
||||
|
||||
// QueryCodeRequest is the request type for the Query/Code RPC method
|
||||
message QueryCodeRequest {
|
||||
uint64 code_id = 1; // grpc-gateway_out does not support Go style CodID
|
||||
}
|
||||
|
||||
// CodeInfoResponse contains code meta data from CodeInfo
|
||||
message CodeInfoResponse {
|
||||
option (gogoproto.equal) = true;
|
||||
|
||||
uint64 code_id = 1 [
|
||||
(gogoproto.customname) = "CodeID",
|
||||
(gogoproto.jsontag) = "id"
|
||||
]; // id for legacy support
|
||||
string creator = 2;
|
||||
bytes data_hash = 3
|
||||
[ (gogoproto.casttype) =
|
||||
"github.com/tendermint/tendermint/libs/bytes.HexBytes" ];
|
||||
// Used in v1beta1
|
||||
reserved 4, 5;
|
||||
AccessConfig instantiate_permission = 6 [ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// QueryCodeResponse is the response type for the Query/Code RPC method
|
||||
message QueryCodeResponse {
|
||||
option (gogoproto.equal) = true;
|
||||
CodeInfoResponse code_info = 1
|
||||
[ (gogoproto.embed) = true, (gogoproto.jsontag) = "" ];
|
||||
bytes data = 2 [ (gogoproto.jsontag) = "data" ];
|
||||
}
|
||||
|
||||
// QueryCodesRequest is the request type for the Query/Codes RPC method
|
||||
message QueryCodesRequest {
|
||||
// pagination defines an optional pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 1;
|
||||
}
|
||||
|
||||
// QueryCodesResponse is the response type for the Query/Codes RPC method
|
||||
message QueryCodesResponse {
|
||||
repeated CodeInfoResponse code_infos = 1 [ (gogoproto.nullable) = false ];
|
||||
// pagination defines the pagination in the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
|
||||
// QueryPinnedCodesRequest is the request type for the Query/PinnedCodes
|
||||
// RPC method
|
||||
message QueryPinnedCodesRequest {
|
||||
// pagination defines an optional pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 2;
|
||||
}
|
||||
|
||||
// QueryPinnedCodesResponse is the response type for the
|
||||
// Query/PinnedCodes RPC method
|
||||
message QueryPinnedCodesResponse {
|
||||
repeated uint64 code_ids = 1
|
||||
[ (gogoproto.nullable) = false, (gogoproto.customname) = "CodeIDs" ];
|
||||
// pagination defines the pagination in the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
|
||||
// QueryParamsRequest is the request type for the Query/Params RPC method.
|
||||
message QueryParamsRequest {}
|
||||
|
||||
// QueryParamsResponse is the response type for the Query/Params RPC method.
|
||||
message QueryParamsResponse {
|
||||
// params defines the parameters of the module.
|
||||
Params params = 1 [ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// QueryContractsByCreatorRequest is the request type for the
|
||||
// Query/ContractsByCreator RPC method.
|
||||
message QueryContractsByCreatorRequest {
|
||||
// CreatorAddress is the address of contract creator
|
||||
string creator_address = 1;
|
||||
// Pagination defines an optional pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 2;
|
||||
}
|
||||
|
||||
// QueryContractsByCreatorResponse is the response type for the
|
||||
// Query/ContractsByCreator RPC method.
|
||||
message QueryContractsByCreatorResponse {
|
||||
// ContractAddresses result set
|
||||
repeated string contract_addresses = 1;
|
||||
// Pagination defines the pagination in the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
192
proto/wasm/v1/tx.proto
Normal file
192
proto/wasm/v1/tx.proto
Normal file
@ -0,0 +1,192 @@
|
||||
syntax = "proto3";
|
||||
package cosmwasm.wasm.v1;
|
||||
|
||||
import "cosmos/base/v1beta1/coin.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
import "wasm/v1/types.proto";
|
||||
|
||||
option go_package = "github.com/cerc-io/laconicd/x/wasm/types";
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
|
||||
// Msg defines the wasm Msg service.
|
||||
service Msg {
|
||||
// StoreCode to submit Wasm code to the system
|
||||
rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse);
|
||||
// InstantiateContract creates a new smart contract instance for the given
|
||||
// code id.
|
||||
rpc InstantiateContract(MsgInstantiateContract)
|
||||
returns (MsgInstantiateContractResponse);
|
||||
// InstantiateContract2 creates a new smart contract instance for the given
|
||||
// code id with a predictable address
|
||||
rpc InstantiateContract2(MsgInstantiateContract2)
|
||||
returns (MsgInstantiateContract2Response);
|
||||
// Execute submits the given message data to a smart contract
|
||||
rpc ExecuteContract(MsgExecuteContract) returns (MsgExecuteContractResponse);
|
||||
// Migrate runs a code upgrade/ downgrade for a smart contract
|
||||
rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse);
|
||||
// UpdateAdmin sets a new admin for a smart contract
|
||||
rpc UpdateAdmin(MsgUpdateAdmin) returns (MsgUpdateAdminResponse);
|
||||
// ClearAdmin removes any admin stored for a smart contract
|
||||
rpc ClearAdmin(MsgClearAdmin) returns (MsgClearAdminResponse);
|
||||
// UpdateInstantiateConfig updates instantiate config for a smart contract
|
||||
rpc UpdateInstantiateConfig(MsgUpdateInstantiateConfig)
|
||||
returns (MsgUpdateInstantiateConfigResponse);
|
||||
}
|
||||
|
||||
// MsgStoreCode submit Wasm code to the system
|
||||
message MsgStoreCode {
|
||||
// Sender is the that actor that signed the messages
|
||||
string sender = 1;
|
||||
// WASMByteCode can be raw or gzip compressed
|
||||
bytes wasm_byte_code = 2 [ (gogoproto.customname) = "WASMByteCode" ];
|
||||
// Used in v1beta1
|
||||
reserved 3, 4;
|
||||
// InstantiatePermission access control to apply on contract creation,
|
||||
// optional
|
||||
AccessConfig instantiate_permission = 5;
|
||||
}
|
||||
// MsgStoreCodeResponse returns store result data.
|
||||
message MsgStoreCodeResponse {
|
||||
// CodeID is the reference to the stored WASM code
|
||||
uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Checksum is the sha256 hash of the stored code
|
||||
bytes checksum = 2;
|
||||
}
|
||||
|
||||
// MsgInstantiateContract create a new smart contract instance for the given
|
||||
// code id.
|
||||
message MsgInstantiateContract {
|
||||
// Sender is the that actor that signed the messages
|
||||
string sender = 1;
|
||||
// Admin is an optional address that can execute migrations
|
||||
string admin = 2;
|
||||
// CodeID is the reference to the stored WASM code
|
||||
uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Label is optional metadata to be stored with a contract instance.
|
||||
string label = 4;
|
||||
// Msg json encoded message to be passed to the contract on instantiation
|
||||
bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
// Funds coins that are transferred to the contract on instantiation
|
||||
repeated cosmos.base.v1beta1.Coin funds = 6 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
}
|
||||
|
||||
// MsgInstantiateContract2 create a new smart contract instance for the given
|
||||
// code id with a predicable address.
|
||||
message MsgInstantiateContract2 {
|
||||
// Sender is the that actor that signed the messages
|
||||
string sender = 1;
|
||||
// Admin is an optional address that can execute migrations
|
||||
string admin = 2;
|
||||
// CodeID is the reference to the stored WASM code
|
||||
uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Label is optional metadata to be stored with a contract instance.
|
||||
string label = 4;
|
||||
// Msg json encoded message to be passed to the contract on instantiation
|
||||
bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
// Funds coins that are transferred to the contract on instantiation
|
||||
repeated cosmos.base.v1beta1.Coin funds = 6 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
// Salt is an arbitrary value provided by the sender. Size can be 1 to 64.
|
||||
bytes salt = 7;
|
||||
// FixMsg include the msg value into the hash for the predictable address.
|
||||
// Default is false
|
||||
bool fix_msg = 8;
|
||||
}
|
||||
|
||||
// MsgInstantiateContractResponse return instantiation result data
|
||||
message MsgInstantiateContractResponse {
|
||||
// Address is the bech32 address of the new contract instance.
|
||||
string address = 1;
|
||||
// Data contains bytes to returned from the contract
|
||||
bytes data = 2;
|
||||
}
|
||||
|
||||
// MsgInstantiateContract2Response return instantiation result data
|
||||
message MsgInstantiateContract2Response {
|
||||
// Address is the bech32 address of the new contract instance.
|
||||
string address = 1;
|
||||
// Data contains bytes to returned from the contract
|
||||
bytes data = 2;
|
||||
}
|
||||
|
||||
// MsgExecuteContract submits the given message data to a smart contract
|
||||
message MsgExecuteContract {
|
||||
// Sender is the that actor that signed the messages
|
||||
string sender = 1;
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 2;
|
||||
// Msg json encoded message to be passed to the contract
|
||||
bytes msg = 3 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
// Funds coins that are transferred to the contract on execution
|
||||
repeated cosmos.base.v1beta1.Coin funds = 5 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
|
||||
];
|
||||
}
|
||||
|
||||
// MsgExecuteContractResponse returns execution result data.
|
||||
message MsgExecuteContractResponse {
|
||||
// Data contains bytes to returned from the contract
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
// MsgMigrateContract runs a code upgrade/ downgrade for a smart contract
|
||||
message MsgMigrateContract {
|
||||
// Sender is the that actor that signed the messages
|
||||
string sender = 1;
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 2;
|
||||
// CodeID references the new WASM code
|
||||
uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Msg json encoded message to be passed to the contract on migration
|
||||
bytes msg = 4 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
}
|
||||
|
||||
// MsgMigrateContractResponse returns contract migration result data.
|
||||
message MsgMigrateContractResponse {
|
||||
// Data contains same raw bytes returned as data from the wasm contract.
|
||||
// (May be empty)
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
// MsgUpdateAdmin sets a new admin for a smart contract
|
||||
message MsgUpdateAdmin {
|
||||
// Sender is the that actor that signed the messages
|
||||
string sender = 1;
|
||||
// NewAdmin address to be set
|
||||
string new_admin = 2;
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 3;
|
||||
}
|
||||
|
||||
// MsgUpdateAdminResponse returns empty data
|
||||
message MsgUpdateAdminResponse {}
|
||||
|
||||
// MsgClearAdmin removes any admin stored for a smart contract
|
||||
message MsgClearAdmin {
|
||||
// Sender is the actor that signed the messages
|
||||
string sender = 1;
|
||||
// Contract is the address of the smart contract
|
||||
string contract = 3;
|
||||
}
|
||||
|
||||
// MsgClearAdminResponse returns empty data
|
||||
message MsgClearAdminResponse {}
|
||||
|
||||
// MsgUpdateInstantiateConfig updates instantiate config for a smart contract
|
||||
message MsgUpdateInstantiateConfig {
|
||||
// Sender is the that actor that signed the messages
|
||||
string sender = 1;
|
||||
// CodeID references the stored WASM code
|
||||
uint64 code_id = 2 [ (gogoproto.customname) = "CodeID" ];
|
||||
// NewInstantiatePermission is the new access control
|
||||
AccessConfig new_instantiate_permission = 3;
|
||||
}
|
||||
|
||||
// MsgUpdateInstantiateConfigResponse returns empty data
|
||||
message MsgUpdateInstantiateConfigResponse {}
|
||||
144
proto/wasm/v1/types.proto
Normal file
144
proto/wasm/v1/types.proto
Normal file
@ -0,0 +1,144 @@
|
||||
syntax = "proto3";
|
||||
package cosmwasm.wasm.v1;
|
||||
|
||||
import "cosmos_proto/cosmos.proto";
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
option go_package = "github.com/cerc-io/laconicd/x/wasm/types";
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
option (gogoproto.equal_all) = true;
|
||||
|
||||
// AccessType permission types
|
||||
enum AccessType {
|
||||
option (gogoproto.goproto_enum_prefix) = false;
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
// AccessTypeUnspecified placeholder for empty value
|
||||
ACCESS_TYPE_UNSPECIFIED = 0
|
||||
[ (gogoproto.enumvalue_customname) = "AccessTypeUnspecified" ];
|
||||
// AccessTypeNobody forbidden
|
||||
ACCESS_TYPE_NOBODY = 1
|
||||
[ (gogoproto.enumvalue_customname) = "AccessTypeNobody" ];
|
||||
// AccessTypeOnlyAddress restricted to a single address
|
||||
// Deprecated: use AccessTypeAnyOfAddresses instead
|
||||
ACCESS_TYPE_ONLY_ADDRESS = 2
|
||||
[ (gogoproto.enumvalue_customname) = "AccessTypeOnlyAddress" ];
|
||||
// AccessTypeEverybody unrestricted
|
||||
ACCESS_TYPE_EVERYBODY = 3
|
||||
[ (gogoproto.enumvalue_customname) = "AccessTypeEverybody" ];
|
||||
// AccessTypeAnyOfAddresses allow any of the addresses
|
||||
ACCESS_TYPE_ANY_OF_ADDRESSES = 4
|
||||
[ (gogoproto.enumvalue_customname) = "AccessTypeAnyOfAddresses" ];
|
||||
}
|
||||
|
||||
// AccessTypeParam
|
||||
message AccessTypeParam {
|
||||
option (gogoproto.goproto_stringer) = true;
|
||||
AccessType value = 1 [ (gogoproto.moretags) = "yaml:\"value\"" ];
|
||||
}
|
||||
|
||||
// AccessConfig access control type.
|
||||
message AccessConfig {
|
||||
option (gogoproto.goproto_stringer) = true;
|
||||
AccessType permission = 1 [ (gogoproto.moretags) = "yaml:\"permission\"" ];
|
||||
|
||||
// Address
|
||||
// Deprecated: replaced by addresses
|
||||
string address = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ];
|
||||
repeated string addresses = 3 [ (gogoproto.moretags) = "yaml:\"addresses\"" ];
|
||||
}
|
||||
|
||||
// Params defines the set of wasm parameters.
|
||||
message Params {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
AccessConfig code_upload_access = 1 [
|
||||
(gogoproto.nullable) = false,
|
||||
(gogoproto.moretags) = "yaml:\"code_upload_access\""
|
||||
];
|
||||
AccessType instantiate_default_permission = 2
|
||||
[ (gogoproto.moretags) = "yaml:\"instantiate_default_permission\"" ];
|
||||
}
|
||||
|
||||
// CodeInfo is data for the uploaded contract WASM code
|
||||
message CodeInfo {
|
||||
// CodeHash is the unique identifier created by wasmvm
|
||||
bytes code_hash = 1;
|
||||
// Creator address who initially stored the code
|
||||
string creator = 2;
|
||||
// Used in v1beta1
|
||||
reserved 3, 4;
|
||||
// InstantiateConfig access control to apply on contract creation, optional
|
||||
AccessConfig instantiate_config = 5 [ (gogoproto.nullable) = false ];
|
||||
}
|
||||
|
||||
// ContractInfo stores a WASM contract instance
|
||||
message ContractInfo {
|
||||
option (gogoproto.equal) = true;
|
||||
|
||||
// CodeID is the reference to the stored Wasm code
|
||||
uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Creator address who initially instantiated the contract
|
||||
string creator = 2;
|
||||
// Admin is an optional address that can execute migrations
|
||||
string admin = 3;
|
||||
// Label is optional metadata to be stored with a contract instance.
|
||||
string label = 4;
|
||||
// Created Tx position when the contract was instantiated.
|
||||
AbsoluteTxPosition created = 5;
|
||||
string ibc_port_id = 6 [ (gogoproto.customname) = "IBCPortID" ];
|
||||
|
||||
// Extension is an extension point to store custom metadata within the
|
||||
// persistence model.
|
||||
google.protobuf.Any extension = 7
|
||||
[ (cosmos_proto.accepts_interface) = "ContractInfoExtension" ];
|
||||
}
|
||||
|
||||
// ContractCodeHistoryOperationType actions that caused a code change
|
||||
enum ContractCodeHistoryOperationType {
|
||||
option (gogoproto.goproto_enum_prefix) = false;
|
||||
// ContractCodeHistoryOperationTypeUnspecified placeholder for empty value
|
||||
CONTRACT_CODE_HISTORY_OPERATION_TYPE_UNSPECIFIED = 0
|
||||
[ (gogoproto.enumvalue_customname) =
|
||||
"ContractCodeHistoryOperationTypeUnspecified" ];
|
||||
// ContractCodeHistoryOperationTypeInit on chain contract instantiation
|
||||
CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT = 1
|
||||
[ (gogoproto.enumvalue_customname) =
|
||||
"ContractCodeHistoryOperationTypeInit" ];
|
||||
// ContractCodeHistoryOperationTypeMigrate code migration
|
||||
CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE = 2
|
||||
[ (gogoproto.enumvalue_customname) =
|
||||
"ContractCodeHistoryOperationTypeMigrate" ];
|
||||
// ContractCodeHistoryOperationTypeGenesis based on genesis data
|
||||
CONTRACT_CODE_HISTORY_OPERATION_TYPE_GENESIS = 3
|
||||
[ (gogoproto.enumvalue_customname) =
|
||||
"ContractCodeHistoryOperationTypeGenesis" ];
|
||||
}
|
||||
|
||||
// ContractCodeHistoryEntry metadata to a contract.
|
||||
message ContractCodeHistoryEntry {
|
||||
ContractCodeHistoryOperationType operation = 1;
|
||||
// CodeID is the reference to the stored WASM code
|
||||
uint64 code_id = 2 [ (gogoproto.customname) = "CodeID" ];
|
||||
// Updated Tx position when the operation was executed.
|
||||
AbsoluteTxPosition updated = 3;
|
||||
bytes msg = 4 [ (gogoproto.casttype) = "RawContractMessage" ];
|
||||
}
|
||||
|
||||
// AbsoluteTxPosition is a unique transaction position that allows for global
|
||||
// ordering of transactions.
|
||||
message AbsoluteTxPosition {
|
||||
// BlockHeight is the block the contract was created at
|
||||
uint64 block_height = 1;
|
||||
// TxIndex is a monotonic counter within the block (actual transaction index,
|
||||
// or gas consumed)
|
||||
uint64 tx_index = 2;
|
||||
}
|
||||
|
||||
// Model is a struct that holds a KV pair
|
||||
message Model {
|
||||
// hex-encode key to read it better (this is often ascii)
|
||||
bytes key = 1 [ (gogoproto.casttype) =
|
||||
"github.com/tendermint/tendermint/libs/bytes.HexBytes" ];
|
||||
// base64-encode raw value
|
||||
bytes value = 2;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
# Validator Guide for laconic_81337-6 Testnet
|
||||
# Validator Guide for laconic_81337-5 Testnet
|
||||
|
||||
## Hardware Prerequisites
|
||||
|
||||
@ -48,8 +48,8 @@ sudo apt install git curl build-essential make jq -y
|
||||
# Remove any existing installation of `go`
|
||||
sudo rm -rf /usr/local/go
|
||||
|
||||
# Install Go version 1.19.7
|
||||
curl https://dl.google.com/go/go1.19.7.linux-amd64.tar.gz | sudo tar -C/usr/local -zxvf -
|
||||
# Install Go version 1.18.8
|
||||
curl https://dl.google.com/go/go1.18.8.linux-amd64.tar.gz | sudo tar -C/usr/local -zxvf -
|
||||
|
||||
# Update env variables to include go
|
||||
cat <<'EOF' >>$HOME/.profile
|
||||
@ -67,7 +67,7 @@ Check the version of go installed
|
||||
```sh
|
||||
go version
|
||||
|
||||
# Should return something like: go version go1.19.7 linux/amd64
|
||||
# Should return something like: go version go1.17.2 linux/amd64
|
||||
```
|
||||
|
||||
---
|
||||
@ -80,17 +80,16 @@ cd laconicd
|
||||
|
||||
# Checkout main branch
|
||||
git fetch --all
|
||||
git checkout v0.8.0
|
||||
git checkout v0.6.0
|
||||
|
||||
# Build and install laconic
|
||||
make VERSION=v0.8.0 install
|
||||
make install
|
||||
```
|
||||
|
||||
Verify your installation
|
||||
|
||||
```sh
|
||||
laconicd version --long
|
||||
|
||||
```
|
||||
|
||||
On running the above command, you should see a similar response like this. Make sure that the _version_ and _commit
|
||||
@ -123,13 +122,13 @@ Make sure the directory `~/.laconicd` does not exist or is empty
|
||||
>In order to run the below commands in a docker container:
|
||||
>```sh
|
||||
>docker run -ti -v ~/.laconicd:/root/.laconicd \
|
||||
>git.vdb.to/cerc-io/laconicd/laconicd:v0.8.0 /bin/sh
|
||||
>git.vdb.to/cerc-io/laconicd/laconicd:v0.6.0 /bin/sh
|
||||
>```
|
||||
---
|
||||
|
||||
```sh
|
||||
# Initialize the validator node
|
||||
laconicd init <your-node-moniker> --chain-id laconic_81337-6
|
||||
laconicd init <your-node-moniker> --chain-id laconic_81337-5
|
||||
```
|
||||
|
||||
Running the above commands will initialize the validator node with default configuration. The config files will be saved in the default location (`~/.laconicd/config`).
|
||||
@ -169,7 +168,7 @@ Create Your `gentx` transaction file
|
||||
```sh
|
||||
laconicd gentx <key-name> 12900000000000000000000achk \
|
||||
--pubkey=$(laconicd tendermint show-validator) \
|
||||
--chain-id="laconic_81337-6" \
|
||||
--chain-id="laconic_81337-5" \
|
||||
--moniker="<your-moniker-name>" \
|
||||
--website="<your-validator-website>" \
|
||||
--details="<your-validator-description>" \
|
||||
@ -199,10 +198,10 @@ Submit your `gentx` file to the [https://github.com/cerc-io/laconic-testnet](htt
|
||||
To submit the gentx file, follow the below process:
|
||||
|
||||
- Fork the [https://github.com/cerc-io/laconic-testnet](https://github.com/cerc-io/laconic-testnet) repository
|
||||
- Upload your gentx file in the `laconic_81337-6/config/gentxs` folder
|
||||
- Upload your gentx file in the `laconic_81337-5/config/gentxs` folder
|
||||
- Submit Pull Request to [https://github.com/cerc-io/laconic-testnet](https://github.com/cerc-io/laconic-testnet) with name `ADD <your-moniker> gentx`
|
||||
|
||||
The genesis file will be published in the `laconic_81337-6/config/` folder within the [https://github.com/cerc-io/laconic-testnet](https://github.com/cerc-io/laconic-testnet) repository.
|
||||
The genesis file will be published in the `laconic_81337-5/config/` folder within the [https://github.com/cerc-io/laconic-testnet](https://github.com/cerc-io/laconic-testnet) repository.
|
||||
|
||||
# CONTINUE WITH BELOW STEPS ONLY AFTER GENESIS FILE HAS BEEN PUBLISHED
|
||||
|
||||
@ -272,33 +271,25 @@ journalctl -f -u laconicd
|
||||
In this example the Tendermint RPC and Prometheus metrics ports are exposed only to localhost. You may want to change 127.0.0.1 to private or public network interface of your host if you need to access these ports remotely.
|
||||
|
||||
```sh
|
||||
docker create \
|
||||
--name laconic-testnet-6 \
|
||||
--restart always \
|
||||
-v ~/.laconicd:/root/.laconicd \
|
||||
-p 26656:26656 \
|
||||
-p 127.0.0.1:26657:26657 \
|
||||
-p 127.0.0.1:26660:26660 \
|
||||
git.vdb.to/cerc-io/laconicd/laconicd:v0.8.0 \
|
||||
laconicd start --gql-playground --gql-server --log_level=warn
|
||||
docker create --name laconic-testnet-5 -v ~/.laconicd:/root/.laconicd -p 26656:26656 -p 127.0.0.1:26657:26657 -p 127.0.0.1:26660:26660 git.vdb.to/cerc-io/laconicd/laconicd:v0.6.0 laconicd start --gql-playground --gql-server --log_level=warn
|
||||
```
|
||||
|
||||
### Run validator node
|
||||
|
||||
```sh
|
||||
docker start laconic-testnet-6
|
||||
docker start laconic-testnet-5
|
||||
```
|
||||
|
||||
### Check validator node logs
|
||||
|
||||
```sh
|
||||
docker logs laconic-testnet-6
|
||||
docker logs laconic-testnet-5
|
||||
```
|
||||
|
||||
### Run shell inside docker container
|
||||
|
||||
```sh
|
||||
docker exec -ti laconic-testnet-6 /bin/sh
|
||||
docker exec -ti laconic-testnet-5 /bin/sh
|
||||
```
|
||||
---
|
||||
## Helpful commands
|
||||
|
||||
@ -10,8 +10,9 @@ laconicd_rest_endpoint=http://laconicd:1317
|
||||
laconicd_gql_endpoint=http://laconicd:9473/api
|
||||
# Run tests
|
||||
docker network inspect sdk_tests_default
|
||||
docker compose logs laconicd
|
||||
docker compose exec laconicd sh -c "curl --retry 10 --retry-delay 3 --retry-connrefused http://127.0.0.1:9473/api"
|
||||
docker compose exec laconicd sh -c "curl --retry 10 --retry-delay 3 --retry-connrefused http://localhost:9473/api"
|
||||
sleep 30s
|
||||
docker logs laconicd
|
||||
docker compose exec laconicd sh -c "curl http://127.0.0.1:9473/api"
|
||||
docker compose exec laconicd sh -c "curl http://localhost:9473/api"
|
||||
|
||||
docker compose exec sdk-test-runner sh -c "COSMOS_CHAIN_ID=${cosmos_chain_id} LACONICD_REST_ENDPOINT=${laconicd_rest_endpoint} LACONICD_GQL_ENDPOINT=${laconicd_gql_endpoint} PRIVATE_KEY=${laconicd_key} yarn test"
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
|
||||
canonicalJson "github.com/gibson042/canonicaljson-go"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/ipld/go-ipld-prime/codec/dagcbor"
|
||||
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
||||
"github.com/ipld/go-ipld-prime/linking"
|
||||
@ -17,6 +18,7 @@ import (
|
||||
"github.com/ipld/go-ipld-prime/multicodec"
|
||||
basicnode "github.com/ipld/go-ipld-prime/node/basic"
|
||||
"github.com/ipld/go-ipld-prime/storage/memstore"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
var store = memstore.Store{}
|
||||
@ -33,7 +35,7 @@ func GenerateHash(json map[string]interface{}) (string, []byte, error) {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
cidString, err := CIDFromJSONBytes(content)
|
||||
cidString, err := CIDFromJSONBytesUsingIpldPrime(content)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -41,6 +43,16 @@ func GenerateHash(json map[string]interface{}) (string, []byte, error) {
|
||||
return cidString, content, nil
|
||||
}
|
||||
|
||||
// CIDFromJSONBytes returns CID (cbor) for json (as bytes).
|
||||
func CIDFromJSONBytes(content []byte) (string, error) {
|
||||
cid, err := cbor.FromJSON(bytes.NewReader(content), mh.SHA2_256, -1)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return cid.String(), nil
|
||||
}
|
||||
|
||||
// GetAttributeAsString returns a map attribute as string, if possible.
|
||||
func GetAttributeAsString(obj map[string]interface{}, attr string) (string, error) {
|
||||
if value, ok := obj[attr]; ok {
|
||||
@ -54,14 +66,10 @@ func GetAttributeAsString(obj map[string]interface{}, attr string) (string, erro
|
||||
return "", errors.New("attribute not found")
|
||||
}
|
||||
|
||||
// CIDFromJSONBytes returns CID (dagcbor) for json (as bytes).
|
||||
// CIDFromJSONBytesUsingIpldPrime returns CID (dagcbor) for json (as bytes).
|
||||
// This is combination of samples for unmarshalling and linking
|
||||
// see: https://pkg.go.dev/github.com/ipld/go-ipld-prime
|
||||
func CIDFromJSONBytes(content []byte) (string, error) {
|
||||
if len(content) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func CIDFromJSONBytesUsingIpldPrime(content []byte) (string, error) {
|
||||
np := basicnode.Prototype.Any // Pick a stle for the in-memory data.
|
||||
nb := np.NewBuilder() // Create a builder.
|
||||
err := dagjson.Decode(nb, bytes.NewReader(content)) // Hand the builder to decoding -- decoding will fill it in!
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAndValidateCIDGeneration(t *testing.T) {
|
||||
@ -12,12 +11,13 @@ func TestAndValidateCIDGeneration(t *testing.T) {
|
||||
content string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
"empty string", "", "",
|
||||
},
|
||||
{
|
||||
"empty json", "{}", "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua",
|
||||
},
|
||||
// empty string and empty json blows up
|
||||
// {
|
||||
// "empty string", "", "bafyreiengp2sbi6ez34a2jctv34bwyjl7yoliteleaswgcwtqzrhmpyt2m",
|
||||
// },
|
||||
// {
|
||||
// "empty json", "{}", "bafyreihpfkdvib5muloxlj5b3tgdwibjdcu3zdsuhyft33z7gtgnlzlkpm",
|
||||
// },
|
||||
|
||||
{
|
||||
"test record", "{\"build_artifact_cid\":\"QmP8jTG1m9GSDJLCbeWhVSVgEzCPPwXRdCRuJtQ5Tz9Kc9\",\"repo_registration_record_cid\":\"QmSnuWmxptJZdLJpKRarxBMS2Ju2oANVrgbr2xWbie9b2D\",\"tls_cert_cid\":\"QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR\",\"type\":\"WebsiteRegistrationRecord\",\"url\":\"https://cerc.io\",\"version\":\"0.0.1\"}",
|
||||
@ -26,8 +26,10 @@ func TestAndValidateCIDGeneration(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
newImpl, err := CIDFromJSONBytes([]byte(tc.content))
|
||||
deprecatedAndCorrect, _ := CIDFromJSONBytes([]byte(tc.content))
|
||||
newImpl, err := CIDFromJSONBytesUsingIpldPrime([]byte(tc.content))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, deprecatedAndCorrect, newImpl, tc.name)
|
||||
require.Equal(t, tc.expected, newImpl)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ package keeper
|
||||
import (
|
||||
"context"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
@ -27,7 +26,7 @@ func (q Querier) Auctions(c context.Context, req *types.AuctionsRequest) (*types
|
||||
func (q Querier) GetAuction(c context.Context, req *types.AuctionRequest) (*types.AuctionResponse, error) {
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
if req.Id == "" {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
|
||||
}
|
||||
|
||||
resp := q.Keeper.GetAuction(ctx, req.Id)
|
||||
@ -38,10 +37,10 @@ func (q Querier) GetAuction(c context.Context, req *types.AuctionRequest) (*type
|
||||
func (q Querier) GetBid(c context.Context, req *types.BidRequest) (*types.BidResponse, error) {
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
if req.AuctionId == "" {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
|
||||
}
|
||||
if req.Bidder == "" {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "bidder address is required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "bidder address is required")
|
||||
}
|
||||
resp := q.Keeper.GetBid(ctx, req.AuctionId, req.Bidder)
|
||||
return &types.BidResponse{Bid: &resp}, nil
|
||||
@ -51,7 +50,7 @@ func (q Querier) GetBid(c context.Context, req *types.BidRequest) (*types.BidRes
|
||||
func (q Querier) GetBids(c context.Context, req *types.BidsRequest) (*types.BidsResponse, error) {
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
if req.AuctionId == "" {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "auction ID is required")
|
||||
}
|
||||
resp := q.Keeper.GetBids(ctx, req.AuctionId)
|
||||
return &types.BidsResponse{Bids: resp}, nil
|
||||
@ -61,7 +60,7 @@ func (q Querier) GetBids(c context.Context, req *types.BidsRequest) (*types.Bids
|
||||
func (q Querier) AuctionsByBidder(c context.Context, req *types.AuctionsByBidderRequest) (*types.AuctionsByBidderResponse, error) {
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
if req.BidderAddress == "" {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "bidder address is required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "bidder address is required")
|
||||
}
|
||||
resp := q.Keeper.QueryAuctionsByBidder(ctx, req.BidderAddress)
|
||||
return &types.AuctionsByBidderResponse{Auctions: &types.Auctions{Auctions: resp}}, nil
|
||||
@ -71,7 +70,7 @@ func (q Querier) AuctionsByBidder(c context.Context, req *types.AuctionsByBidder
|
||||
func (q Querier) AuctionsByOwner(c context.Context, req *types.AuctionsByOwnerRequest) (*types.AuctionsByOwnerResponse, error) {
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
if req.OwnerAddress == "" {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "owner address is required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "owner address is required")
|
||||
}
|
||||
resp := q.Keeper.QueryAuctionsByOwner(ctx, req.OwnerAddress)
|
||||
return &types.AuctionsByOwnerResponse{Auctions: &types.Auctions{Auctions: resp}}, nil
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"github.com/cerc-io/laconicd/x/auction/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
@ -307,7 +306,7 @@ func (k Keeper) CreateAuction(ctx sdk.Context, msg types.MsgCreateAuction) (*typ
|
||||
// Generate auction Id.
|
||||
account := k.accountKeeper.GetAccount(ctx, signerAddress)
|
||||
if account == nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "Account not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "Account not found.")
|
||||
}
|
||||
|
||||
auctionID := types.AuctionID{
|
||||
@ -341,12 +340,12 @@ func (k Keeper) CreateAuction(ctx sdk.Context, msg types.MsgCreateAuction) (*typ
|
||||
|
||||
func (k Keeper) CommitBid(ctx sdk.Context, msg types.MsgCommitBid) (*types.Bid, error) {
|
||||
if !k.HasAuction(ctx, msg.AuctionId) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Auction not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction not found.")
|
||||
}
|
||||
|
||||
auction := k.GetAuction(ctx, msg.AuctionId)
|
||||
if auction.Status != types.AuctionStatusCommitPhase {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Auction is not in commit phase.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction is not in commit phase.")
|
||||
}
|
||||
|
||||
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
|
||||
@ -391,12 +390,12 @@ func (k Keeper) CommitBid(ctx sdk.Context, msg types.MsgCommitBid) (*types.Bid,
|
||||
// RevealBid reeals a bid committed earlier.
|
||||
func (k Keeper) RevealBid(ctx sdk.Context, msg types.MsgRevealBid) (*types.Auction, error) {
|
||||
if !k.HasAuction(ctx, msg.AuctionId) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Auction not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction not found.")
|
||||
}
|
||||
|
||||
auction := k.GetAuction(ctx, msg.AuctionId)
|
||||
if auction.Status != types.AuctionStatusRevealPhase {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Auction is not in reveal phase.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Auction is not in reveal phase.")
|
||||
}
|
||||
|
||||
signerAddress, err := sdk.AccAddressFromBech32(msg.Signer)
|
||||
@ -405,65 +404,65 @@ func (k Keeper) RevealBid(ctx sdk.Context, msg types.MsgRevealBid) (*types.Aucti
|
||||
}
|
||||
|
||||
if !k.HasBid(ctx, msg.AuctionId, signerAddress.String()) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bid not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bid not found.")
|
||||
}
|
||||
|
||||
bid := k.GetBid(ctx, auction.Id, signerAddress.String())
|
||||
if bid.Status != types.BidStatusCommitted {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bid not in committed state.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bid not in committed state.")
|
||||
}
|
||||
|
||||
revealBytes, err := hex.DecodeString(msg.Reveal)
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal string.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal string.")
|
||||
}
|
||||
|
||||
cid, err := wnsUtils.CIDFromJSONBytes(revealBytes)
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal JSON.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal JSON.")
|
||||
}
|
||||
|
||||
if bid.CommitHash != cid {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Commit hash mismatch.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Commit hash mismatch.")
|
||||
}
|
||||
|
||||
var reveal map[string]interface{}
|
||||
err = json.Unmarshal(revealBytes, &reveal)
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Reveal JSON unmarshal error.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Reveal JSON unmarshal error.")
|
||||
}
|
||||
|
||||
chainID, err := wnsUtils.GetAttributeAsString(reveal, "chainId")
|
||||
if err != nil || chainID != ctx.ChainID() {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal chainID.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal chainID.")
|
||||
}
|
||||
|
||||
auctionID, err := wnsUtils.GetAttributeAsString(reveal, "auctionId")
|
||||
if err != nil || auctionID != msg.AuctionId {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal auction Id.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal auction Id.")
|
||||
}
|
||||
|
||||
bidderAddress, err := wnsUtils.GetAttributeAsString(reveal, "bidderAddress")
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid address.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid address.")
|
||||
}
|
||||
|
||||
if bidderAddress != signerAddress.String() {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Reveal bid address mismatch.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Reveal bid address mismatch.")
|
||||
}
|
||||
|
||||
bidAmountStr, err := wnsUtils.GetAttributeAsString(reveal, "bidAmount")
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid amount.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid amount.")
|
||||
}
|
||||
|
||||
bidAmount, err := sdk.ParseCoinNormalized(bidAmountStr)
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid amount.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid reveal bid amount.")
|
||||
}
|
||||
|
||||
if bidAmount.IsLT(auction.MinimumBid) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bid is lower than minimum bid.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bid is lower than minimum bid.")
|
||||
}
|
||||
|
||||
// Lock bid amount.
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@ -33,19 +32,19 @@ func (msg MsgCreateAuction) Type() string { return "create" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgCreateAuction) ValidateBasic() error {
|
||||
if msg.Signer == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
}
|
||||
|
||||
if msg.CommitsDuration <= 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "commit phase duration invalid.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "commit phase duration invalid.")
|
||||
}
|
||||
|
||||
if msg.RevealsDuration <= 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "reveal phase duration invalid.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "reveal phase duration invalid.")
|
||||
}
|
||||
|
||||
if !msg.MinimumBid.IsPositive() {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "minimum bid should be greater than zero.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "minimum bid should be greater than zero.")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -80,15 +79,15 @@ func (msg MsgCommitBid) Type() string { return "commit" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgCommitBid) ValidateBasic() error {
|
||||
if msg.Signer == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer address.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer address.")
|
||||
}
|
||||
|
||||
if msg.AuctionId == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid auction ID.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid auction ID.")
|
||||
}
|
||||
|
||||
if msg.CommitHash == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid commit hash.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid commit hash.")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -123,15 +122,15 @@ func (msg MsgRevealBid) Type() string { return "reveal" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgRevealBid) ValidateBasic() error {
|
||||
if msg.Signer == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer address.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer address.")
|
||||
}
|
||||
|
||||
if msg.AuctionId == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid auction ID.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid auction ID.")
|
||||
}
|
||||
|
||||
if msg.Reveal == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid reveal data.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid reveal data.")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
337
x/auction/types/tx.pb.gw.go
generated
337
x/auction/types/tx.pb.gw.go
generated
@ -1,337 +0,0 @@
|
||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: vulcanize/auction/v1beta1/tx.proto
|
||||
|
||||
/*
|
||||
Package types is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/descriptor"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Suppress "imported and not used" errors
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
var _ = descriptor.ForMessage
|
||||
var _ = metadata.Join
|
||||
|
||||
var (
|
||||
filter_Msg_CreateAuction_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_CreateAuction_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCreateAuction
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CreateAuction_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CreateAuction(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_CreateAuction_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCreateAuction
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CreateAuction_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CreateAuction(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_CommitBid_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_CommitBid_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCommitBid
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CommitBid_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CommitBid(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_CommitBid_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCommitBid
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CommitBid_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CommitBid(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_RevealBid_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_RevealBid_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgRevealBid
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RevealBid_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.RevealBid(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_RevealBid_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgRevealBid
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RevealBid_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.RevealBid(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerServer registers the http handlers for service Msg to "mux".
|
||||
// UnaryRPC :call MsgServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead.
|
||||
func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error {
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CreateAuction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_CreateAuction_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CreateAuction_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CommitBid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_CommitBid_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CommitBid_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_RevealBid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_RevealBid_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_RevealBid_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerFromEndpoint is same as RegisterMsgHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterMsgHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterMsgHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterMsgHandler registers the http handlers for service Msg to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterMsgHandlerClient(ctx, mux, NewMsgClient(conn))
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerClient registers the http handlers for service Msg
|
||||
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MsgClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MsgClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "MsgClient" to call the correct interceptors.
|
||||
func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error {
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CreateAuction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_CreateAuction_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CreateAuction_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CommitBid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_CommitBid_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CommitBid_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_RevealBid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_RevealBid_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_RevealBid_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_Msg_CreateAuction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "auction", "v1beta1", "create_auction"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_CommitBid_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "auction", "v1beta1", "commit_bid"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_RevealBid_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "auction", "v1beta1", "reveal_bid"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_Msg_CreateAuction_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_CommitBid_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_RevealBid_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
@ -3,7 +3,6 @@ package keeper
|
||||
import (
|
||||
"context"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"github.com/cerc-io/laconicd/x/bond/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
@ -31,7 +30,7 @@ func (q Querier) GetBondByID(c context.Context, req *types.QueryGetBondByIDReque
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
bondID := req.GetId()
|
||||
if len(bondID) == 0 {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "bond id required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "bond id required")
|
||||
}
|
||||
bond := q.Keeper.GetBond(ctx, req.GetId())
|
||||
return &types.QueryGetBondByIDResponse{Bond: &bond}, nil
|
||||
@ -41,7 +40,7 @@ func (q Querier) GetBondsByOwner(c context.Context, req *types.QueryGetBondsByOw
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
owner := req.GetOwner()
|
||||
if len(owner) == 0 {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "owner id required")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "owner id required")
|
||||
}
|
||||
bonds := q.Keeper.QueryBondsByOwner(ctx, owner)
|
||||
return &types.QueryGetBondsByOwnerResponse{Bonds: bonds}, nil
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"github.com/cerc-io/laconicd/x/bond/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
@ -114,7 +113,7 @@ func (k Keeper) CreateBond(ctx sdk.Context, ownerAddress sdk.AccAddress, coins s
|
||||
for _, coin := range coins {
|
||||
balance := k.bankKeeper.HasBalance(ctx, ownerAddress, coin)
|
||||
if !balance {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInsufficientFunds, "failed to create bond; Insufficient funds")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "failed to create bond; Insufficient funds")
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +129,7 @@ func (k Keeper) CreateBond(ctx sdk.Context, ownerAddress sdk.AccAddress, coins s
|
||||
|
||||
bond := types.Bond{Id: bondID, Owner: ownerAddress.String(), Balance: coins}
|
||||
if bond.Balance.IsAnyGT(maxBondAmount) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Max bond amount exceeded.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Max bond amount exceeded.")
|
||||
}
|
||||
|
||||
// Move funds into the bond account module.
|
||||
@ -222,18 +221,18 @@ func (k Keeper) QueryBondsByOwner(ctx sdk.Context, ownerAddress string) []types.
|
||||
// RefillBond refills an existing bond.
|
||||
func (k Keeper) RefillBond(ctx sdk.Context, id string, ownerAddress sdk.AccAddress, coins sdk.Coins) (*types.Bond, error) {
|
||||
if !k.HasBond(ctx, id) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
}
|
||||
|
||||
bond := k.GetBond(ctx, id)
|
||||
if bond.Owner != ownerAddress.String() {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
}
|
||||
|
||||
// Check if account has funds.
|
||||
for _, coin := range coins {
|
||||
if !k.bankKeeper.HasBalance(ctx, ownerAddress, coin) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInsufficientFunds, "Insufficient funds.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "Insufficient funds.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +240,7 @@ func (k Keeper) RefillBond(ctx sdk.Context, id string, ownerAddress sdk.AccAddre
|
||||
|
||||
updatedBalance := bond.Balance.Add(coins...)
|
||||
if updatedBalance.IsAnyGT(maxBondAmount) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Max bond amount exceeded.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Max bond amount exceeded.")
|
||||
}
|
||||
|
||||
// Move funds into the bond account module.
|
||||
@ -260,17 +259,17 @@ func (k Keeper) RefillBond(ctx sdk.Context, id string, ownerAddress sdk.AccAddre
|
||||
// WithdrawBond withdraws funds from a bond.
|
||||
func (k Keeper) WithdrawBond(ctx sdk.Context, id string, ownerAddress sdk.AccAddress, coins sdk.Coins) (*types.Bond, error) {
|
||||
if !k.HasBond(ctx, id) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
}
|
||||
|
||||
bond := k.GetBond(ctx, id)
|
||||
if bond.Owner != ownerAddress.String() {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
}
|
||||
|
||||
updatedBalance, isNeg := bond.Balance.SafeSub(coins...)
|
||||
if isNeg {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInsufficientFunds, "Insufficient bond balance.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "Insufficient bond balance.")
|
||||
}
|
||||
|
||||
// Move funds from the bond into the account.
|
||||
@ -289,18 +288,18 @@ func (k Keeper) WithdrawBond(ctx sdk.Context, id string, ownerAddress sdk.AccAdd
|
||||
// CancelBond cancels a bond, returning funds to the owner.
|
||||
func (k Keeper) CancelBond(ctx sdk.Context, id string, ownerAddress sdk.AccAddress) (*types.Bond, error) {
|
||||
if !k.HasBond(ctx, id) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
}
|
||||
|
||||
bond := k.GetBond(ctx, id)
|
||||
if bond.Owner != ownerAddress.String() {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
}
|
||||
|
||||
// Check if bond is used in other modules.
|
||||
for _, usageKeeper := range k.usageKeepers {
|
||||
if usageKeeper.UsesBond(ctx, id) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, fmt.Sprintf("Bond in use by the '%s' module.", usageKeeper.ModuleName()))
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, fmt.Sprintf("Bond in use by the '%s' module.", usageKeeper.ModuleName()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,7 +330,7 @@ func (k Keeper) GetBondModuleBalances(ctx sdk.Context) sdk.Coins {
|
||||
// TransferCoinsToModuleAccount moves funds from the bonds module account to another module account.
|
||||
func (k Keeper) TransferCoinsToModuleAccount(ctx sdk.Context, id, moduleAccount string, coins sdk.Coins) error {
|
||||
if !k.HasBond(ctx, id) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond not found.")
|
||||
}
|
||||
|
||||
bondObj := k.GetBond(ctx, id)
|
||||
@ -341,13 +340,13 @@ func (k Keeper) TransferCoinsToModuleAccount(ctx sdk.Context, id, moduleAccount
|
||||
|
||||
if isNeg {
|
||||
// Check if bond has sufficient funds.
|
||||
return errorsmod.Wrap(sdkerrors.ErrInsufficientFunds, "Insufficient funds.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "Insufficient funds.")
|
||||
}
|
||||
|
||||
// Move funds from bond module to record rent module.
|
||||
err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, moduleAccount, coins)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Error transferring funds.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Error transferring funds.")
|
||||
}
|
||||
|
||||
// Update bond balance.
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@ -29,10 +28,10 @@ func (msg MsgCreateBond) Type() string { return "create" }
|
||||
|
||||
func (msg MsgCreateBond) ValidateBasic() error {
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
}
|
||||
if len(msg.Coins) == 0 || !msg.Coins.IsValid() {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, "Invalid amount.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "Invalid amount.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -65,13 +64,13 @@ func (msg MsgRefillBond) Type() string { return "refill" }
|
||||
|
||||
func (msg MsgRefillBond) ValidateBasic() error {
|
||||
if len(msg.Id) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, msg.Id)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, msg.Id)
|
||||
}
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
}
|
||||
if len(msg.Coins) == 0 || !msg.Coins.IsValid() {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, "Invalid amount.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "Invalid amount.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -104,13 +103,13 @@ func (msg MsgWithdrawBond) Type() string { return "withdraw" }
|
||||
|
||||
func (msg MsgWithdrawBond) ValidateBasic() error {
|
||||
if len(msg.Id) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, msg.Id)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, msg.Id)
|
||||
}
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
}
|
||||
if len(msg.Coins) == 0 || !msg.Coins.IsValid() {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidCoins, "Invalid amount.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "Invalid amount.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -142,10 +141,10 @@ func (msg MsgCancelBond) Type() string { return "cancel" }
|
||||
|
||||
func (msg MsgCancelBond) ValidateBasic() error {
|
||||
if len(msg.Id) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, msg.Id)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, msg.Id)
|
||||
}
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
420
x/bond/types/tx.pb.gw.go
generated
420
x/bond/types/tx.pb.gw.go
generated
@ -1,420 +0,0 @@
|
||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: vulcanize/bond/v1beta1/tx.proto
|
||||
|
||||
/*
|
||||
Package types is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/descriptor"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Suppress "imported and not used" errors
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
var _ = descriptor.ForMessage
|
||||
var _ = metadata.Join
|
||||
|
||||
var (
|
||||
filter_Msg_CreateBond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_CreateBond_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCreateBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CreateBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CreateBond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_CreateBond_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCreateBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CreateBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CreateBond(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_RefillBond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_RefillBond_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgRefillBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RefillBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.RefillBond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_RefillBond_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgRefillBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RefillBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.RefillBond(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_WithdrawBond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_WithdrawBond_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgWithdrawBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_WithdrawBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.WithdrawBond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_WithdrawBond_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgWithdrawBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_WithdrawBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.WithdrawBond(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_CancelBond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_CancelBond_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCancelBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CancelBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CancelBond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_CancelBond_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgCancelBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_CancelBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CancelBond(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerServer registers the http handlers for service Msg to "mux".
|
||||
// UnaryRPC :call MsgServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead.
|
||||
func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error {
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CreateBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_CreateBond_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CreateBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_RefillBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_RefillBond_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_RefillBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_WithdrawBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_WithdrawBond_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_WithdrawBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CancelBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_CancelBond_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CancelBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerFromEndpoint is same as RegisterMsgHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterMsgHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterMsgHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterMsgHandler registers the http handlers for service Msg to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterMsgHandlerClient(ctx, mux, NewMsgClient(conn))
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerClient registers the http handlers for service Msg
|
||||
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MsgClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MsgClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "MsgClient" to call the correct interceptors.
|
||||
func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error {
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CreateBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_CreateBond_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CreateBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_RefillBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_RefillBond_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_RefillBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_WithdrawBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_WithdrawBond_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_WithdrawBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_CancelBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_CancelBond_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_CancelBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_Msg_CreateBond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "bond", "v1beta1", "create_bond"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_RefillBond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "bond", "v1beta1", "refill_bond"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_WithdrawBond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "bond", "v1beta1", "withdraw_bond"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_CancelBond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "bond", "v1beta1", "cancel_bond"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_Msg_CreateBond_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_RefillBond_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_WithdrawBond_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_CancelBond_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
@ -6,8 +6,8 @@ import (
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
@ -91,61 +91,61 @@ func getBlockValue(block *sdkmath.Int) *big.Int {
|
||||
// if any of the block values is uninitialized (i.e nil) or if the EIP150Hash is an invalid hash.
|
||||
func (cc ChainConfig) Validate() error {
|
||||
if err := validateBlock(cc.HomesteadBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "homesteadBlock")
|
||||
return sdkerrors.Wrap(err, "homesteadBlock")
|
||||
}
|
||||
if err := validateBlock(cc.DAOForkBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "daoForkBlock")
|
||||
return sdkerrors.Wrap(err, "daoForkBlock")
|
||||
}
|
||||
if err := validateBlock(cc.EIP150Block); err != nil {
|
||||
return errorsmod.Wrap(err, "eip150Block")
|
||||
return sdkerrors.Wrap(err, "eip150Block")
|
||||
}
|
||||
if err := validateHash(cc.EIP150Hash); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateBlock(cc.EIP155Block); err != nil {
|
||||
return errorsmod.Wrap(err, "eip155Block")
|
||||
return sdkerrors.Wrap(err, "eip155Block")
|
||||
}
|
||||
if err := validateBlock(cc.EIP158Block); err != nil {
|
||||
return errorsmod.Wrap(err, "eip158Block")
|
||||
return sdkerrors.Wrap(err, "eip158Block")
|
||||
}
|
||||
if err := validateBlock(cc.ByzantiumBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "byzantiumBlock")
|
||||
return sdkerrors.Wrap(err, "byzantiumBlock")
|
||||
}
|
||||
if err := validateBlock(cc.ConstantinopleBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "constantinopleBlock")
|
||||
return sdkerrors.Wrap(err, "constantinopleBlock")
|
||||
}
|
||||
if err := validateBlock(cc.PetersburgBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "petersburgBlock")
|
||||
return sdkerrors.Wrap(err, "petersburgBlock")
|
||||
}
|
||||
if err := validateBlock(cc.IstanbulBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "istanbulBlock")
|
||||
return sdkerrors.Wrap(err, "istanbulBlock")
|
||||
}
|
||||
if err := validateBlock(cc.MuirGlacierBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "muirGlacierBlock")
|
||||
return sdkerrors.Wrap(err, "muirGlacierBlock")
|
||||
}
|
||||
if err := validateBlock(cc.BerlinBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "berlinBlock")
|
||||
return sdkerrors.Wrap(err, "berlinBlock")
|
||||
}
|
||||
if err := validateBlock(cc.LondonBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "londonBlock")
|
||||
return sdkerrors.Wrap(err, "londonBlock")
|
||||
}
|
||||
if err := validateBlock(cc.ArrowGlacierBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "arrowGlacierBlock")
|
||||
return sdkerrors.Wrap(err, "arrowGlacierBlock")
|
||||
}
|
||||
if err := validateBlock(cc.MergeForkBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "mergeForkBlock")
|
||||
return sdkerrors.Wrap(err, "mergeForkBlock")
|
||||
}
|
||||
|
||||
// NOTE: chain ID is not needed to check config order
|
||||
if err := cc.EthereumConfig(nil).CheckConfigForkOrder(); err != nil {
|
||||
return errorsmod.Wrap(err, "invalid config fork order")
|
||||
return sdkerrors.Wrap(err, "invalid config fork order")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHash(hex string) error {
|
||||
if hex != "" && strings.TrimSpace(hex) == "" {
|
||||
return errorsmod.Wrap(types.ErrInvalidChainConfig, "hash cannot be blank")
|
||||
return sdkerrors.Wrap(types.ErrInvalidChainConfig, "hash cannot be blank")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -158,7 +158,7 @@ func validateBlock(block *sdkmath.Int) error {
|
||||
}
|
||||
|
||||
if block.IsNegative() {
|
||||
return errorsmod.Wrapf(
|
||||
return sdkerrors.Wrapf(
|
||||
types.ErrInvalidChainConfig, "block value cannot be negative: %s", block,
|
||||
)
|
||||
}
|
||||
|
||||
@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
@ -90,61 +90,61 @@ func getBlockValue(block *sdkmath.Int) *big.Int {
|
||||
// if any of the block values is uninitialized (i.e nil) or if the EIP150Hash is an invalid hash.
|
||||
func (cc ChainConfig) Validate() error {
|
||||
if err := validateBlock(cc.HomesteadBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "homesteadBlock")
|
||||
return sdkerrors.Wrap(err, "homesteadBlock")
|
||||
}
|
||||
if err := validateBlock(cc.DAOForkBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "daoForkBlock")
|
||||
return sdkerrors.Wrap(err, "daoForkBlock")
|
||||
}
|
||||
if err := validateBlock(cc.EIP150Block); err != nil {
|
||||
return errorsmod.Wrap(err, "eip150Block")
|
||||
return sdkerrors.Wrap(err, "eip150Block")
|
||||
}
|
||||
if err := validateHash(cc.EIP150Hash); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateBlock(cc.EIP155Block); err != nil {
|
||||
return errorsmod.Wrap(err, "eip155Block")
|
||||
return sdkerrors.Wrap(err, "eip155Block")
|
||||
}
|
||||
if err := validateBlock(cc.EIP158Block); err != nil {
|
||||
return errorsmod.Wrap(err, "eip158Block")
|
||||
return sdkerrors.Wrap(err, "eip158Block")
|
||||
}
|
||||
if err := validateBlock(cc.ByzantiumBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "byzantiumBlock")
|
||||
return sdkerrors.Wrap(err, "byzantiumBlock")
|
||||
}
|
||||
if err := validateBlock(cc.ConstantinopleBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "constantinopleBlock")
|
||||
return sdkerrors.Wrap(err, "constantinopleBlock")
|
||||
}
|
||||
if err := validateBlock(cc.PetersburgBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "petersburgBlock")
|
||||
return sdkerrors.Wrap(err, "petersburgBlock")
|
||||
}
|
||||
if err := validateBlock(cc.IstanbulBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "istanbulBlock")
|
||||
return sdkerrors.Wrap(err, "istanbulBlock")
|
||||
}
|
||||
if err := validateBlock(cc.MuirGlacierBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "muirGlacierBlock")
|
||||
return sdkerrors.Wrap(err, "muirGlacierBlock")
|
||||
}
|
||||
if err := validateBlock(cc.BerlinBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "berlinBlock")
|
||||
return sdkerrors.Wrap(err, "berlinBlock")
|
||||
}
|
||||
if err := validateBlock(cc.LondonBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "londonBlock")
|
||||
return sdkerrors.Wrap(err, "londonBlock")
|
||||
}
|
||||
if err := validateBlock(cc.ArrowGlacierBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "arrowGlacierBlock")
|
||||
return sdkerrors.Wrap(err, "arrowGlacierBlock")
|
||||
}
|
||||
if err := validateBlock(cc.MergeForkBlock); err != nil {
|
||||
return errorsmod.Wrap(err, "mergeForkBlock")
|
||||
return sdkerrors.Wrap(err, "mergeForkBlock")
|
||||
}
|
||||
|
||||
// NOTE: chain ID is not needed to check config order
|
||||
if err := cc.EthereumConfig(nil).CheckConfigForkOrder(); err != nil {
|
||||
return errorsmod.Wrap(err, "invalid config fork order")
|
||||
return sdkerrors.Wrap(err, "invalid config fork order")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHash(hex string) error {
|
||||
if hex != "" && strings.TrimSpace(hex) == "" {
|
||||
return errorsmod.Wrap(types.ErrInvalidChainConfig, "hash cannot be blank")
|
||||
return sdkerrors.Wrap(types.ErrInvalidChainConfig, "hash cannot be blank")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -157,7 +157,7 @@ func validateBlock(block *sdkmath.Int) error {
|
||||
}
|
||||
|
||||
if block.IsNegative() {
|
||||
return errorsmod.Wrapf(
|
||||
return sdkerrors.Wrapf(
|
||||
types.ErrInvalidChainConfig, "block value cannot be negative: %s", block,
|
||||
)
|
||||
}
|
||||
|
||||
@ -15,8 +15,6 @@ import (
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
)
|
||||
|
||||
const badPath = "/asdasd"
|
||||
|
||||
func (s *IntegrationTestSuite) TestGRPCQueryParams() {
|
||||
val := s.network.Validators[0]
|
||||
sr := s.Require()
|
||||
@ -30,7 +28,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryParams() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
reqURL + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
},
|
||||
@ -77,7 +75,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryWhoIs() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqUrl + badPath,
|
||||
reqUrl + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(authorityName string) {
|
||||
@ -145,7 +143,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryLookup() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
reqURL + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(authorityName string) {
|
||||
@ -197,7 +195,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryRecordExpiryQueue() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqUrl + badPath,
|
||||
reqUrl + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(bondId string) {
|
||||
@ -269,7 +267,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryAuthorityExpiryQueue() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqUrl + badPath,
|
||||
reqUrl + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(authorityName string) {
|
||||
@ -341,7 +339,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryListRecords() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqUrl + badPath,
|
||||
reqUrl + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(bondId string) {
|
||||
@ -411,7 +409,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryGetRecordByID() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
reqURL + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(bondId string) string {
|
||||
@ -480,7 +478,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryGetRecordByBondID() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
reqURL + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(bondId string) {
|
||||
@ -534,7 +532,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryGetRegistryModuleBalance() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
reqURL + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(bondId string) {
|
||||
@ -585,7 +583,7 @@ func (s *IntegrationTestSuite) TestGRPCQueryNamesList() {
|
||||
}{
|
||||
{
|
||||
"invalid url",
|
||||
reqURL + badPath,
|
||||
reqURL + "/asdasd",
|
||||
true,
|
||||
"",
|
||||
func(authorityName string) {
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
record:
|
||||
type: GeneralRecord
|
||||
name: foo
|
||||
version: 1.0.0
|
||||
tags:
|
||||
- tagA
|
||||
- tagB
|
||||
@ -70,7 +70,7 @@ func UnMarshalMapFromJSONBytes(bytes []byte) map[string]interface{} {
|
||||
|
||||
// GetCid gets the content ID.
|
||||
func GetCid(content []byte) (string, error) {
|
||||
return wnsUtils.CIDFromJSONBytes(content)
|
||||
return wnsUtils.CIDFromJSONBytesUsingIpldPrime(content)
|
||||
}
|
||||
|
||||
// BytesToBase64 encodes a byte array as a base64 string.
|
||||
|
||||
@ -3,7 +3,6 @@ package keeper
|
||||
import (
|
||||
"context"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"github.com/cerc-io/laconicd/x/registry/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
@ -49,7 +48,7 @@ func (q Querier) GetRecord(c context.Context, req *types.QueryRecordByIDRequest)
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
id := req.GetId()
|
||||
if !q.Keeper.HasRecord(ctx, id) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "Record not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "Record not found.")
|
||||
}
|
||||
record := q.Keeper.GetRecord(ctx, id)
|
||||
return &types.QueryRecordByIDResponse{Record: record}, nil
|
||||
@ -87,11 +86,11 @@ func (q Querier) LookupCrn(c context.Context, req *types.QueryLookupCrn) (*types
|
||||
ctx := sdk.UnwrapSDKContext(c)
|
||||
crn := req.GetCrn()
|
||||
if !q.Keeper.HasNameRecord(ctx, crn) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "CRN not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "CRN not found.")
|
||||
}
|
||||
nameRecord := q.Keeper.GetNameRecord(ctx, crn)
|
||||
if nameRecord == nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "name record not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "name record not found.")
|
||||
}
|
||||
return &types.QueryLookupCrnResponse{Name: nameRecord}, nil
|
||||
}
|
||||
@ -101,7 +100,7 @@ func (q Querier) ResolveCrn(c context.Context, req *types.QueryResolveCrn) (*typ
|
||||
crn := req.GetCrn()
|
||||
record := q.Keeper.ResolveCRN(ctx, crn)
|
||||
if record == nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "record not found.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "record not found.")
|
||||
}
|
||||
return &types.QueryResolveCrnResponse{Record: record}, nil
|
||||
}
|
||||
|
||||
@ -3,12 +3,12 @@ package keeper_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/registry/client/cli"
|
||||
"github.com/cerc-io/laconicd/x/registry/helpers"
|
||||
"github.com/cerc-io/laconicd/x/registry/keeper"
|
||||
registrytypes "github.com/cerc-io/laconicd/x/registry/types"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) TestGrpcQueryParams() {
|
||||
@ -39,7 +39,6 @@ func (suite *KeeperTestSuite) TestGrpcGetRecordLists() {
|
||||
examples := []string{
|
||||
"/../helpers/examples/service_provider_example.yml",
|
||||
"/../helpers/examples/website_registration_example.yml",
|
||||
"/../helpers/examples/general_record_example.yml",
|
||||
}
|
||||
testCases := []struct {
|
||||
msg string
|
||||
@ -60,7 +59,7 @@ func (suite *KeeperTestSuite) TestGrpcGetRecordLists() {
|
||||
®istrytypes.QueryListRecordsRequest{},
|
||||
true,
|
||||
false,
|
||||
3,
|
||||
2,
|
||||
},
|
||||
{
|
||||
"Filter with type",
|
||||
@ -80,60 +79,6 @@ func (suite *KeeperTestSuite) TestGrpcGetRecordLists() {
|
||||
false,
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter with tag (extant) (https://git.vdb.to/cerc-io/laconicd/issues/129)",
|
||||
®istrytypes.QueryListRecordsRequest{
|
||||
Attributes: []*registrytypes.QueryListRecordsRequest_KeyValueInput{
|
||||
{
|
||||
Key: "tags",
|
||||
Value: ®istrytypes.QueryListRecordsRequest_ValueInput{
|
||||
Type: "string",
|
||||
String_: "tagA",
|
||||
},
|
||||
},
|
||||
},
|
||||
All: true,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter with tag (non-existent) (https://git.vdb.to/cerc-io/laconicd/issues/129)",
|
||||
®istrytypes.QueryListRecordsRequest{
|
||||
Attributes: []*registrytypes.QueryListRecordsRequest_KeyValueInput{
|
||||
{
|
||||
Key: "tags",
|
||||
Value: ®istrytypes.QueryListRecordsRequest_ValueInput{
|
||||
Type: "string",
|
||||
String_: "NOEXIST",
|
||||
},
|
||||
},
|
||||
},
|
||||
All: true,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"Filter test for key collision (https://git.vdb.to/cerc-io/laconicd/issues/122)",
|
||||
®istrytypes.QueryListRecordsRequest{
|
||||
Attributes: []*registrytypes.QueryListRecordsRequest_KeyValueInput{
|
||||
{
|
||||
Key: "typ",
|
||||
Value: ®istrytypes.QueryListRecordsRequest_ValueInput{
|
||||
Type: "string",
|
||||
String_: "eWebsiteRegistrationRecord",
|
||||
},
|
||||
},
|
||||
},
|
||||
All: true,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"Filter with attributes ServiceProviderRegistration",
|
||||
®istrytypes.QueryListRecordsRequest{
|
||||
@ -178,7 +123,7 @@ func (suite *KeeperTestSuite) TestGrpcGetRecordLists() {
|
||||
} else {
|
||||
sr.NoError(err)
|
||||
sr.Equal(test.noOfRecords, len(resp.GetRecords()))
|
||||
if test.createRecords && test.noOfRecords > 0 {
|
||||
if test.createRecords {
|
||||
recordId = resp.GetRecords()[0].GetId()
|
||||
sr.NotZero(resp.GetRecords())
|
||||
sr.Equal(resp.GetRecords()[0].GetBondId(), suite.bond.GetId())
|
||||
@ -188,25 +133,10 @@ func (suite *KeeperTestSuite) TestGrpcGetRecordLists() {
|
||||
sr.NoError(err)
|
||||
recAttr := helpers.UnMarshalMapFromJSONBytes(bz)
|
||||
for _, attr := range test.req.GetAttributes() {
|
||||
av := keeper.GetAttributeValue(attr.Value)
|
||||
if nil != av && nil != recAttr[attr.Key] &&
|
||||
reflect.Slice == reflect.TypeOf(recAttr[attr.Key]).Kind() &&
|
||||
reflect.Slice != reflect.TypeOf(av).Kind() {
|
||||
found := false
|
||||
allValues := recAttr[attr.Key].([]interface{})
|
||||
for i := range allValues {
|
||||
if av == allValues[i] {
|
||||
fmt.Printf("Found %s in %s", allValues[i], recAttr[attr.Key])
|
||||
found = true
|
||||
}
|
||||
}
|
||||
sr.Equal(true, found, fmt.Sprintf("Unable to find %s in %s", av, recAttr[attr.Key]))
|
||||
if attr.Key[:4] == "x500" {
|
||||
sr.Equal(keeper.GetAttributeValue(attr.Value), recAttr["x500"].(map[string]interface{})[attr.Key[4:]])
|
||||
} else {
|
||||
if attr.Key[:4] == "x500" {
|
||||
sr.Equal(av, recAttr["x500"].(map[string]interface{})[attr.Key[4:]])
|
||||
} else {
|
||||
sr.Equal(av, recAttr[attr.Key])
|
||||
}
|
||||
sr.Equal(keeper.GetAttributeValue(attr.Value), recAttr[attr.Key])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,9 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
auctionkeeper "github.com/cerc-io/laconicd/x/auction/keeper"
|
||||
bondkeeper "github.com/cerc-io/laconicd/x/bond/keeper"
|
||||
"github.com/cerc-io/laconicd/x/registry/helpers"
|
||||
@ -21,7 +19,6 @@ import (
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
||||
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -98,11 +95,6 @@ func NewKeeper(cdc codec.BinaryCodec, accountKeeper auth.AccountKeeper, bankKeep
|
||||
}
|
||||
}
|
||||
|
||||
// Logger returns a module-specific logger.
|
||||
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
|
||||
return ctx.Logger().With("module", types.ModuleName)
|
||||
}
|
||||
|
||||
// GetRecordIndexKey Generates Bond ID -> Bond index key.
|
||||
func GetRecordIndexKey(id string) []byte {
|
||||
return append(PrefixCIDToRecordIndex, []byte(id)...)
|
||||
@ -248,7 +240,7 @@ func (k Keeper) ProcessSetRecord(ctx sdk.Context, msg types.MsgSetRecord) (*type
|
||||
resourceSignBytes, _ := record.GetSignBytes()
|
||||
cid, err := record.GetCID()
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid record JSON")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid record JSON")
|
||||
}
|
||||
|
||||
record.ID = cid
|
||||
@ -263,13 +255,13 @@ func (k Keeper) ProcessSetRecord(ctx sdk.Context, msg types.MsgSetRecord) (*type
|
||||
pubKey, err := legacy.PubKeyFromBytes(helpers.BytesFromBase64(sig.PubKey))
|
||||
if err != nil {
|
||||
fmt.Println("Error decoding pubKey from bytes: ", err)
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Invalid public key.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Invalid public key.")
|
||||
}
|
||||
|
||||
sigOK := pubKey.VerifySignature(resourceSignBytes, helpers.BytesFromBase64(sig.Sig))
|
||||
if !sigOK {
|
||||
fmt.Println("Signature mismatch: ", sig.PubKey)
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Invalid signature.")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Invalid signature.")
|
||||
}
|
||||
record.Owners = append(record.Owners, pubKey.Address().String())
|
||||
}
|
||||
@ -345,26 +337,13 @@ func (k Keeper) ProcessAttributes(ctx sdk.Context, record types.RecordType) erro
|
||||
}
|
||||
}
|
||||
}
|
||||
case "WebsiteRegistrationRecord", "ApplicationRecord", "ApplicationDeploymentRequest",
|
||||
"ApplicationDeploymentRecord", "ApplicationArtifact", "ApplicationDeploymentRemovalRequest",
|
||||
"ApplicationDeploymentRemovalRecord", "DnsRecord", "GeneralRecord":
|
||||
case "WebsiteRegistrationRecord":
|
||||
{
|
||||
// #nosec G705
|
||||
for key := range record.Attributes {
|
||||
attr := record.Attributes[key]
|
||||
if reflect.Slice == reflect.TypeOf(attr).Kind() {
|
||||
av := attr.([]interface{})
|
||||
for i := range av {
|
||||
indexKey := GetAttributesIndexKey(key, av[i])
|
||||
if err := k.SetAttributeMapping(ctx, indexKey, record.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
indexKey := GetAttributesIndexKey(key, attr)
|
||||
if err := k.SetAttributeMapping(ctx, indexKey, record.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
indexKey := GetAttributesIndexKey(key, record.Attributes[key])
|
||||
if err := k.SetAttributeMapping(ctx, indexKey, record.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -381,7 +360,7 @@ func (k Keeper) ProcessAttributes(ctx sdk.Context, record types.RecordType) erro
|
||||
}
|
||||
|
||||
func GetAttributesIndexKey(key string, value interface{}) []byte {
|
||||
keyString := fmt.Sprintf("%s=%s", key, value)
|
||||
keyString := fmt.Sprintf("%s%s", key, value)
|
||||
return append(PrefixAttributesIndex, []byte(keyString)...)
|
||||
}
|
||||
|
||||
@ -409,8 +388,7 @@ func (k Keeper) GetAttributeMapping(ctx sdk.Context, key []byte) ([]string, erro
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
||||
if !store.Has(key) {
|
||||
k.Logger(ctx).Debug(fmt.Sprintf("store doesn't have key: %q", key))
|
||||
return []string{}, nil
|
||||
return nil, fmt.Errorf("store doesn't have key")
|
||||
}
|
||||
|
||||
var recordIds []string
|
||||
|
||||
@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
auctiontypes "github.com/cerc-io/laconicd/x/auction/types"
|
||||
"github.com/cerc-io/laconicd/x/registry/helpers"
|
||||
"github.com/cerc-io/laconicd/x/registry/types"
|
||||
@ -113,12 +112,12 @@ func (k Keeper) updateBlockChangeSetForName(ctx sdk.Context, crn string) {
|
||||
func (k Keeper) getAuthority(ctx sdk.Context, crn string) (string, *url.URL, *types.NameAuthority, error) {
|
||||
parsedCRN, err := url.Parse(crn)
|
||||
if err != nil {
|
||||
return "", nil, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid CRN.")
|
||||
return "", nil, nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid CRN.")
|
||||
}
|
||||
|
||||
name := parsedCRN.Host
|
||||
if !k.HasNameAuthority(ctx, name) {
|
||||
return name, nil, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.")
|
||||
return name, nil, nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.")
|
||||
}
|
||||
authority := k.GetNameAuthority(ctx, name)
|
||||
return name, parsedCRN, &authority, nil
|
||||
@ -132,19 +131,19 @@ func (k Keeper) checkCRNAccess(ctx sdk.Context, signer sdk.AccAddress, crn strin
|
||||
|
||||
formattedCRN := fmt.Sprintf("crn://%s%s", name, parsedCRN.RequestURI())
|
||||
if formattedCRN != crn {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid CRN.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid CRN.")
|
||||
}
|
||||
|
||||
if authority.OwnerAddress != signer.String() {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Access denied.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Access denied.")
|
||||
}
|
||||
|
||||
if authority.Status != types.AuthorityActive {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Authority is not active.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Authority is not active.")
|
||||
}
|
||||
|
||||
if authority.BondId == "" || len(authority.BondId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Authority bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Authority bond not found.")
|
||||
}
|
||||
|
||||
if authority.OwnerPublicKey == "" {
|
||||
@ -324,13 +323,13 @@ func (k Keeper) ProcessReserveSubAuthority(ctx sdk.Context, name string, msg typ
|
||||
|
||||
// Check if parent authority exists.
|
||||
if !k.HasNameAuthority(ctx, parent) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Parent authority not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Parent authority not found.")
|
||||
}
|
||||
parentAuthority := k.GetNameAuthority(ctx, parent)
|
||||
|
||||
// Sub-authority creator needs to be the owner of the parent authority.
|
||||
if parentAuthority.OwnerAddress != msg.Signer {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Access denied.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Access denied.")
|
||||
}
|
||||
|
||||
// Sub-authority owner defaults to parent authority owner.
|
||||
@ -363,17 +362,17 @@ func (k Keeper) createAuthority(ctx sdk.Context, name string, owner string, isRo
|
||||
if k.HasNameAuthority(ctx, name) {
|
||||
authority := k.GetNameAuthority(ctx, name)
|
||||
if authority.Status != types.AuthorityExpired {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name already reserved.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Name already reserved.")
|
||||
}
|
||||
}
|
||||
|
||||
ownerAddress, err := sdk.AccAddressFromBech32(owner)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid owner address.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid owner address.")
|
||||
}
|
||||
ownerAccount := k.accountKeeper.GetAccount(ctx, ownerAddress)
|
||||
if ownerAccount == nil {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnknownAddress, "Account not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnknownAddress, "Account not found.")
|
||||
}
|
||||
|
||||
authority := types.NameAuthority{
|
||||
@ -431,11 +430,11 @@ func (k Keeper) ProcessReserveAuthority(ctx sdk.Context, msg types.MsgReserveAut
|
||||
crn := fmt.Sprintf("crn://%s", msg.GetName())
|
||||
parsedCrn, err := url.Parse(crn)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid name")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid name")
|
||||
}
|
||||
name := parsedCrn.Host
|
||||
if fmt.Sprintf("crn://%s", name) != crn {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid name")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Invalid name")
|
||||
}
|
||||
if strings.Contains(name, ".") {
|
||||
return k.ProcessReserveSubAuthority(ctx, name, msg)
|
||||
@ -451,20 +450,20 @@ func (k Keeper) ProcessSetAuthorityBond(ctx sdk.Context, msg types.MsgSetAuthori
|
||||
name := msg.GetName()
|
||||
signer := msg.GetSigner()
|
||||
if !k.HasNameAuthority(ctx, name) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Name authority not found.")
|
||||
}
|
||||
authority := k.GetNameAuthority(ctx, name)
|
||||
if authority.OwnerAddress != signer {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Access denied")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Access denied")
|
||||
}
|
||||
|
||||
if !k.bondKeeper.HasBond(ctx, msg.BondId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
}
|
||||
//
|
||||
bond := k.bondKeeper.GetBond(ctx, msg.BondId)
|
||||
if bond.Owner != signer {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
}
|
||||
|
||||
// No-op if bond hasn't changed.
|
||||
@ -497,7 +496,7 @@ func (k Keeper) ProcessDeleteName(ctx sdk.Context, msg types.MsgDeleteNameAuthor
|
||||
}
|
||||
|
||||
if !k.HasNameRecord(ctx, msg.Crn) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Name not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Name not found.")
|
||||
}
|
||||
|
||||
// Set CID to empty string.
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
auctionkeeper "github.com/cerc-io/laconicd/x/auction/keeper"
|
||||
auctiontypes "github.com/cerc-io/laconicd/x/auction/types"
|
||||
bondtypes "github.com/cerc-io/laconicd/x/bond/types"
|
||||
@ -159,7 +158,7 @@ func (k RecordKeeper) QueryRecordsByBond(ctx sdk.Context, bondID string) []types
|
||||
// ProcessRenewRecord renews a record.
|
||||
func (k Keeper) ProcessRenewRecord(ctx sdk.Context, msg types.MsgRenewRecord) error {
|
||||
if !k.HasRecord(ctx, msg.RecordId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.")
|
||||
}
|
||||
|
||||
// Check if renewal is required (i.e. expired record marked as deleted).
|
||||
@ -170,7 +169,7 @@ func (k Keeper) ProcessRenewRecord(ctx sdk.Context, msg types.MsgRenewRecord) er
|
||||
}
|
||||
|
||||
if !record.Deleted || expiryTime.After(ctx.BlockTime()) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Renewal not required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Renewal not required.")
|
||||
}
|
||||
|
||||
recordType := record.ToRecordType()
|
||||
@ -185,23 +184,23 @@ func (k Keeper) ProcessRenewRecord(ctx sdk.Context, msg types.MsgRenewRecord) er
|
||||
// ProcessAssociateBond associates a record with a bond.
|
||||
func (k Keeper) ProcessAssociateBond(ctx sdk.Context, msg types.MsgAssociateBond) error {
|
||||
if !k.HasRecord(ctx, msg.RecordId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.")
|
||||
}
|
||||
|
||||
if !k.bondKeeper.HasBond(ctx, msg.BondId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
}
|
||||
|
||||
// Check if already associated with a bond.
|
||||
record := k.GetRecord(ctx, msg.RecordId)
|
||||
if record.BondId != "" || len(record.BondId) != 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond already exists.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond already exists.")
|
||||
}
|
||||
|
||||
// Only the bond owner can associate a record with the bond.
|
||||
bond := k.bondKeeper.GetBond(ctx, msg.BondId)
|
||||
if msg.Signer != bond.Owner {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
}
|
||||
|
||||
record.BondId = msg.BondId
|
||||
@ -219,20 +218,20 @@ func (k Keeper) ProcessAssociateBond(ctx sdk.Context, msg types.MsgAssociateBond
|
||||
// ProcessDissociateBond dissociates a record from its bond.
|
||||
func (k Keeper) ProcessDissociateBond(ctx sdk.Context, msg types.MsgDissociateBond) error {
|
||||
if !k.HasRecord(ctx, msg.RecordId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Record not found.")
|
||||
}
|
||||
|
||||
// Check if associated with a bond.
|
||||
record := k.GetRecord(ctx, msg.RecordId)
|
||||
bondID := record.BondId
|
||||
if bondID == "" || len(bondID) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond not found.")
|
||||
}
|
||||
|
||||
// Only the bond owner can dissociate a record from the bond.
|
||||
bond := k.bondKeeper.GetBond(ctx, bondID)
|
||||
if msg.Signer != bond.Owner {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
}
|
||||
|
||||
// Clear bond ID.
|
||||
@ -246,13 +245,13 @@ func (k Keeper) ProcessDissociateBond(ctx sdk.Context, msg types.MsgDissociateBo
|
||||
// ProcessDissociateRecords dissociates all records associated with a given bond.
|
||||
func (k Keeper) ProcessDissociateRecords(ctx sdk.Context, msg types.MsgDissociateRecords) error {
|
||||
if !k.bondKeeper.HasBond(ctx, msg.BondId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
|
||||
}
|
||||
|
||||
// Only the bond owner can dissociate all records from the bond.
|
||||
bond := k.bondKeeper.GetBond(ctx, msg.BondId)
|
||||
if msg.Signer != bond.Owner {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond owner mismatch.")
|
||||
}
|
||||
|
||||
// Dissociate all records from the bond.
|
||||
@ -270,22 +269,22 @@ func (k Keeper) ProcessDissociateRecords(ctx sdk.Context, msg types.MsgDissociat
|
||||
// ProcessReAssociateRecords switches records from and old to new bond.
|
||||
func (k Keeper) ProcessReAssociateRecords(ctx sdk.Context, msg types.MsgReAssociateRecords) error {
|
||||
if !k.bondKeeper.HasBond(ctx, msg.OldBondId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Old bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Old bond not found.")
|
||||
}
|
||||
|
||||
if !k.bondKeeper.HasBond(ctx, msg.NewBondId) {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "New bond not found.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "New bond not found.")
|
||||
}
|
||||
|
||||
// Only the bond owner can re-associate all records.
|
||||
oldBond := k.bondKeeper.GetBond(ctx, msg.OldBondId)
|
||||
if msg.Signer != oldBond.Owner {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Old bond owner mismatch.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Old bond owner mismatch.")
|
||||
}
|
||||
|
||||
newBond := k.bondKeeper.GetBond(ctx, msg.NewBondId)
|
||||
if msg.Signer != newBond.Owner {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "New bond owner mismatch.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "New bond owner mismatch.")
|
||||
}
|
||||
|
||||
// Re-associate all records.
|
||||
|
||||
4936
x/registry/types/attributes.pb.go
generated
4936
x/registry/types/attributes.pb.go
generated
File diff suppressed because it is too large
Load Diff
@ -50,54 +50,6 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
|
||||
(*Attributes)(nil),
|
||||
&WebsiteRegistrationRecord{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.ApplicationRecord",
|
||||
(*Attributes)(nil),
|
||||
&ApplicationRecord{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.ApplicationDeploymentRequest",
|
||||
(*Attributes)(nil),
|
||||
&ApplicationDeploymentRequest{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.ApplicationDeploymentRecord",
|
||||
(*Attributes)(nil),
|
||||
&ApplicationDeploymentRecord{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.ApplicationArtifact",
|
||||
(*Attributes)(nil),
|
||||
&ApplicationArtifact{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.ApplicationDeploymentRemovalRequest",
|
||||
(*Attributes)(nil),
|
||||
&ApplicationDeploymentRemovalRequest{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.ApplicationDeploymentRemovalRecord",
|
||||
(*Attributes)(nil),
|
||||
&ApplicationDeploymentRemovalRecord{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.DnsRecord",
|
||||
(*Attributes)(nil),
|
||||
&DnsRecord{},
|
||||
)
|
||||
|
||||
registry.RegisterInterface(
|
||||
"vulcanize.registry.v1beta1.GeneralRecord",
|
||||
(*Attributes)(nil),
|
||||
&GeneralRecord{},
|
||||
)
|
||||
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ package types
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@ -33,15 +32,15 @@ func (msg MsgSetName) Type() string { return "set-name" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgSetName) ValidateBasic() error {
|
||||
if msg.Crn == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "CRN is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "CRN is required.")
|
||||
}
|
||||
|
||||
if msg.Cid == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "CID is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "CID is required.")
|
||||
}
|
||||
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -77,11 +76,11 @@ func (msg MsgReserveAuthority) Type() string { return "reserve-authority" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgReserveAuthority) ValidateBasic() error {
|
||||
if len(msg.Name) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "name is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "name is required.")
|
||||
}
|
||||
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -117,15 +116,15 @@ func (msg MsgSetAuthorityBond) Type() string { return "authority-bond" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgSetAuthorityBond) ValidateBasic() error {
|
||||
if len(msg.Name) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "name is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "name is required.")
|
||||
}
|
||||
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
}
|
||||
|
||||
if len(msg.BondId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "bond id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "bond id is required.")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -160,16 +159,16 @@ func (msg MsgDeleteNameAuthority) Type() string { return "delete-name" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgDeleteNameAuthority) ValidateBasic() error {
|
||||
if len(msg.Crn) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "crn is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "crn is required.")
|
||||
}
|
||||
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
}
|
||||
|
||||
_, err := url.Parse(msg.Crn)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid crn.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid crn.")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
@ -35,17 +34,17 @@ func (msg MsgSetRecord) Type() string { return "set-record" }
|
||||
|
||||
func (msg MsgSetRecord) ValidateBasic() error {
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer)
|
||||
}
|
||||
owners := msg.Payload.Record.Owners
|
||||
for _, owner := range owners {
|
||||
if owner == "" {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Record owner not set.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Record owner not set.")
|
||||
}
|
||||
}
|
||||
|
||||
if len(msg.BondId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Bond ID is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Bond ID is required.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -84,11 +83,11 @@ func (msg MsgRenewRecord) Type() string { return "renew-record" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgRenewRecord) ValidateBasic() error {
|
||||
if len(msg.RecordId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "record id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "record id is required.")
|
||||
}
|
||||
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -124,13 +123,13 @@ func (msg MsgAssociateBond) Type() string { return "associate-bond" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgAssociateBond) ValidateBasic() error {
|
||||
if len(msg.RecordId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "record id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "record id is required.")
|
||||
}
|
||||
if len(msg.BondId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "bond id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "bond id is required.")
|
||||
}
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -165,10 +164,10 @@ func (msg MsgDissociateBond) Type() string { return "dissociate-bond" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgDissociateBond) ValidateBasic() error {
|
||||
if len(msg.RecordId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "record id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "record id is required.")
|
||||
}
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -203,10 +202,10 @@ func (msg MsgDissociateRecords) Type() string { return "dissociate-records" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgDissociateRecords) ValidateBasic() error {
|
||||
if len(msg.BondId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "bond id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "bond id is required.")
|
||||
}
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -242,13 +241,13 @@ func (msg MsgReAssociateRecords) Type() string { return "reassociate-records" }
|
||||
// ValidateBasic Implements Msg.
|
||||
func (msg MsgReAssociateRecords) ValidateBasic() error {
|
||||
if len(msg.OldBondId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "old-bond-id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "old-bond-id is required.")
|
||||
}
|
||||
if len(msg.NewBondId) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "new-bond-id is required.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "new-bond-id is required.")
|
||||
}
|
||||
if len(msg.Signer) == 0 {
|
||||
return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer.")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
918
x/registry/types/tx.pb.gw.go
generated
918
x/registry/types/tx.pb.gw.go
generated
@ -1,918 +0,0 @@
|
||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: vulcanize/registry/v1beta1/tx.proto
|
||||
|
||||
/*
|
||||
Package types is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/descriptor"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Suppress "imported and not used" errors
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
var _ = descriptor.ForMessage
|
||||
var _ = metadata.Join
|
||||
|
||||
var (
|
||||
filter_Msg_SetRecord_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_SetRecord_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgSetRecord
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SetRecord_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.SetRecord(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_SetRecord_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgSetRecord
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SetRecord_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.SetRecord(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_RenewRecord_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_RenewRecord_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgRenewRecord
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RenewRecord_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.RenewRecord(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_RenewRecord_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgRenewRecord
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RenewRecord_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.RenewRecord(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_AssociateBond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_AssociateBond_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgAssociateBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_AssociateBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.AssociateBond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_AssociateBond_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgAssociateBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_AssociateBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.AssociateBond(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_DissociateBond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_DissociateBond_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgDissociateBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_DissociateBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.DissociateBond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_DissociateBond_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgDissociateBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_DissociateBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.DissociateBond(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_DissociateRecords_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_DissociateRecords_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgDissociateRecords
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_DissociateRecords_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.DissociateRecords(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_DissociateRecords_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgDissociateRecords
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_DissociateRecords_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.DissociateRecords(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_ReAssociateRecords_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_ReAssociateRecords_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgReAssociateRecords
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ReAssociateRecords_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.ReAssociateRecords(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_ReAssociateRecords_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgReAssociateRecords
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ReAssociateRecords_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.ReAssociateRecords(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_SetName_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_SetName_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgSetName
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SetName_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.SetName(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_SetName_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgSetName
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SetName_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.SetName(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_ReserveName_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_ReserveName_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgReserveAuthority
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ReserveName_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.ReserveName(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_ReserveName_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgReserveAuthority
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ReserveName_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.ReserveName(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_DeleteName_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_DeleteName_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgDeleteNameAuthority
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_DeleteName_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.DeleteName(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_DeleteName_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgDeleteNameAuthority
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_DeleteName_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.DeleteName(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Msg_SetAuthorityBond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Msg_SetAuthorityBond_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgSetAuthorityBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SetAuthorityBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.SetAuthorityBond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Msg_SetAuthorityBond_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq MsgSetAuthorityBond
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SetAuthorityBond_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.SetAuthorityBond(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerServer registers the http handlers for service Msg to "mux".
|
||||
// UnaryRPC :call MsgServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead.
|
||||
func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error {
|
||||
|
||||
mux.Handle("POST", pattern_Msg_SetRecord_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_SetRecord_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_SetRecord_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_RenewRecord_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_RenewRecord_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_RenewRecord_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_AssociateBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_AssociateBond_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_AssociateBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_DissociateBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_DissociateBond_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_DissociateBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_DissociateRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_DissociateRecords_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_DissociateRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_ReAssociateRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_ReAssociateRecords_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_ReAssociateRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_SetName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_SetName_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_SetName_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_ReserveName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_ReserveName_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_ReserveName_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_DeleteName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_DeleteName_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_DeleteName_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_SetAuthorityBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Msg_SetAuthorityBond_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_SetAuthorityBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerFromEndpoint is same as RegisterMsgHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterMsgHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterMsgHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterMsgHandler registers the http handlers for service Msg to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterMsgHandlerClient(ctx, mux, NewMsgClient(conn))
|
||||
}
|
||||
|
||||
// RegisterMsgHandlerClient registers the http handlers for service Msg
|
||||
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MsgClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MsgClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "MsgClient" to call the correct interceptors.
|
||||
func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error {
|
||||
|
||||
mux.Handle("POST", pattern_Msg_SetRecord_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_SetRecord_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_SetRecord_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_RenewRecord_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_RenewRecord_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_RenewRecord_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_AssociateBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_AssociateBond_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_AssociateBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_DissociateBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_DissociateBond_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_DissociateBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_DissociateRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_DissociateRecords_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_DissociateRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_ReAssociateRecords_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_ReAssociateRecords_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_ReAssociateRecords_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_SetName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_SetName_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_SetName_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_ReserveName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_ReserveName_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_ReserveName_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_DeleteName_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_DeleteName_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_DeleteName_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Msg_SetAuthorityBond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Msg_SetAuthorityBond_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Msg_SetAuthorityBond_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_Msg_SetRecord_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "set_record"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_RenewRecord_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "renew_record"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_AssociateBond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "associate_bond"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_DissociateBond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "dissociate_bond"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_DissociateRecords_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "dissociate_records"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_ReAssociateRecords_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "reassociate_records"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_SetName_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "set_name"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_ReserveName_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "reserve_name"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_DeleteName_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "delete_name"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Msg_SetAuthorityBond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"vulcanize", "registry", "v1beta1", "set_authority_bond"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_Msg_SetRecord_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_RenewRecord_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_AssociateBond_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_DissociateBond_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_DissociateRecords_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_ReAssociateRecords_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_SetName_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_ReserveName_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_DeleteName_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Msg_SetAuthorityBond_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
@ -68,78 +68,6 @@ func payLoadAttributes(recordPayLoad map[string]interface{}) (*codectypes.Any, e
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "ApplicationRecord":
|
||||
{
|
||||
var attributes ApplicationRecord
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "ApplicationDeploymentRequest":
|
||||
{
|
||||
var attributes ApplicationDeploymentRequest
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "ApplicationDeploymentRecord":
|
||||
{
|
||||
var attributes ApplicationDeploymentRecord
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "ApplicationDeploymentRemovalRequest":
|
||||
{
|
||||
var attributes ApplicationDeploymentRemovalRequest
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "ApplicationDeploymentRemovalRecord":
|
||||
{
|
||||
var attributes ApplicationDeploymentRemovalRecord
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "ApplicationArtifact":
|
||||
{
|
||||
var attributes ApplicationArtifact
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "DnsRecord":
|
||||
{
|
||||
var attributes DnsRecord
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
case "GeneralRecord":
|
||||
{
|
||||
var attributes GeneralRecord
|
||||
err := json.Unmarshal(bz, &attributes)
|
||||
if err != nil {
|
||||
return &codectypes.Any{}, err
|
||||
}
|
||||
return codectypes.NewAnyWithValue(&attributes)
|
||||
}
|
||||
default:
|
||||
return &codectypes.Any{}, fmt.Errorf("unsupported record type %s", recordType.(string))
|
||||
}
|
||||
@ -207,110 +135,6 @@ func GetJSONBytesFromAny(any codectypes.Any) ([]byte, error) {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "ApplicationRecord":
|
||||
{
|
||||
var attributes ApplicationRecord
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "ApplicationDeploymentRequest":
|
||||
{
|
||||
var attributes ApplicationDeploymentRequest
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "ApplicationDeploymentRecord":
|
||||
{
|
||||
var attributes ApplicationDeploymentRecord
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "ApplicationDeploymentRemovalRequest":
|
||||
{
|
||||
var attributes ApplicationDeploymentRemovalRequest
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "ApplicationDeploymentRemovalRecord":
|
||||
{
|
||||
var attributes ApplicationDeploymentRemovalRecord
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "ApplicationArtifact":
|
||||
{
|
||||
var attributes ApplicationArtifact
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "DnsRecord":
|
||||
{
|
||||
var attributes DnsRecord
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
}
|
||||
}
|
||||
case "GeneralRecord":
|
||||
{
|
||||
var attributes GeneralRecord
|
||||
err := proto.Unmarshal(any.Value, &attributes)
|
||||
if err != nil {
|
||||
panic("Proto unmarshal error")
|
||||
}
|
||||
|
||||
bz, err = json.Marshal(attributes)
|
||||
if err != nil {
|
||||
panic("JSON marshal error")
|
||||
|
||||
205
x/wasm/Governance.md
Normal file
205
x/wasm/Governance.md
Normal file
@ -0,0 +1,205 @@
|
||||
# Governance
|
||||
|
||||
This document gives an overview of how the various governance
|
||||
proposals interact with the CosmWasm contract lifecycle. It is
|
||||
a high-level, technical introduction meant to provide context before
|
||||
looking into the code, or constructing proposals.
|
||||
|
||||
## Proposal Types
|
||||
We have added 9 new wasm specific proposal types that cover the contract's live cycle and authorization:
|
||||
|
||||
* `StoreCodeProposal` - upload a wasm binary
|
||||
* `InstantiateContractProposal` - instantiate a wasm contract
|
||||
* `MigrateContractProposal` - migrate a wasm contract to a new code version
|
||||
* `SudoContractProposal` - call into the protected `sudo` entry point of a contract
|
||||
* `ExecuteContractProposal` - execute a wasm contract as an arbitrary user
|
||||
* `UpdateAdminProposal` - set a new admin for a contract
|
||||
* `ClearAdminProposal` - clear admin for a contract to prevent further migrations
|
||||
* `PinCodes` - pin the given code ids in cache. This trades memory for reduced startup time and lowers gas cost
|
||||
* `UnpinCodes` - unpin the given code ids from the cache. This frees up memory and returns to standard speed and gas cost
|
||||
* `UpdateInstantiateConfigProposal` - update instantiate permissions to a list of given code ids.
|
||||
* `StoreAndInstantiateContractProposal` - upload and instantiate a wasm contract.
|
||||
|
||||
For details see the proposal type [implementation](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/proposal.go)
|
||||
|
||||
### Unit tests
|
||||
[Proposal type validations](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/proposal_test.go)
|
||||
|
||||
## Proposal Handler
|
||||
The [wasmd proposal_handler](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/proposal_handler.go) implements the `gov.Handler` function
|
||||
and executes the wasmd proposal types after a successful tally.
|
||||
|
||||
The proposal handler uses a [`GovAuthorizationPolicy`](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/authz_policy.go#L29) to bypass the existing contract's authorization policy.
|
||||
|
||||
### Tests
|
||||
* [Integration: Submit and execute proposal](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/proposal_integration_test.go)
|
||||
|
||||
## Gov Integration
|
||||
The wasmd proposal handler can be added to the gov router in the [abci app](https://github.com/CosmWasm/wasmd/blob/master/app/app.go#L306)
|
||||
to receive proposal execution calls.
|
||||
```go
|
||||
govRouter.AddRoute(wasm.RouterKey, wasm.NewWasmProposalHandler(app.wasmKeeper, enabledProposals))
|
||||
```
|
||||
|
||||
## Wasmd Authorization Settings
|
||||
|
||||
Settings via sdk `params` module:
|
||||
- `code_upload_access` - who can upload a wasm binary: `Nobody`, `Everybody`, `OnlyAddress`
|
||||
- `instantiate_default_permission` - platform default, who can instantiate a wasm binary when the code owner has not set it
|
||||
|
||||
See [params.go](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/params.go)
|
||||
|
||||
### Init Params Via Genesis
|
||||
|
||||
```json
|
||||
"wasm": {
|
||||
"params": {
|
||||
"code_upload_access": {
|
||||
"permission": "Everybody"
|
||||
},
|
||||
"instantiate_default_permission": "Everybody"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
The values can be updated via gov proposal implemented in the `params` module.
|
||||
|
||||
### Update Params Via [ParamChangeProposal](https://github.com/cosmos/cosmos-sdk/blob/v0.45.3/proto/cosmos/params/v1beta1/params.proto#L10)
|
||||
Example to submit a parameter change gov proposal:
|
||||
```sh
|
||||
wasmd tx gov submit-proposal param-change <proposal-json-file> --from validator --chain-id=testing -b block
|
||||
```
|
||||
#### Content examples
|
||||
* Disable wasm code uploads
|
||||
```json
|
||||
{
|
||||
"title": "Foo",
|
||||
"description": "Bar",
|
||||
"changes": [
|
||||
{
|
||||
"subspace": "wasm",
|
||||
"key": "uploadAccess",
|
||||
"value": {
|
||||
"permission": "Nobody"
|
||||
}
|
||||
}
|
||||
],
|
||||
"deposit": ""
|
||||
}
|
||||
```
|
||||
* Allow wasm code uploads for everybody
|
||||
```json
|
||||
{
|
||||
"title": "Foo",
|
||||
"description": "Bar",
|
||||
"changes": [
|
||||
{
|
||||
"subspace": "wasm",
|
||||
"key": "uploadAccess",
|
||||
"value": {
|
||||
"permission": "Everybody"
|
||||
}
|
||||
}
|
||||
],
|
||||
"deposit": ""
|
||||
}
|
||||
```
|
||||
|
||||
* Restrict code uploads to a single address
|
||||
```json
|
||||
{
|
||||
"title": "Foo",
|
||||
"description": "Bar",
|
||||
"changes": [
|
||||
{
|
||||
"subspace": "wasm",
|
||||
"key": "uploadAccess",
|
||||
"value": {
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq0fr2sh"
|
||||
}
|
||||
}
|
||||
],
|
||||
"deposit": ""
|
||||
}
|
||||
```
|
||||
* Set chain **default** instantiation settings to nobody
|
||||
```json
|
||||
{
|
||||
"title": "Foo",
|
||||
"description": "Bar",
|
||||
"changes": [
|
||||
{
|
||||
"subspace": "wasm",
|
||||
"key": "instantiateAccess",
|
||||
"value": "Nobody"
|
||||
}
|
||||
],
|
||||
"deposit": ""
|
||||
}
|
||||
```
|
||||
* Set chain **default** instantiation settings to everybody
|
||||
```json
|
||||
{
|
||||
"title": "Foo",
|
||||
"description": "Bar",
|
||||
"changes": [
|
||||
{
|
||||
"subspace": "wasm",
|
||||
"key": "instantiateAccess",
|
||||
"value": "Everybody"
|
||||
}
|
||||
],
|
||||
"deposit": ""
|
||||
}
|
||||
```
|
||||
|
||||
### Enable gov proposals at **compile time**.
|
||||
As gov proposals bypass the existing authorization policy they are disabled and require to be enabled at compile time.
|
||||
```
|
||||
-X github.com/CosmWasm/wasmd/app.ProposalsEnabled=true - enable all x/wasm governance proposals (default false)
|
||||
-X github.com/CosmWasm/wasmd/app.EnableSpecificProposals=MigrateContract,UpdateAdmin,ClearAdmin - enable a subset of the x/wasm governance proposal types (overrides ProposalsEnabled)
|
||||
```
|
||||
|
||||
The `ParamChangeProposal` is always enabled.
|
||||
|
||||
### Tests
|
||||
* [params validation unit tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/params_test.go)
|
||||
* [genesis validation tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/genesis_test.go)
|
||||
* [policy integration tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/keeper_test.go)
|
||||
|
||||
## CLI
|
||||
|
||||
```shell script
|
||||
wasmd tx gov submit-proposal [command]
|
||||
|
||||
Available Commands:
|
||||
wasm-store Submit a wasm binary proposal
|
||||
instantiate-contract Submit an instantiate wasm contract proposal
|
||||
migrate-contract Submit a migrate wasm contract to a new code version proposal
|
||||
set-contract-admin Submit a new admin for a contract proposal
|
||||
clear-contract-admin Submit a clear admin for a contract to prevent further migrations proposal
|
||||
...
|
||||
```
|
||||
## Rest
|
||||
New [`ProposalHandlers`](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/client/proposal_handler.go)
|
||||
|
||||
* Integration
|
||||
```shell script
|
||||
gov.NewAppModuleBasic(append(wasmclient.ProposalHandlers, paramsclient.ProposalHandler, distr.ProposalHandler, upgradeclient.ProposalHandler)...),
|
||||
```
|
||||
In [abci app](https://github.com/CosmWasm/wasmd/blob/master/app/app.go#L109)
|
||||
|
||||
### Tests
|
||||
* [Rest Unit tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/client/proposal_handler_test.go)
|
||||
* [Rest smoke LCD test](https://github.com/CosmWasm/wasmd/blob/master/lcd_test/wasm_test.go)
|
||||
|
||||
|
||||
|
||||
## Pull requests
|
||||
* https://github.com/CosmWasm/wasmd/pull/190
|
||||
* https://github.com/CosmWasm/wasmd/pull/186
|
||||
* https://github.com/CosmWasm/wasmd/pull/183
|
||||
* https://github.com/CosmWasm/wasmd/pull/180
|
||||
* https://github.com/CosmWasm/wasmd/pull/179
|
||||
* https://github.com/CosmWasm/wasmd/pull/173
|
||||
137
x/wasm/IBC.md
Normal file
137
x/wasm/IBC.md
Normal file
@ -0,0 +1,137 @@
|
||||
# IBC specification
|
||||
|
||||
This documents how CosmWasm contracts are expected to interact with IBC.
|
||||
|
||||
## General Concepts
|
||||
|
||||
**IBC Enabled** - when instantiating a contract, we detect if it supports IBC messages.
|
||||
We require "feature flags" in the contract/vm handshake to ensure compatibility
|
||||
for features like staking or chain-specific extensions. IBC functionality will require
|
||||
another "feature flag", and the list of "enabled features" can be returned to the `x/wasm`
|
||||
module to control conditional IBC behavior.
|
||||
|
||||
If this feature is enabled, it is considered "IBC Enabled", and that info will
|
||||
be stored in the ContractInfo. (For mock, we assume all contracts are IBC enabled)
|
||||
|
||||
Also, please read the [IBC Docs](https://docs.cosmos.network/master/ibc/overview.html)
|
||||
for detailed descriptions of the terms *Port*, *Client*, *Connection*,
|
||||
and *Channel*
|
||||
|
||||
## Overview
|
||||
|
||||
We use "One Port per Contract", which is the most straight-forward mapping, treating each contract
|
||||
like a module. It does lead to very long portIDs however. Pay special attention to both the Channel establishment
|
||||
(which should be compatible with standard ICS20 modules without changes on their part), as well
|
||||
as how contracts can properly identify their counterparty.
|
||||
|
||||
(We considered on port for the `x/wasm` module and multiplexing on it, but [dismissed that idea](#rejected-ideas))
|
||||
|
||||
* Upon `Instantiate`, if a contract is *IBC Enabled*, we dynamically
|
||||
bind a port for this contract. The port name is `wasm.<contract address>`,
|
||||
eg. `wasm.cosmos1hmdudppzceg27qsuq707tjg8rkgj7g5hnvnw29`
|
||||
* If a *Channel* is being established with a registered `wasm.xyz` port,
|
||||
the `x/wasm.Keeper` will handle this and call into the appropriate
|
||||
contract to determine supported protocol versions during the
|
||||
[`ChanOpenTry` and `ChanOpenAck` phases](https://docs.cosmos.network/master/ibc/overview.html#channels).
|
||||
(See [Channel Handshake Version Negotiation](https://docs.cosmos.network/master/ibc/custom.html#channel-handshake-version-negotiation))
|
||||
* Both the *Port* and the *Channel* are fully owned by one contract.
|
||||
* `x/wasm` will allow both *ORDERED* and *UNORDERED* channels and pass that mode
|
||||
down to the contract in `OnChanOpenTry`, so the contract can decide if it accepts
|
||||
the mode. We will recommend the contract developers stick with *ORDERED* channels
|
||||
for custom protocols unless they can reason about async packet timing.
|
||||
* When sending a packet, the CosmWasm contract must specify the local *ChannelID*.
|
||||
As there is a unique *PortID* per contract, that is filled in by `x/wasm`
|
||||
to produce the globally unique `(PortID, ChannelID)`
|
||||
* When receiving a Packet (or Ack or Timeout), the contracts receives the local
|
||||
*ChannelID* it came from, as well as the packet that was sent by the counterparty.
|
||||
* When receiving an Ack or Timeout packet, the contract also receives the
|
||||
original packet that it sent earlier.
|
||||
* We do not support multihop packets in this model (they are rejected by `x/wasm`).
|
||||
They are currently not fully specified nor implemented in IBC 1.0, so let us
|
||||
simplify our model until this is well established
|
||||
|
||||
## Workflow
|
||||
|
||||
Establishing *Clients* and *Connections* is out of the scope of this
|
||||
module and must be created by the same means as for `ibc-transfer`
|
||||
(via the [go cli](https://github.com/cosmos/relayer) or better [ts-relayer](https://github.com/confio/ts-relayer)).
|
||||
`x/wasm` will bind a unique *Port* for each "IBC Enabled" contract.
|
||||
|
||||
For mocks, all the Packet Handling and Channel Lifecycle Hooks are routed
|
||||
to some Golang stub handler, but containing the contract address, so we
|
||||
can perform contract-specific actions for each packet. In a real setting,
|
||||
we route to the contract that owns the port/channel and call one of it's various
|
||||
entry points.
|
||||
|
||||
Please refer to the CosmWasm repo for all
|
||||
[details on the IBC API from the point of view of a CosmWasm contract](https://github.com/CosmWasm/cosmwasm/blob/main/IBC.md).
|
||||
|
||||
## Future Ideas
|
||||
|
||||
Here are some ideas we may add in the future
|
||||
|
||||
### Dynamic Ports and Channels
|
||||
|
||||
* multiple ports per contract
|
||||
* elastic ports that can be assigned to different contracts
|
||||
* transfer of channels to another contract
|
||||
|
||||
This is inspired by the Agoric design, but also adds considerable complexity to both the `x/wasm`
|
||||
implementation as well as the correctness reasoning of any given contract. This will not be
|
||||
available in the first version of our "IBC Enabled contracts", but we can consider it for later,
|
||||
if there are concrete user cases that would significantly benefit from this added complexity.
|
||||
|
||||
### Add multihop support
|
||||
|
||||
Once the ICS and IBC specs fully establish how multihop packets work, we should add support for that.
|
||||
Both on setting up the routes with OpenChannel, as well as acting as an intermediate relayer (if that is possible)
|
||||
|
||||
## Rejected Ideas
|
||||
|
||||
### One Port per Module
|
||||
|
||||
We decided on "one port per contract", especially after the IBC team raised
|
||||
the max length on port names to allow `wasm-<bech32 address>` to be a valid port.
|
||||
Here are the arguments for "one port for x/wasm" vs "one port per contract". Here
|
||||
was an alternate proposal:
|
||||
|
||||
In this approach, the `x/wasm` module just binds one port to handle all
|
||||
modules. This can be well defined name like `wasm`. Since we always
|
||||
have `(ChannelID, PortID)` for routing messages, we can reuse one port
|
||||
for all contracts as long as we have a clear way to map the `ChannelID`
|
||||
to a specific contract when it is being established.
|
||||
|
||||
|
||||
* On genesis we bind the port `wasm` for all communication with the `x/wasm`
|
||||
module.
|
||||
* The *Port* is fully owned by `x/wasm`
|
||||
* Each *Channel* is fully owned by one contract.
|
||||
* `x/wasm` only accepts *ORDERED Channels* for simplicity of contract
|
||||
correctness.
|
||||
|
||||
To clarify:
|
||||
|
||||
* When a *Channel* is being established with port `wasm`, the
|
||||
`x/wasm.Keeper` must be able to identify for which contract this
|
||||
is destined. **how to do so**??
|
||||
* One idea: the channel name must be the contract address. This means
|
||||
(`wasm`, `cosmos13d...`) will map to the given contract in the wasm module.
|
||||
The problem with this is that if two contracts from chainA want to
|
||||
connect to the same contracts on chainB, they will want to claim the
|
||||
same *ChannelID* and *PortID*. Not sure how to differentiate multiple
|
||||
parties in this way.
|
||||
* Other ideas: have a special field we send on `OnChanOpenInit` that
|
||||
specifies the destination contract, and allow any *ChannelID*.
|
||||
However, looking at [`OnChanOpenInit` function signature](https://docs.cosmos.network/master/ibc/custom.html#implement-ibcmodule-interface-and-callbacks),
|
||||
I don't see a place to put this extra info, without abusing the version field,
|
||||
which is a [specified field](https://docs.cosmos.network/master/ibc/custom.html#channel-handshake-version-negotiation):
|
||||
```
|
||||
Versions must be strings but can implement any versioning structure.
|
||||
If your application plans to have linear releases then semantic versioning is recommended.
|
||||
...
|
||||
Valid version selection includes selecting a compatible version identifier with a subset
|
||||
of features supported by your application for that version.
|
||||
...
|
||||
ICS20 currently implements basic string matching with a
|
||||
single supported version.
|
||||
```
|
||||
219
x/wasm/README.md
Normal file
219
x/wasm/README.md
Normal file
@ -0,0 +1,219 @@
|
||||
# Wasm Module
|
||||
|
||||
This should be a brief overview of the functionality
|
||||
|
||||
## Configuration
|
||||
|
||||
You can add the following section to `config/app.toml`:
|
||||
|
||||
```toml
|
||||
[wasm]
|
||||
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
|
||||
query_gas_limit = 300000
|
||||
# This defines the memory size for Wasm modules that we can keep cached to speed-up instantiation
|
||||
# The value is in MiB not bytes
|
||||
memory_cache_size = 300
|
||||
```
|
||||
|
||||
The values can also be set via CLI flags on with the `start` command:
|
||||
```shell script
|
||||
--wasm.memory_cache_size uint32 Sets the size in MiB (NOT bytes) of an in-memory cache for wasm modules. Set to 0 to disable. (default 100)
|
||||
--wasm.query_gas_limit uint Set the max gas that can be spent on executing a query with a Wasm contract (default 3000000)
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
A number of events are returned to allow good indexing of the transactions from smart contracts.
|
||||
|
||||
Every call to Instantiate or Execute will be tagged with the info on the contract that was executed and who executed it.
|
||||
It should look something like this (with different addresses). The module is always `wasm`, and `code_id` is only present
|
||||
when Instantiating a contract, so you can subscribe to new instances, it is omitted on Execute. There is also an `action` tag
|
||||
which is auto-added by the Cosmos SDK and has a value of either `store-code`, `instantiate` or `execute` depending on which message
|
||||
was sent:
|
||||
|
||||
```json
|
||||
{
|
||||
"Type": "message",
|
||||
"Attr": [
|
||||
{
|
||||
"key": "module",
|
||||
"value": "wasm"
|
||||
},
|
||||
{
|
||||
"key": "action",
|
||||
"value": "instantiate"
|
||||
},
|
||||
{
|
||||
"key": "signer",
|
||||
"value": "cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"
|
||||
},
|
||||
{
|
||||
"key": "code_id",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"key": "_contract_address",
|
||||
"value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If any funds were transferred to the contract as part of the message, or if the contract released funds as part of it's executions,
|
||||
it will receive the typical events associated with sending tokens from bank. In this case, we instantiate the contract and
|
||||
provide a initial balance in the same `MsgInstantiateContract`. We see the following events in addition to the above one:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"Type": "transfer",
|
||||
"Attr": [
|
||||
{
|
||||
"key": "recipient",
|
||||
"value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
},
|
||||
{
|
||||
"key": "sender",
|
||||
"value": "cosmos1ffnqn02ft2psvyv4dyr56nnv6plllf9pm2kpmv"
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "100000denom"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Finally, the contract itself can emit a "custom event" on Execute only (not on Init).
|
||||
There is one event per contract, so if one contract calls a second contract, you may receive
|
||||
one event for the original contract and one for the re-invoked contract. All attributes from the contract are passed through verbatim,
|
||||
and we add a `_contract_address` attribute that contains the actual contract that emitted that event.
|
||||
Here is an example from the escrow contract successfully releasing funds to the destination address:
|
||||
|
||||
```json
|
||||
{
|
||||
"Type": "wasm",
|
||||
"Attr": [
|
||||
{
|
||||
"key": "_contract_address",
|
||||
"value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
},
|
||||
{
|
||||
"key": "action",
|
||||
"value": "release"
|
||||
},
|
||||
{
|
||||
"key": "destination",
|
||||
"value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Pulling this all together
|
||||
|
||||
We will invoke an escrow contract to release to the designated beneficiary.
|
||||
The escrow was previously loaded with `100000denom` (from the above example).
|
||||
In this transaction, we send `5000denom` along with the `MsgExecuteContract`
|
||||
and the contract releases the entire funds (`105000denom`) to the beneficiary.
|
||||
|
||||
We will see all the following events, where you should be able to reconstruct the actions
|
||||
(remember there are two events for each transfer). We see (1) the initial transfer of funds
|
||||
to the contract, (2) the contract custom event that it released funds (3) the transfer of funds
|
||||
from the contract to the beneficiary and (4) the generic x/wasm event stating that the contract
|
||||
was executed (which always appears, while 2 is optional and has information as reliable as the contract):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"Type": "transfer",
|
||||
"Attr": [
|
||||
{
|
||||
"key": "recipient",
|
||||
"value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
},
|
||||
{
|
||||
"key": "sender",
|
||||
"value": "cosmos1zm074khx32hqy20hlshlsd423n07pwlu9cpt37"
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "5000denom"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "wasm",
|
||||
"Attr": [
|
||||
{
|
||||
"key": "_contract_address",
|
||||
"value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
},
|
||||
{
|
||||
"key": "action",
|
||||
"value": "release"
|
||||
},
|
||||
{
|
||||
"key": "destination",
|
||||
"value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "transfer",
|
||||
"Attr": [
|
||||
{
|
||||
"key": "recipient",
|
||||
"value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq"
|
||||
},
|
||||
{
|
||||
"key": "sender",
|
||||
"value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
},
|
||||
{
|
||||
"key": "amount",
|
||||
"value": "105000denom"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Type": "message",
|
||||
"Attr": [
|
||||
{
|
||||
"key": "module",
|
||||
"value": "wasm"
|
||||
},
|
||||
{
|
||||
"key": "action",
|
||||
"value": "execute"
|
||||
},
|
||||
{
|
||||
"key": "signer",
|
||||
"value": "cosmos1zm074khx32hqy20hlshlsd423n07pwlu9cpt37"
|
||||
},
|
||||
{
|
||||
"key": "_contract_address",
|
||||
"value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
A note on this format. This is what we return from our module. However, it seems to me that many events with the same `Type`
|
||||
get merged together somewhere along the stack, so in this case, you *may* end up with one "transfer" event with the info for
|
||||
both transfers. Double check when evaluating the event logs, I will document better with more experience, especially when I
|
||||
find out the entire path for the events.
|
||||
|
||||
## Messages
|
||||
|
||||
TODO
|
||||
|
||||
## CLI
|
||||
|
||||
TODO - working, but not the nicest interface (json + bash = bleh). Use to upload, but I suggest to focus on frontend / js tooling
|
||||
|
||||
## Rest
|
||||
|
||||
TODO - main supported interface, under rapid change
|
||||
133
x/wasm/alias.go
Normal file
133
x/wasm/alias.go
Normal file
@ -0,0 +1,133 @@
|
||||
// nolint
|
||||
// autogenerated code using github.com/rigelrozanski/multitool
|
||||
// aliases generated for the following subdirectories:
|
||||
// ALIASGEN: github.com/cerc-io/laconicd/x/wasm/types
|
||||
// ALIASGEN: github.com/cerc-io/laconicd/x/wasm/keeper
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
const (
|
||||
firstCodeID = 1
|
||||
ModuleName = types.ModuleName
|
||||
StoreKey = types.StoreKey
|
||||
TStoreKey = types.TStoreKey
|
||||
QuerierRoute = types.QuerierRoute
|
||||
RouterKey = types.RouterKey
|
||||
WasmModuleEventType = types.WasmModuleEventType
|
||||
AttributeKeyContractAddr = types.AttributeKeyContractAddr
|
||||
ProposalTypeStoreCode = types.ProposalTypeStoreCode
|
||||
ProposalTypeInstantiateContract = types.ProposalTypeInstantiateContract
|
||||
ProposalTypeMigrateContract = types.ProposalTypeMigrateContract
|
||||
ProposalTypeUpdateAdmin = types.ProposalTypeUpdateAdmin
|
||||
ProposalTypeClearAdmin = types.ProposalTypeClearAdmin
|
||||
QueryListContractByCode = keeper.QueryListContractByCode
|
||||
QueryGetContract = keeper.QueryGetContract
|
||||
QueryGetContractState = keeper.QueryGetContractState
|
||||
QueryGetCode = keeper.QueryGetCode
|
||||
QueryListCode = keeper.QueryListCode
|
||||
QueryMethodContractStateSmart = keeper.QueryMethodContractStateSmart
|
||||
QueryMethodContractStateAll = keeper.QueryMethodContractStateAll
|
||||
QueryMethodContractStateRaw = keeper.QueryMethodContractStateRaw
|
||||
)
|
||||
|
||||
var (
|
||||
// functions aliases
|
||||
RegisterCodec = types.RegisterLegacyAminoCodec
|
||||
RegisterInterfaces = types.RegisterInterfaces
|
||||
ValidateGenesis = types.ValidateGenesis
|
||||
ConvertToProposals = types.ConvertToProposals
|
||||
GetCodeKey = types.GetCodeKey
|
||||
GetContractAddressKey = types.GetContractAddressKey
|
||||
GetContractStorePrefixKey = types.GetContractStorePrefix
|
||||
NewCodeInfo = types.NewCodeInfo
|
||||
NewAbsoluteTxPosition = types.NewAbsoluteTxPosition
|
||||
NewContractInfo = types.NewContractInfo
|
||||
NewEnv = types.NewEnv
|
||||
NewWasmCoins = types.NewWasmCoins
|
||||
DefaultWasmConfig = types.DefaultWasmConfig
|
||||
DefaultParams = types.DefaultParams
|
||||
InitGenesis = keeper.InitGenesis
|
||||
ExportGenesis = keeper.ExportGenesis
|
||||
NewMessageHandler = keeper.NewDefaultMessageHandler
|
||||
DefaultEncoders = keeper.DefaultEncoders
|
||||
EncodeBankMsg = keeper.EncodeBankMsg
|
||||
NoCustomMsg = keeper.NoCustomMsg
|
||||
EncodeStakingMsg = keeper.EncodeStakingMsg
|
||||
EncodeWasmMsg = keeper.EncodeWasmMsg
|
||||
NewKeeper = keeper.NewKeeper
|
||||
DefaultQueryPlugins = keeper.DefaultQueryPlugins
|
||||
BankQuerier = keeper.BankQuerier
|
||||
NoCustomQuerier = keeper.NoCustomQuerier
|
||||
StakingQuerier = keeper.StakingQuerier
|
||||
WasmQuerier = keeper.WasmQuerier
|
||||
CreateTestInput = keeper.CreateTestInput
|
||||
TestHandler = keeper.TestHandler
|
||||
NewWasmProposalHandler = keeper.NewWasmProposalHandler
|
||||
NewQuerier = keeper.Querier
|
||||
ContractFromPortID = keeper.ContractFromPortID
|
||||
WithWasmEngine = keeper.WithWasmEngine
|
||||
NewCountTXDecorator = keeper.NewCountTXDecorator
|
||||
|
||||
// variable aliases
|
||||
ModuleCdc = types.ModuleCdc
|
||||
DefaultCodespace = types.DefaultCodespace
|
||||
ErrCreateFailed = types.ErrCreateFailed
|
||||
ErrAccountExists = types.ErrAccountExists
|
||||
ErrInstantiateFailed = types.ErrInstantiateFailed
|
||||
ErrExecuteFailed = types.ErrExecuteFailed
|
||||
ErrGasLimit = types.ErrGasLimit
|
||||
ErrInvalidGenesis = types.ErrInvalidGenesis
|
||||
ErrNotFound = types.ErrNotFound
|
||||
ErrQueryFailed = types.ErrQueryFailed
|
||||
ErrInvalidMsg = types.ErrInvalidMsg
|
||||
KeyLastCodeID = types.KeyLastCodeID
|
||||
KeyLastInstanceID = types.KeyLastInstanceID
|
||||
CodeKeyPrefix = types.CodeKeyPrefix
|
||||
ContractKeyPrefix = types.ContractKeyPrefix
|
||||
ContractStorePrefix = types.ContractStorePrefix
|
||||
EnableAllProposals = types.EnableAllProposals
|
||||
DisableAllProposals = types.DisableAllProposals
|
||||
)
|
||||
|
||||
type (
|
||||
ProposalType = types.ProposalType
|
||||
GenesisState = types.GenesisState
|
||||
Code = types.Code
|
||||
Contract = types.Contract
|
||||
MsgStoreCode = types.MsgStoreCode
|
||||
MsgStoreCodeResponse = types.MsgStoreCodeResponse
|
||||
MsgInstantiateContract = types.MsgInstantiateContract
|
||||
MsgInstantiateContract2 = types.MsgInstantiateContract2
|
||||
MsgInstantiateContractResponse = types.MsgInstantiateContractResponse
|
||||
MsgExecuteContract = types.MsgExecuteContract
|
||||
MsgExecuteContractResponse = types.MsgExecuteContractResponse
|
||||
MsgMigrateContract = types.MsgMigrateContract
|
||||
MsgMigrateContractResponse = types.MsgMigrateContractResponse
|
||||
MsgUpdateAdmin = types.MsgUpdateAdmin
|
||||
MsgUpdateAdminResponse = types.MsgUpdateAdminResponse
|
||||
MsgClearAdmin = types.MsgClearAdmin
|
||||
MsgWasmIBCCall = types.MsgIBCSend
|
||||
MsgClearAdminResponse = types.MsgClearAdminResponse
|
||||
MsgServer = types.MsgServer
|
||||
Model = types.Model
|
||||
CodeInfo = types.CodeInfo
|
||||
ContractInfo = types.ContractInfo
|
||||
CreatedAt = types.AbsoluteTxPosition
|
||||
Config = types.WasmConfig
|
||||
CodeInfoResponse = types.CodeInfoResponse
|
||||
MessageHandler = keeper.SDKMessageHandler
|
||||
BankEncoder = keeper.BankEncoder
|
||||
CustomEncoder = keeper.CustomEncoder
|
||||
StakingEncoder = keeper.StakingEncoder
|
||||
WasmEncoder = keeper.WasmEncoder
|
||||
MessageEncoders = keeper.MessageEncoders
|
||||
Keeper = keeper.Keeper
|
||||
QueryHandler = keeper.QueryHandler
|
||||
CustomQuerier = keeper.CustomQuerier
|
||||
QueryPlugins = keeper.QueryPlugins
|
||||
Option = keeper.Option
|
||||
)
|
||||
834
x/wasm/client/cli/gov_tx.go
Normal file
834
x/wasm/client/cli/gov_tx.go
Normal file
@ -0,0 +1,834 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
||||
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func ProposalStoreCodeCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "wasm-store [wasm file] --title [text] --description [text] --run-as [address] --unpin-code [unpin_code] --source [source] --builder [builder] --code-hash [code_hash]",
|
||||
Short: "Submit a wasm binary proposal",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := parseStoreCodeArgs(args[0], clientCtx.FromAddress, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runAs, err := cmd.Flags().GetString(flagRunAs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("run-as: %s", err)
|
||||
}
|
||||
if len(runAs) == 0 {
|
||||
return errors.New("run-as address is required")
|
||||
}
|
||||
|
||||
unpinCode, err := cmd.Flags().GetBool(flagUnpinCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, builder, codeHash, err := parseVerificationFlags(src.WASMByteCode, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content := types.StoreCodeProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
RunAs: runAs,
|
||||
WASMByteCode: src.WASMByteCode,
|
||||
InstantiatePermission: src.InstantiatePermission,
|
||||
UnpinCode: unpinCode,
|
||||
Source: source,
|
||||
Builder: builder,
|
||||
CodeHash: codeHash,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagRunAs, "", "The address that is stored as code creator")
|
||||
cmd.Flags().Bool(flagUnpinCode, false, "Unpin code on upload, optional")
|
||||
cmd.Flags().String(flagSource, "", "Code Source URL is a valid absolute HTTPS URI to the contract's source code,")
|
||||
cmd.Flags().String(flagBuilder, "", "Builder is a valid docker image name with tag, such as \"cosmwasm/workspace-optimizer:0.12.9\"")
|
||||
cmd.Flags().BytesHex(flagCodeHash, nil, "CodeHash is the sha256 hash of the wasm code")
|
||||
addInstantiatePermissionFlags(cmd)
|
||||
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseVerificationFlags(wasm []byte, flags *flag.FlagSet) (string, string, []byte, error) {
|
||||
source, err := flags.GetString(flagSource)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("source: %s", err)
|
||||
}
|
||||
builder, err := flags.GetString(flagBuilder)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("builder: %s", err)
|
||||
}
|
||||
codeHash, err := flags.GetBytesHex(flagCodeHash)
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("codeHash: %s", err)
|
||||
}
|
||||
|
||||
// if any set require others to be set
|
||||
if len(source) != 0 || len(builder) != 0 || len(codeHash) != 0 {
|
||||
if source == "" {
|
||||
return "", "", nil, fmt.Errorf("source is required")
|
||||
}
|
||||
if _, err = url.ParseRequestURI(source); err != nil {
|
||||
return "", "", nil, fmt.Errorf("source: %s", err)
|
||||
}
|
||||
if builder == "" {
|
||||
return "", "", nil, fmt.Errorf("builder is required")
|
||||
}
|
||||
if _, err := reference.ParseDockerRef(builder); err != nil {
|
||||
return "", "", nil, fmt.Errorf("builder: %s", err)
|
||||
}
|
||||
if len(codeHash) == 0 {
|
||||
return "", "", nil, fmt.Errorf("code hash is required")
|
||||
}
|
||||
// wasm is unzipped in parseStoreCodeArgs
|
||||
// checksum generation will be decoupled here
|
||||
// reference https://github.com/CosmWasm/wasmvm/issues/359
|
||||
checksum := sha256.Sum256(wasm)
|
||||
if !bytes.Equal(checksum[:], codeHash) {
|
||||
return "", "", nil, fmt.Errorf("code-hash mismatch: %X, checksum: %X", codeHash, checksum)
|
||||
}
|
||||
}
|
||||
return source, builder, codeHash, nil
|
||||
}
|
||||
|
||||
func ProposalInstantiateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "instantiate-contract [code_id_int64] [json_encoded_init_args] --label [text] --title [text] --description [text] --run-as [address] --admin [address,optional] --amount [coins,optional]",
|
||||
Short: "Submit an instantiate wasm contract proposal",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.FromAddress, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runAs, err := cmd.Flags().GetString(flagRunAs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("run-as: %s", err)
|
||||
}
|
||||
if len(runAs) == 0 {
|
||||
return errors.New("run-as address is required")
|
||||
}
|
||||
|
||||
content := types.InstantiateContractProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
RunAs: runAs,
|
||||
Admin: src.Admin,
|
||||
CodeID: src.CodeID,
|
||||
Label: src.Label,
|
||||
Msg: src.Msg,
|
||||
Funds: src.Funds,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
|
||||
cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
|
||||
cmd.Flags().String(flagAdmin, "", "Address or key name of an admin")
|
||||
cmd.Flags().String(flagRunAs, "", "The address that pays the init funds. It is the creator of the contract and passed to the contract as sender on proposal execution")
|
||||
cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalInstantiateContract2Cmd() *cobra.Command {
|
||||
decoder := newArgDecoder(hex.DecodeString)
|
||||
cmd := &cobra.Command{
|
||||
Use: "instantiate-contract-2 [code_id_int64] [json_encoded_init_args] [salt] --label [text] --title [text] --description [text] --run-as [address] --admin [address,optional] --amount [coins,optional] --fix-msg [bool,optional]",
|
||||
Short: "Submit an instantiate wasm contract proposal with predictable address",
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.FromAddress, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runAs, err := cmd.Flags().GetString(flagRunAs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("run-as: %s", err)
|
||||
}
|
||||
if len(runAs) == 0 {
|
||||
return errors.New("run-as address is required")
|
||||
}
|
||||
|
||||
salt, err := decoder.DecodeString(args[2])
|
||||
if err != nil {
|
||||
return fmt.Errorf("salt: %w", err)
|
||||
}
|
||||
|
||||
fixMsg, err := cmd.Flags().GetBool(flagFixMsg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fix msg: %w", err)
|
||||
}
|
||||
|
||||
content := types.NewInstantiateContract2Proposal(proposalTitle, proposalDescr, runAs, src.Admin, src.CodeID, src.Label, src.Msg, src.Funds, salt, fixMsg)
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
|
||||
cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
|
||||
cmd.Flags().String(flagAdmin, "", "Address of an admin")
|
||||
cmd.Flags().String(flagRunAs, "", "The address that pays the init funds. It is the creator of the contract and passed to the contract as sender on proposal execution")
|
||||
cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
cmd.Flags().Bool(flagFixMsg, false, "An optional flag to include the json_encoded_init_args for the predictable address generation mode")
|
||||
decoder.RegisterFlags(cmd.PersistentFlags(), "salt")
|
||||
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalStoreAndInstantiateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "store-instantiate [wasm file] [json_encoded_init_args] --label [text] --title [text] --description [text] --run-as [address]" +
|
||||
"--unpin-code [unpin_code,optional] --source [source,optional] --builder [builder,optional] --code-hash [code_hash,optional] --admin [address,optional] --amount [coins,optional]",
|
||||
Short: "Submit and instantiate a wasm contract proposal",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := parseStoreCodeArgs(args[0], clientCtx.FromAddress, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runAs, err := cmd.Flags().GetString(flagRunAs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("run-as: %s", err)
|
||||
}
|
||||
if len(runAs) == 0 {
|
||||
return errors.New("run-as address is required")
|
||||
}
|
||||
|
||||
unpinCode, err := cmd.Flags().GetBool(flagUnpinCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, builder, codeHash, err := parseVerificationFlags(src.WASMByteCode, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
amountStr, err := cmd.Flags().GetString(flagAmount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
amount, err := sdk.ParseCoinsNormalized(amountStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
label, err := cmd.Flags().GetString(flagLabel)
|
||||
if err != nil {
|
||||
return fmt.Errorf("label: %s", err)
|
||||
}
|
||||
if label == "" {
|
||||
return errors.New("label is required on all contracts")
|
||||
}
|
||||
adminStr, err := cmd.Flags().GetString(flagAdmin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin: %s", err)
|
||||
}
|
||||
noAdmin, err := cmd.Flags().GetBool(flagNoAdmin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("no-admin: %s", err)
|
||||
}
|
||||
|
||||
// ensure sensible admin is set (or explicitly immutable)
|
||||
if adminStr == "" && !noAdmin {
|
||||
return fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)")
|
||||
}
|
||||
if adminStr != "" && noAdmin {
|
||||
return fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true")
|
||||
}
|
||||
|
||||
if adminStr != "" {
|
||||
addr, err := sdk.AccAddressFromBech32(adminStr)
|
||||
if err != nil {
|
||||
info, err := clientCtx.Keyring.Key(adminStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin %s", err)
|
||||
}
|
||||
adminStr = info.GetAddress().String()
|
||||
} else {
|
||||
adminStr = addr.String()
|
||||
}
|
||||
}
|
||||
|
||||
content := types.StoreAndInstantiateContractProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
RunAs: runAs,
|
||||
WASMByteCode: src.WASMByteCode,
|
||||
InstantiatePermission: src.InstantiatePermission,
|
||||
UnpinCode: unpinCode,
|
||||
Source: source,
|
||||
Builder: builder,
|
||||
CodeHash: codeHash,
|
||||
Admin: adminStr,
|
||||
Label: label,
|
||||
Msg: []byte(args[1]),
|
||||
Funds: amount,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagRunAs, "", "The address that is stored as code creator. It is the creator of the contract and passed to the contract as sender on proposal execution")
|
||||
cmd.Flags().Bool(flagUnpinCode, false, "Unpin code on upload, optional")
|
||||
cmd.Flags().String(flagSource, "", "Code Source URL is a valid absolute HTTPS URI to the contract's source code,")
|
||||
cmd.Flags().String(flagBuilder, "", "Builder is a valid docker image name with tag, such as \"cosmwasm/workspace-optimizer:0.12.9\"")
|
||||
cmd.Flags().BytesHex(flagCodeHash, nil, "CodeHash is the sha256 hash of the wasm code")
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
|
||||
cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
|
||||
cmd.Flags().String(flagAdmin, "", "Address or key name of an admin")
|
||||
cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
addInstantiatePermissionFlags(cmd)
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalMigrateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "migrate-contract [contract_addr_bech32] [new_code_id_int64] [json_encoded_migration_args]",
|
||||
Short: "Submit a migrate wasm contract to a new code version proposal",
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := parseMigrateContractArgs(args, clientCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := types.MigrateContractProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
Contract: src.Contract,
|
||||
CodeID: src.CodeID,
|
||||
Msg: src.Msg,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalExecuteContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "execute-contract [contract_addr_bech32] [json_encoded_migration_args]",
|
||||
Short: "Submit a execute wasm contract proposal (run by any address)",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contract := args[0]
|
||||
execMsg := []byte(args[1])
|
||||
amountStr, err := cmd.Flags().GetString(flagAmount)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
funds, err := sdk.ParseCoinsNormalized(amountStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
runAs, err := cmd.Flags().GetString(flagRunAs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("run-as: %s", err)
|
||||
}
|
||||
|
||||
if len(runAs) == 0 {
|
||||
return errors.New("run-as address is required")
|
||||
}
|
||||
|
||||
content := types.ExecuteContractProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
Contract: contract,
|
||||
Msg: execMsg,
|
||||
RunAs: runAs,
|
||||
Funds: funds,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
cmd.Flags().String(flagRunAs, "", "The address that is passed as sender to the contract on proposal execution")
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
|
||||
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalSudoContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "sudo-contract [contract_addr_bech32] [json_encoded_migration_args]",
|
||||
Short: "Submit a sudo wasm contract proposal (to call privileged commands)",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contract := args[0]
|
||||
sudoMsg := []byte(args[1])
|
||||
|
||||
content := types.SudoContractProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
Contract: contract,
|
||||
Msg: sudoMsg,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
// proposal flagsExecute
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalUpdateContractAdminCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set-contract-admin [contract_addr_bech32] [new_admin_addr_bech32]",
|
||||
Short: "Submit a new admin for a contract proposal",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := parseUpdateContractAdminArgs(args, clientCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := types.UpdateAdminProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
Contract: src.Contract,
|
||||
NewAdmin: src.NewAdmin,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalClearContractAdminCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "clear-contract-admin [contract_addr_bech32]",
|
||||
Short: "Submit a clear admin for a contract to prevent further migrations proposal",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := types.ClearAdminProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
Contract: args[0],
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ProposalPinCodesCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "pin-codes [code-ids]",
|
||||
Short: "Submit a pin code proposal for pinning a code to cache",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
codeIds, err := parsePinCodesArgs(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := types.PinCodesProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
CodeIDs: codeIds,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parsePinCodesArgs(args []string) ([]uint64, error) {
|
||||
codeIDs := make([]uint64, len(args))
|
||||
for i, c := range args {
|
||||
codeID, err := strconv.ParseUint(c, 10, 64)
|
||||
if err != nil {
|
||||
return codeIDs, fmt.Errorf("code IDs: %s", err)
|
||||
}
|
||||
codeIDs[i] = codeID
|
||||
}
|
||||
return codeIDs, nil
|
||||
}
|
||||
|
||||
func ProposalUnpinCodesCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "unpin-codes [code-ids]",
|
||||
Short: "Submit a unpin code proposal for unpinning a code to cache",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
codeIds, err := parsePinCodesArgs(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := types.UnpinCodesProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
CodeIDs: codeIds,
|
||||
}
|
||||
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseAccessConfig(raw string) (c types.AccessConfig, err error) {
|
||||
switch raw {
|
||||
case "nobody":
|
||||
return types.AllowNobody, nil
|
||||
case "everybody":
|
||||
return types.AllowEverybody, nil
|
||||
default:
|
||||
parts := strings.Split(raw, ",")
|
||||
addrs := make([]sdk.AccAddress, len(parts))
|
||||
for i, v := range parts {
|
||||
addr, err := sdk.AccAddressFromBech32(v)
|
||||
if err != nil {
|
||||
return types.AccessConfig{}, fmt.Errorf("unable to parse address %q: %s", v, err)
|
||||
}
|
||||
addrs[i] = addr
|
||||
}
|
||||
defer func() { // convert panic in ".With" to error for better output
|
||||
if r := recover(); r != nil {
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
cfg := types.AccessTypeAnyOfAddresses.With(addrs...)
|
||||
return cfg, cfg.ValidateBasic()
|
||||
}
|
||||
}
|
||||
|
||||
func parseAccessConfigUpdates(args []string) ([]types.AccessConfigUpdate, error) {
|
||||
updates := make([]types.AccessConfigUpdate, len(args))
|
||||
for i, c := range args {
|
||||
// format: code_id:access_config
|
||||
// access_config: nobody|everybody|address(es)
|
||||
parts := strings.Split(c, ":")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid format")
|
||||
}
|
||||
|
||||
codeID, err := strconv.ParseUint(parts[0], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid code ID: %s", err)
|
||||
}
|
||||
|
||||
accessConfig, err := parseAccessConfig(parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updates[i] = types.AccessConfigUpdate{
|
||||
CodeID: codeID,
|
||||
InstantiatePermission: accessConfig,
|
||||
}
|
||||
}
|
||||
return updates, nil
|
||||
}
|
||||
|
||||
func ProposalUpdateInstantiateConfigCmd() *cobra.Command {
|
||||
bech32Prefix := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
||||
cmd := &cobra.Command{
|
||||
Use: "update-instantiate-config [code-id:permission]...",
|
||||
Short: "Submit an update instantiate config proposal.",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Long: strings.TrimSpace(
|
||||
fmt.Sprintf(`Submit an update instantiate config proposal for multiple code ids.
|
||||
|
||||
Example:
|
||||
$ %s tx gov submit-proposal update-instantiate-config 1:nobody 2:everybody 3:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm,%s1vx8knpllrj7n963p9ttd80w47kpacrhuts497x
|
||||
`, version.AppName, bech32Prefix, bech32Prefix)),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updates, err := parseAccessConfigUpdates(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := types.UpdateInstantiateConfigProposal{
|
||||
Title: proposalTitle,
|
||||
Description: proposalDescr,
|
||||
AccessConfigUpdates: updates,
|
||||
}
|
||||
msg, err := govv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
// proposal flags
|
||||
cmd.Flags().String(cli.FlagTitle, "", "Title of proposal")
|
||||
cmd.Flags().String(cli.FlagDescription, "", "Description of proposal")
|
||||
cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getProposalInfo(cmd *cobra.Command) (client.Context, string, string, sdk.Coins, error) {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return client.Context{}, "", "", nil, err
|
||||
}
|
||||
|
||||
proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle)
|
||||
if err != nil {
|
||||
return clientCtx, proposalTitle, "", nil, err
|
||||
}
|
||||
|
||||
proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription)
|
||||
if err != nil {
|
||||
return client.Context{}, proposalTitle, proposalDescr, nil, err
|
||||
}
|
||||
|
||||
depositArg, err := cmd.Flags().GetString(cli.FlagDeposit)
|
||||
if err != nil {
|
||||
return client.Context{}, proposalTitle, proposalDescr, nil, err
|
||||
}
|
||||
|
||||
deposit, err := sdk.ParseCoinsNormalized(depositArg)
|
||||
if err != nil {
|
||||
return client.Context{}, proposalTitle, proposalDescr, deposit, err
|
||||
}
|
||||
|
||||
return clientCtx, proposalTitle, proposalDescr, deposit, nil
|
||||
}
|
||||
158
x/wasm/client/cli/gov_tx_test.go
Normal file
158
x/wasm/client/cli/gov_tx_test.go
Normal file
@ -0,0 +1,158 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestParseAccessConfigUpdates(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src []string
|
||||
exp []types.AccessConfigUpdate
|
||||
expErr bool
|
||||
}{
|
||||
"nobody": {
|
||||
src: []string{"1:nobody"},
|
||||
exp: []types.AccessConfigUpdate{{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeNobody},
|
||||
}},
|
||||
},
|
||||
"everybody": {
|
||||
src: []string{"1:everybody"},
|
||||
exp: []types.AccessConfigUpdate{{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeEverybody},
|
||||
}},
|
||||
},
|
||||
"any of addresses - single": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
|
||||
exp: []types.AccessConfigUpdate{
|
||||
{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeAnyOfAddresses,
|
||||
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"any of addresses - multiple": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
|
||||
exp: []types.AccessConfigUpdate{
|
||||
{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeAnyOfAddresses,
|
||||
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"multiple code ids with different permissions": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", "2:nobody"},
|
||||
exp: []types.AccessConfigUpdate{
|
||||
{
|
||||
CodeID: 1,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeAnyOfAddresses,
|
||||
Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
|
||||
},
|
||||
}, {
|
||||
CodeID: 2,
|
||||
InstantiatePermission: types.AccessConfig{
|
||||
Permission: types.AccessTypeNobody,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"any of addresses - empty list": {
|
||||
src: []string{"1:"},
|
||||
expErr: true,
|
||||
},
|
||||
"any of addresses - invalid address": {
|
||||
src: []string{"1:foo"},
|
||||
expErr: true,
|
||||
},
|
||||
"any of addresses - duplicate address": {
|
||||
src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
|
||||
expErr: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotErr := parseAccessConfigUpdates(spec.src)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCodeInfoFlags(t *testing.T) {
|
||||
correctSource := "https://github.com/CosmWasm/wasmd/blob/main/x/wasm/keeper/testdata/hackatom.wasm"
|
||||
correctBuilderRef := "cosmwasm/workspace-optimizer:0.12.9"
|
||||
|
||||
wasmBin, err := os.ReadFile("../../keeper/testdata/hackatom.wasm")
|
||||
require.NoError(t, err)
|
||||
|
||||
checksumStr := "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b"
|
||||
|
||||
specs := map[string]struct {
|
||||
args []string
|
||||
expErr bool
|
||||
}{
|
||||
"source missing": {
|
||||
args: []string{"--builder=" + correctBuilderRef, "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"builder missing": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"code hash missing": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef},
|
||||
expErr: true,
|
||||
},
|
||||
"source format wrong": {
|
||||
args: []string{"--code-source-url=" + "format_wrong", "--builder=" + correctBuilderRef, "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"builder format wrong": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + "format//", "--code-hash=" + checksumStr},
|
||||
expErr: true,
|
||||
},
|
||||
"code hash wrong": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef, "--code-hash=" + "AA"},
|
||||
expErr: true,
|
||||
},
|
||||
"happy path, none set": {
|
||||
args: []string{},
|
||||
expErr: false,
|
||||
},
|
||||
"happy path all set": {
|
||||
args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef, "--code-hash=" + checksumStr},
|
||||
expErr: false,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
flags := ProposalStoreCodeCmd().Flags()
|
||||
require.NoError(t, flags.Parse(spec.args))
|
||||
_, _, _, gotErr := parseVerificationFlags(wasmBin, flags)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
163
x/wasm/client/cli/new_tx.go
Normal file
163
x/wasm/client/cli/new_tx.go
Normal file
@ -0,0 +1,163 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// MigrateContractCmd will migrate a contract to a new code version
|
||||
func MigrateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "migrate [contract_addr_bech32] [new_code_id_int64] [json_encoded_migration_args]",
|
||||
Short: "Migrate a wasm contract to a new code version",
|
||||
Aliases: []string{"update", "mig", "m"},
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := parseMigrateContractArgs(args, clientCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return nil
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseMigrateContractArgs(args []string, cliCtx client.Context) (types.MsgMigrateContract, error) {
|
||||
// get the id of the code to instantiate
|
||||
codeID, err := strconv.ParseUint(args[1], 10, 64)
|
||||
if err != nil {
|
||||
return types.MsgMigrateContract{}, sdkerrors.Wrap(err, "code id")
|
||||
}
|
||||
|
||||
migrateMsg := args[2]
|
||||
|
||||
msg := types.MsgMigrateContract{
|
||||
Sender: cliCtx.GetFromAddress().String(),
|
||||
Contract: args[0],
|
||||
CodeID: codeID,
|
||||
Msg: []byte(migrateMsg),
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// UpdateContractAdminCmd sets an new admin for a contract
|
||||
func UpdateContractAdminCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set-contract-admin [contract_addr_bech32] [new_admin_addr_bech32]",
|
||||
Short: "Set new admin for a contract",
|
||||
Aliases: []string{"new-admin", "admin", "set-adm", "sa"},
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := parseUpdateContractAdminArgs(args, clientCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseUpdateContractAdminArgs(args []string, cliCtx client.Context) (types.MsgUpdateAdmin, error) {
|
||||
msg := types.MsgUpdateAdmin{
|
||||
Sender: cliCtx.GetFromAddress().String(),
|
||||
Contract: args[0],
|
||||
NewAdmin: args[1],
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// ClearContractAdminCmd clears an admin for a contract
|
||||
func ClearContractAdminCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "clear-contract-admin [contract_addr_bech32]",
|
||||
Short: "Clears admin for a contract to prevent further migrations",
|
||||
Aliases: []string{"clear-admin", "clr-adm"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.MsgClearAdmin{
|
||||
Sender: clientCtx.GetFromAddress().String(),
|
||||
Contract: args[0],
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// UpdateInstantiateConfigCmd updates instantiate config for a smart contract.
|
||||
func UpdateInstantiateConfigCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "update-instantiate-config [code_id_int64]",
|
||||
Short: "Update instantiate config for a codeID",
|
||||
Aliases: []string{"update-instantiate-config"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
codeID, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
perm, err := parseAccessConfigFlags(cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.MsgUpdateInstantiateConfig{
|
||||
Sender: string(clientCtx.GetFromAddress()),
|
||||
CodeID: codeID,
|
||||
NewInstantiatePermission: perm,
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
addInstantiatePermissionFlags(cmd)
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
674
x/wasm/client/cli/query.go
Normal file
674
x/wasm/client/cli/query.go
Normal file
@ -0,0 +1,674 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
wasmvm "github.com/CosmWasm/wasmvm"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func GetQueryCmd() *cobra.Command {
|
||||
queryCmd := &cobra.Command{
|
||||
Use: types.ModuleName,
|
||||
Short: "Querying commands for the wasm module",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
SilenceUsage: true,
|
||||
}
|
||||
queryCmd.AddCommand(
|
||||
GetCmdListCode(),
|
||||
GetCmdListContractByCode(),
|
||||
GetCmdQueryCode(),
|
||||
GetCmdQueryCodeInfo(),
|
||||
GetCmdGetContractInfo(),
|
||||
GetCmdGetContractHistory(),
|
||||
GetCmdGetContractState(),
|
||||
GetCmdListPinnedCode(),
|
||||
GetCmdLibVersion(),
|
||||
GetCmdQueryParams(),
|
||||
GetCmdBuildAddress(),
|
||||
GetCmdListContractsByCreator(),
|
||||
)
|
||||
return queryCmd
|
||||
}
|
||||
|
||||
// GetCmdLibVersion gets current libwasmvm version.
|
||||
func GetCmdLibVersion() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "libwasmvm-version",
|
||||
Short: "Get libwasmvm version",
|
||||
Long: "Get libwasmvm version",
|
||||
Aliases: []string{"lib-version"},
|
||||
Args: cobra.ExactArgs(0),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
version, err := wasmvm.LibwasmvmVersion()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving libwasmvm version: %w", err)
|
||||
}
|
||||
fmt.Println(version)
|
||||
return nil
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdBuildAddress build a contract address
|
||||
func GetCmdBuildAddress() *cobra.Command {
|
||||
decoder := newArgDecoder(hex.DecodeString)
|
||||
cmd := &cobra.Command{
|
||||
Use: "build-address [code-hash] [creator-address] [salt-hex-encoded] [json_encoded_init_args (required when set as fixed)]",
|
||||
Short: "build contract address",
|
||||
Aliases: []string{"address"},
|
||||
Args: cobra.RangeArgs(3, 4),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
codeHash, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("code-hash: %s", err)
|
||||
}
|
||||
creator, err := sdk.AccAddressFromBech32(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("creator: %s", err)
|
||||
}
|
||||
salt, err := hex.DecodeString(args[2])
|
||||
switch {
|
||||
case err != nil:
|
||||
return fmt.Errorf("salt: %s", err)
|
||||
case len(salt) == 0:
|
||||
return errors.New("empty salt")
|
||||
}
|
||||
|
||||
if len(args) == 3 {
|
||||
cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, []byte{}).String())
|
||||
return nil
|
||||
}
|
||||
msg := types.RawContractMessage(args[3])
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("init message: %s", err)
|
||||
}
|
||||
cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, msg).String())
|
||||
return nil
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
decoder.RegisterFlags(cmd.PersistentFlags(), "salt")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdListCode lists all wasm code uploaded
|
||||
func GetCmdListCode() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list-code",
|
||||
Short: "List all wasm bytecode on the chain",
|
||||
Long: "List all wasm bytecode on the chain",
|
||||
Aliases: []string{"list-codes", "codes", "lco"},
|
||||
Args: cobra.ExactArgs(0),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.Codes(
|
||||
context.Background(),
|
||||
&types.QueryCodesRequest{
|
||||
Pagination: pageReq,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
flags.AddPaginationFlagsToCmd(cmd, "list codes")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdListContractByCode lists all wasm code uploaded for given code id
|
||||
func GetCmdListContractByCode() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list-contract-by-code [code_id]",
|
||||
Short: "List wasm all bytecode on the chain for given code id",
|
||||
Long: "List wasm all bytecode on the chain for given code id",
|
||||
Aliases: []string{"list-contracts-by-code", "list-contracts", "contracts", "lca"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
codeID, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if codeID == 0 {
|
||||
return errors.New("empty code id")
|
||||
}
|
||||
|
||||
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.ContractsByCode(
|
||||
context.Background(),
|
||||
&types.QueryContractsByCodeRequest{
|
||||
CodeId: codeID,
|
||||
Pagination: pageReq,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
flags.AddPaginationFlagsToCmd(cmd, "list contracts by code")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdQueryCode returns the bytecode for a given contract
|
||||
func GetCmdQueryCode() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "code [code_id] [output filename]",
|
||||
Short: "Downloads wasm bytecode for given code id",
|
||||
Long: "Downloads wasm bytecode for given code id",
|
||||
Aliases: []string{"source-code", "source"},
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
codeID, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.Code(
|
||||
context.Background(),
|
||||
&types.QueryCodeRequest{
|
||||
CodeId: codeID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(res.Data) == 0 {
|
||||
return fmt.Errorf("contract not found")
|
||||
}
|
||||
|
||||
fmt.Printf("Downloading wasm code to %s\n", args[1])
|
||||
return os.WriteFile(args[1], res.Data, 0o600)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdQueryCodeInfo returns the code info for a given code id
|
||||
func GetCmdQueryCodeInfo() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "code-info [code_id]",
|
||||
Short: "Prints out metadata of a code id",
|
||||
Long: "Prints out metadata of a code id",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
codeID, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.Code(
|
||||
context.Background(),
|
||||
&types.QueryCodeRequest{
|
||||
CodeId: codeID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.CodeInfoResponse == nil {
|
||||
return fmt.Errorf("contract not found")
|
||||
}
|
||||
|
||||
return clientCtx.PrintProto(res.CodeInfoResponse)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdGetContractInfo gets details about a given contract
|
||||
func GetCmdGetContractInfo() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "contract [bech32_address]",
|
||||
Short: "Prints out metadata of a contract given its address",
|
||||
Long: "Prints out metadata of a contract given its address",
|
||||
Aliases: []string{"meta", "c"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.ContractInfo(
|
||||
context.Background(),
|
||||
&types.QueryContractInfoRequest{
|
||||
Address: args[0],
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdGetContractState dumps full internal state of a given contract
|
||||
func GetCmdGetContractState() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "contract-state",
|
||||
Short: "Querying commands for the wasm module",
|
||||
Aliases: []string{"state", "cs", "s"},
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
SilenceUsage: true,
|
||||
}
|
||||
cmd.AddCommand(
|
||||
GetCmdGetContractStateAll(),
|
||||
GetCmdGetContractStateRaw(),
|
||||
GetCmdGetContractStateSmart(),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func GetCmdGetContractStateAll() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "all [bech32_address]",
|
||||
Short: "Prints out all internal state of a contract given its address",
|
||||
Long: "Prints out all internal state of a contract given its address",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.AllContractState(
|
||||
context.Background(),
|
||||
&types.QueryAllContractStateRequest{
|
||||
Address: args[0],
|
||||
Pagination: pageReq,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
flags.AddPaginationFlagsToCmd(cmd, "contract state")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func GetCmdGetContractStateRaw() *cobra.Command {
|
||||
decoder := newArgDecoder(hex.DecodeString)
|
||||
cmd := &cobra.Command{
|
||||
Use: "raw [bech32_address] [key]",
|
||||
Short: "Prints out internal state for key of a contract given its address",
|
||||
Long: "Prints out internal state for of a contract given its address",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryData, err := decoder.DecodeString(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.RawContractState(
|
||||
context.Background(),
|
||||
&types.QueryRawContractStateRequest{
|
||||
Address: args[0],
|
||||
QueryData: queryData,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
decoder.RegisterFlags(cmd.PersistentFlags(), "key argument")
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func GetCmdGetContractStateSmart() *cobra.Command {
|
||||
decoder := newArgDecoder(asciiDecodeString)
|
||||
cmd := &cobra.Command{
|
||||
Use: "smart [bech32_address] [query]",
|
||||
Short: "Calls contract with given address with query data and prints the returned result",
|
||||
Long: "Calls contract with given address with query data and prints the returned result",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if args[1] == "" {
|
||||
return errors.New("query data must not be empty")
|
||||
}
|
||||
|
||||
queryData, err := decoder.DecodeString(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode query: %s", err)
|
||||
}
|
||||
if !json.Valid(queryData) {
|
||||
return errors.New("query data must be json")
|
||||
}
|
||||
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.SmartContractState(
|
||||
context.Background(),
|
||||
&types.QuerySmartContractStateRequest{
|
||||
Address: args[0],
|
||||
QueryData: queryData,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
decoder.RegisterFlags(cmd.PersistentFlags(), "query argument")
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdGetContractHistory prints the code history for a given contract
|
||||
func GetCmdGetContractHistory() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "contract-history [bech32_address]",
|
||||
Short: "Prints out the code history for a contract given its address",
|
||||
Long: "Prints out the code history for a contract given its address",
|
||||
Aliases: []string{"history", "hist", "ch"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.ContractHistory(
|
||||
context.Background(),
|
||||
&types.QueryContractHistoryRequest{
|
||||
Address: args[0],
|
||||
Pagination: pageReq,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
flags.AddPaginationFlagsToCmd(cmd, "contract history")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdListPinnedCode lists all wasm code ids that are pinned
|
||||
func GetCmdListPinnedCode() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "pinned",
|
||||
Short: "List all pinned code ids",
|
||||
Long: "List all pinned code ids",
|
||||
Args: cobra.ExactArgs(0),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.PinnedCodes(
|
||||
context.Background(),
|
||||
&types.QueryPinnedCodesRequest{
|
||||
Pagination: pageReq,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
flags.AddPaginationFlagsToCmd(cmd, "list codes")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdListContractsByCreator lists all contracts by creator
|
||||
func GetCmdListContractsByCreator() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list-contracts-by-creator [creator]",
|
||||
Short: "List all contracts by creator",
|
||||
Long: "List all contracts by creator",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
res, err := queryClient.ContractsByCreator(
|
||||
context.Background(),
|
||||
&types.QueryContractsByCreatorRequest{
|
||||
CreatorAddress: args[0],
|
||||
Pagination: pageReq,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientCtx.PrintProto(res)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type argumentDecoder struct {
|
||||
// dec is the default decoder
|
||||
dec func(string) ([]byte, error)
|
||||
asciiF, hexF, b64F bool
|
||||
}
|
||||
|
||||
func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder {
|
||||
return &argumentDecoder{dec: def}
|
||||
}
|
||||
|
||||
func (a *argumentDecoder) RegisterFlags(f *flag.FlagSet, argName string) {
|
||||
f.BoolVar(&a.asciiF, "ascii", false, "ascii encoded "+argName)
|
||||
f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName)
|
||||
f.BoolVar(&a.b64F, "b64", false, "base64 encoded "+argName)
|
||||
}
|
||||
|
||||
func (a *argumentDecoder) DecodeString(s string) ([]byte, error) {
|
||||
found := -1
|
||||
for i, v := range []*bool{&a.asciiF, &a.hexF, &a.b64F} {
|
||||
if !*v {
|
||||
continue
|
||||
}
|
||||
if found != -1 {
|
||||
return nil, errors.New("multiple decoding flags used")
|
||||
}
|
||||
found = i
|
||||
}
|
||||
switch found {
|
||||
case 0:
|
||||
return asciiDecodeString(s)
|
||||
case 1:
|
||||
return hex.DecodeString(s)
|
||||
case 2:
|
||||
return base64.StdEncoding.DecodeString(s)
|
||||
default:
|
||||
return a.dec(s)
|
||||
}
|
||||
}
|
||||
|
||||
func asciiDecodeString(s string) ([]byte, error) {
|
||||
return []byte(s), nil
|
||||
}
|
||||
|
||||
// sdk ReadPageRequest expects binary but we encoded to base64 in our marshaller
|
||||
func withPageKeyDecoded(flagSet *flag.FlagSet) *flag.FlagSet {
|
||||
encoded, err := flagSet.GetString(flags.FlagPageKey)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
raw, err := base64.StdEncoding.DecodeString(encoded)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
err = flagSet.Set(flags.FlagPageKey, string(raw))
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return flagSet
|
||||
}
|
||||
|
||||
// GetCmdQueryParams implements a command to return the current wasm
|
||||
// parameters.
|
||||
func GetCmdQueryParams() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "params",
|
||||
Short: "Query the current wasm parameters",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
queryClient := types.NewQueryClient(clientCtx)
|
||||
|
||||
params := &types.QueryParamsRequest{}
|
||||
res, err := queryClient.Params(cmd.Context(), params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return clientCtx.PrintProto(&res.Params)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
544
x/wasm/client/cli/tx.go
Normal file
544
x/wasm/client/cli/tx.go
Normal file
@ -0,0 +1,544 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/ioutils"
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
const (
|
||||
flagAmount = "amount"
|
||||
flagLabel = "label"
|
||||
flagSource = "code-source-url"
|
||||
flagBuilder = "builder"
|
||||
flagCodeHash = "code-hash"
|
||||
flagAdmin = "admin"
|
||||
flagNoAdmin = "no-admin"
|
||||
flagFixMsg = "fix-msg"
|
||||
flagRunAs = "run-as"
|
||||
flagInstantiateByEverybody = "instantiate-everybody"
|
||||
flagInstantiateNobody = "instantiate-nobody"
|
||||
flagInstantiateByAddress = "instantiate-only-address"
|
||||
flagInstantiateByAnyOfAddress = "instantiate-anyof-addresses"
|
||||
flagUnpinCode = "unpin-code"
|
||||
flagAllowedMsgKeys = "allow-msg-keys"
|
||||
flagAllowedRawMsgs = "allow-raw-msgs"
|
||||
flagExpiration = "expiration"
|
||||
flagMaxCalls = "max-calls"
|
||||
flagMaxFunds = "max-funds"
|
||||
flagAllowAllMsgs = "allow-all-messages"
|
||||
flagNoTokenTransfer = "no-token-transfer" //nolint:gosec
|
||||
)
|
||||
|
||||
// GetTxCmd returns the transaction commands for this module
|
||||
func GetTxCmd() *cobra.Command {
|
||||
txCmd := &cobra.Command{
|
||||
Use: types.ModuleName,
|
||||
Short: "Wasm transaction subcommands",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
SilenceUsage: true,
|
||||
}
|
||||
txCmd.AddCommand(
|
||||
StoreCodeCmd(),
|
||||
InstantiateContractCmd(),
|
||||
InstantiateContract2Cmd(),
|
||||
ExecuteContractCmd(),
|
||||
MigrateContractCmd(),
|
||||
UpdateContractAdminCmd(),
|
||||
ClearContractAdminCmd(),
|
||||
GrantAuthorizationCmd(),
|
||||
UpdateInstantiateConfigCmd(),
|
||||
)
|
||||
return txCmd
|
||||
}
|
||||
|
||||
// StoreCodeCmd will upload code to be reused.
|
||||
func StoreCodeCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "store [wasm file]",
|
||||
Short: "Upload a wasm binary",
|
||||
Aliases: []string{"upload", "st", "s"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := parseStoreCodeArgs(args[0], clientCtx.GetFromAddress(), cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
addInstantiatePermissionFlags(cmd)
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseStoreCodeArgs(file string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgStoreCode, error) {
|
||||
wasm, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return types.MsgStoreCode{}, err
|
||||
}
|
||||
|
||||
// gzip the wasm file
|
||||
if ioutils.IsWasm(wasm) {
|
||||
wasm, err = ioutils.GzipIt(wasm)
|
||||
|
||||
if err != nil {
|
||||
return types.MsgStoreCode{}, err
|
||||
}
|
||||
} else if !ioutils.IsGzip(wasm) {
|
||||
return types.MsgStoreCode{}, fmt.Errorf("invalid input file. Use wasm binary or gzip")
|
||||
}
|
||||
|
||||
perm, err := parseAccessConfigFlags(flags)
|
||||
if err != nil {
|
||||
return types.MsgStoreCode{}, err
|
||||
}
|
||||
|
||||
msg := types.MsgStoreCode{
|
||||
Sender: sender.String(),
|
||||
WASMByteCode: wasm,
|
||||
InstantiatePermission: perm,
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
func parseAccessConfigFlags(flags *flag.FlagSet) (*types.AccessConfig, error) {
|
||||
addrs, err := flags.GetStringSlice(flagInstantiateByAnyOfAddress)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("flag any of: %s", err)
|
||||
}
|
||||
if len(addrs) != 0 {
|
||||
acceptedAddrs := make([]sdk.AccAddress, len(addrs))
|
||||
for i, v := range addrs {
|
||||
acceptedAddrs[i], err = sdk.AccAddressFromBech32(v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse %q: %w", v, err)
|
||||
}
|
||||
}
|
||||
x := types.AccessTypeAnyOfAddresses.With(acceptedAddrs...)
|
||||
return &x, nil
|
||||
}
|
||||
|
||||
onlyAddrStr, err := flags.GetString(flagInstantiateByAddress)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("instantiate by address: %s", err)
|
||||
}
|
||||
if onlyAddrStr != "" {
|
||||
return nil, fmt.Errorf("not supported anymore. Use: %s", flagInstantiateByAnyOfAddress)
|
||||
}
|
||||
everybodyStr, err := flags.GetString(flagInstantiateByEverybody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("instantiate by everybody: %s", err)
|
||||
}
|
||||
if everybodyStr != "" {
|
||||
ok, err := strconv.ParseBool(everybodyStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("boolean value expected for instantiate by everybody: %s", err)
|
||||
}
|
||||
if ok {
|
||||
return &types.AllowEverybody, nil
|
||||
}
|
||||
}
|
||||
|
||||
nobodyStr, err := flags.GetString(flagInstantiateNobody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("instantiate by nobody: %s", err)
|
||||
}
|
||||
if nobodyStr != "" {
|
||||
ok, err := strconv.ParseBool(nobodyStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("boolean value expected for instantiate by nobody: %s", err)
|
||||
}
|
||||
if ok {
|
||||
return &types.AllowNobody, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func addInstantiatePermissionFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().String(flagInstantiateByEverybody, "", "Everybody can instantiate a contract from the code, optional")
|
||||
cmd.Flags().String(flagInstantiateNobody, "", "Nobody except the governance process can instantiate a contract from the code, optional")
|
||||
cmd.Flags().String(flagInstantiateByAddress, "", fmt.Sprintf("Removed: use %s instead", flagInstantiateByAnyOfAddress))
|
||||
cmd.Flags().StringSlice(flagInstantiateByAnyOfAddress, []string{}, "Any of the addresses can instantiate a contract from the code, optional")
|
||||
}
|
||||
|
||||
// InstantiateContractCmd will instantiate a contract from previously uploaded code.
|
||||
func InstantiateContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --admin [address,optional] --amount [coins,optional] ",
|
||||
Short: "Instantiate a wasm contract",
|
||||
Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message.
|
||||
Each contract instance has a unique address assigned.
|
||||
Example:
|
||||
$ %s tx wasm instantiate 1 '{"foo":"bar"}' --admin="$(%s keys show mykey -a)" \
|
||||
--from mykey --amount="100ustake" --label "local0.1.0"
|
||||
`, version.AppName, version.AppName),
|
||||
Aliases: []string{"start", "init", "inst", "i"},
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.GetFromAddress(), cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
|
||||
cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
|
||||
cmd.Flags().String(flagAdmin, "", "Address or key name of an admin")
|
||||
cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// InstantiateContract2Cmd will instantiate a contract from previously uploaded code with predicable address generated
|
||||
func InstantiateContract2Cmd() *cobra.Command {
|
||||
decoder := newArgDecoder(hex.DecodeString)
|
||||
cmd := &cobra.Command{
|
||||
Use: "instantiate2 [code_id_int64] [json_encoded_init_args] [salt] --label [text] --admin [address,optional] --amount [coins,optional] " +
|
||||
"--fix-msg [bool,optional]",
|
||||
Short: "Instantiate a wasm contract with predictable address",
|
||||
Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message.
|
||||
Each contract instance has a unique address assigned. They are assigned automatically but in order to have predictable addresses
|
||||
for special use cases, the given 'salt' argument and '--fix-msg' parameters can be used to generate a custom address.
|
||||
|
||||
Predictable address example (also see '%s query wasm build-address -h'):
|
||||
$ %s tx wasm instantiate2 1 '{"foo":"bar"}' $(echo -n "testing" | xxd -ps) --admin="$(%s keys show mykey -a)" \
|
||||
--from mykey --amount="100ustake" --label "local0.1.0" \
|
||||
--fix-msg
|
||||
`, version.AppName, version.AppName, version.AppName),
|
||||
Aliases: []string{"start", "init", "inst", "i"},
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
salt, err := decoder.DecodeString(args[2])
|
||||
if err != nil {
|
||||
return fmt.Errorf("salt: %w", err)
|
||||
}
|
||||
fixMsg, err := cmd.Flags().GetBool(flagFixMsg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fix msg: %w", err)
|
||||
}
|
||||
data, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.GetFromAddress(), cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg := &types.MsgInstantiateContract2{
|
||||
Sender: data.Sender,
|
||||
Admin: data.Admin,
|
||||
CodeID: data.CodeID,
|
||||
Label: data.Label,
|
||||
Msg: data.Msg,
|
||||
Funds: data.Funds,
|
||||
Salt: salt,
|
||||
FixMsg: fixMsg,
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
|
||||
cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
|
||||
cmd.Flags().String(flagAdmin, "", "Address or key name of an admin")
|
||||
cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
|
||||
cmd.Flags().Bool(flagFixMsg, false, "An optional flag to include the json_encoded_init_args for the predictable address generation mode")
|
||||
decoder.RegisterFlags(cmd.PersistentFlags(), "salt")
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseInstantiateArgs(rawCodeID, initMsg string, kr keyring.Keyring, sender sdk.AccAddress, flags *flag.FlagSet) (*types.MsgInstantiateContract, error) {
|
||||
// get the id of the code to instantiate
|
||||
codeID, err := strconv.ParseUint(rawCodeID, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
amountStr, err := flags.GetString(flagAmount)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
amount, err := sdk.ParseCoinsNormalized(amountStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
label, err := flags.GetString(flagLabel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("label: %s", err)
|
||||
}
|
||||
if label == "" {
|
||||
return nil, errors.New("label is required on all contracts")
|
||||
}
|
||||
adminStr, err := flags.GetString(flagAdmin)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("admin: %s", err)
|
||||
}
|
||||
|
||||
noAdmin, err := flags.GetBool(flagNoAdmin)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no-admin: %s", err)
|
||||
}
|
||||
|
||||
// ensure sensible admin is set (or explicitly immutable)
|
||||
if adminStr == "" && !noAdmin {
|
||||
return nil, fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)")
|
||||
}
|
||||
if adminStr != "" && noAdmin {
|
||||
return nil, fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true")
|
||||
}
|
||||
|
||||
if adminStr != "" {
|
||||
addr, err := sdk.AccAddressFromBech32(adminStr)
|
||||
if err != nil {
|
||||
info, err := kr.Key(adminStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("admin %s", err)
|
||||
}
|
||||
adminStr = info.GetAddress().String()
|
||||
} else {
|
||||
adminStr = addr.String()
|
||||
}
|
||||
}
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
msg := types.MsgInstantiateContract{
|
||||
Sender: sender.String(),
|
||||
CodeID: codeID,
|
||||
Label: label,
|
||||
Funds: amount,
|
||||
Msg: []byte(initMsg),
|
||||
Admin: adminStr,
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
// ExecuteContractCmd will instantiate a contract from previously uploaded code.
|
||||
func ExecuteContractCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "execute [contract_addr_bech32] [json_encoded_send_args] --amount [coins,optional]",
|
||||
Short: "Execute a command on a wasm contract",
|
||||
Aliases: []string{"run", "call", "exec", "ex", "e"},
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := parseExecuteArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
|
||||
},
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagAmount, "", "Coins to send to the contract along with command")
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseExecuteArgs(contractAddr string, execMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgExecuteContract, error) {
|
||||
amountStr, err := flags.GetString(flagAmount)
|
||||
if err != nil {
|
||||
return types.MsgExecuteContract{}, fmt.Errorf("amount: %s", err)
|
||||
}
|
||||
|
||||
amount, err := sdk.ParseCoinsNormalized(amountStr)
|
||||
if err != nil {
|
||||
return types.MsgExecuteContract{}, err
|
||||
}
|
||||
|
||||
return types.MsgExecuteContract{
|
||||
Sender: sender.String(),
|
||||
Contract: contractAddr,
|
||||
Funds: amount,
|
||||
Msg: []byte(execMsg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GrantAuthorizationCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "grant [grantee] [message_type=\"execution\"|\"migration\"] [contract_addr_bech32] --allow-raw-msgs [msg1,msg2,...] --allow-msg-keys [key1,key2,...] --allow-all-messages",
|
||||
Short: "Grant authorization to an address",
|
||||
Long: fmt.Sprintf(`Grant authorization to an address.
|
||||
Examples:
|
||||
$ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --max-calls 1 --no-token-transfer --expiration 1667979596
|
||||
|
||||
$ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --max-funds 100000uwasm --expiration 1667979596
|
||||
|
||||
$ %s tx grant <grantee_addr> execution <contract_addr> --allow-all-messages --max-calls 5 --max-funds 100000uwasm --expiration 1667979596
|
||||
`, version.AppName, version.AppName, version.AppName),
|
||||
Args: cobra.ExactArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientTxContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
grantee, err := sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contract, err := sdk.AccAddressFromBech32(args[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgKeys, err := cmd.Flags().GetStringSlice(flagAllowedMsgKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawMsgs, err := cmd.Flags().GetStringSlice(flagAllowedRawMsgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maxFundsStr, err := cmd.Flags().GetString(flagMaxFunds)
|
||||
if err != nil {
|
||||
return fmt.Errorf("max funds: %s", err)
|
||||
}
|
||||
|
||||
maxCalls, err := cmd.Flags().GetUint64(flagMaxCalls)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exp, err := cmd.Flags().GetInt64(flagExpiration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exp == 0 {
|
||||
return errors.New("expiration must be set")
|
||||
}
|
||||
|
||||
allowAllMsgs, err := cmd.Flags().GetBool(flagAllowAllMsgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
noTokenTransfer, err := cmd.Flags().GetBool(flagNoTokenTransfer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var limit types.ContractAuthzLimitX
|
||||
switch {
|
||||
case maxFundsStr != "" && maxCalls != 0 && !noTokenTransfer:
|
||||
maxFunds, err := sdk.ParseCoinsNormalized(maxFundsStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("max funds: %s", err)
|
||||
}
|
||||
limit = types.NewCombinedLimit(maxCalls, maxFunds...)
|
||||
case maxFundsStr != "" && maxCalls == 0 && !noTokenTransfer:
|
||||
maxFunds, err := sdk.ParseCoinsNormalized(maxFundsStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("max funds: %s", err)
|
||||
}
|
||||
limit = types.NewMaxFundsLimit(maxFunds...)
|
||||
case maxCalls != 0 && noTokenTransfer && maxFundsStr == "":
|
||||
limit = types.NewMaxCallsLimit(maxCalls)
|
||||
default:
|
||||
return errors.New("invalid limit setup")
|
||||
}
|
||||
|
||||
var filter types.ContractAuthzFilterX
|
||||
switch {
|
||||
case allowAllMsgs && len(msgKeys) != 0 || allowAllMsgs && len(rawMsgs) != 0 || len(msgKeys) != 0 && len(rawMsgs) != 0:
|
||||
return errors.New("cannot set more than one filter within one grant")
|
||||
case allowAllMsgs:
|
||||
filter = types.NewAllowAllMessagesFilter()
|
||||
case len(msgKeys) != 0:
|
||||
filter = types.NewAcceptedMessageKeysFilter(msgKeys...)
|
||||
case len(rawMsgs) != 0:
|
||||
msgs := make([]types.RawContractMessage, len(rawMsgs))
|
||||
for i, msg := range rawMsgs {
|
||||
msgs[i] = types.RawContractMessage(msg)
|
||||
}
|
||||
filter = types.NewAcceptedMessagesFilter(msgs...)
|
||||
default:
|
||||
return errors.New("invalid filter setup")
|
||||
}
|
||||
|
||||
grant, err := types.NewContractGrant(contract, limit, filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var authorization authz.Authorization
|
||||
switch args[1] {
|
||||
case "execution":
|
||||
authorization = types.NewContractExecutionAuthorization(*grant)
|
||||
case "migration":
|
||||
authorization = types.NewContractMigrationAuthorization(*grant)
|
||||
default:
|
||||
return fmt.Errorf("%s authorization type not supported", args[1])
|
||||
}
|
||||
|
||||
grantMsg, err := authz.NewMsgGrant(clientCtx.GetFromAddress(), grantee, authorization, time.Unix(0, exp))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), grantMsg)
|
||||
},
|
||||
}
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
cmd.Flags().StringSlice(flagAllowedMsgKeys, []string{}, "Allowed msg keys")
|
||||
cmd.Flags().StringSlice(flagAllowedRawMsgs, []string{}, "Allowed raw msgs")
|
||||
cmd.Flags().Uint64(flagMaxCalls, 0, "Maximal number of calls to the contract")
|
||||
cmd.Flags().String(flagMaxFunds, "", "Maximal amount of tokens transferable to the contract.")
|
||||
cmd.Flags().Int64(flagExpiration, 0, "The Unix timestamp.")
|
||||
cmd.Flags().Bool(flagAllowAllMsgs, false, "Allow all messages")
|
||||
cmd.Flags().Bool(flagNoTokenTransfer, false, "Don't allow token transfer")
|
||||
return cmd
|
||||
}
|
||||
59
x/wasm/client/cli/tx_test.go
Normal file
59
x/wasm/client/cli/tx_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestParseAccessConfigFlags(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
args []string
|
||||
expCfg *types.AccessConfig
|
||||
expErr bool
|
||||
}{
|
||||
"nobody": {
|
||||
args: []string{"--instantiate-nobody=true"},
|
||||
expCfg: &types.AccessConfig{Permission: types.AccessTypeNobody},
|
||||
},
|
||||
"everybody": {
|
||||
args: []string{"--instantiate-everybody=true"},
|
||||
expCfg: &types.AccessConfig{Permission: types.AccessTypeEverybody},
|
||||
},
|
||||
"only address": {
|
||||
args: []string{"--instantiate-only-address=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"},
|
||||
expErr: true,
|
||||
},
|
||||
"only address - invalid": {
|
||||
args: []string{"--instantiate-only-address=foo"},
|
||||
expErr: true,
|
||||
},
|
||||
"any of address": {
|
||||
args: []string{"--instantiate-anyof-addresses=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"},
|
||||
expCfg: &types.AccessConfig{Permission: types.AccessTypeAnyOfAddresses, Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"}},
|
||||
},
|
||||
"any of address - invalid": {
|
||||
args: []string{"--instantiate-anyof-addresses=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,foo"},
|
||||
expErr: true,
|
||||
},
|
||||
"not set": {
|
||||
args: []string{},
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
flags := StoreCodeCmd().Flags()
|
||||
require.NoError(t, flags.Parse(spec.args))
|
||||
gotCfg, gotErr := parseAccessConfigFlags(flags)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
assert.Equal(t, spec.expCfg, gotCfg)
|
||||
})
|
||||
}
|
||||
}
|
||||
25
x/wasm/client/proposal_handler.go
Normal file
25
x/wasm/client/proposal_handler.go
Normal file
@ -0,0 +1,25 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/client/cli"
|
||||
"github.com/cerc-io/laconicd/x/wasm/client/rest" //nolint:staticcheck
|
||||
)
|
||||
|
||||
// ProposalHandlers define the wasm cli proposal types and rest handler.
|
||||
// Deprecated: the rest package will be removed. You can use the GRPC gateway instead
|
||||
var ProposalHandlers = []govclient.ProposalHandler{
|
||||
govclient.NewProposalHandler(cli.ProposalStoreCodeCmd, rest.StoreCodeProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalInstantiateContractCmd, rest.InstantiateProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalMigrateContractCmd, rest.MigrateProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalExecuteContractCmd, rest.ExecuteProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalSudoContractCmd, rest.SudoProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalUpdateContractAdminCmd, rest.UpdateContractAdminProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalClearContractAdminCmd, rest.ClearContractAdminProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalPinCodesCmd, rest.PinCodeProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalUnpinCodesCmd, rest.UnpinCodeProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalUpdateInstantiateConfigCmd, rest.UpdateInstantiateConfigProposalHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalStoreAndInstantiateContractCmd, rest.EmptyRestHandler),
|
||||
govclient.NewProposalHandler(cli.ProposalInstantiateContract2Cmd, rest.EmptyRestHandler),
|
||||
}
|
||||
381
x/wasm/client/proposal_handler_test.go
Normal file
381
x/wasm/client/proposal_handler_test.go
Normal file
@ -0,0 +1,381 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
)
|
||||
|
||||
func TestGovRestHandlers(t *testing.T) {
|
||||
type dict map[string]interface{}
|
||||
var (
|
||||
anyAddress = "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz"
|
||||
aBaseReq = dict{
|
||||
"from": anyAddress,
|
||||
"memo": "rest test",
|
||||
"chain_id": "testing",
|
||||
"account_number": "1",
|
||||
"sequence": "1",
|
||||
"fees": []dict{{"denom": "ustake", "amount": "1000000"}},
|
||||
}
|
||||
)
|
||||
encodingConfig := keeper.MakeEncodingConfig(t)
|
||||
clientCtx := client.Context{}.
|
||||
WithCodec(encodingConfig.Marshaler).
|
||||
WithTxConfig(encodingConfig.TxConfig).
|
||||
WithLegacyAmino(encodingConfig.Amino).
|
||||
WithInput(os.Stdin).
|
||||
WithAccountRetriever(authtypes.AccountRetriever{}).
|
||||
WithBroadcastMode(flags.BroadcastBlock).
|
||||
WithChainID("testing")
|
||||
|
||||
// router setup as in gov/client/rest/tx.go
|
||||
propSubRtr := mux.NewRouter().PathPrefix("/gov/proposals").Subrouter()
|
||||
for _, ph := range ProposalHandlers {
|
||||
r := ph.RESTHandler(clientCtx)
|
||||
propSubRtr.HandleFunc(fmt.Sprintf("/%s", r.SubRoute), r.Handler).Methods("POST")
|
||||
}
|
||||
|
||||
specs := map[string]struct {
|
||||
srcBody dict
|
||||
srcPath string
|
||||
expCode int
|
||||
}{
|
||||
"store-code": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": []byte("valid wasm byte code"),
|
||||
"source": "https://example.com/",
|
||||
"builder": "cosmwasm/workspace-optimizer:v0.12.9",
|
||||
"code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D",
|
||||
"instantiate_permission": dict{
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"store-code without verification info": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": []byte("valid wasm byte code"),
|
||||
"instantiate_permission": dict{
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"store-code without permission": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": []byte("valid wasm byte code"),
|
||||
"source": "https://example.com/",
|
||||
"builder": "cosmwasm/workspace-optimizer:v0.12.9",
|
||||
"code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D",
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"store-code invalid permission": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": []byte("valid wasm byte code"),
|
||||
"source": "https://example.com/",
|
||||
"builder": "cosmwasm/workspace-optimizer:v0.12.9",
|
||||
"code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D",
|
||||
"instantiate_permission": dict{
|
||||
"permission": "Nobody",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"store-code with incomplete proposal data: blank title": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": []byte("valid wasm byte code"),
|
||||
"source": "https://example.com/",
|
||||
"code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D",
|
||||
"builder": "cosmwasm/workspace-optimizer:v0.12.9",
|
||||
"instantiate_permission": dict{
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"store-code with incomplete content data: no wasm_byte_code": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": "",
|
||||
"builder": "cosmwasm/workspace-optimizer:v0.12.9",
|
||||
"source": "https://example.com/",
|
||||
"code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D",
|
||||
"instantiate_permission": dict{
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"store-code with incomplete content data: no builder": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": "",
|
||||
"source": "https://example.com/",
|
||||
"code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D",
|
||||
"instantiate_permission": dict{
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"store-code with incomplete content data: no code hash": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": "",
|
||||
"builder": "cosmwasm/workspace-optimizer:v0.12.9",
|
||||
"source": "https://example.com/",
|
||||
"instantiate_permission": dict{
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"store-code with incomplete content data: no source": {
|
||||
srcPath: "/gov/proposals/wasm_store_code",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "store-code",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"wasm_byte_code": "",
|
||||
"builder": "cosmwasm/workspace-optimizer:v0.12.9",
|
||||
"code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D",
|
||||
"instantiate_permission": dict{
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"instantiate contract": {
|
||||
srcPath: "/gov/proposals/wasm_instantiate",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "instantiate",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"admin": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"code_id": "1",
|
||||
"label": "https://example.com/",
|
||||
"msg": dict{"recipient": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz"},
|
||||
"funds": []dict{{"denom": "ustake", "amount": "100"}},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"migrate contract": {
|
||||
srcPath: "/gov/proposals/wasm_migrate",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"code_id": "1",
|
||||
"msg": dict{"foo": "bar"},
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"execute contract": {
|
||||
srcPath: "/gov/proposals/wasm_execute",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"msg": dict{"foo": "bar"},
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"execute contract fails with no run_as": {
|
||||
srcPath: "/gov/proposals/wasm_execute",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"msg": dict{"foo": "bar"},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"execute contract fails with no message": {
|
||||
srcPath: "/gov/proposals/wasm_execute",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"sudo contract": {
|
||||
srcPath: "/gov/proposals/wasm_sudo",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"msg": dict{"foo": "bar"},
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"sudo contract fails with no message": {
|
||||
srcPath: "/gov/proposals/wasm_sudo",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusBadRequest,
|
||||
},
|
||||
"update contract admin": {
|
||||
srcPath: "/gov/proposals/wasm_update_admin",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"new_admin": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz",
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
"clear contract admin": {
|
||||
srcPath: "/gov/proposals/wasm_clear_admin",
|
||||
srcBody: dict{
|
||||
"title": "Test Proposal",
|
||||
"description": "My proposal",
|
||||
"type": "migrate",
|
||||
"contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"deposit": []dict{{"denom": "ustake", "amount": "10"}},
|
||||
"proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
|
||||
"base_req": aBaseReq,
|
||||
},
|
||||
expCode: http.StatusOK,
|
||||
},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
src, err := json.Marshal(spec.srcBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
// when
|
||||
r := httptest.NewRequest("POST", spec.srcPath, bytes.NewReader(src))
|
||||
w := httptest.NewRecorder()
|
||||
propSubRtr.ServeHTTP(w, r)
|
||||
|
||||
// then
|
||||
require.Equal(t, spec.expCode, w.Code, w.Body.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
547
x/wasm/client/rest/gov.go
Normal file
547
x/wasm/client/rest/gov.go
Normal file
@ -0,0 +1,547 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
type StoreCodeProposalJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
RunAs string `json:"run_as" yaml:"run_as"`
|
||||
// WASMByteCode can be raw or gzip compressed
|
||||
WASMByteCode []byte `json:"wasm_byte_code" yaml:"wasm_byte_code"`
|
||||
// InstantiatePermission to apply on contract creation, optional
|
||||
InstantiatePermission *types.AccessConfig `json:"instantiate_permission" yaml:"instantiate_permission"`
|
||||
|
||||
// UnpinCode indicates if the code should not be pinned as part of the proposal.
|
||||
UnpinCode bool `json:"unpin_code" yaml:"unpin_code"`
|
||||
|
||||
// Source is the URL where the code is hosted
|
||||
Source string `json:"source" yaml:"source"`
|
||||
// Builder is the docker image used to build the code deterministically, used for smart
|
||||
// contract verification
|
||||
Builder string `json:"builder" yaml:"builder"`
|
||||
// CodeHash is the SHA256 sum of the code outputted by optimizer, used for smart contract verification
|
||||
CodeHash []byte `json:"code_hash" yaml:"code_hash"`
|
||||
}
|
||||
|
||||
func (s StoreCodeProposalJSONReq) Content() govtypes.Content {
|
||||
return &types.StoreCodeProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
RunAs: s.RunAs,
|
||||
WASMByteCode: s.WASMByteCode,
|
||||
InstantiatePermission: s.InstantiatePermission,
|
||||
UnpinCode: s.UnpinCode,
|
||||
Source: s.Source,
|
||||
Builder: s.Builder,
|
||||
CodeHash: s.CodeHash,
|
||||
}
|
||||
}
|
||||
|
||||
func (s StoreCodeProposalJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s StoreCodeProposalJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s StoreCodeProposalJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func StoreCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "wasm_store_code",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req StoreCodeProposalJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type InstantiateProposalJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
RunAs string `json:"run_as" yaml:"run_as"`
|
||||
// Admin is an optional address that can execute migrations
|
||||
Admin string `json:"admin,omitempty" yaml:"admin"`
|
||||
Code uint64 `json:"code_id" yaml:"code_id"`
|
||||
Label string `json:"label" yaml:"label"`
|
||||
Msg json.RawMessage `json:"msg" yaml:"msg"`
|
||||
Funds sdk.Coins `json:"funds" yaml:"funds"`
|
||||
}
|
||||
|
||||
func (s InstantiateProposalJSONReq) Content() govtypes.Content {
|
||||
return &types.InstantiateContractProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
RunAs: s.RunAs,
|
||||
Admin: s.Admin,
|
||||
CodeID: s.Code,
|
||||
Label: s.Label,
|
||||
Msg: types.RawContractMessage(s.Msg),
|
||||
Funds: s.Funds,
|
||||
}
|
||||
}
|
||||
|
||||
func (s InstantiateProposalJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s InstantiateProposalJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s InstantiateProposalJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func InstantiateProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "wasm_instantiate",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req InstantiateProposalJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type MigrateProposalJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
Contract string `json:"contract" yaml:"contract"`
|
||||
Code uint64 `json:"code_id" yaml:"code_id"`
|
||||
Msg json.RawMessage `json:"msg" yaml:"msg"`
|
||||
}
|
||||
|
||||
func (s MigrateProposalJSONReq) Content() govtypes.Content {
|
||||
return &types.MigrateContractProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
Contract: s.Contract,
|
||||
CodeID: s.Code,
|
||||
Msg: types.RawContractMessage(s.Msg),
|
||||
}
|
||||
}
|
||||
|
||||
func (s MigrateProposalJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s MigrateProposalJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s MigrateProposalJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func MigrateProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "wasm_migrate",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req MigrateProposalJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type ExecuteProposalJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
Contract string `json:"contract" yaml:"contract"`
|
||||
Msg json.RawMessage `json:"msg" yaml:"msg"`
|
||||
// RunAs is the role that is passed to the contract's environment
|
||||
RunAs string `json:"run_as" yaml:"run_as"`
|
||||
Funds sdk.Coins `json:"funds" yaml:"funds"`
|
||||
}
|
||||
|
||||
func (s ExecuteProposalJSONReq) Content() govtypes.Content {
|
||||
return &types.ExecuteContractProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
Contract: s.Contract,
|
||||
Msg: types.RawContractMessage(s.Msg),
|
||||
RunAs: s.RunAs,
|
||||
Funds: s.Funds,
|
||||
}
|
||||
}
|
||||
|
||||
func (s ExecuteProposalJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s ExecuteProposalJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s ExecuteProposalJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func ExecuteProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "wasm_execute",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req ExecuteProposalJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type SudoProposalJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
Contract string `json:"contract" yaml:"contract"`
|
||||
Msg json.RawMessage `json:"msg" yaml:"msg"`
|
||||
}
|
||||
|
||||
func (s SudoProposalJSONReq) Content() govtypes.Content {
|
||||
return &types.SudoContractProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
Contract: s.Contract,
|
||||
Msg: types.RawContractMessage(s.Msg),
|
||||
}
|
||||
}
|
||||
|
||||
func (s SudoProposalJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s SudoProposalJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s SudoProposalJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func SudoProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "wasm_sudo",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req SudoProposalJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type UpdateAdminJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
NewAdmin string `json:"new_admin" yaml:"new_admin"`
|
||||
Contract string `json:"contract" yaml:"contract"`
|
||||
}
|
||||
|
||||
func (s UpdateAdminJSONReq) Content() govtypes.Content {
|
||||
return &types.UpdateAdminProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
Contract: s.Contract,
|
||||
NewAdmin: s.NewAdmin,
|
||||
}
|
||||
}
|
||||
|
||||
func (s UpdateAdminJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s UpdateAdminJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s UpdateAdminJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func UpdateContractAdminProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "wasm_update_admin",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req UpdateAdminJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type ClearAdminJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
Contract string `json:"contract" yaml:"contract"`
|
||||
}
|
||||
|
||||
func (s ClearAdminJSONReq) Content() govtypes.Content {
|
||||
return &types.ClearAdminProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
Contract: s.Contract,
|
||||
}
|
||||
}
|
||||
|
||||
func (s ClearAdminJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s ClearAdminJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s ClearAdminJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func ClearContractAdminProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "wasm_clear_admin",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req ClearAdminJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type PinCodeJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
CodeIDs []uint64 `json:"code_ids" yaml:"code_ids"`
|
||||
}
|
||||
|
||||
func (s PinCodeJSONReq) Content() govtypes.Content {
|
||||
return &types.PinCodesProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
CodeIDs: s.CodeIDs,
|
||||
}
|
||||
}
|
||||
|
||||
func (s PinCodeJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s PinCodeJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s PinCodeJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func PinCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "pin_code",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req PinCodeJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type UnpinCodeJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
|
||||
CodeIDs []uint64 `json:"code_ids" yaml:"code_ids"`
|
||||
}
|
||||
|
||||
func (s UnpinCodeJSONReq) Content() govtypes.Content {
|
||||
return &types.UnpinCodesProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
CodeIDs: s.CodeIDs,
|
||||
}
|
||||
}
|
||||
|
||||
func (s UnpinCodeJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s UnpinCodeJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s UnpinCodeJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func UnpinCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "unpin_code",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req UnpinCodeJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type UpdateInstantiateConfigProposalJSONReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Proposer string `json:"proposer" yaml:"proposer"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
AccessConfigUpdates []types.AccessConfigUpdate `json:"access_config_updates" yaml:"access_config_updates"`
|
||||
}
|
||||
|
||||
func (s UpdateInstantiateConfigProposalJSONReq) Content() govtypes.Content {
|
||||
return &types.UpdateInstantiateConfigProposal{
|
||||
Title: s.Title,
|
||||
Description: s.Description,
|
||||
AccessConfigUpdates: s.AccessConfigUpdates,
|
||||
}
|
||||
}
|
||||
|
||||
func (s UpdateInstantiateConfigProposalJSONReq) GetProposer() string {
|
||||
return s.Proposer
|
||||
}
|
||||
|
||||
func (s UpdateInstantiateConfigProposalJSONReq) GetDeposit() sdk.Coins {
|
||||
return s.Deposit
|
||||
}
|
||||
|
||||
func (s UpdateInstantiateConfigProposalJSONReq) GetBaseReq() rest.BaseReq {
|
||||
return s.BaseReq
|
||||
}
|
||||
|
||||
func UpdateInstantiateConfigProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "update_instantiate_config",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
var req UpdateInstantiateConfigProposalJSONReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
toStdTxResponse(cliCtx, w, req)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type wasmProposalData interface {
|
||||
Content() govtypes.Content
|
||||
GetProposer() string
|
||||
GetDeposit() sdk.Coins
|
||||
GetBaseReq() rest.BaseReq
|
||||
}
|
||||
|
||||
func toStdTxResponse(cliCtx client.Context, w http.ResponseWriter, data wasmProposalData) {
|
||||
proposerAddr, err := sdk.AccAddressFromBech32(data.GetProposer())
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
msg, err := govtypes.NewMsgSubmitProposal(data.Content(), data.GetDeposit(), proposerAddr)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
baseReq := data.GetBaseReq().Sanitize()
|
||||
if !baseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
tx.WriteGeneratedTxResponse(cliCtx, w, baseReq, msg)
|
||||
}
|
||||
|
||||
func EmptyRestHandler(cliCtx client.Context) govrest.ProposalRESTHandler {
|
||||
return govrest.ProposalRESTHandler{
|
||||
SubRoute: "unsupported",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, "Legacy REST Routes are not supported for gov proposals")
|
||||
},
|
||||
}
|
||||
}
|
||||
86
x/wasm/client/rest/new_tx.go
Normal file
86
x/wasm/client/rest/new_tx.go
Normal file
@ -0,0 +1,86 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func registerNewTxRoutes(cliCtx client.Context, r *mux.Router) {
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}/admin", setContractAdminHandlerFn(cliCtx)).Methods("PUT")
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}/code", migrateContractHandlerFn(cliCtx)).Methods("PUT")
|
||||
}
|
||||
|
||||
type migrateContractReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Admin string `json:"admin,omitempty" yaml:"admin"`
|
||||
CodeID uint64 `json:"code_id" yaml:"code_id"`
|
||||
Msg []byte `json:"msg,omitempty" yaml:"msg"`
|
||||
}
|
||||
|
||||
type updateContractAdministrateReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Admin string `json:"admin,omitempty" yaml:"admin"`
|
||||
}
|
||||
|
||||
func setContractAdminHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req updateContractAdministrateReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
contractAddr := vars["contractAddr"]
|
||||
|
||||
req.BaseReq = req.BaseReq.Sanitize()
|
||||
if !req.BaseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
|
||||
msg := &types.MsgUpdateAdmin{
|
||||
Sender: req.BaseReq.From,
|
||||
NewAdmin: req.Admin,
|
||||
Contract: contractAddr,
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func migrateContractHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req migrateContractReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
contractAddr := vars["contractAddr"]
|
||||
|
||||
req.BaseReq = req.BaseReq.Sanitize()
|
||||
if !req.BaseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
|
||||
msg := &types.MsgMigrateContract{
|
||||
Sender: req.BaseReq.From,
|
||||
Contract: contractAddr,
|
||||
CodeID: req.CodeID,
|
||||
Msg: req.Msg,
|
||||
}
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg)
|
||||
}
|
||||
}
|
||||
270
x/wasm/client/rest/query.go
Normal file
270
x/wasm/client/rest/query.go
Normal file
@ -0,0 +1,270 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func registerQueryRoutes(cliCtx client.Context, r *mux.Router) {
|
||||
r.HandleFunc("/wasm/code", listCodesHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/wasm/code/{codeID}", queryCodeHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/wasm/code/{codeID}/contracts", listContractsByCodeHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}", queryContractHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}/state", queryContractStateAllHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}/history", queryContractHistoryFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}/smart/{query}", queryContractStateSmartHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET")
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}/raw/{key}", queryContractStateRawHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET")
|
||||
}
|
||||
|
||||
func listCodesHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, keeper.QueryListCode)
|
||||
res, height, err := cliCtx.Query(route)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
||||
}
|
||||
}
|
||||
|
||||
func queryCodeHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s/%d", types.QuerierRoute, keeper.QueryGetCode, codeID)
|
||||
res, height, err := cliCtx.Query(route)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if len(res) == 0 {
|
||||
rest.WriteErrorResponse(w, http.StatusNotFound, "contract not found")
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
||||
}
|
||||
}
|
||||
|
||||
func listContractsByCodeHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s/%d", types.QuerierRoute, keeper.QueryListContractByCode, codeID)
|
||||
res, height, err := cliCtx.Query(route)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
||||
}
|
||||
}
|
||||
|
||||
func queryContractHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContract, addr.String())
|
||||
res, height, err := cliCtx.Query(route)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
||||
}
|
||||
}
|
||||
|
||||
func queryContractStateAllHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateAll)
|
||||
res, height, err := cliCtx.Query(route)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// parse res
|
||||
var resultData []types.Model
|
||||
err = json.Unmarshal(res, &resultData)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, cliCtx, resultData)
|
||||
}
|
||||
}
|
||||
|
||||
func queryContractStateRawHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := newArgDecoder(hex.DecodeString)
|
||||
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
decoder.encoding = mux.Vars(r)["encoding"]
|
||||
queryData, err := decoder.DecodeString(mux.Vars(r)["key"])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateRaw)
|
||||
res, height, err := cliCtx.QueryWithData(route, queryData)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
// ensure this is base64 encoded
|
||||
encoded := base64.StdEncoding.EncodeToString(res)
|
||||
rest.PostProcessResponse(w, cliCtx, encoded)
|
||||
}
|
||||
}
|
||||
|
||||
type smartResponse struct {
|
||||
Smart []byte `json:"smart"`
|
||||
}
|
||||
|
||||
func queryContractStateSmartHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := newArgDecoder(hex.DecodeString)
|
||||
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
decoder.encoding = mux.Vars(r)["encoding"]
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateSmart)
|
||||
|
||||
queryData, err := decoder.DecodeString(mux.Vars(r)["query"])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
res, height, err := cliCtx.QueryWithData(route, queryData)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
// return as raw bytes (to be base64-encoded)
|
||||
responseData := smartResponse{Smart: res}
|
||||
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, cliCtx, responseData)
|
||||
}
|
||||
}
|
||||
|
||||
func queryContractHistoryFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryContractHistory, addr.String())
|
||||
res, height, err := cliCtx.Query(route)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
rest.PostProcessResponse(w, cliCtx, json.RawMessage(res))
|
||||
}
|
||||
}
|
||||
|
||||
type argumentDecoder struct {
|
||||
// dec is the default decoder
|
||||
dec func(string) ([]byte, error)
|
||||
encoding string
|
||||
}
|
||||
|
||||
func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder {
|
||||
return &argumentDecoder{dec: def}
|
||||
}
|
||||
|
||||
func (a *argumentDecoder) DecodeString(s string) ([]byte, error) {
|
||||
switch a.encoding {
|
||||
case "hex":
|
||||
return hex.DecodeString(s)
|
||||
case "base64":
|
||||
return base64.StdEncoding.DecodeString(s)
|
||||
default:
|
||||
return a.dec(s)
|
||||
}
|
||||
}
|
||||
15
x/wasm/client/rest/rest.go
Normal file
15
x/wasm/client/rest/rest.go
Normal file
@ -0,0 +1,15 @@
|
||||
// Deprecated: the rest package will be removed. You can use the GRPC gateway instead
|
||||
package rest
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// RegisterRoutes registers staking-related REST handlers to a router
|
||||
// Deprecated: the rest package will be removed. You can use the GRPC gateway instead
|
||||
func RegisterRoutes(cliCtx client.Context, r *mux.Router) {
|
||||
registerQueryRoutes(cliCtx, r)
|
||||
registerTxRoutes(cliCtx, r)
|
||||
registerNewTxRoutes(cliCtx, r)
|
||||
}
|
||||
149
x/wasm/client/rest/tx.go
Normal file
149
x/wasm/client/rest/tx.go
Normal file
@ -0,0 +1,149 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/ioutils"
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func registerTxRoutes(cliCtx client.Context, r *mux.Router) {
|
||||
r.HandleFunc("/wasm/code", storeCodeHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/wasm/code/{codeId}", instantiateContractHandlerFn(cliCtx)).Methods("POST")
|
||||
r.HandleFunc("/wasm/contract/{contractAddr}", executeContractHandlerFn(cliCtx)).Methods("POST")
|
||||
}
|
||||
|
||||
type storeCodeReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
WasmBytes []byte `json:"wasm_bytes"`
|
||||
}
|
||||
|
||||
type instantiateContractReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
Label string `json:"label" yaml:"label"`
|
||||
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
|
||||
Admin string `json:"admin,omitempty" yaml:"admin"`
|
||||
Msg []byte `json:"msg" yaml:"msg"`
|
||||
}
|
||||
|
||||
type executeContractReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
ExecMsg []byte `json:"exec_msg" yaml:"exec_msg"`
|
||||
Amount sdk.Coins `json:"coins" yaml:"coins"`
|
||||
}
|
||||
|
||||
func storeCodeHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req storeCodeReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
|
||||
req.BaseReq = req.BaseReq.Sanitize()
|
||||
if !req.BaseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
wasm := req.WasmBytes
|
||||
|
||||
// gzip the wasm file
|
||||
if ioutils.IsWasm(wasm) {
|
||||
wasm, err = ioutils.GzipIt(wasm)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
} else if !ioutils.IsGzip(wasm) {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, "Invalid input file, use wasm binary or zip")
|
||||
return
|
||||
}
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
msg := types.MsgStoreCode{
|
||||
Sender: req.BaseReq.From,
|
||||
WASMByteCode: wasm,
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, &msg)
|
||||
}
|
||||
}
|
||||
|
||||
func instantiateContractHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req instantiateContractReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
|
||||
req.BaseReq = req.BaseReq.Sanitize()
|
||||
if !req.BaseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
|
||||
// get the id of the code to instantiate
|
||||
codeID, err := strconv.ParseUint(vars["codeId"], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := types.MsgInstantiateContract{
|
||||
Sender: req.BaseReq.From,
|
||||
CodeID: codeID,
|
||||
Label: req.Label,
|
||||
Funds: req.Deposit,
|
||||
Msg: req.Msg,
|
||||
Admin: req.Admin,
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, &msg)
|
||||
}
|
||||
}
|
||||
|
||||
func executeContractHandlerFn(cliCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req executeContractReq
|
||||
if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) {
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
contractAddr := vars["contractAddr"]
|
||||
|
||||
req.BaseReq = req.BaseReq.Sanitize()
|
||||
if !req.BaseReq.ValidateBasic(w) {
|
||||
return
|
||||
}
|
||||
|
||||
msg := types.MsgExecuteContract{
|
||||
Sender: req.BaseReq.From,
|
||||
Contract: contractAddr,
|
||||
Msg: req.ExecMsg,
|
||||
Funds: req.Amount,
|
||||
}
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, &msg)
|
||||
}
|
||||
}
|
||||
34
x/wasm/common_test.go
Normal file
34
x/wasm/common_test.go
Normal file
@ -0,0 +1,34 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// ensure store code returns the expected response
|
||||
func assertStoreCodeResponse(t *testing.T, data []byte, expected uint64) {
|
||||
var pStoreResp MsgStoreCodeResponse
|
||||
require.NoError(t, pStoreResp.Unmarshal(data))
|
||||
require.Equal(t, pStoreResp.CodeID, expected)
|
||||
}
|
||||
|
||||
// ensure execution returns the expected data
|
||||
func assertExecuteResponse(t *testing.T, data []byte, expected []byte) {
|
||||
var pExecResp MsgExecuteContractResponse
|
||||
require.NoError(t, pExecResp.Unmarshal(data))
|
||||
require.Equal(t, pExecResp.Data, expected)
|
||||
}
|
||||
|
||||
// ensures this returns a valid bech32 address and returns it
|
||||
func parseInitResponse(t *testing.T, data []byte) string {
|
||||
var pInstResp MsgInstantiateContractResponse
|
||||
require.NoError(t, pInstResp.Unmarshal(data))
|
||||
require.NotEmpty(t, pInstResp.Address)
|
||||
addr := pInstResp.Address
|
||||
// ensure this is a valid sdk address
|
||||
_, err := sdk.AccAddressFromBech32(addr)
|
||||
require.NoError(t, err)
|
||||
return addr
|
||||
}
|
||||
96
x/wasm/genesis_test.go
Normal file
96
x/wasm/genesis_test.go
Normal file
@ -0,0 +1,96 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInitGenesis(t *testing.T) {
|
||||
data := setupTest(t)
|
||||
|
||||
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
|
||||
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
|
||||
creator := data.faucet.NewFundedRandomAccount(data.ctx, deposit.Add(deposit...)...)
|
||||
fred := data.faucet.NewFundedRandomAccount(data.ctx, topUp...)
|
||||
|
||||
h := data.module.Route().Handler()
|
||||
q := data.module.LegacyQuerierHandler(nil)
|
||||
|
||||
msg := MsgStoreCode{
|
||||
Sender: creator.String(),
|
||||
WASMByteCode: testContract,
|
||||
}
|
||||
err := msg.ValidateBasic()
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := h(data.ctx, &msg)
|
||||
require.NoError(t, err)
|
||||
assertStoreCodeResponse(t, res.Data, 1)
|
||||
|
||||
_, _, bob := keyPubAddr()
|
||||
initMsg := initMsg{
|
||||
Verifier: fred,
|
||||
Beneficiary: bob,
|
||||
}
|
||||
initMsgBz, err := json.Marshal(initMsg)
|
||||
require.NoError(t, err)
|
||||
|
||||
initCmd := MsgInstantiateContract{
|
||||
Sender: creator.String(),
|
||||
CodeID: firstCodeID,
|
||||
Msg: initMsgBz,
|
||||
Funds: deposit,
|
||||
Label: "testing",
|
||||
}
|
||||
res, err = h(data.ctx, &initCmd)
|
||||
require.NoError(t, err)
|
||||
contractBech32Addr := parseInitResponse(t, res.Data)
|
||||
|
||||
execCmd := MsgExecuteContract{
|
||||
Sender: fred.String(),
|
||||
Contract: contractBech32Addr,
|
||||
Msg: []byte(`{"release":{}}`),
|
||||
Funds: topUp,
|
||||
}
|
||||
res, err = h(data.ctx, &execCmd)
|
||||
require.NoError(t, err)
|
||||
// from https://github.com/CosmWasm/cosmwasm/blob/master/contracts/hackatom/src/contract.rs#L167
|
||||
assertExecuteResponse(t, res.Data, []byte{0xf0, 0x0b, 0xaa})
|
||||
|
||||
// ensure all contract state is as after init
|
||||
assertCodeList(t, q, data.ctx, 1)
|
||||
assertCodeBytes(t, q, data.ctx, 1, testContract)
|
||||
|
||||
assertContractList(t, q, data.ctx, 1, []string{contractBech32Addr})
|
||||
assertContractInfo(t, q, data.ctx, contractBech32Addr, 1, creator)
|
||||
assertContractState(t, q, data.ctx, contractBech32Addr, state{
|
||||
Verifier: fred.String(),
|
||||
Beneficiary: bob.String(),
|
||||
Funder: creator.String(),
|
||||
})
|
||||
|
||||
// export into genstate
|
||||
genState := ExportGenesis(data.ctx, &data.keeper)
|
||||
|
||||
// create new app to import genstate into
|
||||
newData := setupTest(t)
|
||||
q2 := newData.module.LegacyQuerierHandler(nil)
|
||||
|
||||
// initialize new app with genstate
|
||||
InitGenesis(newData.ctx, &newData.keeper, *genState)
|
||||
|
||||
// run same checks again on newdata, to make sure it was reinitialized correctly
|
||||
assertCodeList(t, q2, newData.ctx, 1)
|
||||
assertCodeBytes(t, q2, newData.ctx, 1, testContract)
|
||||
|
||||
assertContractList(t, q2, newData.ctx, 1, []string{contractBech32Addr})
|
||||
assertContractInfo(t, q2, newData.ctx, contractBech32Addr, 1, creator)
|
||||
assertContractState(t, q2, newData.ctx, contractBech32Addr, state{
|
||||
Verifier: fred.String(),
|
||||
Beneficiary: bob.String(),
|
||||
Funder: creator.String(),
|
||||
})
|
||||
}
|
||||
77
x/wasm/handler.go
Normal file
77
x/wasm/handler.go
Normal file
@ -0,0 +1,77 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// NewHandler returns a handler for "wasm" type messages.
|
||||
func NewHandler(k types.ContractOpsKeeper) sdk.Handler {
|
||||
msgServer := keeper.NewMsgServerImpl(k)
|
||||
|
||||
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
||||
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
||||
|
||||
var (
|
||||
res proto.Message
|
||||
err error
|
||||
)
|
||||
switch msg := msg.(type) {
|
||||
case *MsgStoreCode: //nolint:typecheck
|
||||
res, err = msgServer.StoreCode(sdk.WrapSDKContext(ctx), msg)
|
||||
case *MsgInstantiateContract:
|
||||
res, err = msgServer.InstantiateContract(sdk.WrapSDKContext(ctx), msg)
|
||||
case *MsgInstantiateContract2:
|
||||
res, err = msgServer.InstantiateContract2(sdk.WrapSDKContext(ctx), msg)
|
||||
case *MsgExecuteContract:
|
||||
res, err = msgServer.ExecuteContract(sdk.WrapSDKContext(ctx), msg)
|
||||
case *MsgMigrateContract:
|
||||
res, err = msgServer.MigrateContract(sdk.WrapSDKContext(ctx), msg)
|
||||
case *MsgUpdateAdmin:
|
||||
res, err = msgServer.UpdateAdmin(sdk.WrapSDKContext(ctx), msg)
|
||||
case *MsgClearAdmin:
|
||||
res, err = msgServer.ClearAdmin(sdk.WrapSDKContext(ctx), msg)
|
||||
case *types.MsgUpdateInstantiateConfig:
|
||||
res, err = msgServer.UpdateInstantiateConfig(sdk.WrapSDKContext(ctx), msg)
|
||||
default:
|
||||
errMsg := fmt.Sprintf("unrecognized wasm message type: %T", msg)
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
|
||||
}
|
||||
|
||||
ctx = ctx.WithEventManager(filterMessageEvents(ctx))
|
||||
return sdk.WrapServiceResult(ctx, res, err)
|
||||
}
|
||||
}
|
||||
|
||||
// filterMessageEvents returns the same events with all of type == EventTypeMessage removed except
|
||||
// for wasm message types.
|
||||
// this is so only our top-level message event comes through
|
||||
func filterMessageEvents(ctx sdk.Context) *sdk.EventManager {
|
||||
m := sdk.NewEventManager()
|
||||
for _, e := range ctx.EventManager().Events() {
|
||||
if e.Type == sdk.EventTypeMessage &&
|
||||
!hasWasmModuleAttribute(e.Attributes) {
|
||||
continue
|
||||
}
|
||||
m.EmitEvent(e)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func hasWasmModuleAttribute(attrs []abci.EventAttribute) bool {
|
||||
for _, a := range attrs {
|
||||
if sdk.AttributeKeyModule == string(a.Key) &&
|
||||
types.ModuleName == string(a.Value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
357
x/wasm/ibc.go
Normal file
357
x/wasm/ibc.go
Normal file
@ -0,0 +1,357 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types"
|
||||
host "github.com/cosmos/ibc-go/v4/modules/core/24-host"
|
||||
ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
var _ porttypes.IBCModule = IBCHandler{}
|
||||
|
||||
// internal interface that is implemented by ibc middleware
|
||||
type appVersionGetter interface {
|
||||
// GetAppVersion returns the application level version with all middleware data stripped out
|
||||
GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool)
|
||||
}
|
||||
|
||||
type IBCHandler struct {
|
||||
keeper types.IBCContractKeeper
|
||||
channelKeeper types.ChannelKeeper
|
||||
appVersionGetter appVersionGetter
|
||||
}
|
||||
|
||||
func NewIBCHandler(k types.IBCContractKeeper, ck types.ChannelKeeper, vg appVersionGetter) IBCHandler {
|
||||
return IBCHandler{keeper: k, channelKeeper: ck, appVersionGetter: vg}
|
||||
}
|
||||
|
||||
// OnChanOpenInit implements the IBCModule interface
|
||||
func (i IBCHandler) OnChanOpenInit(
|
||||
ctx sdk.Context,
|
||||
order channeltypes.Order,
|
||||
connectionHops []string,
|
||||
portID string,
|
||||
channelID string,
|
||||
chanCap *capabilitytypes.Capability,
|
||||
counterParty channeltypes.Counterparty,
|
||||
version string,
|
||||
) (string, error) {
|
||||
// ensure port, version, capability
|
||||
if err := ValidateChannelParams(channelID); err != nil {
|
||||
return "", err
|
||||
}
|
||||
contractAddr, err := ContractFromPortID(portID)
|
||||
if err != nil {
|
||||
return "", sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
|
||||
msg := wasmvmtypes.IBCChannelOpenMsg{
|
||||
OpenInit: &wasmvmtypes.IBCOpenInit{
|
||||
Channel: wasmvmtypes.IBCChannel{
|
||||
Endpoint: wasmvmtypes.IBCEndpoint{PortID: portID, ChannelID: channelID},
|
||||
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{PortID: counterParty.PortId, ChannelID: counterParty.ChannelId},
|
||||
Order: order.String(),
|
||||
// DESIGN V3: this may be "" ??
|
||||
Version: version,
|
||||
ConnectionID: connectionHops[0], // At the moment this list must be of length 1. In the future multi-hop channels may be supported.
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Allow contracts to return a version (or default to proposed version if unset)
|
||||
acceptedVersion, err := i.keeper.OnOpenChannel(ctx, contractAddr, msg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if acceptedVersion == "" {
|
||||
acceptedVersion = version
|
||||
}
|
||||
|
||||
// Claim channel capability passed back by IBC module
|
||||
if err := i.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
|
||||
return "", sdkerrors.Wrap(err, "claim capability")
|
||||
}
|
||||
return acceptedVersion, nil
|
||||
}
|
||||
|
||||
// OnChanOpenTry implements the IBCModule interface
|
||||
func (i IBCHandler) OnChanOpenTry(
|
||||
ctx sdk.Context,
|
||||
order channeltypes.Order,
|
||||
connectionHops []string,
|
||||
portID, channelID string,
|
||||
chanCap *capabilitytypes.Capability,
|
||||
counterParty channeltypes.Counterparty,
|
||||
counterpartyVersion string,
|
||||
) (string, error) {
|
||||
// ensure port, version, capability
|
||||
if err := ValidateChannelParams(channelID); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
contractAddr, err := ContractFromPortID(portID)
|
||||
if err != nil {
|
||||
return "", sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
|
||||
msg := wasmvmtypes.IBCChannelOpenMsg{
|
||||
OpenTry: &wasmvmtypes.IBCOpenTry{
|
||||
Channel: wasmvmtypes.IBCChannel{
|
||||
Endpoint: wasmvmtypes.IBCEndpoint{PortID: portID, ChannelID: channelID},
|
||||
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{PortID: counterParty.PortId, ChannelID: counterParty.ChannelId},
|
||||
Order: order.String(),
|
||||
Version: counterpartyVersion,
|
||||
ConnectionID: connectionHops[0], // At the moment this list must be of length 1. In the future multi-hop channels may be supported.
|
||||
},
|
||||
CounterpartyVersion: counterpartyVersion,
|
||||
},
|
||||
}
|
||||
|
||||
// Allow contracts to return a version (or default to counterpartyVersion if unset)
|
||||
version, err := i.keeper.OnOpenChannel(ctx, contractAddr, msg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if version == "" {
|
||||
version = counterpartyVersion
|
||||
}
|
||||
|
||||
// Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos
|
||||
// (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry)
|
||||
// If module can already authenticate the capability then module already owns it, so we don't need to claim
|
||||
// Otherwise, module does not have channel capability, and we must claim it from IBC
|
||||
if !i.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
|
||||
// Only claim channel capability passed back by IBC module if we do not already own it
|
||||
if err := i.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
|
||||
return "", sdkerrors.Wrap(err, "claim capability")
|
||||
}
|
||||
}
|
||||
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// OnChanOpenAck implements the IBCModule interface
|
||||
func (i IBCHandler) OnChanOpenAck(
|
||||
ctx sdk.Context,
|
||||
portID, channelID string,
|
||||
counterpartyChannelID string,
|
||||
counterpartyVersion string,
|
||||
) error {
|
||||
contractAddr, err := ContractFromPortID(portID)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
channelInfo.Counterparty.ChannelId = counterpartyChannelID
|
||||
|
||||
appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
|
||||
msg := wasmvmtypes.IBCChannelConnectMsg{
|
||||
OpenAck: &wasmvmtypes.IBCOpenAck{
|
||||
Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion),
|
||||
CounterpartyVersion: counterpartyVersion,
|
||||
},
|
||||
}
|
||||
return i.keeper.OnConnectChannel(ctx, contractAddr, msg)
|
||||
}
|
||||
|
||||
// OnChanOpenConfirm implements the IBCModule interface
|
||||
func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error {
|
||||
contractAddr, err := ContractFromPortID(portID)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
msg := wasmvmtypes.IBCChannelConnectMsg{
|
||||
OpenConfirm: &wasmvmtypes.IBCOpenConfirm{
|
||||
Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion),
|
||||
},
|
||||
}
|
||||
return i.keeper.OnConnectChannel(ctx, contractAddr, msg)
|
||||
}
|
||||
|
||||
// OnChanCloseInit implements the IBCModule interface
|
||||
func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error {
|
||||
contractAddr, err := ContractFromPortID(portID)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
|
||||
msg := wasmvmtypes.IBCChannelCloseMsg{
|
||||
CloseInit: &wasmvmtypes.IBCCloseInit{Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion)},
|
||||
}
|
||||
err = i.keeper.OnCloseChannel(ctx, contractAddr, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// emit events?
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// OnChanCloseConfirm implements the IBCModule interface
|
||||
func (i IBCHandler) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error {
|
||||
// counterparty has closed the channel
|
||||
contractAddr, err := ContractFromPortID(portID)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID)
|
||||
}
|
||||
|
||||
msg := wasmvmtypes.IBCChannelCloseMsg{
|
||||
CloseConfirm: &wasmvmtypes.IBCCloseConfirm{Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion)},
|
||||
}
|
||||
err = i.keeper.OnCloseChannel(ctx, contractAddr, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// emit events?
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func toWasmVMChannel(portID, channelID string, channelInfo channeltypes.Channel, appVersion string) wasmvmtypes.IBCChannel {
|
||||
return wasmvmtypes.IBCChannel{
|
||||
Endpoint: wasmvmtypes.IBCEndpoint{PortID: portID, ChannelID: channelID},
|
||||
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{PortID: channelInfo.Counterparty.PortId, ChannelID: channelInfo.Counterparty.ChannelId},
|
||||
Order: channelInfo.Ordering.String(),
|
||||
Version: appVersion,
|
||||
ConnectionID: channelInfo.ConnectionHops[0], // At the moment this list must be of length 1. In the future multi-hop channels may be supported.
|
||||
}
|
||||
}
|
||||
|
||||
// OnRecvPacket implements the IBCModule interface
|
||||
func (i IBCHandler) OnRecvPacket(
|
||||
ctx sdk.Context,
|
||||
packet channeltypes.Packet,
|
||||
relayer sdk.AccAddress,
|
||||
) ibcexported.Acknowledgement {
|
||||
contractAddr, err := ContractFromPortID(packet.DestinationPort)
|
||||
if err != nil {
|
||||
return channeltypes.NewErrorAcknowledgement(sdkerrors.Wrapf(err, "contract port id"))
|
||||
}
|
||||
msg := wasmvmtypes.IBCPacketReceiveMsg{Packet: newIBCPacket(packet), Relayer: relayer.String()}
|
||||
ack, err := i.keeper.OnRecvPacket(ctx, contractAddr, msg)
|
||||
if err != nil {
|
||||
return channeltypes.NewErrorAcknowledgement(err)
|
||||
}
|
||||
return ContractConfirmStateAck(ack)
|
||||
}
|
||||
|
||||
var _ ibcexported.Acknowledgement = ContractConfirmStateAck{}
|
||||
|
||||
type ContractConfirmStateAck []byte
|
||||
|
||||
func (w ContractConfirmStateAck) Success() bool {
|
||||
return true // always commit state
|
||||
}
|
||||
|
||||
func (w ContractConfirmStateAck) Acknowledgement() []byte {
|
||||
return w
|
||||
}
|
||||
|
||||
// OnAcknowledgementPacket implements the IBCModule interface
|
||||
func (i IBCHandler) OnAcknowledgementPacket(
|
||||
ctx sdk.Context,
|
||||
packet channeltypes.Packet,
|
||||
acknowledgement []byte,
|
||||
relayer sdk.AccAddress,
|
||||
) error {
|
||||
contractAddr, err := ContractFromPortID(packet.SourcePort)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
|
||||
err = i.keeper.OnAckPacket(ctx, contractAddr, wasmvmtypes.IBCPacketAckMsg{
|
||||
Acknowledgement: wasmvmtypes.IBCAcknowledgement{Data: acknowledgement},
|
||||
OriginalPacket: newIBCPacket(packet),
|
||||
Relayer: relayer.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "on ack")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnTimeoutPacket implements the IBCModule interface
|
||||
func (i IBCHandler) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error {
|
||||
contractAddr, err := ContractFromPortID(packet.SourcePort)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(err, "contract port id")
|
||||
}
|
||||
msg := wasmvmtypes.IBCPacketTimeoutMsg{Packet: newIBCPacket(packet), Relayer: relayer.String()}
|
||||
err = i.keeper.OnTimeoutPacket(ctx, contractAddr, msg)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "on timeout")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newIBCPacket(packet channeltypes.Packet) wasmvmtypes.IBCPacket {
|
||||
timeout := wasmvmtypes.IBCTimeout{
|
||||
Timestamp: packet.TimeoutTimestamp,
|
||||
}
|
||||
if !packet.TimeoutHeight.IsZero() {
|
||||
timeout.Block = &wasmvmtypes.IBCTimeoutBlock{
|
||||
Height: packet.TimeoutHeight.RevisionHeight,
|
||||
Revision: packet.TimeoutHeight.RevisionNumber,
|
||||
}
|
||||
}
|
||||
|
||||
return wasmvmtypes.IBCPacket{
|
||||
Data: packet.Data,
|
||||
Src: wasmvmtypes.IBCEndpoint{ChannelID: packet.SourceChannel, PortID: packet.SourcePort},
|
||||
Dest: wasmvmtypes.IBCEndpoint{ChannelID: packet.DestinationChannel, PortID: packet.DestinationPort},
|
||||
Sequence: packet.Sequence,
|
||||
Timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func ValidateChannelParams(channelID string) error {
|
||||
// NOTE: for escrow address security only 2^32 channels are allowed to be created
|
||||
// Issue: https://github.com/cosmos/cosmos-sdk/issues/7737
|
||||
channelSequence, err := channeltypes.ParseChannelSequence(channelID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if channelSequence > math.MaxUint32 {
|
||||
return sdkerrors.Wrapf(types.ErrMaxIBCChannels, "channel sequence %d is greater than max allowed transfer channels %d", channelSequence, math.MaxUint32)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
126
x/wasm/ibc_integration_test.go
Normal file
126
x/wasm/ibc_integration_test.go
Normal file
@ -0,0 +1,126 @@
|
||||
package wasm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
wasmvm "github.com/CosmWasm/wasmvm"
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
ibctesting "github.com/cosmos/ibc-go/v4/testing"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
wasmibctesting "github.com/cerc-io/laconicd/x/wasm/ibctesting"
|
||||
wasmkeeper "github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting"
|
||||
)
|
||||
|
||||
func TestOnChanOpenInitVersion(t *testing.T) {
|
||||
const startVersion = "v1"
|
||||
specs := map[string]struct {
|
||||
contractRsp *wasmvmtypes.IBC3ChannelOpenResponse
|
||||
expVersion string
|
||||
}{
|
||||
"different version": {
|
||||
contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{Version: "v2"},
|
||||
expVersion: "v2",
|
||||
},
|
||||
"no response": {
|
||||
expVersion: startVersion,
|
||||
},
|
||||
"empty result": {
|
||||
contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{},
|
||||
expVersion: startVersion,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
myContract := &wasmtesting.MockIBCContractCallbacks{
|
||||
IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) {
|
||||
return spec.contractRsp, 0, nil
|
||||
},
|
||||
}
|
||||
var (
|
||||
chainAOpts = []wasmkeeper.Option{
|
||||
wasmkeeper.WithWasmEngine(
|
||||
wasmtesting.NewIBCContractMockWasmer(myContract)),
|
||||
}
|
||||
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts)
|
||||
chainA = coordinator.GetChain(wasmibctesting.GetChainID(0))
|
||||
chainB = coordinator.GetChain(wasmibctesting.GetChainID(1))
|
||||
myContractAddr = chainA.SeedNewContractInstance()
|
||||
contractInfo = chainA.App.WasmKeeper.GetContractInfo(chainA.GetContext(), myContractAddr)
|
||||
)
|
||||
|
||||
path := wasmibctesting.NewPath(chainA, chainB)
|
||||
coordinator.SetupConnections(path)
|
||||
|
||||
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
||||
PortID: contractInfo.IBCPortID,
|
||||
Version: startVersion,
|
||||
Order: channeltypes.UNORDERED,
|
||||
}
|
||||
require.NoError(t, path.EndpointA.ChanOpenInit())
|
||||
assert.Equal(t, spec.expVersion, path.EndpointA.ChannelConfig.Version)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOnChanOpenTryVersion(t *testing.T) {
|
||||
const startVersion = ibctransfertypes.Version
|
||||
specs := map[string]struct {
|
||||
contractRsp *wasmvmtypes.IBC3ChannelOpenResponse
|
||||
expVersion string
|
||||
}{
|
||||
"different version": {
|
||||
contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{Version: "v2"},
|
||||
expVersion: "v2",
|
||||
},
|
||||
"no response": {
|
||||
expVersion: startVersion,
|
||||
},
|
||||
"empty result": {
|
||||
contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{},
|
||||
expVersion: startVersion,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
myContract := &wasmtesting.MockIBCContractCallbacks{
|
||||
IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) {
|
||||
return spec.contractRsp, 0, nil
|
||||
},
|
||||
}
|
||||
var (
|
||||
chainAOpts = []wasmkeeper.Option{
|
||||
wasmkeeper.WithWasmEngine(
|
||||
wasmtesting.NewIBCContractMockWasmer(myContract)),
|
||||
}
|
||||
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts)
|
||||
chainA = coordinator.GetChain(wasmibctesting.GetChainID(0))
|
||||
chainB = coordinator.GetChain(wasmibctesting.GetChainID(1))
|
||||
myContractAddr = chainA.SeedNewContractInstance()
|
||||
contractInfo = chainA.ContractInfo(myContractAddr)
|
||||
)
|
||||
|
||||
path := wasmibctesting.NewPath(chainA, chainB)
|
||||
coordinator.SetupConnections(path)
|
||||
|
||||
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
||||
PortID: contractInfo.IBCPortID,
|
||||
Version: startVersion,
|
||||
Order: channeltypes.UNORDERED,
|
||||
}
|
||||
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
||||
PortID: ibctransfertypes.PortID,
|
||||
Version: ibctransfertypes.Version,
|
||||
Order: channeltypes.UNORDERED,
|
||||
}
|
||||
|
||||
require.NoError(t, path.EndpointB.ChanOpenInit())
|
||||
require.NoError(t, path.EndpointA.ChanOpenTry())
|
||||
assert.Equal(t, spec.expVersion, path.EndpointA.ChannelConfig.Version)
|
||||
})
|
||||
}
|
||||
}
|
||||
124
x/wasm/ibc_reflect_test.go
Normal file
124
x/wasm/ibc_reflect_test.go
Normal file
@ -0,0 +1,124 @@
|
||||
package wasm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
ibctesting "github.com/cosmos/ibc-go/v4/testing"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
wasmibctesting "github.com/cerc-io/laconicd/x/wasm/ibctesting"
|
||||
wasmkeeper "github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
)
|
||||
|
||||
func TestIBCReflectContract(t *testing.T) {
|
||||
// scenario:
|
||||
// chain A: ibc_reflect_send.wasm
|
||||
// chain B: reflect.wasm + ibc_reflect.wasm
|
||||
//
|
||||
// Chain A "ibc_reflect_send" sends a IBC packet "on channel connect" event to chain B "ibc_reflect"
|
||||
// "ibc_reflect" sends a submessage to "reflect" which is returned as submessage.
|
||||
|
||||
var (
|
||||
coordinator = wasmibctesting.NewCoordinator(t, 2)
|
||||
chainA = coordinator.GetChain(wasmibctesting.GetChainID(0))
|
||||
chainB = coordinator.GetChain(wasmibctesting.GetChainID(1))
|
||||
)
|
||||
coordinator.CommitBlock(chainA, chainB)
|
||||
|
||||
initMsg := []byte(`{}`)
|
||||
codeID := chainA.StoreCodeFile("./keeper/testdata/ibc_reflect_send.wasm").CodeID
|
||||
sendContractAddr := chainA.InstantiateContract(codeID, initMsg)
|
||||
|
||||
reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect.wasm").CodeID
|
||||
initMsg = wasmkeeper.IBCReflectInitMsg{
|
||||
ReflectCodeID: reflectID,
|
||||
}.GetBytes(t)
|
||||
codeID = chainB.StoreCodeFile("./keeper/testdata/ibc_reflect.wasm").CodeID
|
||||
|
||||
reflectContractAddr := chainB.InstantiateContract(codeID, initMsg)
|
||||
var (
|
||||
sourcePortID = chainA.ContractInfo(sendContractAddr).IBCPortID
|
||||
counterpartPortID = chainB.ContractInfo(reflectContractAddr).IBCPortID
|
||||
)
|
||||
coordinator.CommitBlock(chainA, chainB)
|
||||
coordinator.UpdateTime()
|
||||
|
||||
require.Equal(t, chainA.CurrentHeader.Time, chainB.CurrentHeader.Time)
|
||||
path := wasmibctesting.NewPath(chainA, chainB)
|
||||
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
||||
PortID: sourcePortID,
|
||||
Version: "ibc-reflect-v1",
|
||||
Order: channeltypes.ORDERED,
|
||||
}
|
||||
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
||||
PortID: counterpartPortID,
|
||||
Version: "ibc-reflect-v1",
|
||||
Order: channeltypes.ORDERED,
|
||||
}
|
||||
|
||||
coordinator.SetupConnections(path)
|
||||
coordinator.CreateChannels(path)
|
||||
|
||||
// TODO: query both contracts directly to ensure they have registered the proper connection
|
||||
// (and the chainB has created a reflect contract)
|
||||
|
||||
// there should be one packet to relay back and forth (whoami)
|
||||
// TODO: how do I find the packet that was previously sent by the smart contract?
|
||||
// Coordinator.RecvPacket requires channeltypes.Packet as input?
|
||||
// Given the source (portID, channelID), we should be able to count how many packets are pending, query the data
|
||||
// and submit them to the other side (same with acks). This is what the real relayer does. I guess the test framework doesn't?
|
||||
|
||||
// Update: I dug through the code, especially channel.Keeper.SendPacket, and it only writes a commitment
|
||||
// only writes I see: https://github.com/cosmos/cosmos-sdk/blob/31fdee0228bd6f3e787489c8e4434aabc8facb7d/x/ibc/core/04-channel/keeper/packet.go#L115-L116
|
||||
// commitment is hashed packet: https://github.com/cosmos/cosmos-sdk/blob/31fdee0228bd6f3e787489c8e4434aabc8facb7d/x/ibc/core/04-channel/types/packet.go#L14-L34
|
||||
// how is the relayer supposed to get the original packet data??
|
||||
// eg. ibctransfer doesn't store the packet either: https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc/applications/transfer/keeper/relay.go#L145-L162
|
||||
// ... or I guess the original packet data is only available in the event logs????
|
||||
// https://github.com/cosmos/cosmos-sdk/blob/31fdee0228bd6f3e787489c8e4434aabc8facb7d/x/ibc/core/04-channel/keeper/packet.go#L121-L132
|
||||
|
||||
// ensure the expected packet was prepared, and relay it
|
||||
require.Equal(t, 1, len(chainA.PendingSendPackets))
|
||||
require.Equal(t, 0, len(chainB.PendingSendPackets))
|
||||
err := coordinator.RelayAndAckPendingPackets(path)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(chainA.PendingSendPackets))
|
||||
require.Equal(t, 0, len(chainB.PendingSendPackets))
|
||||
|
||||
// let's query the source contract and make sure it registered an address
|
||||
query := ReflectSendQueryMsg{Account: &AccountQuery{ChannelID: path.EndpointA.ChannelID}}
|
||||
var account AccountResponse
|
||||
err = chainA.SmartQuery(sendContractAddr.String(), query, &account)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, account.RemoteAddr)
|
||||
require.Empty(t, account.RemoteBalance)
|
||||
|
||||
// close channel
|
||||
coordinator.CloseChannel(path)
|
||||
|
||||
// let's query the source contract and make sure it registered an address
|
||||
account = AccountResponse{}
|
||||
err = chainA.SmartQuery(sendContractAddr.String(), query, &account)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "not found")
|
||||
}
|
||||
|
||||
type ReflectSendQueryMsg struct {
|
||||
Admin *struct{} `json:"admin,omitempty"`
|
||||
ListAccounts *struct{} `json:"list_accounts,omitempty"`
|
||||
Account *AccountQuery `json:"account,omitempty"`
|
||||
}
|
||||
|
||||
type AccountQuery struct {
|
||||
ChannelID string `json:"channel_id"`
|
||||
}
|
||||
|
||||
type AccountResponse struct {
|
||||
LastUpdateTime uint64 `json:"last_update_time,string"`
|
||||
RemoteAddr string `json:"remote_addr"`
|
||||
RemoteBalance wasmvmtypes.Coins `json:"remote_balance"`
|
||||
}
|
||||
82
x/wasm/ibc_test.go
Normal file
82
x/wasm/ibc_test.go
Normal file
@ -0,0 +1,82 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMapToWasmVMIBCPacket(t *testing.T) {
|
||||
var myTimestamp uint64 = 1
|
||||
specs := map[string]struct {
|
||||
src channeltypes.Packet
|
||||
exp wasmvmtypes.IBCPacket
|
||||
}{
|
||||
"with height timeout": {
|
||||
src: IBCPacketFixture(),
|
||||
exp: wasmvmtypes.IBCPacket{
|
||||
Data: []byte("myData"),
|
||||
Src: wasmvmtypes.IBCEndpoint{PortID: "srcPort", ChannelID: "channel-1"},
|
||||
Dest: wasmvmtypes.IBCEndpoint{PortID: "destPort", ChannelID: "channel-2"},
|
||||
Sequence: 1,
|
||||
Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Height: 1, Revision: 2}},
|
||||
},
|
||||
},
|
||||
"with time timeout": {
|
||||
src: IBCPacketFixture(func(p *channeltypes.Packet) {
|
||||
p.TimeoutTimestamp = myTimestamp
|
||||
p.TimeoutHeight = clienttypes.Height{}
|
||||
}),
|
||||
exp: wasmvmtypes.IBCPacket{
|
||||
Data: []byte("myData"),
|
||||
Src: wasmvmtypes.IBCEndpoint{PortID: "srcPort", ChannelID: "channel-1"},
|
||||
Dest: wasmvmtypes.IBCEndpoint{PortID: "destPort", ChannelID: "channel-2"},
|
||||
Sequence: 1,
|
||||
Timeout: wasmvmtypes.IBCTimeout{Timestamp: myTimestamp},
|
||||
},
|
||||
}, "with time and height timeout": {
|
||||
src: IBCPacketFixture(func(p *channeltypes.Packet) {
|
||||
p.TimeoutTimestamp = myTimestamp
|
||||
}),
|
||||
exp: wasmvmtypes.IBCPacket{
|
||||
Data: []byte("myData"),
|
||||
Src: wasmvmtypes.IBCEndpoint{PortID: "srcPort", ChannelID: "channel-1"},
|
||||
Dest: wasmvmtypes.IBCEndpoint{PortID: "destPort", ChannelID: "channel-2"},
|
||||
Sequence: 1,
|
||||
Timeout: wasmvmtypes.IBCTimeout{
|
||||
Block: &wasmvmtypes.IBCTimeoutBlock{Height: 1, Revision: 2},
|
||||
Timestamp: myTimestamp,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := newIBCPacket(spec.src)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func IBCPacketFixture(mutators ...func(p *channeltypes.Packet)) channeltypes.Packet {
|
||||
r := channeltypes.Packet{
|
||||
Sequence: 1,
|
||||
SourcePort: "srcPort",
|
||||
SourceChannel: "channel-1",
|
||||
DestinationPort: "destPort",
|
||||
DestinationChannel: "channel-2",
|
||||
Data: []byte("myData"),
|
||||
TimeoutHeight: clienttypes.Height{
|
||||
RevisionHeight: 1,
|
||||
RevisionNumber: 2,
|
||||
},
|
||||
TimeoutTimestamp: 0,
|
||||
}
|
||||
for _, m := range mutators {
|
||||
m(&r)
|
||||
}
|
||||
return r
|
||||
}
|
||||
2
x/wasm/ibctesting/README.md
Normal file
2
x/wasm/ibctesting/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# testing package for ibc
|
||||
Customized version of cosmos-sdk x/ibc/testing
|
||||
594
x/wasm/ibctesting/chain.go
Normal file
594
x/wasm/ibctesting/chain.go
Normal file
@ -0,0 +1,594 @@
|
||||
package ibctesting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
|
||||
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking/teststaking"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types"
|
||||
host "github.com/cosmos/ibc-go/v4/modules/core/24-host"
|
||||
"github.com/cosmos/ibc-go/v4/modules/core/exported"
|
||||
"github.com/cosmos/ibc-go/v4/modules/core/types"
|
||||
ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"
|
||||
ibctesting "github.com/cosmos/ibc-go/v4/testing"
|
||||
"github.com/cosmos/ibc-go/v4/testing/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmprotoversion "github.com/tendermint/tendermint/proto/tendermint/version"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
tmversion "github.com/tendermint/tendermint/version"
|
||||
|
||||
"github.com/cerc-io/laconicd/app"
|
||||
"github.com/cerc-io/laconicd/app/params"
|
||||
"github.com/cerc-io/laconicd/x/wasm"
|
||||
)
|
||||
|
||||
var MaxAccounts = 10
|
||||
|
||||
type SenderAccount struct {
|
||||
SenderPrivKey cryptotypes.PrivKey
|
||||
SenderAccount authtypes.AccountI
|
||||
}
|
||||
|
||||
// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI
|
||||
// header and the validators of the TestChain. It also contains a field called ChainID. This
|
||||
// is the clientID that *other* chains use to refer to this TestChain. The SenderAccount
|
||||
// is used for delivering transactions through the application state.
|
||||
// NOTE: the actual application uses an empty chain-id for ease of testing.
|
||||
type TestChain struct {
|
||||
t *testing.T
|
||||
|
||||
Coordinator *Coordinator
|
||||
App *app.WasmApp
|
||||
ChainID string
|
||||
LastHeader *ibctmtypes.Header // header for last block height committed
|
||||
CurrentHeader tmproto.Header // header for current block height
|
||||
QueryServer types.QueryServer
|
||||
TxConfig client.TxConfig
|
||||
Codec codec.BinaryCodec
|
||||
|
||||
Vals *tmtypes.ValidatorSet
|
||||
NextVals *tmtypes.ValidatorSet
|
||||
|
||||
// Signers is a map from validator address to the PrivValidator
|
||||
// The map is converted into an array that is the same order as the validators right before signing commit
|
||||
// This ensures that signers will always be in correct order even as validator powers change.
|
||||
// If a test adds a new validator after chain creation, then the signer map must be updated to include
|
||||
// the new PrivValidator entry.
|
||||
Signers map[string]tmtypes.PrivValidator
|
||||
|
||||
// autogenerated sender private key
|
||||
SenderPrivKey cryptotypes.PrivKey
|
||||
SenderAccount authtypes.AccountI
|
||||
SenderAccounts []SenderAccount
|
||||
|
||||
PendingSendPackets []channeltypes.Packet
|
||||
}
|
||||
|
||||
type PacketAck struct {
|
||||
Packet channeltypes.Packet
|
||||
Ack []byte
|
||||
}
|
||||
|
||||
// NewTestChain initializes a new test chain with a default of 4 validators
|
||||
// Use this function if the tests do not need custom control over the validator set
|
||||
func NewTestChain(t *testing.T, coord *Coordinator, chainID string, opts ...wasm.Option) *TestChain {
|
||||
// generate validators private/public key
|
||||
var (
|
||||
validatorsPerChain = 4
|
||||
validators = make([]*tmtypes.Validator, 0, validatorsPerChain)
|
||||
signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain)
|
||||
)
|
||||
|
||||
for i := 0; i < validatorsPerChain; i++ {
|
||||
privVal := mock.NewPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
validators = append(validators, tmtypes.NewValidator(pubKey, 1))
|
||||
signersByAddress[pubKey.Address().String()] = privVal
|
||||
}
|
||||
|
||||
// construct validator set;
|
||||
// Note that the validators are sorted by voting power
|
||||
// or, if equal, by address lexical order
|
||||
valSet := tmtypes.NewValidatorSet(validators)
|
||||
|
||||
return NewTestChainWithValSet(t, coord, chainID, valSet, signersByAddress, opts...)
|
||||
}
|
||||
|
||||
// NewTestChainWithValSet initializes a new TestChain instance with the given validator set
|
||||
// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of
|
||||
// bond denom to use for tests.
|
||||
//
|
||||
// The first block height is committed to state in order to allow for client creations on
|
||||
// counterparty chains. The TestChain will return with a block height starting at 2.
|
||||
//
|
||||
// Time management is handled by the Coordinator in order to ensure synchrony between chains.
|
||||
// Each update of any chain increments the block header time for all chains by 5 seconds.
|
||||
//
|
||||
// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this
|
||||
// constructor function.
|
||||
//
|
||||
// CONTRACT: Validator array must be provided in the order expected by Tendermint.
|
||||
// i.e. sorted first by power and then lexicographically by address.
|
||||
func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator, opts ...wasm.Option) *TestChain {
|
||||
genAccs := []authtypes.GenesisAccount{}
|
||||
genBals := []banktypes.Balance{}
|
||||
senderAccs := []SenderAccount{}
|
||||
|
||||
// generate genesis accounts
|
||||
for i := 0; i < MaxAccounts; i++ {
|
||||
senderPrivKey := secp256k1.GenPrivKey()
|
||||
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0)
|
||||
amount, ok := sdk.NewIntFromString("10000000000000000000")
|
||||
require.True(t, ok)
|
||||
|
||||
// add sender account
|
||||
balance := banktypes.Balance{
|
||||
Address: acc.GetAddress().String(),
|
||||
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)),
|
||||
}
|
||||
|
||||
genAccs = append(genAccs, acc)
|
||||
genBals = append(genBals, balance)
|
||||
|
||||
senderAcc := SenderAccount{
|
||||
SenderAccount: acc,
|
||||
SenderPrivKey: senderPrivKey,
|
||||
}
|
||||
|
||||
senderAccs = append(senderAccs, senderAcc)
|
||||
}
|
||||
|
||||
wasmApp := app.SetupWithGenesisValSet(t, valSet, genAccs, chainID, opts, genBals...)
|
||||
|
||||
// create current header and call begin block
|
||||
header := tmproto.Header{
|
||||
ChainID: chainID,
|
||||
Height: 1,
|
||||
Time: coord.CurrentTime.UTC(),
|
||||
}
|
||||
|
||||
txConfig := params.MakeEncodingConfig().TxConfig
|
||||
|
||||
// create an account to send transactions from
|
||||
chain := &TestChain{
|
||||
t: t,
|
||||
Coordinator: coord,
|
||||
ChainID: chainID,
|
||||
App: wasmApp,
|
||||
CurrentHeader: header,
|
||||
QueryServer: wasmApp.IBCKeeper,
|
||||
TxConfig: txConfig,
|
||||
Codec: wasmApp.AppCodec(),
|
||||
Vals: valSet,
|
||||
NextVals: valSet,
|
||||
Signers: signers,
|
||||
SenderPrivKey: senderAccs[0].SenderPrivKey,
|
||||
SenderAccount: senderAccs[0].SenderAccount,
|
||||
SenderAccounts: senderAccs,
|
||||
}
|
||||
|
||||
coord.CommitBlock(chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
// GetContext returns the current context for the application.
|
||||
func (chain *TestChain) GetContext() sdk.Context {
|
||||
return chain.App.BaseApp.NewContext(false, chain.CurrentHeader)
|
||||
}
|
||||
|
||||
// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof
|
||||
// for the query and the height at which the proof will succeed on a tendermint verifier.
|
||||
func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) {
|
||||
return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight())
|
||||
}
|
||||
|
||||
// QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof
|
||||
// for the query and the height at which the proof will succeed on a tendermint verifier.
|
||||
func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) {
|
||||
res := chain.App.Query(abci.RequestQuery{
|
||||
Path: fmt.Sprintf("store/%s/key", host.StoreKey),
|
||||
Height: height - 1,
|
||||
Data: key,
|
||||
Prove: true,
|
||||
})
|
||||
|
||||
merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps)
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
proof, err := chain.App.AppCodec().Marshal(&merkleProof)
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
revision := clienttypes.ParseChainID(chain.ChainID)
|
||||
|
||||
// proof height + 1 is returned as the proof created corresponds to the height the proof
|
||||
// was created in the IAVL tree. Tendermint and subsequently the clients that rely on it
|
||||
// have heights 1 above the IAVL tree. Thus we return proof height + 1
|
||||
return proof, clienttypes.NewHeight(revision, uint64(res.Height)+1)
|
||||
}
|
||||
|
||||
// QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof
|
||||
// for the query and the height at which the proof will succeed on a tendermint verifier.
|
||||
func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) {
|
||||
res := chain.App.Query(abci.RequestQuery{
|
||||
Path: "store/upgrade/key",
|
||||
Height: int64(height - 1),
|
||||
Data: key,
|
||||
Prove: true,
|
||||
})
|
||||
|
||||
merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps)
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
proof, err := chain.App.AppCodec().Marshal(&merkleProof)
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
revision := clienttypes.ParseChainID(chain.ChainID)
|
||||
|
||||
// proof height + 1 is returned as the proof created corresponds to the height the proof
|
||||
// was created in the IAVL tree. Tendermint and subsequently the clients that rely on it
|
||||
// have heights 1 above the IAVL tree. Thus we return proof height + 1
|
||||
return proof, clienttypes.NewHeight(revision, uint64(res.Height+1))
|
||||
}
|
||||
|
||||
// QueryConsensusStateProof performs an abci query for a consensus state
|
||||
// stored on the given clientID. The proof and consensusHeight are returned.
|
||||
func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) {
|
||||
clientState := chain.GetClientState(clientID)
|
||||
|
||||
consensusHeight := clientState.GetLatestHeight().(clienttypes.Height)
|
||||
consensusKey := host.FullConsensusStateKey(clientID, consensusHeight)
|
||||
proofConsensus, _ := chain.QueryProof(consensusKey)
|
||||
|
||||
return proofConsensus, consensusHeight
|
||||
}
|
||||
|
||||
// NextBlock sets the last header to the current header and increments the current header to be
|
||||
// at the next block height. It does not update the time as that is handled by the Coordinator.
|
||||
// It will call Endblock and Commit and apply the validator set changes to the next validators
|
||||
// of the next block being created. This follows the Tendermint protocol of applying valset changes
|
||||
// returned on block `n` to the validators of block `n+2`.
|
||||
// It calls BeginBlock with the new block created before returning.
|
||||
func (chain *TestChain) NextBlock() {
|
||||
res := chain.App.EndBlock(abci.RequestEndBlock{Height: chain.CurrentHeader.Height})
|
||||
|
||||
chain.App.Commit()
|
||||
|
||||
// set the last header to the current header
|
||||
// use nil trusted fields
|
||||
chain.LastHeader = chain.CurrentTMClientHeader()
|
||||
|
||||
// val set changes returned from previous block get applied to the next validators
|
||||
// of this block. See tendermint spec for details.
|
||||
chain.Vals = chain.NextVals
|
||||
chain.NextVals = ibctesting.ApplyValSetChanges(chain.t, chain.Vals, res.ValidatorUpdates)
|
||||
|
||||
// increment the current header
|
||||
chain.CurrentHeader = tmproto.Header{
|
||||
ChainID: chain.ChainID,
|
||||
Height: chain.App.LastBlockHeight() + 1,
|
||||
AppHash: chain.App.LastCommitID().Hash,
|
||||
// NOTE: the time is increased by the coordinator to maintain time synchrony amongst
|
||||
// chains.
|
||||
Time: chain.CurrentHeader.Time,
|
||||
ValidatorsHash: chain.Vals.Hash(),
|
||||
NextValidatorsHash: chain.NextVals.Hash(),
|
||||
}
|
||||
|
||||
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
|
||||
}
|
||||
|
||||
// sendMsgs delivers a transaction through the application without returning the result.
|
||||
func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error {
|
||||
_, err := chain.SendMsgs(msgs...)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendMsgs delivers a transaction through the application. It updates the senders sequence
|
||||
// number and updates the TestChain's headers. It returns the result and error if one
|
||||
// occurred.
|
||||
func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) {
|
||||
// ensure the chain has the latest time
|
||||
chain.Coordinator.UpdateTimeForChain(chain)
|
||||
|
||||
_, r, err := app.SignAndDeliver(
|
||||
chain.t,
|
||||
chain.TxConfig,
|
||||
chain.App.BaseApp,
|
||||
chain.GetContext().BlockHeader(),
|
||||
msgs,
|
||||
chain.ChainID,
|
||||
[]uint64{chain.SenderAccount.GetAccountNumber()},
|
||||
[]uint64{chain.SenderAccount.GetSequence()},
|
||||
chain.SenderPrivKey,
|
||||
)
|
||||
|
||||
// NextBlock calls app.Commit()
|
||||
chain.NextBlock()
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
|
||||
// increment sequence for successful transaction execution
|
||||
err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chain.Coordinator.IncrementTime()
|
||||
|
||||
chain.captureIBCEvents(r)
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (chain *TestChain) captureIBCEvents(r *sdk.Result) {
|
||||
toSend := getSendPackets(r.Events)
|
||||
if len(toSend) > 0 {
|
||||
// Keep a queue on the chain that we can relay in tests
|
||||
chain.PendingSendPackets = append(chain.PendingSendPackets, toSend...)
|
||||
}
|
||||
}
|
||||
|
||||
// GetClientState retrieves the client state for the provided clientID. The client is
|
||||
// expected to exist otherwise testing will fail.
|
||||
func (chain *TestChain) GetClientState(clientID string) exported.ClientState {
|
||||
clientState, found := chain.App.IBCKeeper.ClientKeeper.GetClientState(chain.GetContext(), clientID)
|
||||
require.True(chain.t, found)
|
||||
|
||||
return clientState
|
||||
}
|
||||
|
||||
// GetConsensusState retrieves the consensus state for the provided clientID and height.
|
||||
// It will return a success boolean depending on if consensus state exists or not.
|
||||
func (chain *TestChain) GetConsensusState(clientID string, height exported.Height) (exported.ConsensusState, bool) {
|
||||
return chain.App.IBCKeeper.ClientKeeper.GetClientConsensusState(chain.GetContext(), clientID, height)
|
||||
}
|
||||
|
||||
// GetValsAtHeight will return the validator set of the chain at a given height. It will return
|
||||
// a success boolean depending on if the validator set exists or not at that height.
|
||||
func (chain *TestChain) GetValsAtHeight(height int64) (*tmtypes.ValidatorSet, bool) {
|
||||
histInfo, ok := chain.App.StakingKeeper.GetHistoricalInfo(chain.GetContext(), height)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
valSet := stakingtypes.Validators(histInfo.Valset)
|
||||
|
||||
tmValidators, err := teststaking.ToTmValidators(valSet, sdk.DefaultPowerReduction)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tmtypes.NewValidatorSet(tmValidators), true
|
||||
}
|
||||
|
||||
// GetAcknowledgement retrieves an acknowledgement for the provided packet. If the
|
||||
// acknowledgement does not exist then testing will fail.
|
||||
func (chain *TestChain) GetAcknowledgement(packet exported.PacketI) []byte {
|
||||
ack, found := chain.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
||||
require.True(chain.t, found)
|
||||
|
||||
return ack
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix for used by a chain in connection creation
|
||||
func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix {
|
||||
return commitmenttypes.NewMerklePrefix(chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix().Bytes())
|
||||
}
|
||||
|
||||
// ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the
|
||||
// light client on the source chain.
|
||||
func (chain *TestChain) ConstructUpdateTMClientHeader(counterparty *TestChain, clientID string) (*ibctmtypes.Header, error) {
|
||||
return chain.ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty, clientID, clienttypes.ZeroHeight())
|
||||
}
|
||||
|
||||
// ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the
|
||||
// light client on the source chain.
|
||||
func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctmtypes.Header, error) {
|
||||
header := counterparty.LastHeader
|
||||
// Relayer must query for LatestHeight on client to get TrustedHeight if the trusted height is not set
|
||||
if trustedHeight.IsZero() {
|
||||
trustedHeight = chain.GetClientState(clientID).GetLatestHeight().(clienttypes.Height)
|
||||
}
|
||||
var (
|
||||
tmTrustedVals *tmtypes.ValidatorSet
|
||||
ok bool
|
||||
)
|
||||
// Once we get TrustedHeight from client, we must query the validators from the counterparty chain
|
||||
// If the LatestHeight == LastHeader.Height, then TrustedValidators are current validators
|
||||
// If LatestHeight < LastHeader.Height, we can query the historical validator set from HistoricalInfo
|
||||
if trustedHeight == counterparty.LastHeader.GetHeight() {
|
||||
tmTrustedVals = counterparty.Vals
|
||||
} else {
|
||||
// NOTE: We need to get validators from counterparty at height: trustedHeight+1
|
||||
// since the last trusted validators for a header at height h
|
||||
// is the NextValidators at h+1 committed to in header h by
|
||||
// NextValidatorsHash
|
||||
tmTrustedVals, ok = counterparty.GetValsAtHeight(int64(trustedHeight.RevisionHeight + 1))
|
||||
if !ok {
|
||||
return nil, sdkerrors.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight)
|
||||
}
|
||||
}
|
||||
// inject trusted fields into last header
|
||||
// for now assume revision number is 0
|
||||
header.TrustedHeight = trustedHeight
|
||||
|
||||
trustedVals, err := tmTrustedVals.ToProto()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header.TrustedValidators = trustedVals
|
||||
|
||||
return header, nil
|
||||
}
|
||||
|
||||
// ExpireClient fast forwards the chain's block time by the provided amount of time which will
|
||||
// expire any clients with a trusting period less than or equal to this amount of time.
|
||||
func (chain *TestChain) ExpireClient(amount time.Duration) {
|
||||
chain.Coordinator.IncrementTimeBy(amount)
|
||||
}
|
||||
|
||||
// CurrentTMClientHeader creates a TM header using the current header parameters
|
||||
// on the chain. The trusted fields in the header are set to nil.
|
||||
func (chain *TestChain) CurrentTMClientHeader() *ibctmtypes.Header {
|
||||
return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, chain.NextVals, nil, chain.Signers)
|
||||
}
|
||||
|
||||
// CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow
|
||||
// caller flexibility to use params that differ from the chain.
|
||||
func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctmtypes.Header {
|
||||
var (
|
||||
valSet *tmproto.ValidatorSet
|
||||
trustedVals *tmproto.ValidatorSet
|
||||
)
|
||||
require.NotNil(chain.t, tmValSet)
|
||||
|
||||
vsetHash := tmValSet.Hash()
|
||||
nextValHash := nextVals.Hash()
|
||||
|
||||
tmHeader := tmtypes.Header{
|
||||
Version: tmprotoversion.Consensus{Block: tmversion.BlockProtocol, App: 2},
|
||||
ChainID: chainID,
|
||||
Height: blockHeight,
|
||||
Time: timestamp,
|
||||
LastBlockID: MakeBlockID(make([]byte, tmhash.Size), 10_000, make([]byte, tmhash.Size)),
|
||||
LastCommitHash: chain.App.LastCommitID().Hash,
|
||||
DataHash: tmhash.Sum([]byte("data_hash")),
|
||||
ValidatorsHash: vsetHash,
|
||||
NextValidatorsHash: nextValHash,
|
||||
ConsensusHash: tmhash.Sum([]byte("consensus_hash")),
|
||||
AppHash: chain.CurrentHeader.AppHash,
|
||||
LastResultsHash: tmhash.Sum([]byte("last_results_hash")),
|
||||
EvidenceHash: tmhash.Sum([]byte("evidence_hash")),
|
||||
ProposerAddress: tmValSet.Proposer.Address, //nolint:staticcheck
|
||||
}
|
||||
|
||||
hhash := tmHeader.Hash()
|
||||
blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set")))
|
||||
voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet)
|
||||
|
||||
// MakeCommit expects a signer array in the same order as the validator array.
|
||||
// Thus we iterate over the ordered validator set and construct a signer array
|
||||
// from the signer map in the same order.
|
||||
signerArr := make([]tmtypes.PrivValidator, len(tmValSet.Validators))
|
||||
for i, v := range tmValSet.Validators {
|
||||
signerArr[i] = signers[v.Address.String()]
|
||||
}
|
||||
|
||||
commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signerArr, timestamp)
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
signedHeader := &tmproto.SignedHeader{
|
||||
Header: tmHeader.ToProto(),
|
||||
Commit: commit.ToProto(),
|
||||
}
|
||||
|
||||
valSet, err = tmValSet.ToProto()
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
if tmTrustedVals != nil {
|
||||
trustedVals, err = tmTrustedVals.ToProto()
|
||||
require.NoError(chain.t, err)
|
||||
}
|
||||
|
||||
// The trusted fields may be nil. They may be filled before relaying messages to a client.
|
||||
// The relayer is responsible for querying client and injecting appropriate trusted fields.
|
||||
return &ibctmtypes.Header{
|
||||
SignedHeader: signedHeader,
|
||||
ValidatorSet: valSet,
|
||||
TrustedHeight: trustedHeight,
|
||||
TrustedValidators: trustedVals,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeBlockID copied unimported test functions from tmtypes to use them here
|
||||
func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.BlockID {
|
||||
return tmtypes.BlockID{
|
||||
Hash: hash,
|
||||
PartSetHeader: tmtypes.PartSetHeader{
|
||||
Total: partSetSize,
|
||||
Hash: partSetHash,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CreatePortCapability binds and claims a capability for the given portID if it does not
|
||||
// already exist. This function will fail testing on any resulting error.
|
||||
// NOTE: only creation of a capability for a transfer or mock port is supported
|
||||
// Other applications must bind to the port in InitGenesis or modify this code.
|
||||
func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID string) {
|
||||
// check if the portId is already binded, if not bind it
|
||||
_, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.PortPath(portID))
|
||||
if !ok {
|
||||
// create capability using the IBC capability keeper
|
||||
cap, err := chain.App.ScopedIBCKeeper.NewCapability(chain.GetContext(), host.PortPath(portID))
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
// claim capability using the scopedKeeper
|
||||
err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, host.PortPath(portID))
|
||||
require.NoError(chain.t, err)
|
||||
}
|
||||
|
||||
chain.NextBlock()
|
||||
}
|
||||
|
||||
// GetPortCapability returns the port capability for the given portID. The capability must
|
||||
// exist, otherwise testing will fail.
|
||||
func (chain *TestChain) GetPortCapability(portID string) *capabilitytypes.Capability {
|
||||
cap, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.PortPath(portID))
|
||||
require.True(chain.t, ok)
|
||||
|
||||
return cap
|
||||
}
|
||||
|
||||
// CreateChannelCapability binds and claims a capability for the given portID and channelID
|
||||
// if it does not already exist. This function will fail testing on any resulting error. The
|
||||
// scoped keeper passed in will claim the new capability.
|
||||
func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID, channelID string) {
|
||||
capName := host.ChannelCapabilityPath(portID, channelID)
|
||||
// check if the portId is already binded, if not bind it
|
||||
_, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), capName)
|
||||
if !ok {
|
||||
cap, err := chain.App.ScopedIBCKeeper.NewCapability(chain.GetContext(), capName)
|
||||
require.NoError(chain.t, err)
|
||||
err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, capName)
|
||||
require.NoError(chain.t, err)
|
||||
}
|
||||
|
||||
chain.NextBlock()
|
||||
}
|
||||
|
||||
// GetChannelCapability returns the channel capability for the given portID and channelID.
|
||||
// The capability must exist, otherwise testing will fail.
|
||||
func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabilitytypes.Capability {
|
||||
cap, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.ChannelCapabilityPath(portID, channelID))
|
||||
require.True(chain.t, ok)
|
||||
|
||||
return cap
|
||||
}
|
||||
|
||||
func (chain *TestChain) Balance(acc sdk.AccAddress, denom string) sdk.Coin {
|
||||
return chain.App.BankKeeper.GetBalance(chain.GetContext(), acc, denom)
|
||||
}
|
||||
|
||||
func (chain *TestChain) AllBalances(acc sdk.AccAddress) sdk.Coins {
|
||||
return chain.App.BankKeeper.GetAllBalances(chain.GetContext(), acc)
|
||||
}
|
||||
317
x/wasm/ibctesting/coordinator.go
Normal file
317
x/wasm/ibctesting/coordinator.go
Normal file
@ -0,0 +1,317 @@
|
||||
package ibctesting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
host "github.com/cosmos/ibc-go/v4/modules/core/24-host"
|
||||
ibctesting "github.com/cosmos/ibc-go/v4/testing"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
wasmkeeper "github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
)
|
||||
|
||||
const ChainIDPrefix = "testchain"
|
||||
|
||||
var (
|
||||
globalStartTime = time.Date(2020, 12, 4, 10, 30, 0, 0, time.UTC)
|
||||
TimeIncrement = time.Second * 5
|
||||
)
|
||||
|
||||
// Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains
|
||||
// in sync with regards to time.
|
||||
type Coordinator struct {
|
||||
t *testing.T
|
||||
|
||||
CurrentTime time.Time
|
||||
Chains map[string]*TestChain
|
||||
}
|
||||
|
||||
// NewCoordinator initializes Coordinator with N TestChain's
|
||||
func NewCoordinator(t *testing.T, n int, opts ...[]wasmkeeper.Option) *Coordinator {
|
||||
chains := make(map[string]*TestChain)
|
||||
coord := &Coordinator{
|
||||
t: t,
|
||||
CurrentTime: globalStartTime,
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
chainID := GetChainID(i)
|
||||
var x []wasmkeeper.Option
|
||||
if len(opts) > i {
|
||||
x = opts[i]
|
||||
}
|
||||
chains[chainID] = NewTestChain(t, coord, chainID, x...)
|
||||
}
|
||||
coord.Chains = chains
|
||||
|
||||
return coord
|
||||
}
|
||||
|
||||
// IncrementTime iterates through all the TestChain's and increments their current header time
|
||||
// by 5 seconds.
|
||||
//
|
||||
// CONTRACT: this function must be called after every Commit on any TestChain.
|
||||
func (coord *Coordinator) IncrementTime() {
|
||||
coord.IncrementTimeBy(TimeIncrement)
|
||||
}
|
||||
|
||||
// IncrementTimeBy iterates through all the TestChain's and increments their current header time
|
||||
// by specified time.
|
||||
func (coord *Coordinator) IncrementTimeBy(increment time.Duration) {
|
||||
coord.CurrentTime = coord.CurrentTime.Add(increment).UTC()
|
||||
coord.UpdateTime()
|
||||
}
|
||||
|
||||
// UpdateTime updates all clocks for the TestChains to the current global time.
|
||||
func (coord *Coordinator) UpdateTime() {
|
||||
for _, chain := range coord.Chains {
|
||||
coord.UpdateTimeForChain(chain)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateTimeForChain updates the clock for a specific chain.
|
||||
func (coord *Coordinator) UpdateTimeForChain(chain *TestChain) {
|
||||
chain.CurrentHeader.Time = coord.CurrentTime.UTC()
|
||||
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
|
||||
}
|
||||
|
||||
// Setup constructs a TM client, connection, and channel on both chains provided. It will
|
||||
// fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned
|
||||
// for both chains. The channels created are connected to the ibc-transfer application.
|
||||
func (coord *Coordinator) Setup(path *Path) {
|
||||
coord.SetupConnections(path)
|
||||
|
||||
// channels can also be referenced through the returned connections
|
||||
coord.CreateChannels(path)
|
||||
}
|
||||
|
||||
// SetupClients is a helper function to create clients on both chains. It assumes the
|
||||
// caller does not anticipate any errors.
|
||||
func (coord *Coordinator) SetupClients(path *Path) {
|
||||
err := path.EndpointA.CreateClient()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
err = path.EndpointB.CreateClient()
|
||||
require.NoError(coord.t, err)
|
||||
}
|
||||
|
||||
// SetupClientConnections is a helper function to create clients and the appropriate
|
||||
// connections on both the source and counterparty chain. It assumes the caller does not
|
||||
// anticipate any errors.
|
||||
func (coord *Coordinator) SetupConnections(path *Path) {
|
||||
coord.SetupClients(path)
|
||||
|
||||
coord.CreateConnections(path)
|
||||
}
|
||||
|
||||
// CreateConnection constructs and executes connection handshake messages in order to create
|
||||
// OPEN channels on chainA and chainB. The connection information of for chainA and chainB
|
||||
// are returned within a TestConnection struct. The function expects the connections to be
|
||||
// successfully opened otherwise testing will fail.
|
||||
func (coord *Coordinator) CreateConnections(path *Path) {
|
||||
err := path.EndpointA.ConnOpenInit()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
err = path.EndpointB.ConnOpenTry()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
err = path.EndpointA.ConnOpenAck()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
err = path.EndpointB.ConnOpenConfirm()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
// ensure counterparty is up to date
|
||||
err = path.EndpointA.UpdateClient()
|
||||
require.NoError(coord.t, err)
|
||||
}
|
||||
|
||||
// CreateMockChannels constructs and executes channel handshake messages to create OPEN
|
||||
// channels that use a mock application module that returns nil on all callbacks. This
|
||||
// function is expects the channels to be successfully opened otherwise testing will
|
||||
// fail.
|
||||
func (coord *Coordinator) CreateMockChannels(path *Path) {
|
||||
path.EndpointA.ChannelConfig.PortID = ibctesting.MockPort
|
||||
path.EndpointB.ChannelConfig.PortID = ibctesting.MockPort
|
||||
|
||||
coord.CreateChannels(path)
|
||||
}
|
||||
|
||||
// CreateTransferChannels constructs and executes channel handshake messages to create OPEN
|
||||
// ibc-transfer channels on chainA and chainB. The function expects the channels to be
|
||||
// successfully opened otherwise testing will fail.
|
||||
func (coord *Coordinator) CreateTransferChannels(path *Path) {
|
||||
path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort
|
||||
path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort
|
||||
|
||||
coord.CreateChannels(path)
|
||||
}
|
||||
|
||||
// CreateChannel constructs and executes channel handshake messages in order to create
|
||||
// OPEN channels on chainA and chainB. The function expects the channels to be successfully
|
||||
// opened otherwise testing will fail.
|
||||
func (coord *Coordinator) CreateChannels(path *Path) {
|
||||
err := path.EndpointA.ChanOpenInit()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
err = path.EndpointB.ChanOpenTry()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
err = path.EndpointA.ChanOpenAck()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
err = path.EndpointB.ChanOpenConfirm()
|
||||
require.NoError(coord.t, err)
|
||||
|
||||
// ensure counterparty is up to date
|
||||
err = path.EndpointA.UpdateClient()
|
||||
require.NoError(coord.t, err)
|
||||
}
|
||||
|
||||
// GetChain returns the TestChain using the given chainID and returns an error if it does
|
||||
// not exist.
|
||||
func (coord *Coordinator) GetChain(chainID string) *TestChain {
|
||||
chain, found := coord.Chains[chainID]
|
||||
require.True(coord.t, found, fmt.Sprintf("%s chain does not exist", chainID))
|
||||
return chain
|
||||
}
|
||||
|
||||
// GetChainID returns the chainID used for the provided index.
|
||||
func GetChainID(index int) string {
|
||||
return ChainIDPrefix + strconv.Itoa(index)
|
||||
}
|
||||
|
||||
// CommitBlock commits a block on the provided indexes and then increments the global time.
|
||||
//
|
||||
// CONTRACT: the passed in list of indexes must not contain duplicates
|
||||
func (coord *Coordinator) CommitBlock(chains ...*TestChain) {
|
||||
for _, chain := range chains {
|
||||
chain.NextBlock()
|
||||
}
|
||||
coord.IncrementTime()
|
||||
}
|
||||
|
||||
// CommitNBlocks commits n blocks to state and updates the block height by 1 for each commit.
|
||||
func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) {
|
||||
for i := uint64(0); i < n; i++ {
|
||||
chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
|
||||
chain.NextBlock()
|
||||
coord.IncrementTime()
|
||||
}
|
||||
}
|
||||
|
||||
// ConnOpenInitOnBothChains initializes a connection on both endpoints with the state INIT
|
||||
// using the OpenInit handshake call.
|
||||
func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error {
|
||||
if err := path.EndpointA.ConnOpenInit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointB.ConnOpenInit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointA.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointB.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain
|
||||
// with the state INIT using the OpenInit handshake call.
|
||||
func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error {
|
||||
// NOTE: only creation of a capability for a transfer or mock port is supported
|
||||
// Other applications must bind to the port in InitGenesis or modify this code.
|
||||
|
||||
if err := path.EndpointA.ChanOpenInit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointB.ChanOpenInit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointA.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointB.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RelayAndAckPendingPackets sends pending packages from path.EndpointA to the counterparty chain and acks
|
||||
func (coord *Coordinator) RelayAndAckPendingPackets(path *Path) error {
|
||||
// get all the packet to relay src->dest
|
||||
src := path.EndpointA
|
||||
coord.t.Logf("Relay: %d Packets A->B, %d Packets B->A\n", len(src.Chain.PendingSendPackets), len(path.EndpointB.Chain.PendingSendPackets))
|
||||
for i, v := range src.Chain.PendingSendPackets {
|
||||
err := path.RelayPacket(v, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src.Chain.PendingSendPackets = append(src.Chain.PendingSendPackets[0:i], src.Chain.PendingSendPackets[i+1:]...)
|
||||
}
|
||||
|
||||
src = path.EndpointB
|
||||
for i, v := range src.Chain.PendingSendPackets {
|
||||
err := path.RelayPacket(v, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src.Chain.PendingSendPackets = append(src.Chain.PendingSendPackets[0:i], src.Chain.PendingSendPackets[i+1:]...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TimeoutPendingPackets returns the package to source chain to let the IBC app revert any operation.
|
||||
// from A to A
|
||||
func (coord *Coordinator) TimeoutPendingPackets(path *Path) error {
|
||||
src := path.EndpointA
|
||||
dest := path.EndpointB
|
||||
|
||||
toSend := src.Chain.PendingSendPackets
|
||||
coord.t.Logf("Timeout %d Packets A->A\n", len(toSend))
|
||||
|
||||
if err := src.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Increment time and commit block so that 5 second delay period passes between send and receive
|
||||
coord.IncrementTime()
|
||||
coord.CommitBlock(src.Chain, dest.Chain)
|
||||
for _, packet := range toSend {
|
||||
// get proof of packet unreceived on dest
|
||||
packetKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
||||
proofUnreceived, proofHeight := dest.QueryProof(packetKey)
|
||||
timeoutMsg := channeltypes.NewMsgTimeout(packet, packet.Sequence, proofUnreceived, proofHeight, src.Chain.SenderAccount.GetAddress().String())
|
||||
err := src.Chain.sendMsgs(timeoutMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
src.Chain.PendingSendPackets = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseChannel close channel on both sides
|
||||
func (coord *Coordinator) CloseChannel(path *Path) {
|
||||
err := path.EndpointA.ChanCloseInit()
|
||||
require.NoError(coord.t, err)
|
||||
coord.IncrementTime()
|
||||
err = path.EndpointB.UpdateClient()
|
||||
require.NoError(coord.t, err)
|
||||
err = path.EndpointB.ChanCloseConfirm()
|
||||
require.NoError(coord.t, err)
|
||||
}
|
||||
597
x/wasm/ibctesting/endpoint.go
Normal file
597
x/wasm/ibctesting/endpoint.go
Normal file
@ -0,0 +1,597 @@
|
||||
package ibctesting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
|
||||
connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types"
|
||||
host "github.com/cosmos/ibc-go/v4/modules/core/24-host"
|
||||
"github.com/cosmos/ibc-go/v4/modules/core/exported"
|
||||
ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"
|
||||
ibctesting "github.com/cosmos/ibc-go/v4/testing"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Endpoint is a which represents a channel endpoint and its associated
|
||||
// client and connections. It contains client, connection, and channel
|
||||
// configuration parameters. Endpoint functions will utilize the parameters
|
||||
// set in the configuration structs when executing IBC messages.
|
||||
type Endpoint struct {
|
||||
Chain *TestChain
|
||||
Counterparty *Endpoint
|
||||
ClientID string
|
||||
ConnectionID string
|
||||
ChannelID string
|
||||
|
||||
ClientConfig ibctesting.ClientConfig
|
||||
ConnectionConfig *ibctesting.ConnectionConfig
|
||||
ChannelConfig *ibctesting.ChannelConfig
|
||||
}
|
||||
|
||||
// NewEndpoint constructs a new endpoint without the counterparty.
|
||||
// CONTRACT: the counterparty endpoint must be set by the caller.
|
||||
func NewEndpoint(
|
||||
chain *TestChain, clientConfig ibctesting.ClientConfig,
|
||||
connectionConfig *ibctesting.ConnectionConfig, channelConfig *ibctesting.ChannelConfig,
|
||||
) *Endpoint {
|
||||
return &Endpoint{
|
||||
Chain: chain,
|
||||
ClientConfig: clientConfig,
|
||||
ConnectionConfig: connectionConfig,
|
||||
ChannelConfig: channelConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultEndpoint constructs a new endpoint using default values.
|
||||
// CONTRACT: the counterparty endpoitn must be set by the caller.
|
||||
func NewDefaultEndpoint(chain *TestChain) *Endpoint {
|
||||
return &Endpoint{
|
||||
Chain: chain,
|
||||
ClientConfig: ibctesting.NewTendermintConfig(),
|
||||
ConnectionConfig: ibctesting.NewConnectionConfig(),
|
||||
ChannelConfig: ibctesting.NewChannelConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
// QueryProof queries proof associated with this endpoint using the lastest client state
|
||||
// height on the counterparty chain.
|
||||
func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) {
|
||||
// obtain the counterparty client representing the chain associated with the endpoint
|
||||
clientState := endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID)
|
||||
|
||||
// query proof on the counterparty using the latest height of the IBC client
|
||||
return endpoint.QueryProofAtHeight(key, clientState.GetLatestHeight().GetRevisionHeight())
|
||||
}
|
||||
|
||||
// QueryProofAtHeight queries proof associated with this endpoint using the proof height
|
||||
// provided
|
||||
func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) {
|
||||
// query proof on the counterparty using the latest height of the IBC client
|
||||
return endpoint.Chain.QueryProofAtHeight(key, int64(height))
|
||||
}
|
||||
|
||||
// CreateClient creates an IBC client on the endpoint. It will update the
|
||||
// clientID for the endpoint if the message is successfully executed.
|
||||
// NOTE: a solo machine client will be created with an empty diversifier.
|
||||
func (endpoint *Endpoint) CreateClient() (err error) {
|
||||
// ensure counterparty has committed state
|
||||
endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain)
|
||||
|
||||
var (
|
||||
clientState exported.ClientState
|
||||
consensusState exported.ConsensusState
|
||||
)
|
||||
|
||||
switch endpoint.ClientConfig.GetClientType() {
|
||||
case exported.Tendermint:
|
||||
tmConfig, ok := endpoint.ClientConfig.(*ibctesting.TendermintConfig)
|
||||
require.True(endpoint.Chain.t, ok)
|
||||
|
||||
height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height)
|
||||
clientState = ibctmtypes.NewClientState(
|
||||
endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift,
|
||||
height, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, tmConfig.AllowUpdateAfterExpiry, tmConfig.AllowUpdateAfterMisbehaviour,
|
||||
)
|
||||
consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState()
|
||||
case exported.Solomachine:
|
||||
// TODO
|
||||
// solo := NewSolomachine(chain.t, endpoint.Chain.Codec, clientID, "", 1)
|
||||
// clientState = solo.ClientState()
|
||||
// consensusState = solo.ConsensusState()
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := clienttypes.NewMsgCreateClient(
|
||||
clientState, consensusState, endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
require.NoError(endpoint.Chain.t, err)
|
||||
|
||||
res, err := endpoint.Chain.SendMsgs(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint.ClientID, err = ibctesting.ParseClientIDFromEvents(res.GetEvents())
|
||||
require.NoError(endpoint.Chain.t, err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateClient updates the IBC client associated with the endpoint.
|
||||
func (endpoint *Endpoint) UpdateClient() (err error) {
|
||||
// ensure counterparty has committed state
|
||||
endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain)
|
||||
|
||||
var header exported.Header
|
||||
|
||||
switch endpoint.ClientConfig.GetClientType() {
|
||||
case exported.Tendermint:
|
||||
header, err = endpoint.Chain.ConstructUpdateTMClientHeader(endpoint.Counterparty.Chain, endpoint.ClientID)
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, err := clienttypes.NewMsgUpdateClient(
|
||||
endpoint.ClientID, header,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
require.NoError(endpoint.Chain.t, err)
|
||||
|
||||
return endpoint.Chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
// ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint.
|
||||
func (endpoint *Endpoint) ConnOpenInit() error {
|
||||
msg := connectiontypes.NewMsgConnectionOpenInit(
|
||||
endpoint.ClientID,
|
||||
endpoint.Counterparty.ClientID,
|
||||
endpoint.Counterparty.Chain.GetPrefix(), ibctesting.DefaultOpenInitVersion, endpoint.ConnectionConfig.DelayPeriod,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
res, err := endpoint.Chain.SendMsgs(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint.ConnectionID, err = ibctesting.ParseConnectionIDFromEvents(res.GetEvents())
|
||||
require.NoError(endpoint.Chain.t, err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConnOpenTry will construct and execute a MsgConnectionOpenTry on the associated endpoint.
|
||||
func (endpoint *Endpoint) ConnOpenTry() error {
|
||||
if err := endpoint.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof()
|
||||
|
||||
msg := connectiontypes.NewMsgConnectionOpenTry(
|
||||
endpoint.ClientID, endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID,
|
||||
counterpartyClient, endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ibctesting.ConnectionVersion}, endpoint.ConnectionConfig.DelayPeriod,
|
||||
proofInit, proofClient, proofConsensus,
|
||||
proofHeight, consensusHeight,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
res, err := endpoint.Chain.SendMsgs(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if endpoint.ConnectionID == "" {
|
||||
endpoint.ConnectionID, err = ibctesting.ParseConnectionIDFromEvents(res.GetEvents())
|
||||
require.NoError(endpoint.Chain.t, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConnOpenAck will construct and execute a MsgConnectionOpenAck on the associated endpoint.
|
||||
func (endpoint *Endpoint) ConnOpenAck() error {
|
||||
if err := endpoint.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
counterpartyClient, proofClient, proofConsensus, consensusHeight, proofTry, proofHeight := endpoint.QueryConnectionHandshakeProof()
|
||||
|
||||
msg := connectiontypes.NewMsgConnectionOpenAck(
|
||||
endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, counterpartyClient, // testing doesn't use flexible selection
|
||||
proofTry, proofClient, proofConsensus,
|
||||
proofHeight, consensusHeight,
|
||||
ibctesting.ConnectionVersion,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
return endpoint.Chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
// ConnOpenConfirm will construct and execute a MsgConnectionOpenConfirm on the associated endpoint.
|
||||
func (endpoint *Endpoint) ConnOpenConfirm() error {
|
||||
if err := endpoint.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID)
|
||||
proof, height := endpoint.Counterparty.Chain.QueryProof(connectionKey)
|
||||
|
||||
msg := connectiontypes.NewMsgConnectionOpenConfirm(
|
||||
endpoint.ConnectionID,
|
||||
proof, height,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
return endpoint.Chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
// QueryConnectionHandshakeProof returns all the proofs necessary to execute OpenTry or Open Ack of
|
||||
// the connection handshakes. It returns the counterparty client state, proof of the counterparty
|
||||
// client state, proof of the counterparty consensus state, the consensus state height, proof of
|
||||
// the counterparty connection, and the proof height for all the proofs returned.
|
||||
func (endpoint *Endpoint) QueryConnectionHandshakeProof() (
|
||||
clientState exported.ClientState, proofClient,
|
||||
proofConsensus []byte, consensusHeight clienttypes.Height,
|
||||
proofConnection []byte, proofHeight clienttypes.Height,
|
||||
) {
|
||||
// obtain the client state on the counterparty chain
|
||||
clientState = endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID)
|
||||
|
||||
// query proof for the client state on the counterparty
|
||||
clientKey := host.FullClientStateKey(endpoint.Counterparty.ClientID)
|
||||
proofClient, proofHeight = endpoint.Counterparty.QueryProof(clientKey)
|
||||
|
||||
consensusHeight = clientState.GetLatestHeight().(clienttypes.Height)
|
||||
|
||||
// query proof for the consensus state on the counterparty
|
||||
consensusKey := host.FullConsensusStateKey(endpoint.Counterparty.ClientID, consensusHeight)
|
||||
proofConsensus, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight())
|
||||
|
||||
// query proof for the connection on the counterparty
|
||||
connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID)
|
||||
proofConnection, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ChanOpenInit will construct and execute a MsgChannelOpenInit on the associated endpoint.
|
||||
func (endpoint *Endpoint) ChanOpenInit() error {
|
||||
msg := channeltypes.NewMsgChannelOpenInit(
|
||||
endpoint.ChannelConfig.PortID,
|
||||
endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID},
|
||||
endpoint.Counterparty.ChannelConfig.PortID,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
res, err := endpoint.Chain.SendMsgs(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint.ChannelID, err = ibctesting.ParseChannelIDFromEvents(res.GetEvents())
|
||||
require.NoError(endpoint.Chain.t, err)
|
||||
|
||||
// update version to selected app version
|
||||
// NOTE: this update must be performed after SendMsgs()
|
||||
endpoint.ChannelConfig.Version = endpoint.GetChannel().Version
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChanOpenTry will construct and execute a MsgChannelOpenTry on the associated endpoint.
|
||||
func (endpoint *Endpoint) ChanOpenTry() error {
|
||||
if err := endpoint.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
|
||||
proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey)
|
||||
|
||||
msg := channeltypes.NewMsgChannelOpenTry(
|
||||
endpoint.ChannelConfig.PortID,
|
||||
endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID},
|
||||
endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version,
|
||||
proof, height,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
res, err := endpoint.Chain.SendMsgs(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if endpoint.ChannelID == "" {
|
||||
endpoint.ChannelID, err = ibctesting.ParseChannelIDFromEvents(res.GetEvents())
|
||||
require.NoError(endpoint.Chain.t, err)
|
||||
}
|
||||
|
||||
// update version to selected app version
|
||||
// NOTE: this update must be performed after the endpoint channelID is set
|
||||
endpoint.ChannelConfig.Version = endpoint.GetChannel().Version
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChanOpenAck will construct and execute a MsgChannelOpenAck on the associated endpoint.
|
||||
func (endpoint *Endpoint) ChanOpenAck() error {
|
||||
if err := endpoint.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
|
||||
proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey)
|
||||
|
||||
msg := channeltypes.NewMsgChannelOpenAck(
|
||||
endpoint.ChannelConfig.PortID, endpoint.ChannelID,
|
||||
endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version, // testing doesn't use flexible selection
|
||||
proof, height,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
if err := endpoint.Chain.sendMsgs(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint.ChannelConfig.Version = endpoint.GetChannel().Version
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint.
|
||||
func (endpoint *Endpoint) ChanOpenConfirm() error {
|
||||
if err := endpoint.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
|
||||
proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey)
|
||||
|
||||
msg := channeltypes.NewMsgChannelOpenConfirm(
|
||||
endpoint.ChannelConfig.PortID, endpoint.ChannelID,
|
||||
proof, height,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
return endpoint.Chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
// ChanCloseInit will construct and execute a MsgChannelCloseInit on the associated endpoint.
|
||||
//
|
||||
// NOTE: does not work with ibc-transfer module
|
||||
func (endpoint *Endpoint) ChanCloseInit() error {
|
||||
msg := channeltypes.NewMsgChannelCloseInit(
|
||||
endpoint.ChannelConfig.PortID, endpoint.ChannelID,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
return endpoint.Chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
// ChanCloseConfirm will construct and execute a NewMsgChannelCloseConfirm on the associated endpoint.
|
||||
func (endpoint *Endpoint) ChanCloseConfirm() error {
|
||||
channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID)
|
||||
proof, proofHeight := endpoint.Counterparty.QueryProof(channelKey)
|
||||
|
||||
msg := channeltypes.NewMsgChannelCloseConfirm(
|
||||
endpoint.ChannelConfig.PortID, endpoint.ChannelID,
|
||||
proof, proofHeight,
|
||||
endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
return endpoint.Chain.sendMsgs(msg)
|
||||
}
|
||||
|
||||
// SendPacket sends a packet through the channel keeper using the associated endpoint
|
||||
// The counterparty client is updated so proofs can be sent to the counterparty chain.
|
||||
func (endpoint *Endpoint) SendPacket(packet exported.PacketI) error {
|
||||
channelCap := endpoint.Chain.GetChannelCapability(packet.GetSourcePort(), packet.GetSourceChannel())
|
||||
|
||||
// no need to send message, acting as a module
|
||||
err := endpoint.Chain.App.IBCKeeper.ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), channelCap, packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// commit changes since no message was sent
|
||||
endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
|
||||
|
||||
return endpoint.Counterparty.UpdateClient()
|
||||
}
|
||||
|
||||
// RecvPacket receives a packet on the associated endpoint.
|
||||
// The counterparty client is updated.
|
||||
func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error {
|
||||
_, err := endpoint.RecvPacketWithResult(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecvPacketWithResult receives a packet on the associated endpoint and the result
|
||||
// of the transaction is returned. The counterparty client is updated.
|
||||
func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk.Result, error) {
|
||||
// get proof of packet commitment on source
|
||||
packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
||||
proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey)
|
||||
|
||||
recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
|
||||
|
||||
// receive on counterparty and update source client
|
||||
res, err := endpoint.Chain.SendMsgs(recvMsg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := endpoint.Counterparty.UpdateClient(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint.
|
||||
// The counterparty client is updated.
|
||||
func (endpoint *Endpoint) WriteAcknowledgement(ack exported.Acknowledgement, packet exported.PacketI) error {
|
||||
channelCap := endpoint.Chain.GetChannelCapability(packet.GetDestPort(), packet.GetDestChannel())
|
||||
|
||||
// no need to send message, acting as a handler
|
||||
err := endpoint.Chain.App.IBCKeeper.ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), channelCap, packet, ack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// commit changes since no message was sent
|
||||
endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
|
||||
|
||||
return endpoint.Counterparty.UpdateClient()
|
||||
}
|
||||
|
||||
// AcknowledgePacket sends a MsgAcknowledgement to the channel associated with the endpoint.
|
||||
func (endpoint *Endpoint) AcknowledgePacket(packet channeltypes.Packet, ack []byte) error {
|
||||
// get proof of acknowledgement on counterparty
|
||||
packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
||||
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
|
||||
|
||||
ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
|
||||
|
||||
return endpoint.Chain.sendMsgs(ackMsg)
|
||||
}
|
||||
|
||||
// TimeoutPacket sends a MsgTimeout to the channel associated with the endpoint.
|
||||
func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error {
|
||||
// get proof for timeout based on channel order
|
||||
var packetKey []byte
|
||||
|
||||
switch endpoint.ChannelConfig.Order {
|
||||
case channeltypes.ORDERED:
|
||||
packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel())
|
||||
case channeltypes.UNORDERED:
|
||||
packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
||||
default:
|
||||
return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order)
|
||||
}
|
||||
|
||||
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
|
||||
nextSeqRecv, found := endpoint.Counterparty.Chain.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID)
|
||||
require.True(endpoint.Chain.t, found)
|
||||
|
||||
timeoutMsg := channeltypes.NewMsgTimeout(
|
||||
packet, nextSeqRecv,
|
||||
proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
|
||||
return endpoint.Chain.sendMsgs(timeoutMsg)
|
||||
}
|
||||
|
||||
// TimeoutOnClose sends a MsgTimeoutOnClose to the channel associated with the endpoint.
|
||||
func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error {
|
||||
// get proof for timeout based on channel order
|
||||
var packetKey []byte
|
||||
|
||||
switch endpoint.ChannelConfig.Order {
|
||||
case channeltypes.ORDERED:
|
||||
packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel())
|
||||
case channeltypes.UNORDERED:
|
||||
packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
||||
default:
|
||||
return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order)
|
||||
}
|
||||
|
||||
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
|
||||
|
||||
channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel())
|
||||
proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey)
|
||||
|
||||
nextSeqRecv, found := endpoint.Counterparty.Chain.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID)
|
||||
require.True(endpoint.Chain.t, found)
|
||||
|
||||
timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose(
|
||||
packet, nextSeqRecv,
|
||||
proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(),
|
||||
)
|
||||
|
||||
return endpoint.Chain.sendMsgs(timeoutOnCloseMsg)
|
||||
}
|
||||
|
||||
// SetChannelClosed sets a channel state to CLOSED.
|
||||
func (endpoint *Endpoint) SetChannelClosed() error {
|
||||
channel := endpoint.GetChannel()
|
||||
|
||||
channel.State = channeltypes.CLOSED
|
||||
endpoint.Chain.App.IBCKeeper.ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel)
|
||||
|
||||
endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain)
|
||||
|
||||
return endpoint.Counterparty.UpdateClient()
|
||||
}
|
||||
|
||||
// GetClientState retrieves the Client State for this endpoint. The
|
||||
// client state is expected to exist otherwise testing will fail.
|
||||
func (endpoint *Endpoint) GetClientState() exported.ClientState {
|
||||
return endpoint.Chain.GetClientState(endpoint.ClientID)
|
||||
}
|
||||
|
||||
// SetClientState sets the client state for this endpoint.
|
||||
func (endpoint *Endpoint) SetClientState(clientState exported.ClientState) {
|
||||
endpoint.Chain.App.IBCKeeper.ClientKeeper.SetClientState(endpoint.Chain.GetContext(), endpoint.ClientID, clientState)
|
||||
}
|
||||
|
||||
// GetConsensusState retrieves the Consensus State for this endpoint at the provided height.
|
||||
// The consensus state is expected to exist otherwise testing will fail.
|
||||
func (endpoint *Endpoint) GetConsensusState(height exported.Height) exported.ConsensusState {
|
||||
consensusState, found := endpoint.Chain.GetConsensusState(endpoint.ClientID, height)
|
||||
require.True(endpoint.Chain.t, found)
|
||||
|
||||
return consensusState
|
||||
}
|
||||
|
||||
// SetConsensusState sets the consensus state for this endpoint.
|
||||
func (endpoint *Endpoint) SetConsensusState(consensusState exported.ConsensusState, height exported.Height) {
|
||||
endpoint.Chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState(endpoint.Chain.GetContext(), endpoint.ClientID, height, consensusState)
|
||||
}
|
||||
|
||||
// GetConnection retrieves an IBC Connection for the endpoint. The
|
||||
// connection is expected to exist otherwise testing will fail.
|
||||
func (endpoint *Endpoint) GetConnection() connectiontypes.ConnectionEnd {
|
||||
connection, found := endpoint.Chain.App.IBCKeeper.ConnectionKeeper.GetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID)
|
||||
require.True(endpoint.Chain.t, found)
|
||||
|
||||
return connection
|
||||
}
|
||||
|
||||
// SetConnection sets the connection for this endpoint.
|
||||
func (endpoint *Endpoint) SetConnection(connection connectiontypes.ConnectionEnd) {
|
||||
endpoint.Chain.App.IBCKeeper.ConnectionKeeper.SetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID, connection)
|
||||
}
|
||||
|
||||
// GetChannel retrieves an IBC Channel for the endpoint. The channel
|
||||
// is expected to exist otherwise testing will fail.
|
||||
func (endpoint *Endpoint) GetChannel() channeltypes.Channel {
|
||||
channel, found := endpoint.Chain.App.IBCKeeper.ChannelKeeper.GetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID)
|
||||
require.True(endpoint.Chain.t, found)
|
||||
|
||||
return channel
|
||||
}
|
||||
|
||||
// SetChannel sets the channel for this endpoint.
|
||||
func (endpoint *Endpoint) SetChannel(channel channeltypes.Channel) {
|
||||
endpoint.Chain.App.IBCKeeper.ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel)
|
||||
}
|
||||
|
||||
// QueryClientStateProof performs and abci query for a client stat associated
|
||||
// with this endpoint and returns the ClientState along with the proof.
|
||||
func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) {
|
||||
// retrieve client state to provide proof for
|
||||
clientState := endpoint.GetClientState()
|
||||
|
||||
clientKey := host.FullClientStateKey(endpoint.ClientID)
|
||||
proofClient, _ := endpoint.QueryProof(clientKey)
|
||||
|
||||
return clientState, proofClient
|
||||
}
|
||||
118
x/wasm/ibctesting/event_utils.go
Normal file
118
x/wasm/ibctesting/event_utils.go
Normal file
@ -0,0 +1,118 @@
|
||||
package ibctesting
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
func getSendPackets(evts []abci.Event) []channeltypes.Packet {
|
||||
var res []channeltypes.Packet
|
||||
for _, evt := range evts {
|
||||
if evt.Type == channeltypes.EventTypeSendPacket {
|
||||
packet := parsePacketFromEvent(evt)
|
||||
res = append(res, packet)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Used for various debug statements above when needed... do not remove
|
||||
// func showEvent(evt abci.Event) {
|
||||
// fmt.Printf("evt.Type: %s\n", evt.Type)
|
||||
// for _, attr := range evt.Attributes {
|
||||
// fmt.Printf(" %s = %s\n", string(attr.Key), string(attr.Value))
|
||||
// }
|
||||
//}
|
||||
|
||||
func parsePacketFromEvent(evt abci.Event) channeltypes.Packet {
|
||||
return channeltypes.Packet{
|
||||
Sequence: getUintField(evt, channeltypes.AttributeKeySequence),
|
||||
SourcePort: getField(evt, channeltypes.AttributeKeySrcPort),
|
||||
SourceChannel: getField(evt, channeltypes.AttributeKeySrcChannel),
|
||||
DestinationPort: getField(evt, channeltypes.AttributeKeyDstPort),
|
||||
DestinationChannel: getField(evt, channeltypes.AttributeKeyDstChannel),
|
||||
Data: getHexField(evt, channeltypes.AttributeKeyDataHex),
|
||||
TimeoutHeight: parseTimeoutHeight(getField(evt, channeltypes.AttributeKeyTimeoutHeight)),
|
||||
TimeoutTimestamp: getUintField(evt, channeltypes.AttributeKeyTimeoutTimestamp),
|
||||
}
|
||||
}
|
||||
|
||||
func getHexField(evt abci.Event, key string) []byte {
|
||||
got := getField(evt, key)
|
||||
if got == "" {
|
||||
return nil
|
||||
}
|
||||
bz, err := hex.DecodeString(got)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
}
|
||||
|
||||
// return the value for the attribute with the given name
|
||||
func getField(evt abci.Event, key string) string {
|
||||
for _, attr := range evt.Attributes {
|
||||
if string(attr.Key) == key {
|
||||
return string(attr.Value)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getUintField(evt abci.Event, key string) uint64 {
|
||||
raw := getField(evt, key)
|
||||
return toUint64(raw)
|
||||
}
|
||||
|
||||
func toUint64(raw string) uint64 {
|
||||
if raw == "" {
|
||||
return 0
|
||||
}
|
||||
i, err := strconv.ParseUint(raw, 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func parseTimeoutHeight(raw string) clienttypes.Height {
|
||||
chunks := strings.Split(raw, "-")
|
||||
return clienttypes.Height{
|
||||
RevisionNumber: toUint64(chunks[0]),
|
||||
RevisionHeight: toUint64(chunks[1]),
|
||||
}
|
||||
}
|
||||
|
||||
func ParsePortIDFromEvents(events sdk.Events) (string, error) {
|
||||
for _, ev := range events {
|
||||
if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry {
|
||||
for _, attr := range ev.Attributes {
|
||||
if string(attr.Key) == channeltypes.AttributeKeyPortID {
|
||||
return string(attr.Value), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("port id event attribute not found")
|
||||
}
|
||||
|
||||
func ParseChannelVersionFromEvents(events sdk.Events) (string, error) {
|
||||
for _, ev := range events {
|
||||
if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry {
|
||||
for _, attr := range ev.Attributes {
|
||||
if string(attr.Key) == channeltypes.AttributeVersion {
|
||||
return string(attr.Value), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("version event attribute not found")
|
||||
}
|
||||
52
x/wasm/ibctesting/faucet.go
Normal file
52
x/wasm/ibctesting/faucet.go
Normal file
@ -0,0 +1,52 @@
|
||||
package ibctesting
|
||||
|
||||
import (
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/app"
|
||||
)
|
||||
|
||||
// Fund an address with the given amount in default denom
|
||||
func (chain *TestChain) Fund(addr sdk.AccAddress, amount sdk.Int) {
|
||||
require.NoError(chain.t, chain.sendMsgs(&banktypes.MsgSend{
|
||||
FromAddress: chain.SenderAccount.GetAddress().String(),
|
||||
ToAddress: addr.String(),
|
||||
Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)),
|
||||
}))
|
||||
}
|
||||
|
||||
// SendNonDefaultSenderMsgs delivers a transaction through the application. It returns the result and error if one
|
||||
// occurred.
|
||||
func (chain *TestChain) SendNonDefaultSenderMsgs(senderPrivKey cryptotypes.PrivKey, msgs ...sdk.Msg) (*sdk.Result, error) {
|
||||
require.NotEqual(chain.t, chain.SenderPrivKey, senderPrivKey, "use SendMsgs method")
|
||||
|
||||
// ensure the chain has the latest time
|
||||
chain.Coordinator.UpdateTimeForChain(chain)
|
||||
|
||||
addr := sdk.AccAddress(senderPrivKey.PubKey().Address().Bytes())
|
||||
account := chain.App.AccountKeeper.GetAccount(chain.GetContext(), addr)
|
||||
require.NotNil(chain.t, account)
|
||||
_, r, err := app.SignAndDeliver(
|
||||
chain.t,
|
||||
chain.TxConfig,
|
||||
chain.App.BaseApp,
|
||||
chain.GetContext().BlockHeader(),
|
||||
msgs,
|
||||
chain.ChainID,
|
||||
[]uint64{account.GetAccountNumber()},
|
||||
[]uint64{account.GetSequence()},
|
||||
senderPrivKey,
|
||||
)
|
||||
|
||||
// SignAndDeliver calls app.Commit()
|
||||
chain.NextBlock()
|
||||
chain.Coordinator.IncrementTime()
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
chain.captureIBCEvents(r)
|
||||
return r, nil
|
||||
}
|
||||
113
x/wasm/ibctesting/path.go
Normal file
113
x/wasm/ibctesting/path.go
Normal file
@ -0,0 +1,113 @@
|
||||
package ibctesting
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
ibctesting "github.com/cosmos/ibc-go/v4/testing"
|
||||
)
|
||||
|
||||
// Path contains two endpoints representing two chains connected over IBC
|
||||
type Path struct {
|
||||
EndpointA *Endpoint
|
||||
EndpointB *Endpoint
|
||||
}
|
||||
|
||||
// NewPath constructs an endpoint for each chain using the default values
|
||||
// for the endpoints. Each endpoint is updated to have a pointer to the
|
||||
// counterparty endpoint.
|
||||
func NewPath(chainA, chainB *TestChain) *Path {
|
||||
endpointA := NewDefaultEndpoint(chainA)
|
||||
endpointB := NewDefaultEndpoint(chainB)
|
||||
|
||||
endpointA.Counterparty = endpointB
|
||||
endpointB.Counterparty = endpointA
|
||||
|
||||
return &Path{
|
||||
EndpointA: endpointA,
|
||||
EndpointB: endpointB,
|
||||
}
|
||||
}
|
||||
|
||||
// SetChannelOrdered sets the channel order for both endpoints to ORDERED.
|
||||
func (path *Path) SetChannelOrdered() {
|
||||
path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED
|
||||
path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED
|
||||
}
|
||||
|
||||
// RelayPacket attempts to relay the packet first on EndpointA and then on EndpointB
|
||||
// if EndpointA does not contain a packet commitment for that packet. An error is returned
|
||||
// if a relay step fails or the packet commitment does not exist on either endpoint.
|
||||
func (path *Path) RelayPacket(packet channeltypes.Packet, ack []byte) error {
|
||||
pc := path.EndpointA.Chain.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
||||
if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointA.Chain.App.AppCodec(), packet)) {
|
||||
|
||||
// packet found, relay from A to B
|
||||
if err := path.EndpointB.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := path.EndpointB.RecvPacketWithResult(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ack, err := ibctesting.ParseAckFromEvents(res.GetEvents())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointA.AcknowledgePacket(packet, ack); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
pc = path.EndpointB.Chain.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
||||
if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointB.Chain.App.AppCodec(), packet)) {
|
||||
|
||||
// packet found, relay B to A
|
||||
if err := path.EndpointA.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := path.EndpointA.RecvPacketWithResult(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ack, err := ibctesting.ParseAckFromEvents(res.GetEvents())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := path.EndpointB.AcknowledgePacket(packet, ack); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("packet commitment does not exist on either endpoint for provided packet")
|
||||
}
|
||||
|
||||
// SendMsg delivers the provided messages to the chain. The counterparty
|
||||
// client is updated with the new source consensus state.
|
||||
func (path *Path) SendMsg(msgs ...sdk.Msg) error {
|
||||
if err := path.EndpointA.Chain.sendMsgs(msgs...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := path.EndpointA.UpdateClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
return path.EndpointB.UpdateClient()
|
||||
}
|
||||
|
||||
func (path *Path) Invert() *Path {
|
||||
return &Path{
|
||||
EndpointA: path.EndpointB,
|
||||
EndpointB: path.EndpointA,
|
||||
}
|
||||
}
|
||||
138
x/wasm/ibctesting/wasm.go
Normal file
138
x/wasm/ibctesting/wasm.go
Normal file
@ -0,0 +1,138 @@
|
||||
package ibctesting
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
ibctesting "github.com/cosmos/ibc-go/v4/testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/golang/protobuf/proto" //nolint
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/rand"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
var wasmIdent = []byte("\x00\x61\x73\x6D")
|
||||
|
||||
// SeedNewContractInstance stores some wasm code and instantiates a new contract on this chain.
|
||||
// This method can be called to prepare the store with some valid CodeInfo and ContractInfo. The returned
|
||||
// Address is the contract address for this instance. Test should make use of this data and/or use NewIBCContractMockWasmer
|
||||
// for using a contract mock in Go.
|
||||
func (chain *TestChain) SeedNewContractInstance() sdk.AccAddress {
|
||||
pInstResp := chain.StoreCode(append(wasmIdent, rand.Bytes(10)...))
|
||||
codeID := pInstResp.CodeID
|
||||
|
||||
anyAddressStr := chain.SenderAccount.GetAddress().String()
|
||||
initMsg := []byte(fmt.Sprintf(`{"verifier": %q, "beneficiary": %q}`, anyAddressStr, anyAddressStr))
|
||||
return chain.InstantiateContract(codeID, initMsg)
|
||||
}
|
||||
|
||||
func (chain *TestChain) StoreCodeFile(filename string) types.MsgStoreCodeResponse {
|
||||
wasmCode, err := os.ReadFile(filename)
|
||||
require.NoError(chain.t, err)
|
||||
if strings.HasSuffix(filename, "wasm") { // compress for gas limit
|
||||
var buf bytes.Buffer
|
||||
gz := gzip.NewWriter(&buf)
|
||||
_, err := gz.Write(wasmCode)
|
||||
require.NoError(chain.t, err)
|
||||
err = gz.Close()
|
||||
require.NoError(chain.t, err)
|
||||
wasmCode = buf.Bytes()
|
||||
}
|
||||
return chain.StoreCode(wasmCode)
|
||||
}
|
||||
|
||||
func (chain *TestChain) StoreCode(byteCode []byte) types.MsgStoreCodeResponse {
|
||||
storeMsg := &types.MsgStoreCode{
|
||||
Sender: chain.SenderAccount.GetAddress().String(),
|
||||
WASMByteCode: byteCode,
|
||||
}
|
||||
r, err := chain.SendMsgs(storeMsg)
|
||||
require.NoError(chain.t, err)
|
||||
protoResult := chain.parseSDKResultData(r)
|
||||
require.Len(chain.t, protoResult.Data, 1)
|
||||
// unmarshal protobuf response from data
|
||||
var pInstResp types.MsgStoreCodeResponse
|
||||
require.NoError(chain.t, pInstResp.Unmarshal(protoResult.Data[0].Data))
|
||||
require.NotEmpty(chain.t, pInstResp.CodeID)
|
||||
require.NotEmpty(chain.t, pInstResp.Checksum)
|
||||
return pInstResp
|
||||
}
|
||||
|
||||
func (chain *TestChain) InstantiateContract(codeID uint64, initMsg []byte) sdk.AccAddress {
|
||||
instantiateMsg := &types.MsgInstantiateContract{
|
||||
Sender: chain.SenderAccount.GetAddress().String(),
|
||||
Admin: chain.SenderAccount.GetAddress().String(),
|
||||
CodeID: codeID,
|
||||
Label: "ibc-test",
|
||||
Msg: initMsg,
|
||||
Funds: sdk.Coins{ibctesting.TestCoin},
|
||||
}
|
||||
|
||||
r, err := chain.SendMsgs(instantiateMsg)
|
||||
require.NoError(chain.t, err)
|
||||
protoResult := chain.parseSDKResultData(r)
|
||||
require.Len(chain.t, protoResult.Data, 1)
|
||||
|
||||
var pExecResp types.MsgInstantiateContractResponse
|
||||
require.NoError(chain.t, pExecResp.Unmarshal(protoResult.Data[0].Data))
|
||||
a, err := sdk.AccAddressFromBech32(pExecResp.Address)
|
||||
require.NoError(chain.t, err)
|
||||
return a
|
||||
}
|
||||
|
||||
// SmartQuery This will serialize the query message and submit it to the contract.
|
||||
// The response is parsed into the provided interface.
|
||||
// Usage: SmartQuery(addr, QueryMsg{Foo: 1}, &response)
|
||||
func (chain *TestChain) SmartQuery(contractAddr string, queryMsg interface{}, response interface{}) error {
|
||||
msg, err := json.Marshal(queryMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := types.QuerySmartContractStateRequest{
|
||||
Address: contractAddr,
|
||||
QueryData: msg,
|
||||
}
|
||||
reqBin, err := proto.Marshal(&req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: what is the query?
|
||||
res := chain.App.Query(abci.RequestQuery{
|
||||
Path: "/cosmwasm.wasm.v1.Query/SmartContractState",
|
||||
Data: reqBin,
|
||||
})
|
||||
|
||||
if res.Code != 0 {
|
||||
return fmt.Errorf("query failed: (%d) %s", res.Code, res.Log)
|
||||
}
|
||||
|
||||
// unpack protobuf
|
||||
var resp types.QuerySmartContractStateResponse
|
||||
err = proto.Unmarshal(res.Value, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// unpack json content
|
||||
return json.Unmarshal(resp.Data, response)
|
||||
}
|
||||
|
||||
func (chain *TestChain) parseSDKResultData(r *sdk.Result) sdk.TxMsgData {
|
||||
var protoResult sdk.TxMsgData
|
||||
require.NoError(chain.t, proto.Unmarshal(r.Data, &protoResult))
|
||||
return protoResult
|
||||
}
|
||||
|
||||
// ContractInfo is a helper function to returns the ContractInfo for the given contract address
|
||||
func (chain *TestChain) ContractInfo(contractAddr sdk.AccAddress) *types.ContractInfo {
|
||||
return chain.App.WasmKeeper.GetContractInfo(chain.GetContext(), contractAddr)
|
||||
}
|
||||
41
x/wasm/ioutils/ioutil.go
Normal file
41
x/wasm/ioutils/ioutil.go
Normal file
@ -0,0 +1,41 @@
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// Uncompress expects a valid gzip source to unpack or fails. See IsGzip
|
||||
func Uncompress(gzipSrc []byte, limit uint64) ([]byte, error) {
|
||||
if uint64(len(gzipSrc)) > limit {
|
||||
return nil, types.ErrLimit
|
||||
}
|
||||
zr, err := gzip.NewReader(bytes.NewReader(gzipSrc))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zr.Multistream(false)
|
||||
defer zr.Close()
|
||||
return io.ReadAll(LimitReader(zr, int64(limit)))
|
||||
}
|
||||
|
||||
// LimitReader returns a Reader that reads from r
|
||||
// but stops with types.ErrLimit after n bytes.
|
||||
// The underlying implementation is a *io.LimitedReader.
|
||||
func LimitReader(r io.Reader, n int64) io.Reader {
|
||||
return &LimitedReader{r: &io.LimitedReader{R: r, N: n}}
|
||||
}
|
||||
|
||||
type LimitedReader struct {
|
||||
r *io.LimitedReader
|
||||
}
|
||||
|
||||
func (l *LimitedReader) Read(p []byte) (n int, err error) {
|
||||
if l.r.N <= 0 {
|
||||
return 0, types.ErrLimit
|
||||
}
|
||||
return l.r.Read(p)
|
||||
}
|
||||
82
x/wasm/ioutils/ioutil_test.go
Normal file
82
x/wasm/ioutils/ioutil_test.go
Normal file
@ -0,0 +1,82 @@
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestUncompress(t *testing.T) {
|
||||
wasmRaw, err := os.ReadFile("../keeper/testdata/hackatom.wasm")
|
||||
require.NoError(t, err)
|
||||
|
||||
wasmGzipped, err := os.ReadFile("../keeper/testdata/hackatom.wasm.gzip")
|
||||
require.NoError(t, err)
|
||||
|
||||
const maxSize = 400_000
|
||||
|
||||
specs := map[string]struct {
|
||||
src []byte
|
||||
expError error
|
||||
expResult []byte
|
||||
}{
|
||||
"handle wasm compressed": {
|
||||
src: wasmGzipped,
|
||||
expResult: wasmRaw,
|
||||
},
|
||||
"handle gzip identifier only": {
|
||||
src: gzipIdent,
|
||||
expError: io.ErrUnexpectedEOF,
|
||||
},
|
||||
"handle broken gzip": {
|
||||
src: append(gzipIdent, byte(0x1)),
|
||||
expError: io.ErrUnexpectedEOF,
|
||||
},
|
||||
"handle incomplete gzip": {
|
||||
src: wasmGzipped[:len(wasmGzipped)-5],
|
||||
expError: io.ErrUnexpectedEOF,
|
||||
},
|
||||
"handle limit gzip output": {
|
||||
src: asGzip(bytes.Repeat([]byte{0x1}, maxSize)),
|
||||
expResult: bytes.Repeat([]byte{0x1}, maxSize),
|
||||
},
|
||||
"handle big gzip output": {
|
||||
src: asGzip(bytes.Repeat([]byte{0x1}, maxSize+1)),
|
||||
expError: types.ErrLimit,
|
||||
},
|
||||
"handle other big gzip output": {
|
||||
src: asGzip(bytes.Repeat([]byte{0x1}, 2*maxSize)),
|
||||
expError: types.ErrLimit,
|
||||
},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
r, err := Uncompress(spec.src, maxSize)
|
||||
require.True(t, errors.Is(spec.expError, err), "exp %v got %+v", spec.expError, err)
|
||||
if spec.expError != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, spec.expResult, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func asGzip(src []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
zipper := gzip.NewWriter(&buf)
|
||||
if _, err := io.Copy(zipper, bytes.NewReader(src)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := zipper.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
43
x/wasm/ioutils/utils.go
Normal file
43
x/wasm/ioutils/utils.go
Normal file
@ -0,0 +1,43 @@
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
)
|
||||
|
||||
// Note: []byte can never be const as they are inherently mutable
|
||||
var (
|
||||
// magic bytes to identify gzip.
|
||||
// See https://www.ietf.org/rfc/rfc1952.txt
|
||||
// and https://github.com/golang/go/blob/master/src/net/http/sniff.go#L186
|
||||
gzipIdent = []byte("\x1F\x8B\x08")
|
||||
|
||||
wasmIdent = []byte("\x00\x61\x73\x6D")
|
||||
)
|
||||
|
||||
// IsGzip returns checks if the file contents are gzip compressed
|
||||
func IsGzip(input []byte) bool {
|
||||
return len(input) >= 3 && bytes.Equal(gzipIdent, input[0:3])
|
||||
}
|
||||
|
||||
// IsWasm checks if the file contents are of wasm binary
|
||||
func IsWasm(input []byte) bool {
|
||||
return bytes.Equal(input[:4], wasmIdent)
|
||||
}
|
||||
|
||||
// GzipIt compresses the input ([]byte)
|
||||
func GzipIt(input []byte) ([]byte, error) {
|
||||
// Create gzip writer.
|
||||
var b bytes.Buffer
|
||||
w := gzip.NewWriter(&b)
|
||||
_, err := w.Write(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = w.Close() // You must close this first to flush the bytes to the buffer.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
68
x/wasm/ioutils/utils_test.go
Normal file
68
x/wasm/ioutils/utils_test.go
Normal file
@ -0,0 +1,68 @@
|
||||
package ioutils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func GetTestData() ([]byte, []byte, []byte, error) {
|
||||
wasmCode, err := os.ReadFile("../keeper/testdata/hackatom.wasm")
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
gzipData, err := GzipIt(wasmCode)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
someRandomStr := []byte("hello world")
|
||||
|
||||
return wasmCode, someRandomStr, gzipData, nil
|
||||
}
|
||||
|
||||
func TestIsWasm(t *testing.T) {
|
||||
wasmCode, someRandomStr, gzipData, err := GetTestData()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Log("should return false for some random string data")
|
||||
require.False(t, IsWasm(someRandomStr))
|
||||
t.Log("should return false for gzip data")
|
||||
require.False(t, IsWasm(gzipData))
|
||||
t.Log("should return true for exact wasm")
|
||||
require.True(t, IsWasm(wasmCode))
|
||||
}
|
||||
|
||||
func TestIsGzip(t *testing.T) {
|
||||
wasmCode, someRandomStr, gzipData, err := GetTestData()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.False(t, IsGzip(wasmCode))
|
||||
require.False(t, IsGzip(someRandomStr))
|
||||
require.False(t, IsGzip(nil))
|
||||
require.True(t, IsGzip(gzipData[0:3]))
|
||||
require.True(t, IsGzip(gzipData))
|
||||
}
|
||||
|
||||
func TestGzipIt(t *testing.T) {
|
||||
wasmCode, someRandomStr, _, err := GetTestData()
|
||||
originalGzipData := []byte{
|
||||
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 202, 72, 205, 201, 201, 87, 40, 207, 47, 202, 73, 1,
|
||||
4, 0, 0, 255, 255, 133, 17, 74, 13, 11, 0, 0, 0,
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Log("gzip wasm with no error")
|
||||
_, err = GzipIt(wasmCode)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Log("gzip of a string should return exact gzip data")
|
||||
strToGzip, err := GzipIt(someRandomStr)
|
||||
|
||||
require.True(t, IsGzip(strToGzip))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, originalGzipData, strToGzip)
|
||||
}
|
||||
76
x/wasm/keeper/addresses.go
Normal file
76
x/wasm/keeper/addresses.go
Normal file
@ -0,0 +1,76 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/address"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// AddressGenerator abstract address generator to be used for a single contract address
|
||||
type AddressGenerator func(ctx sdk.Context, codeID uint64, checksum []byte) sdk.AccAddress
|
||||
|
||||
// ClassicAddressGenerator generates a contract address using codeID and instanceID sequence
|
||||
func (k Keeper) ClassicAddressGenerator() AddressGenerator {
|
||||
return func(ctx sdk.Context, codeID uint64, _ []byte) sdk.AccAddress {
|
||||
instanceID := k.autoIncrementID(ctx, types.KeyLastInstanceID)
|
||||
return BuildContractAddressClassic(codeID, instanceID)
|
||||
}
|
||||
}
|
||||
|
||||
// PredicableAddressGenerator generates a predictable contract address
|
||||
func PredicableAddressGenerator(creator sdk.AccAddress, salt []byte, msg []byte, fixMsg bool) AddressGenerator {
|
||||
return func(ctx sdk.Context, _ uint64, checksum []byte) sdk.AccAddress {
|
||||
if !fixMsg { // clear msg to not be included in the address generation
|
||||
msg = []byte{}
|
||||
}
|
||||
return BuildContractAddressPredictable(checksum, creator, salt, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// BuildContractAddressClassic builds an sdk account address for a contract.
|
||||
func BuildContractAddressClassic(codeID, instanceID uint64) sdk.AccAddress {
|
||||
contractID := make([]byte, 16)
|
||||
binary.BigEndian.PutUint64(contractID[:8], codeID)
|
||||
binary.BigEndian.PutUint64(contractID[8:], instanceID)
|
||||
return address.Module(types.ModuleName, contractID)[:types.ContractAddrLen]
|
||||
}
|
||||
|
||||
// BuildContractAddressPredictable generates a contract address for the wasm module with len = types.ContractAddrLen using the
|
||||
// Cosmos SDK address.Module function.
|
||||
// Internally a key is built containing:
|
||||
// (len(checksum) | checksum | len(sender_address) | sender_address | len(salt) | salt| len(initMsg) | initMsg).
|
||||
//
|
||||
// All method parameter values must be valid and not nil.
|
||||
func BuildContractAddressPredictable(checksum []byte, creator sdk.AccAddress, salt, initMsg types.RawContractMessage) sdk.AccAddress {
|
||||
if len(checksum) != 32 {
|
||||
panic("invalid checksum")
|
||||
}
|
||||
if err := sdk.VerifyAddressFormat(creator); err != nil {
|
||||
panic(fmt.Sprintf("creator: %s", err))
|
||||
}
|
||||
if err := types.ValidateSalt(salt); err != nil {
|
||||
panic(fmt.Sprintf("salt: %s", err))
|
||||
}
|
||||
if err := initMsg.ValidateBasic(); len(initMsg) != 0 && err != nil {
|
||||
panic(fmt.Sprintf("initMsg: %s", err))
|
||||
}
|
||||
checksum = UInt64LengthPrefix(checksum)
|
||||
creator = UInt64LengthPrefix(creator)
|
||||
salt = UInt64LengthPrefix(salt)
|
||||
initMsg = UInt64LengthPrefix(initMsg)
|
||||
key := make([]byte, len(checksum)+len(creator)+len(salt)+len(initMsg))
|
||||
copy(key[0:], checksum)
|
||||
copy(key[len(checksum):], creator)
|
||||
copy(key[len(checksum)+len(creator):], salt)
|
||||
copy(key[len(checksum)+len(creator)+len(salt):], initMsg)
|
||||
return address.Module(types.ModuleName, key)[:types.ContractAddrLen]
|
||||
}
|
||||
|
||||
// UInt64LengthPrefix prepend big endian encoded byte length
|
||||
func UInt64LengthPrefix(bz []byte) []byte {
|
||||
return append(sdk.Uint64ToBigEndian(uint64(len(bz))), bz...)
|
||||
}
|
||||
432
x/wasm/keeper/addresses_test.go
Normal file
432
x/wasm/keeper/addresses_test.go
Normal file
@ -0,0 +1,432 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
)
|
||||
|
||||
func TestBuildContractAddress(t *testing.T) {
|
||||
x, y := sdk.GetConfig().GetBech32AccountAddrPrefix(), sdk.GetConfig().GetBech32AccountPubPrefix()
|
||||
t.Cleanup(func() {
|
||||
sdk.GetConfig().SetBech32PrefixForAccount(x, y)
|
||||
})
|
||||
sdk.GetConfig().SetBech32PrefixForAccount("purple", "purple")
|
||||
|
||||
// test vectors generated via cosmjs: https://github.com/cosmos/cosmjs/pull/1253/files
|
||||
type Spec struct {
|
||||
In struct {
|
||||
Checksum tmbytes.HexBytes `json:"checksum"`
|
||||
Creator sdk.AccAddress `json:"creator"`
|
||||
Salt tmbytes.HexBytes `json:"salt"`
|
||||
Msg string `json:"msg"`
|
||||
} `json:"in"`
|
||||
Out struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
} `json:"out"`
|
||||
}
|
||||
var specs []Spec
|
||||
require.NoError(t, json.Unmarshal([]byte(goldenMasterPredictableContractAddr), &specs))
|
||||
require.NotEmpty(t, specs)
|
||||
for i, spec := range specs {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
// when
|
||||
gotAddr := BuildContractAddressPredictable(spec.In.Checksum, spec.In.Creator, spec.In.Salt.Bytes(), []byte(spec.In.Msg))
|
||||
|
||||
require.Equal(t, spec.Out.Address.String(), gotAddr.String())
|
||||
require.NoError(t, sdk.VerifyAddressFormat(gotAddr))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const goldenMasterPredictableContractAddr = `[
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "61",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000",
|
||||
"addressData": "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1t6r960j945lfv8mhl4mage2rg97w63xeynwrupum2s2l7em4lprs9ce5hk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "61",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d",
|
||||
"addressData": "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1px25n9sgj3a99q0zcl4awx7my6s6mxqegmdd2lmvf5lwxh080q6suttktr"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "61",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1svexu428ywc4htrxfn4tezjcsl38qqata8aany4033auafr529ns4v254c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
|
||||
"addressData": "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1jwzvvfyvpwchrccxl476pxf7c83qawsqv3f2820q0zyrav6eg4jqdcq7gc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
|
||||
"addressData": "9a8d5f98fb186825401a26206158e7a1213311a9b6a87944469913655af52ffb"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1n2x4lx8mrp5z2sq6ycsxzk885ysnxydfk658j3zxnyfk2kh49lasesxf6j"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "932f07bc53f7d0b0b43cb5a54ac3e245b205e6ae6f7c1d991dc6af4a2ff9ac18"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1jvhs00zn7lgtpdpukkj54slzgkeqte4wda7pmxgac6h55tle4svq8cmp60"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "61",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000",
|
||||
"addressData": "9725e94f528d8b78d33c25f3dfcd60e6142d8be60ab36f6a5b59036fd51560db"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1juj7jn6j3k9h35euyhealntquc2zmzlxp2ek76jmtypkl4g4vrdsfwmwxk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "61",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d",
|
||||
"addressData": "b056e539bbaf447ba18f3f13b792970111fc78933eb6700f4d227b5216d63658"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1kptw2wdm4az8hgv08ufm0y5hqyglc7yn86m8qr6dyfa4y9kkxevqmkm9q3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "61",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "6c98434180f052294ff89fb6d2dae34f9f4468b0b8e6e7c002b2a44adee39abd"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1djvyxsvq7pfzjnlcn7md9khrf705g69shrnw0sqzk2jy4hhrn27sjh2ysy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
|
||||
"addressData": "0aaf1c31c5d529d21d898775bc35b3416f47bfd99188c334c6c716102cbd3101"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1p2h3cvw9655ay8vfsa6mcddng9h5007ejxyvxdxxcutpqt9axyqsagmmay"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
|
||||
"addressData": "36fe6ab732187cdfed46290b448b32eb7f4798e7a4968b0537de8a842cbf030e"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1xmlx4dejrp7dlm2x9y95fzejadl50x885jtgkpfhm69ggt9lqv8qk3vn4f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "a0d0c942adac6f3e5e7c23116c4c42a24e96e0ab75f53690ec2d3de16067c751"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple15rgvjs4d43hnuhnuyvgkcnzz5f8fdc9twh6ndy8v9577zcr8cags40l9dt"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "61",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000",
|
||||
"addressData": "b95c467218d408a0f93046f227b6ece7fe18133ff30113db4d2a7becdfeca141"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1h9wyvusc6sy2p7fsgmez0dhvullpsyel7vq38k6d9fa7ehlv59qsvnyh36"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "61",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d",
|
||||
"addressData": "23fe45dbbd45dc6cd25244a74b6e99e7a65bf0bac2f2842a05049d37555a3ae6"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1y0lytkaaghwxe5jjgjn5km5eu7n9hu96ctegg2s9qjwnw4268tnqxhg60a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "61",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "6faea261ed63baa65b05726269e83b217fa6205dc7d9fb74f9667d004a69c082"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1d7h2yc0dvwa2vkc9wf3xn6pmy9l6vgzaclvlka8eve7sqjnfczpqqsdnwu"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
|
||||
"addressData": "67a3ab6384729925fdb144574628ce96836fe098d2c6be4e84ac106b2728d96c"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1v736kcuyw2vjtld3g3t5v2xwj6pklcyc6trtun5y4sgxkfegm9kq7vgpnt"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
|
||||
"addressData": "23a121263bfce05c144f4af86f3d8a9f87dc56f9dc48dbcffc8c5a614da4c661"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1ywsjzf3mlns9c9z0ftux70v2n7rac4hem3ydhnlu33dxzndycesssc7x2m"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "dd90dba6d6fcd5fb9c9c8f536314eb1bb29cb5aa084b633c5806b926a5636b58"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1mkgdhfkkln2lh8yu3afkx98trwefedd2pp9kx0zcq6ujdftrddvq50esay"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "61",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000",
|
||||
"addressData": "547a743022f4f1af05b102f57bf1c1c7d7ee81bae427dc20d36b2c4ec57612ae"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple123a8gvpz7nc67pd3qt6hhuwpclt7aqd6usnacgxndvkya3tkz2hq5hz38f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "61",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d",
|
||||
"addressData": "416e169110e4b411bc53162d7503b2bbf14d6b36b1413a4f4c9af622696e9665"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1g9hpdygsuj6pr0znzckh2qajh0c566ekk9qn5n6vntmzy6twjejsrl9alk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "61",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "619a0988b92d8796cea91dea63cbb1f1aefa4a6b6ee5c5d1e937007252697220"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1vxdqnz9e9kredn4frh4x8ja37xh05jntdmjut50fxuq8y5nfwgsquu9mxh"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": null
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
|
||||
"addressData": "d8af856a6a04852d19b647ad6d4336eb26e077f740aef1a0331db34d299a885a"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1mzhc26n2qjzj6xdkg7kk6sekavnwqalhgzh0rgpnrke562v63pdq8grp8q"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
|
||||
"addressData": "c7fb7bea96daab23e416c4fcf328215303005e1d0d5424257335568e5381e33c"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1clahh65km24j8eqkcn70x2pp2vpsqhsap42zgftnx4tgu5upuv7q9ywjws"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": {
|
||||
"checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
|
||||
"creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
|
||||
"creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
|
||||
"salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
"msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
|
||||
},
|
||||
"intermediate": {
|
||||
"key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
|
||||
"addressData": "ccdf9dea141a6c2475870529ab38fae9dec30df28e005894fe6578b66133ab4a"
|
||||
},
|
||||
"out": {
|
||||
"address": "purple1en0em6s5rfkzgav8q556kw86a80vxr0j3cq93987v4utvcfn4d9q0tql4w"
|
||||
}
|
||||
}
|
||||
]
|
||||
`
|
||||
96
x/wasm/keeper/ante.go
Normal file
96
x/wasm/keeper/ante.go
Normal file
@ -0,0 +1,96 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// CountTXDecorator ante handler to count the tx position in a block.
|
||||
type CountTXDecorator struct {
|
||||
storeKey sdk.StoreKey
|
||||
}
|
||||
|
||||
// NewCountTXDecorator constructor
|
||||
func NewCountTXDecorator(storeKey sdk.StoreKey) *CountTXDecorator {
|
||||
return &CountTXDecorator{storeKey: storeKey}
|
||||
}
|
||||
|
||||
// AnteHandle handler stores a tx counter with current height encoded in the store to let the app handle
|
||||
// global rollback behavior instead of keeping state in the handler itself.
|
||||
// The ante handler passes the counter value via sdk.Context upstream. See `types.TXCounter(ctx)` to read the value.
|
||||
// Simulations don't get a tx counter value assigned.
|
||||
func (a CountTXDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
if simulate {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
store := ctx.KVStore(a.storeKey)
|
||||
currentHeight := ctx.BlockHeight()
|
||||
|
||||
var txCounter uint32 // start with 0
|
||||
// load counter when exists
|
||||
if bz := store.Get(types.TXCounterPrefix); bz != nil {
|
||||
lastHeight, val := decodeHeightCounter(bz)
|
||||
if currentHeight == lastHeight {
|
||||
// then use stored counter
|
||||
txCounter = val
|
||||
} // else use `0` from above to start with
|
||||
}
|
||||
// store next counter value for current height
|
||||
store.Set(types.TXCounterPrefix, encodeHeightCounter(currentHeight, txCounter+1))
|
||||
|
||||
return next(types.WithTXCounter(ctx, txCounter), tx, simulate)
|
||||
}
|
||||
|
||||
func encodeHeightCounter(height int64, counter uint32) []byte {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, counter)
|
||||
return append(sdk.Uint64ToBigEndian(uint64(height)), b...)
|
||||
}
|
||||
|
||||
func decodeHeightCounter(bz []byte) (int64, uint32) {
|
||||
return int64(sdk.BigEndianToUint64(bz[0:8])), binary.BigEndian.Uint32(bz[8:])
|
||||
}
|
||||
|
||||
// LimitSimulationGasDecorator ante decorator to limit gas in simulation calls
|
||||
type LimitSimulationGasDecorator struct {
|
||||
gasLimit *sdk.Gas
|
||||
}
|
||||
|
||||
// NewLimitSimulationGasDecorator constructor accepts nil value to fallback to block gas limit.
|
||||
func NewLimitSimulationGasDecorator(gasLimit *sdk.Gas) *LimitSimulationGasDecorator {
|
||||
if gasLimit != nil && *gasLimit == 0 {
|
||||
panic("gas limit must not be zero")
|
||||
}
|
||||
return &LimitSimulationGasDecorator{gasLimit: gasLimit}
|
||||
}
|
||||
|
||||
// AnteHandle that limits the maximum gas available in simulations only.
|
||||
// A custom max value can be configured and will be applied when set. The value should not
|
||||
// exceed the max block gas limit.
|
||||
// Different values on nodes are not consensus breaking as they affect only
|
||||
// simulations but may have effect on client user experience.
|
||||
//
|
||||
// When no custom value is set then the max block gas is used as default limit.
|
||||
func (d LimitSimulationGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
if !simulate {
|
||||
// Wasm code is not executed in checkTX so that we don't need to limit it further.
|
||||
// Tendermint rejects the TX afterwards when the tx.gas > max block gas.
|
||||
// On deliverTX we rely on the tendermint/sdk mechanics that ensure
|
||||
// tx has gas set and gas < max block gas
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// apply custom node gas limit
|
||||
if d.gasLimit != nil {
|
||||
return next(ctx.WithGasMeter(sdk.NewGasMeter(*d.gasLimit)), tx, simulate)
|
||||
}
|
||||
|
||||
// default to max block gas when set, to be on the safe side
|
||||
if maxGas := ctx.ConsensusParams().GetBlock().MaxGas; maxGas > 0 {
|
||||
return next(ctx.WithGasMeter(sdk.NewGasMeter(sdk.Gas(maxGas))), tx, simulate)
|
||||
}
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
189
x/wasm/keeper/ante_test.go
Normal file
189
x/wasm/keeper/ante_test.go
Normal file
@ -0,0 +1,189 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestCountTxDecorator(t *testing.T) {
|
||||
keyWasm := sdk.NewKVStoreKey(types.StoreKey)
|
||||
db := dbm.NewMemDB()
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(keyWasm, sdk.StoreTypeIAVL, db)
|
||||
require.NoError(t, ms.LoadLatestVersion())
|
||||
const myCurrentBlockHeight = 100
|
||||
|
||||
specs := map[string]struct {
|
||||
setupDB func(t *testing.T, ctx sdk.Context)
|
||||
simulate bool
|
||||
nextAssertAnte func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error)
|
||||
expErr bool
|
||||
}{
|
||||
"no initial counter set": {
|
||||
setupDB: func(t *testing.T, ctx sdk.Context) {},
|
||||
nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
|
||||
gotCounter, ok := types.TXCounter(ctx)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, uint32(0), gotCounter)
|
||||
// and stored +1
|
||||
bz := ctx.MultiStore().GetKVStore(keyWasm).Get(types.TXCounterPrefix)
|
||||
assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 0, 0, 0, 1}, bz)
|
||||
return ctx, nil
|
||||
},
|
||||
},
|
||||
"persistent counter incremented - big endian": {
|
||||
setupDB: func(t *testing.T, ctx sdk.Context) {
|
||||
bz := []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 1, 0, 0, 2}
|
||||
ctx.MultiStore().GetKVStore(keyWasm).Set(types.TXCounterPrefix, bz)
|
||||
},
|
||||
nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
|
||||
gotCounter, ok := types.TXCounter(ctx)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, uint32(1<<24+2), gotCounter)
|
||||
// and stored +1
|
||||
bz := ctx.MultiStore().GetKVStore(keyWasm).Get(types.TXCounterPrefix)
|
||||
assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 1, 0, 0, 3}, bz)
|
||||
return ctx, nil
|
||||
},
|
||||
},
|
||||
"old height counter replaced": {
|
||||
setupDB: func(t *testing.T, ctx sdk.Context) {
|
||||
previousHeight := byte(myCurrentBlockHeight - 1)
|
||||
bz := []byte{0, 0, 0, 0, 0, 0, 0, previousHeight, 0, 0, 0, 1}
|
||||
ctx.MultiStore().GetKVStore(keyWasm).Set(types.TXCounterPrefix, bz)
|
||||
},
|
||||
nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
|
||||
gotCounter, ok := types.TXCounter(ctx)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, uint32(0), gotCounter)
|
||||
// and stored +1
|
||||
bz := ctx.MultiStore().GetKVStore(keyWasm).Get(types.TXCounterPrefix)
|
||||
assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 0, 0, 0, 1}, bz)
|
||||
return ctx, nil
|
||||
},
|
||||
},
|
||||
"simulation not persisted": {
|
||||
setupDB: func(t *testing.T, ctx sdk.Context) {
|
||||
},
|
||||
simulate: true,
|
||||
nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
|
||||
_, ok := types.TXCounter(ctx)
|
||||
assert.False(t, ok)
|
||||
require.True(t, simulate)
|
||||
// and not stored
|
||||
assert.False(t, ctx.MultiStore().GetKVStore(keyWasm).Has(types.TXCounterPrefix))
|
||||
return ctx, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ctx := sdk.NewContext(ms.CacheMultiStore(), tmproto.Header{
|
||||
Height: myCurrentBlockHeight,
|
||||
Time: time.Date(2021, time.September, 27, 12, 0, 0, 0, time.UTC),
|
||||
}, false, log.NewNopLogger())
|
||||
|
||||
spec.setupDB(t, ctx)
|
||||
var anyTx sdk.Tx
|
||||
|
||||
// when
|
||||
ante := keeper.NewCountTXDecorator(keyWasm)
|
||||
_, gotErr := ante.AnteHandle(ctx, anyTx, spec.simulate, spec.nextAssertAnte)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimitSimulationGasDecorator(t *testing.T) {
|
||||
var (
|
||||
hundred sdk.Gas = 100
|
||||
zero sdk.Gas = 0
|
||||
)
|
||||
specs := map[string]struct {
|
||||
customLimit *sdk.Gas
|
||||
consumeGas sdk.Gas
|
||||
maxBlockGas int64
|
||||
simulation bool
|
||||
expErr interface{}
|
||||
}{
|
||||
"custom limit set": {
|
||||
customLimit: &hundred,
|
||||
consumeGas: hundred + 1,
|
||||
maxBlockGas: -1,
|
||||
simulation: true,
|
||||
expErr: sdk.ErrorOutOfGas{Descriptor: "testing"},
|
||||
},
|
||||
"block limit set": {
|
||||
maxBlockGas: 100,
|
||||
consumeGas: hundred + 1,
|
||||
simulation: true,
|
||||
expErr: sdk.ErrorOutOfGas{Descriptor: "testing"},
|
||||
},
|
||||
"no limits set": {
|
||||
maxBlockGas: -1,
|
||||
consumeGas: hundred + 1,
|
||||
simulation: true,
|
||||
},
|
||||
"both limits set, custom applies": {
|
||||
customLimit: &hundred,
|
||||
consumeGas: hundred - 1,
|
||||
maxBlockGas: 10,
|
||||
simulation: true,
|
||||
},
|
||||
"not a simulation": {
|
||||
customLimit: &hundred,
|
||||
consumeGas: hundred + 1,
|
||||
simulation: false,
|
||||
},
|
||||
"zero custom limit": {
|
||||
customLimit: &zero,
|
||||
simulation: true,
|
||||
expErr: "gas limit must not be zero",
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
nextAnte := consumeGasAnteHandler(spec.consumeGas)
|
||||
ctx := sdk.Context{}.
|
||||
WithGasMeter(sdk.NewInfiniteGasMeter()).
|
||||
WithConsensusParams(&abci.ConsensusParams{
|
||||
Block: &abci.BlockParams{MaxGas: spec.maxBlockGas},
|
||||
})
|
||||
// when
|
||||
if spec.expErr != nil {
|
||||
require.PanicsWithValue(t, spec.expErr, func() {
|
||||
ante := keeper.NewLimitSimulationGasDecorator(spec.customLimit)
|
||||
ante.AnteHandle(ctx, nil, spec.simulation, nextAnte)
|
||||
})
|
||||
return
|
||||
}
|
||||
ante := keeper.NewLimitSimulationGasDecorator(spec.customLimit)
|
||||
ante.AnteHandle(ctx, nil, spec.simulation, nextAnte)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func consumeGasAnteHandler(gasToConsume sdk.Gas) sdk.AnteHandler {
|
||||
return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
|
||||
ctx.GasMeter().ConsumeGas(gasToConsume, "testing")
|
||||
return ctx, nil
|
||||
}
|
||||
}
|
||||
43
x/wasm/keeper/api.go
Normal file
43
x/wasm/keeper/api.go
Normal file
@ -0,0 +1,43 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
wasmvm "github.com/CosmWasm/wasmvm"
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultGasCostHumanAddress is how moch SDK gas we charge to convert to a human address format
|
||||
DefaultGasCostHumanAddress = 5
|
||||
// DefaultGasCostCanonicalAddress is how moch SDK gas we charge to convert to a canonical address format
|
||||
DefaultGasCostCanonicalAddress = 4
|
||||
|
||||
// DefaultDeserializationCostPerByte The formular should be `len(data) * deserializationCostPerByte`
|
||||
DefaultDeserializationCostPerByte = 1
|
||||
)
|
||||
|
||||
var (
|
||||
costHumanize = DefaultGasCostHumanAddress * DefaultGasMultiplier
|
||||
costCanonical = DefaultGasCostCanonicalAddress * DefaultGasMultiplier
|
||||
costJSONDeserialization = wasmvmtypes.UFraction{
|
||||
Numerator: DefaultDeserializationCostPerByte * DefaultGasMultiplier,
|
||||
Denominator: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func humanAddress(canon []byte) (string, uint64, error) {
|
||||
if err := sdk.VerifyAddressFormat(canon); err != nil {
|
||||
return "", costHumanize, err
|
||||
}
|
||||
return sdk.AccAddress(canon).String(), costHumanize, nil
|
||||
}
|
||||
|
||||
func canonicalAddress(human string) ([]byte, uint64, error) {
|
||||
bz, err := sdk.AccAddressFromBech32(human)
|
||||
return bz, costCanonical, err
|
||||
}
|
||||
|
||||
var cosmwasmAPI = wasmvm.GoAPI{
|
||||
HumanAddress: humanAddress,
|
||||
CanonicalAddress: canonicalAddress,
|
||||
}
|
||||
63
x/wasm/keeper/authz_policy.go
Normal file
63
x/wasm/keeper/authz_policy.go
Normal file
@ -0,0 +1,63 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// ChainAccessConfigs chain settings
|
||||
type ChainAccessConfigs struct {
|
||||
Upload types.AccessConfig
|
||||
Instantiate types.AccessConfig
|
||||
}
|
||||
|
||||
// NewChainAccessConfigs constructor
|
||||
func NewChainAccessConfigs(upload types.AccessConfig, instantiate types.AccessConfig) ChainAccessConfigs {
|
||||
return ChainAccessConfigs{Upload: upload, Instantiate: instantiate}
|
||||
}
|
||||
|
||||
type AuthorizationPolicy interface {
|
||||
CanCreateCode(chainConfigs ChainAccessConfigs, actor sdk.AccAddress, contractConfig types.AccessConfig) bool
|
||||
CanInstantiateContract(c types.AccessConfig, actor sdk.AccAddress) bool
|
||||
CanModifyContract(admin, actor sdk.AccAddress) bool
|
||||
CanModifyCodeAccessConfig(creator, actor sdk.AccAddress, isSubset bool) bool
|
||||
}
|
||||
|
||||
type DefaultAuthorizationPolicy struct{}
|
||||
|
||||
func (p DefaultAuthorizationPolicy) CanCreateCode(chainConfigs ChainAccessConfigs, actor sdk.AccAddress, contractConfig types.AccessConfig) bool {
|
||||
return chainConfigs.Upload.Allowed(actor) &&
|
||||
contractConfig.IsSubset(chainConfigs.Instantiate)
|
||||
}
|
||||
|
||||
func (p DefaultAuthorizationPolicy) CanInstantiateContract(config types.AccessConfig, actor sdk.AccAddress) bool {
|
||||
return config.Allowed(actor)
|
||||
}
|
||||
|
||||
func (p DefaultAuthorizationPolicy) CanModifyContract(admin, actor sdk.AccAddress) bool {
|
||||
return admin != nil && admin.Equals(actor)
|
||||
}
|
||||
|
||||
func (p DefaultAuthorizationPolicy) CanModifyCodeAccessConfig(creator, actor sdk.AccAddress, isSubset bool) bool {
|
||||
return creator != nil && creator.Equals(actor) && isSubset
|
||||
}
|
||||
|
||||
type GovAuthorizationPolicy struct{}
|
||||
|
||||
// CanCreateCode implements AuthorizationPolicy.CanCreateCode to allow gov actions. Always returns true.
|
||||
func (p GovAuthorizationPolicy) CanCreateCode(ChainAccessConfigs, sdk.AccAddress, types.AccessConfig) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p GovAuthorizationPolicy) CanInstantiateContract(types.AccessConfig, sdk.AccAddress) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p GovAuthorizationPolicy) CanModifyContract(sdk.AccAddress, sdk.AccAddress) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p GovAuthorizationPolicy) CanModifyCodeAccessConfig(sdk.AccAddress, sdk.AccAddress, bool) bool {
|
||||
return true
|
||||
}
|
||||
345
x/wasm/keeper/authz_policy_test.go
Normal file
345
x/wasm/keeper/authz_policy_test.go
Normal file
@ -0,0 +1,345 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestDefaultAuthzPolicyCanCreateCode(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
specs := map[string]struct {
|
||||
chainConfigs ChainAccessConfigs
|
||||
contractInstConf types.AccessConfig
|
||||
actor sdk.AccAddress
|
||||
exp bool
|
||||
panics bool
|
||||
}{
|
||||
"upload nobody": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowNobody, types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
exp: false,
|
||||
},
|
||||
"upload everybody": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
exp: true,
|
||||
},
|
||||
"upload only address - same": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(myActorAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
exp: true,
|
||||
},
|
||||
"upload only address - different": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(otherAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
exp: false,
|
||||
},
|
||||
"upload any address - included": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
exp: true,
|
||||
},
|
||||
"upload any address - not included": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
exp: false,
|
||||
},
|
||||
"contract config - subtype": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody),
|
||||
contractInstConf: types.AccessTypeAnyOfAddresses.With(myActorAddress),
|
||||
exp: true,
|
||||
},
|
||||
"contract config - not subtype": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowNobody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
exp: false,
|
||||
},
|
||||
"upload undefined config - panics": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessConfig{}, types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
panics: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := DefaultAuthorizationPolicy{}
|
||||
if !spec.panics {
|
||||
got := policy.CanCreateCode(spec.chainConfigs, myActorAddress, spec.contractInstConf)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
return
|
||||
}
|
||||
assert.Panics(t, func() {
|
||||
policy.CanCreateCode(spec.chainConfigs, myActorAddress, spec.contractInstConf)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAuthzPolicyCanInstantiateContract(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
specs := map[string]struct {
|
||||
config types.AccessConfig
|
||||
actor sdk.AccAddress
|
||||
exp bool
|
||||
panics bool
|
||||
}{
|
||||
"nobody": {
|
||||
config: types.AllowNobody,
|
||||
exp: false,
|
||||
},
|
||||
"everybody": {
|
||||
config: types.AllowEverybody,
|
||||
exp: true,
|
||||
},
|
||||
"only address - same": {
|
||||
config: types.AccessTypeOnlyAddress.With(myActorAddress),
|
||||
exp: true,
|
||||
},
|
||||
"only address - different": {
|
||||
config: types.AccessTypeOnlyAddress.With(otherAddress),
|
||||
exp: false,
|
||||
},
|
||||
"any address - included": {
|
||||
config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress),
|
||||
exp: true,
|
||||
},
|
||||
"any address - not included": {
|
||||
config: types.AccessTypeAnyOfAddresses.With(otherAddress),
|
||||
exp: false,
|
||||
},
|
||||
"undefined config - panics": {
|
||||
config: types.AccessConfig{},
|
||||
panics: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := DefaultAuthorizationPolicy{}
|
||||
if !spec.panics {
|
||||
got := policy.CanInstantiateContract(spec.config, myActorAddress)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
return
|
||||
}
|
||||
assert.Panics(t, func() {
|
||||
policy.CanInstantiateContract(spec.config, myActorAddress)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAuthzPolicyCanModifyContract(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
|
||||
specs := map[string]struct {
|
||||
admin sdk.AccAddress
|
||||
exp bool
|
||||
}{
|
||||
"same as actor": {
|
||||
admin: myActorAddress,
|
||||
exp: true,
|
||||
},
|
||||
"different admin": {
|
||||
admin: otherAddress,
|
||||
exp: false,
|
||||
},
|
||||
"no admin": {
|
||||
exp: false,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := DefaultAuthorizationPolicy{}
|
||||
got := policy.CanModifyContract(spec.admin, myActorAddress)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultAuthzPolicyCanModifyCodeAccessConfig(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
|
||||
specs := map[string]struct {
|
||||
admin sdk.AccAddress
|
||||
subset bool
|
||||
exp bool
|
||||
}{
|
||||
"same as actor - subset": {
|
||||
admin: myActorAddress,
|
||||
subset: true,
|
||||
exp: true,
|
||||
},
|
||||
"same as actor - not subset": {
|
||||
admin: myActorAddress,
|
||||
subset: false,
|
||||
exp: false,
|
||||
},
|
||||
"different admin": {
|
||||
admin: otherAddress,
|
||||
exp: false,
|
||||
},
|
||||
"no admin": {
|
||||
exp: false,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := DefaultAuthorizationPolicy{}
|
||||
got := policy.CanModifyCodeAccessConfig(spec.admin, myActorAddress, spec.subset)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGovAuthzPolicyCanCreateCode(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
specs := map[string]struct {
|
||||
chainConfigs ChainAccessConfigs
|
||||
contractInstConf types.AccessConfig
|
||||
actor sdk.AccAddress
|
||||
}{
|
||||
"upload nobody": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowNobody, types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
"upload everybody": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
"upload only address - same": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(myActorAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
"upload only address - different": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(otherAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
"upload any address - included": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
"upload any address - not included": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress), types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
"contract config - subtype": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody),
|
||||
contractInstConf: types.AccessTypeAnyOfAddresses.With(myActorAddress),
|
||||
},
|
||||
"contract config - not subtype": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowNobody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
"upload undefined config - not panics": {
|
||||
chainConfigs: NewChainAccessConfigs(types.AccessConfig{}, types.AllowEverybody),
|
||||
contractInstConf: types.AllowEverybody,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := GovAuthorizationPolicy{}
|
||||
got := policy.CanCreateCode(spec.chainConfigs, myActorAddress, spec.contractInstConf)
|
||||
assert.True(t, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGovAuthzPolicyCanInstantiateContract(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
specs := map[string]struct {
|
||||
config types.AccessConfig
|
||||
actor sdk.AccAddress
|
||||
}{
|
||||
"nobody": {
|
||||
config: types.AllowNobody,
|
||||
},
|
||||
"everybody": {
|
||||
config: types.AllowEverybody,
|
||||
},
|
||||
"only address - same": {
|
||||
config: types.AccessTypeOnlyAddress.With(myActorAddress),
|
||||
},
|
||||
"only address - different": {
|
||||
config: types.AccessTypeOnlyAddress.With(otherAddress),
|
||||
},
|
||||
"any address - included": {
|
||||
config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress),
|
||||
},
|
||||
"any address - not included": {
|
||||
config: types.AccessTypeAnyOfAddresses.With(otherAddress),
|
||||
},
|
||||
"undefined config - panics": {
|
||||
config: types.AccessConfig{},
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := GovAuthorizationPolicy{}
|
||||
got := policy.CanInstantiateContract(spec.config, myActorAddress)
|
||||
assert.True(t, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGovAuthzPolicyCanModifyContract(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
|
||||
specs := map[string]struct {
|
||||
admin sdk.AccAddress
|
||||
}{
|
||||
"same as actor": {
|
||||
admin: myActorAddress,
|
||||
},
|
||||
"different admin": {
|
||||
admin: otherAddress,
|
||||
},
|
||||
"no admin": {},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := GovAuthorizationPolicy{}
|
||||
got := policy.CanModifyContract(spec.admin, myActorAddress)
|
||||
assert.True(t, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGovAuthzPolicyCanModifyCodeAccessConfig(t *testing.T) {
|
||||
myActorAddress := RandomAccountAddress(t)
|
||||
otherAddress := RandomAccountAddress(t)
|
||||
|
||||
specs := map[string]struct {
|
||||
admin sdk.AccAddress
|
||||
subset bool
|
||||
}{
|
||||
"same as actor - subset": {
|
||||
admin: myActorAddress,
|
||||
subset: true,
|
||||
},
|
||||
"same as actor - not subset": {
|
||||
admin: myActorAddress,
|
||||
subset: false,
|
||||
},
|
||||
"different admin": {
|
||||
admin: otherAddress,
|
||||
},
|
||||
"no admin": {},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
policy := GovAuthorizationPolicy{}
|
||||
got := policy.CanModifyCodeAccessConfig(spec.admin, myActorAddress, spec.subset)
|
||||
assert.True(t, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
102
x/wasm/keeper/bench_test.go
Normal file
102
x/wasm/keeper/bench_test.go
Normal file
@ -0,0 +1,102 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/stretchr/testify/require"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// BenchmarkVerification benchmarks secp256k1 verification which is 1000 gas based on cpu time.
|
||||
//
|
||||
// Just this function is copied from
|
||||
// https://github.com/cosmos/cosmos-sdk/blob/90e9370bd80d9a3d41f7203ddb71166865561569/crypto/keys/internal/benchmarking/bench.go#L48-L62
|
||||
// And thus under the GO license (BSD style)
|
||||
func BenchmarkGasNormalization(b *testing.B) {
|
||||
priv := secp256k1.GenPrivKey()
|
||||
pub := priv.PubKey()
|
||||
|
||||
// use a short message, so this time doesn't get dominated by hashing.
|
||||
message := []byte("Hello, world!")
|
||||
signature, err := priv.Sign(message)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
pub.VerifySignature(message, signature)
|
||||
}
|
||||
}
|
||||
|
||||
// By comparing the timing for queries on pinned vs unpinned, the difference gives us the overhead of
|
||||
// instantiating an unpinned contract. That value can be used to determine a reasonable gas price
|
||||
// for the InstantiationCost
|
||||
func BenchmarkInstantiationOverhead(b *testing.B) {
|
||||
specs := map[string]struct {
|
||||
pinned bool
|
||||
db func() dbm.DB
|
||||
}{
|
||||
"unpinned, memory db": {
|
||||
db: func() dbm.DB { return dbm.NewMemDB() },
|
||||
},
|
||||
"pinned, memory db": {
|
||||
db: func() dbm.DB { return dbm.NewMemDB() },
|
||||
pinned: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
wasmConfig := types.WasmConfig{MemoryCacheSize: 0}
|
||||
ctx, keepers := createTestInput(b, false, AvailableCapabilities, wasmConfig, spec.db())
|
||||
example := InstantiateHackatomExampleContract(b, ctx, keepers)
|
||||
if spec.pinned {
|
||||
require.NoError(b, keepers.ContractKeeper.PinCode(ctx, example.CodeID))
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := keepers.WasmKeeper.QuerySmart(ctx, example.Contract, []byte(`{"verifier":{}}`))
|
||||
require.NoError(b, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the time it takes to compile some wasm code the first time.
|
||||
// This will help us adjust pricing for UploadCode
|
||||
func BenchmarkCompilation(b *testing.B) {
|
||||
specs := map[string]struct {
|
||||
wasmFile string
|
||||
}{
|
||||
"hackatom": {
|
||||
wasmFile: "./testdata/hackatom.wasm",
|
||||
},
|
||||
"burner": {
|
||||
wasmFile: "./testdata/burner.wasm",
|
||||
},
|
||||
"ibc_reflect": {
|
||||
wasmFile: "./testdata/ibc_reflect.wasm",
|
||||
},
|
||||
}
|
||||
|
||||
for name, spec := range specs {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
wasmConfig := types.WasmConfig{MemoryCacheSize: 0}
|
||||
db := dbm.NewMemDB()
|
||||
ctx, keepers := createTestInput(b, false, AvailableCapabilities, wasmConfig, db)
|
||||
|
||||
// print out code size for comparisons
|
||||
code, err := os.ReadFile(spec.wasmFile)
|
||||
require.NoError(b, err)
|
||||
b.Logf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b(size: %d) ", len(code))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = StoreExampleContract(b, ctx, keepers, spec.wasmFile)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
130
x/wasm/keeper/contract_keeper.go
Normal file
130
x/wasm/keeper/contract_keeper.go
Normal file
@ -0,0 +1,130 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
var _ types.ContractOpsKeeper = PermissionedKeeper{}
|
||||
|
||||
// decoratedKeeper contains a subset of the wasm keeper that are already or can be guarded by an authorization policy in the future
|
||||
type decoratedKeeper interface {
|
||||
create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig, authZ AuthorizationPolicy) (codeID uint64, checksum []byte, err error)
|
||||
|
||||
instantiate(
|
||||
ctx sdk.Context,
|
||||
codeID uint64,
|
||||
creator, admin sdk.AccAddress,
|
||||
initMsg []byte,
|
||||
label string,
|
||||
deposit sdk.Coins,
|
||||
addressGenerator AddressGenerator,
|
||||
authZ AuthorizationPolicy,
|
||||
) (sdk.AccAddress, []byte, error)
|
||||
|
||||
migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) ([]byte, error)
|
||||
setContractAdmin(ctx sdk.Context, contractAddress, caller, newAdmin sdk.AccAddress, authZ AuthorizationPolicy) error
|
||||
pinCode(ctx sdk.Context, codeID uint64) error
|
||||
unpinCode(ctx sdk.Context, codeID uint64) error
|
||||
execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error)
|
||||
Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error)
|
||||
setContractInfoExtension(ctx sdk.Context, contract sdk.AccAddress, extra types.ContractInfoExtension) error
|
||||
setAccessConfig(ctx sdk.Context, codeID uint64, caller sdk.AccAddress, newConfig types.AccessConfig, autz AuthorizationPolicy) error
|
||||
ClassicAddressGenerator() AddressGenerator
|
||||
}
|
||||
|
||||
type PermissionedKeeper struct {
|
||||
authZPolicy AuthorizationPolicy
|
||||
nested decoratedKeeper
|
||||
}
|
||||
|
||||
func NewPermissionedKeeper(nested decoratedKeeper, authZPolicy AuthorizationPolicy) *PermissionedKeeper {
|
||||
return &PermissionedKeeper{authZPolicy: authZPolicy, nested: nested}
|
||||
}
|
||||
|
||||
func NewGovPermissionKeeper(nested decoratedKeeper) *PermissionedKeeper {
|
||||
return NewPermissionedKeeper(nested, GovAuthorizationPolicy{})
|
||||
}
|
||||
|
||||
func NewDefaultPermissionKeeper(nested decoratedKeeper) *PermissionedKeeper {
|
||||
return NewPermissionedKeeper(nested, DefaultAuthorizationPolicy{})
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig) (codeID uint64, checksum []byte, err error) {
|
||||
return p.nested.create(ctx, creator, wasmCode, instantiateAccess, p.authZPolicy)
|
||||
}
|
||||
|
||||
// Instantiate creates an instance of a WASM contract using the classic sequence based address generator
|
||||
func (p PermissionedKeeper) Instantiate(
|
||||
ctx sdk.Context,
|
||||
codeID uint64,
|
||||
creator, admin sdk.AccAddress,
|
||||
initMsg []byte,
|
||||
label string,
|
||||
deposit sdk.Coins,
|
||||
) (sdk.AccAddress, []byte, error) {
|
||||
return p.nested.instantiate(ctx, codeID, creator, admin, initMsg, label, deposit, p.nested.ClassicAddressGenerator(), p.authZPolicy)
|
||||
}
|
||||
|
||||
// Instantiate2 creates an instance of a WASM contract using the predictable address generator
|
||||
func (p PermissionedKeeper) Instantiate2(
|
||||
ctx sdk.Context,
|
||||
codeID uint64,
|
||||
creator, admin sdk.AccAddress,
|
||||
initMsg []byte,
|
||||
label string,
|
||||
deposit sdk.Coins,
|
||||
salt []byte,
|
||||
fixMsg bool,
|
||||
) (sdk.AccAddress, []byte, error) {
|
||||
return p.nested.instantiate(
|
||||
ctx,
|
||||
codeID,
|
||||
creator,
|
||||
admin,
|
||||
initMsg,
|
||||
label,
|
||||
deposit,
|
||||
PredicableAddressGenerator(creator, salt, initMsg, fixMsg),
|
||||
p.authZPolicy,
|
||||
)
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) {
|
||||
return p.nested.execute(ctx, contractAddress, caller, msg, coins)
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) Migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte) ([]byte, error) {
|
||||
return p.nested.migrate(ctx, contractAddress, caller, newCodeID, msg, p.authZPolicy)
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error) {
|
||||
return p.nested.Sudo(ctx, contractAddress, msg)
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) UpdateContractAdmin(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newAdmin sdk.AccAddress) error {
|
||||
return p.nested.setContractAdmin(ctx, contractAddress, caller, newAdmin, p.authZPolicy)
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) ClearContractAdmin(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress) error {
|
||||
return p.nested.setContractAdmin(ctx, contractAddress, caller, nil, p.authZPolicy)
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) PinCode(ctx sdk.Context, codeID uint64) error {
|
||||
return p.nested.pinCode(ctx, codeID)
|
||||
}
|
||||
|
||||
func (p PermissionedKeeper) UnpinCode(ctx sdk.Context, codeID uint64) error {
|
||||
return p.nested.unpinCode(ctx, codeID)
|
||||
}
|
||||
|
||||
// SetContractInfoExtension updates the extra attributes that can be stored with the contract info
|
||||
func (p PermissionedKeeper) SetContractInfoExtension(ctx sdk.Context, contract sdk.AccAddress, extra types.ContractInfoExtension) error {
|
||||
return p.nested.setContractInfoExtension(ctx, contract, extra)
|
||||
}
|
||||
|
||||
// SetAccessConfig updates the access config of a code id.
|
||||
func (p PermissionedKeeper) SetAccessConfig(ctx sdk.Context, codeID uint64, caller sdk.AccAddress, newConfig types.AccessConfig) error {
|
||||
return p.nested.setAccessConfig(ctx, codeID, caller, newConfig, p.authZPolicy)
|
||||
}
|
||||
168
x/wasm/keeper/contract_keeper_test.go
Normal file
168
x/wasm/keeper/contract_keeper_test.go
Normal file
@ -0,0 +1,168 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestInstantiate2(t *testing.T) {
|
||||
parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities)
|
||||
example := StoreHackatomExampleContract(t, parentCtx, keepers)
|
||||
otherExample := StoreReflectContract(t, parentCtx, keepers)
|
||||
mock := &wasmtesting.MockWasmer{}
|
||||
wasmtesting.MakeInstantiable(mock)
|
||||
keepers.WasmKeeper.wasmVM = mock // set mock to not fail on contract init message
|
||||
|
||||
verifierAddr := RandomAccountAddress(t)
|
||||
beneficiaryAddr := RandomAccountAddress(t)
|
||||
initMsg := mustMarshal(t, HackatomExampleInitMsg{Verifier: verifierAddr, Beneficiary: beneficiaryAddr})
|
||||
|
||||
otherAddr := keepers.Faucet.NewFundedRandomAccount(parentCtx, sdk.NewInt64Coin("denom", 1_000_000_000))
|
||||
|
||||
const (
|
||||
mySalt = "my salt"
|
||||
myLabel = "my label"
|
||||
)
|
||||
// create instances for duplicate checks
|
||||
exampleContract := func(t *testing.T, ctx sdk.Context, fixMsg bool) {
|
||||
_, _, err := keepers.ContractKeeper.Instantiate2(
|
||||
ctx,
|
||||
example.CodeID,
|
||||
example.CreatorAddr,
|
||||
nil,
|
||||
initMsg,
|
||||
myLabel,
|
||||
sdk.NewCoins(sdk.NewInt64Coin("denom", 1)),
|
||||
[]byte(mySalt),
|
||||
fixMsg,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
exampleWithFixMsg := func(t *testing.T, ctx sdk.Context) {
|
||||
exampleContract(t, ctx, true)
|
||||
}
|
||||
exampleWithoutFixMsg := func(t *testing.T, ctx sdk.Context) {
|
||||
exampleContract(t, ctx, false)
|
||||
}
|
||||
specs := map[string]struct {
|
||||
setup func(t *testing.T, ctx sdk.Context)
|
||||
codeID uint64
|
||||
sender sdk.AccAddress
|
||||
salt []byte
|
||||
initMsg json.RawMessage
|
||||
fixMsg bool
|
||||
expErr error
|
||||
}{
|
||||
"fix msg - generates different address than without fixMsg": {
|
||||
setup: exampleWithoutFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: example.CreatorAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: initMsg,
|
||||
fixMsg: true,
|
||||
},
|
||||
"fix msg - different sender": {
|
||||
setup: exampleWithFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: otherAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: initMsg,
|
||||
fixMsg: true,
|
||||
},
|
||||
"fix msg - different code": {
|
||||
setup: exampleWithFixMsg,
|
||||
codeID: otherExample.CodeID,
|
||||
sender: example.CreatorAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: []byte(`{}`),
|
||||
fixMsg: true,
|
||||
},
|
||||
"fix msg - different salt": {
|
||||
setup: exampleWithFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: example.CreatorAddr,
|
||||
salt: []byte("other salt"),
|
||||
initMsg: initMsg,
|
||||
fixMsg: true,
|
||||
},
|
||||
"fix msg - different init msg": {
|
||||
setup: exampleWithFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: example.CreatorAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}),
|
||||
fixMsg: true,
|
||||
},
|
||||
"different sender": {
|
||||
setup: exampleWithoutFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: otherAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: initMsg,
|
||||
},
|
||||
"different code": {
|
||||
setup: exampleWithoutFixMsg,
|
||||
codeID: otherExample.CodeID,
|
||||
sender: example.CreatorAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: []byte(`{}`),
|
||||
},
|
||||
"different salt": {
|
||||
setup: exampleWithoutFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: example.CreatorAddr,
|
||||
salt: []byte(`other salt`),
|
||||
initMsg: initMsg,
|
||||
},
|
||||
"different init msg - reject same address": {
|
||||
setup: exampleWithoutFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: example.CreatorAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}),
|
||||
expErr: types.ErrDuplicate,
|
||||
},
|
||||
"fix msg - long msg": {
|
||||
setup: exampleWithFixMsg,
|
||||
codeID: example.CodeID,
|
||||
sender: otherAddr,
|
||||
salt: []byte(mySalt),
|
||||
initMsg: []byte(fmt.Sprintf(`{"foo":%q}`, strings.Repeat("b", math.MaxInt16+1))), // too long kills CI
|
||||
fixMsg: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ctx, _ := parentCtx.CacheContext()
|
||||
spec.setup(t, ctx)
|
||||
gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate2(
|
||||
ctx,
|
||||
spec.codeID,
|
||||
spec.sender,
|
||||
nil,
|
||||
spec.initMsg,
|
||||
myLabel,
|
||||
sdk.NewCoins(sdk.NewInt64Coin("denom", 2)),
|
||||
spec.salt,
|
||||
spec.fixMsg,
|
||||
)
|
||||
if spec.expErr != nil {
|
||||
assert.ErrorIs(t, gotErr, spec.expErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
assert.NotEmpty(t, gotAddr)
|
||||
})
|
||||
}
|
||||
}
|
||||
67
x/wasm/keeper/events.go
Normal file
67
x/wasm/keeper/events.go
Normal file
@ -0,0 +1,67 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// newWasmModuleEvent creates with wasm module event for interacting with the given contract. Adds custom attributes
|
||||
// to this event.
|
||||
func newWasmModuleEvent(customAttributes []wasmvmtypes.EventAttribute, contractAddr sdk.AccAddress) (sdk.Events, error) {
|
||||
attrs, err := contractSDKEventAttributes(customAttributes, contractAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// each wasm invocation always returns one sdk.Event
|
||||
return sdk.Events{sdk.NewEvent(types.WasmModuleEventType, attrs...)}, nil
|
||||
}
|
||||
|
||||
const eventTypeMinLength = 2
|
||||
|
||||
// newCustomEvents converts wasmvm events from a contract response to sdk type events
|
||||
func newCustomEvents(evts wasmvmtypes.Events, contractAddr sdk.AccAddress) (sdk.Events, error) {
|
||||
events := make(sdk.Events, 0, len(evts))
|
||||
for _, e := range evts {
|
||||
typ := strings.TrimSpace(e.Type)
|
||||
if len(typ) <= eventTypeMinLength {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Event type too short: '%s'", typ))
|
||||
}
|
||||
attributes, err := contractSDKEventAttributes(e.Attributes, contractAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, sdk.NewEvent(fmt.Sprintf("%s%s", types.CustomContractEventPrefix, typ), attributes...))
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// convert and add contract address issuing this event
|
||||
func contractSDKEventAttributes(customAttributes []wasmvmtypes.EventAttribute, contractAddr sdk.AccAddress) ([]sdk.Attribute, error) {
|
||||
attrs := []sdk.Attribute{sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String())}
|
||||
// append attributes from wasm to the sdk.Event
|
||||
for _, l := range customAttributes {
|
||||
// ensure key and value are non-empty (and trim what is there)
|
||||
key := strings.TrimSpace(l.Key)
|
||||
if len(key) == 0 {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Empty attribute key. Value: %s", l.Value))
|
||||
}
|
||||
value := strings.TrimSpace(l.Value)
|
||||
// TODO: check if this is legal in the SDK - if it is, we can remove this check
|
||||
if len(value) == 0 {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Empty attribute value. Key: %s", key))
|
||||
}
|
||||
// and reserve all _* keys for our use (not contract)
|
||||
if strings.HasPrefix(key, types.AttributeReservedPrefix) {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Attribute key starts with reserved prefix %s: '%s'", types.AttributeReservedPrefix, key))
|
||||
}
|
||||
attrs = append(attrs, sdk.NewAttribute(key, value))
|
||||
}
|
||||
return attrs, nil
|
||||
}
|
||||
290
x/wasm/keeper/events_test.go
Normal file
290
x/wasm/keeper/events_test.go
Normal file
@ -0,0 +1,290 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestHasWasmModuleEvent(t *testing.T) {
|
||||
myContractAddr := RandomAccountAddress(t)
|
||||
specs := map[string]struct {
|
||||
srcEvents []sdk.Event
|
||||
exp bool
|
||||
}{
|
||||
"event found": {
|
||||
srcEvents: []sdk.Event{
|
||||
sdk.NewEvent(types.WasmModuleEventType, sdk.NewAttribute("_contract_address", myContractAddr.String())),
|
||||
},
|
||||
exp: true,
|
||||
},
|
||||
"different event: not found": {
|
||||
srcEvents: []sdk.Event{
|
||||
sdk.NewEvent(types.CustomContractEventPrefix, sdk.NewAttribute("_contract_address", myContractAddr.String())),
|
||||
},
|
||||
exp: false,
|
||||
},
|
||||
"event with different address: not found": {
|
||||
srcEvents: []sdk.Event{
|
||||
sdk.NewEvent(types.WasmModuleEventType, sdk.NewAttribute("_contract_address", RandomBech32AccountAddress(t))),
|
||||
},
|
||||
exp: false,
|
||||
},
|
||||
"no event": {
|
||||
srcEvents: []sdk.Event{},
|
||||
exp: false,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
em := sdk.NewEventManager()
|
||||
em.EmitEvents(spec.srcEvents)
|
||||
ctx := sdk.Context{}.WithContext(context.Background()).WithEventManager(em)
|
||||
|
||||
got := hasWasmModuleEvent(ctx, myContractAddr)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCustomEvents(t *testing.T) {
|
||||
myContract := RandomAccountAddress(t)
|
||||
specs := map[string]struct {
|
||||
src wasmvmtypes.Events
|
||||
exp sdk.Events
|
||||
isError bool
|
||||
}{
|
||||
"all good": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "foo",
|
||||
Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}},
|
||||
}},
|
||||
exp: sdk.Events{sdk.NewEvent("wasm-foo",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("myKey", "myVal"))},
|
||||
},
|
||||
"multiple attributes": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "foo",
|
||||
Attributes: []wasmvmtypes.EventAttribute{
|
||||
{Key: "myKey", Value: "myVal"},
|
||||
{Key: "myOtherKey", Value: "myOtherVal"},
|
||||
},
|
||||
}},
|
||||
exp: sdk.Events{sdk.NewEvent("wasm-foo",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("myKey", "myVal"),
|
||||
sdk.NewAttribute("myOtherKey", "myOtherVal"))},
|
||||
},
|
||||
"multiple events": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "foo",
|
||||
Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}},
|
||||
}, {
|
||||
Type: "bar",
|
||||
Attributes: []wasmvmtypes.EventAttribute{{Key: "otherKey", Value: "otherVal"}},
|
||||
}},
|
||||
exp: sdk.Events{
|
||||
sdk.NewEvent("wasm-foo",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("myKey", "myVal")),
|
||||
sdk.NewEvent("wasm-bar",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("otherKey", "otherVal")),
|
||||
},
|
||||
},
|
||||
"without attributes": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "foo",
|
||||
}},
|
||||
exp: sdk.Events{sdk.NewEvent("wasm-foo",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()))},
|
||||
},
|
||||
"error on short event type": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "f",
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"error on _contract_address": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "foo",
|
||||
Attributes: []wasmvmtypes.EventAttribute{{Key: "_contract_address", Value: RandomBech32AccountAddress(t)}},
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"error on reserved prefix": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "wasm",
|
||||
Attributes: []wasmvmtypes.EventAttribute{
|
||||
{Key: "_reserved", Value: "is skipped"},
|
||||
{Key: "normal", Value: "is used"},
|
||||
},
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"error on empty value": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "boom",
|
||||
Attributes: []wasmvmtypes.EventAttribute{
|
||||
{Key: "some", Value: "data"},
|
||||
{Key: "key", Value: ""},
|
||||
},
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"error on empty key": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "boom",
|
||||
Attributes: []wasmvmtypes.EventAttribute{
|
||||
{Key: "some", Value: "data"},
|
||||
{Key: "", Value: "value"},
|
||||
},
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"error on whitespace type": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: " f ",
|
||||
Attributes: []wasmvmtypes.EventAttribute{
|
||||
{Key: "some", Value: "data"},
|
||||
},
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"error on only whitespace key": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "boom",
|
||||
Attributes: []wasmvmtypes.EventAttribute{
|
||||
{Key: "some", Value: "data"},
|
||||
{Key: "\n\n\n\n", Value: "value"},
|
||||
},
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"error on only whitespace value": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: "boom",
|
||||
Attributes: []wasmvmtypes.EventAttribute{
|
||||
{Key: "some", Value: "data"},
|
||||
{Key: "myKey", Value: " \t\r\n"},
|
||||
},
|
||||
}},
|
||||
isError: true,
|
||||
},
|
||||
"strip out whitespace": {
|
||||
src: wasmvmtypes.Events{{
|
||||
Type: " food\n",
|
||||
Attributes: []wasmvmtypes.EventAttribute{{Key: "my Key", Value: "\tmyVal"}},
|
||||
}},
|
||||
exp: sdk.Events{sdk.NewEvent("wasm-food",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("my Key", "myVal"))},
|
||||
},
|
||||
"empty event elements": {
|
||||
src: make(wasmvmtypes.Events, 10),
|
||||
isError: true,
|
||||
},
|
||||
"nil": {
|
||||
exp: sdk.Events{},
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
gotEvent, err := newCustomEvents(spec.src, myContract)
|
||||
if spec.isError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, spec.exp, gotEvent)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWasmModuleEvent(t *testing.T) {
|
||||
myContract := RandomAccountAddress(t)
|
||||
specs := map[string]struct {
|
||||
src []wasmvmtypes.EventAttribute
|
||||
exp sdk.Events
|
||||
isError bool
|
||||
}{
|
||||
"all good": {
|
||||
src: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}},
|
||||
exp: sdk.Events{sdk.NewEvent("wasm",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("myKey", "myVal"))},
|
||||
},
|
||||
"multiple attributes": {
|
||||
src: []wasmvmtypes.EventAttribute{
|
||||
{Key: "myKey", Value: "myVal"},
|
||||
{Key: "myOtherKey", Value: "myOtherVal"},
|
||||
},
|
||||
exp: sdk.Events{sdk.NewEvent("wasm",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("myKey", "myVal"),
|
||||
sdk.NewAttribute("myOtherKey", "myOtherVal"))},
|
||||
},
|
||||
"without attributes": {
|
||||
exp: sdk.Events{sdk.NewEvent("wasm",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()))},
|
||||
},
|
||||
"error on _contract_address": {
|
||||
src: []wasmvmtypes.EventAttribute{{Key: "_contract_address", Value: RandomBech32AccountAddress(t)}},
|
||||
isError: true,
|
||||
},
|
||||
"error on whitespace key": {
|
||||
src: []wasmvmtypes.EventAttribute{{Key: " ", Value: "value"}},
|
||||
isError: true,
|
||||
},
|
||||
"error on whitespace value": {
|
||||
src: []wasmvmtypes.EventAttribute{{Key: "key", Value: "\n\n\n"}},
|
||||
isError: true,
|
||||
},
|
||||
"strip whitespace": {
|
||||
src: []wasmvmtypes.EventAttribute{{Key: " my-real-key ", Value: "\n\n\nsome-val\t\t\t"}},
|
||||
exp: sdk.Events{sdk.NewEvent("wasm",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
sdk.NewAttribute("my-real-key", "some-val"))},
|
||||
},
|
||||
"empty elements": {
|
||||
src: make([]wasmvmtypes.EventAttribute, 10),
|
||||
isError: true,
|
||||
},
|
||||
"nil": {
|
||||
exp: sdk.Events{sdk.NewEvent("wasm",
|
||||
sdk.NewAttribute("_contract_address", myContract.String()),
|
||||
)},
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
gotEvent, err := newWasmModuleEvent(spec.src, myContract)
|
||||
if spec.isError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, spec.exp, gotEvent)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// returns true when a wasm module event was emitted for this contract already
|
||||
func hasWasmModuleEvent(ctx sdk.Context, contractAddr sdk.AccAddress) bool {
|
||||
for _, e := range ctx.EventManager().Events() {
|
||||
if e.Type == types.WasmModuleEventType {
|
||||
for _, a := range e.Attributes {
|
||||
if string(a.Key) == types.AttributeKeyContractAddr && string(a.Value) == contractAddr.String() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
252
x/wasm/keeper/gas_register.go
Normal file
252
x/wasm/keeper/gas_register.go
Normal file
@ -0,0 +1,252 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultGasMultiplier is how many CosmWasm gas points = 1 Cosmos SDK gas point.
|
||||
//
|
||||
// CosmWasm gas strategy is documented in https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta/docs/GAS.md.
|
||||
// Cosmos SDK reference costs can be found here: https://github.com/cosmos/cosmos-sdk/blob/v0.42.10/store/types/gas.go#L198-L209.
|
||||
//
|
||||
// The original multiplier of 100 up to CosmWasm 0.16 was based on
|
||||
// "A write at ~3000 gas and ~200us = 10 gas per us (microsecond) cpu/io
|
||||
// Rough timing have 88k gas at 90us, which is equal to 1k sdk gas... (one read)"
|
||||
// as well as manual Wasmer benchmarks from 2019. This was then multiplied by 150_000
|
||||
// in the 0.16 -> 1.0 upgrade (https://github.com/CosmWasm/cosmwasm/pull/1120).
|
||||
//
|
||||
// The multiplier deserves more reproducible benchmarking and a strategy that allows easy adjustments.
|
||||
// This is tracked in https://github.com/CosmWasm/wasmd/issues/566 and https://github.com/CosmWasm/wasmd/issues/631.
|
||||
// Gas adjustments are consensus breaking but may happen in any release marked as consensus breaking.
|
||||
// Do not make assumptions on how much gas an operation will consume in places that are hard to adjust,
|
||||
// such as hardcoding them in contracts.
|
||||
//
|
||||
// Please note that all gas prices returned to wasmvm should have this multiplied.
|
||||
// Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938055852
|
||||
DefaultGasMultiplier uint64 = 140_000_000
|
||||
// DefaultInstanceCost is how much SDK gas we charge each time we load a WASM instance.
|
||||
// Creating a new instance is costly, and this helps put a recursion limit to contracts calling contracts.
|
||||
// Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938056803
|
||||
DefaultInstanceCost uint64 = 60_000
|
||||
// DefaultCompileCost is how much SDK gas is charged *per byte* for compiling WASM code.
|
||||
// Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938056803
|
||||
DefaultCompileCost uint64 = 3
|
||||
// DefaultEventAttributeDataCost is how much SDK gas is charged *per byte* for attribute data in events.
|
||||
// This is used with len(key) + len(value)
|
||||
DefaultEventAttributeDataCost uint64 = 1
|
||||
// DefaultContractMessageDataCost is how much SDK gas is charged *per byte* of the message that goes to the contract
|
||||
// This is used with len(msg). Note that the message is deserialized in the receiving contract and this is charged
|
||||
// with wasm gas already. The derserialization of results is also charged in wasmvm. I am unsure if we need to add
|
||||
// additional costs here.
|
||||
// Note: also used for error fields on reply, and data on reply. Maybe these should be pulled out to a different (non-zero) field
|
||||
DefaultContractMessageDataCost uint64 = 0
|
||||
// DefaultPerAttributeCost is how much SDK gas we charge per attribute count.
|
||||
DefaultPerAttributeCost uint64 = 10
|
||||
// DefaultPerCustomEventCost is how much SDK gas we charge per event count.
|
||||
DefaultPerCustomEventCost uint64 = 20
|
||||
// DefaultEventAttributeDataFreeTier number of bytes of total attribute data we do not charge.
|
||||
DefaultEventAttributeDataFreeTier = 100
|
||||
)
|
||||
|
||||
// default: 0.15 gas.
|
||||
// see https://github.com/CosmWasm/wasmd/pull/898#discussion_r937727200
|
||||
var defaultPerByteUncompressCost = wasmvmtypes.UFraction{
|
||||
Numerator: 15,
|
||||
Denominator: 100,
|
||||
}
|
||||
|
||||
// DefaultPerByteUncompressCost is how much SDK gas we charge per source byte to unpack
|
||||
func DefaultPerByteUncompressCost() wasmvmtypes.UFraction {
|
||||
return defaultPerByteUncompressCost
|
||||
}
|
||||
|
||||
// GasRegister abstract source for gas costs
|
||||
type GasRegister interface {
|
||||
// NewContractInstanceCosts costs to crate a new contract instance from code
|
||||
NewContractInstanceCosts(pinned bool, msgLen int) sdk.Gas
|
||||
// CompileCosts costs to persist and "compile" a new wasm contract
|
||||
CompileCosts(byteLength int) sdk.Gas
|
||||
// UncompressCosts costs to unpack a new wasm contract
|
||||
UncompressCosts(byteLength int) sdk.Gas
|
||||
// InstantiateContractCosts costs when interacting with a wasm contract
|
||||
InstantiateContractCosts(pinned bool, msgLen int) sdk.Gas
|
||||
// ReplyCosts costs to to handle a message reply
|
||||
ReplyCosts(pinned bool, reply wasmvmtypes.Reply) sdk.Gas
|
||||
// EventCosts costs to persist an event
|
||||
EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) sdk.Gas
|
||||
// ToWasmVMGas converts from sdk gas to wasmvm gas
|
||||
ToWasmVMGas(source sdk.Gas) uint64
|
||||
// FromWasmVMGas converts from wasmvm gas to sdk gas
|
||||
FromWasmVMGas(source uint64) sdk.Gas
|
||||
}
|
||||
|
||||
// WasmGasRegisterConfig config type
|
||||
type WasmGasRegisterConfig struct {
|
||||
// InstanceCost costs when interacting with a wasm contract
|
||||
InstanceCost sdk.Gas
|
||||
// CompileCosts costs to persist and "compile" a new wasm contract
|
||||
CompileCost sdk.Gas
|
||||
// UncompressCost costs per byte to unpack a contract
|
||||
UncompressCost wasmvmtypes.UFraction
|
||||
// GasMultiplier is how many cosmwasm gas points = 1 sdk gas point
|
||||
// SDK reference costs can be found here: https://github.com/cosmos/cosmos-sdk/blob/02c6c9fafd58da88550ab4d7d494724a477c8a68/store/types/gas.go#L153-L164
|
||||
GasMultiplier sdk.Gas
|
||||
// EventPerAttributeCost is how much SDK gas is charged *per byte* for attribute data in events.
|
||||
// This is used with len(key) + len(value)
|
||||
EventPerAttributeCost sdk.Gas
|
||||
// EventAttributeDataCost is how much SDK gas is charged *per byte* for attribute data in events.
|
||||
// This is used with len(key) + len(value)
|
||||
EventAttributeDataCost sdk.Gas
|
||||
// EventAttributeDataFreeTier number of bytes of total attribute data that is free of charge
|
||||
EventAttributeDataFreeTier uint64
|
||||
// ContractMessageDataCost SDK gas charged *per byte* of the message that goes to the contract
|
||||
// This is used with len(msg)
|
||||
ContractMessageDataCost sdk.Gas
|
||||
// CustomEventCost cost per custom event
|
||||
CustomEventCost uint64
|
||||
}
|
||||
|
||||
// DefaultGasRegisterConfig default values
|
||||
func DefaultGasRegisterConfig() WasmGasRegisterConfig {
|
||||
return WasmGasRegisterConfig{
|
||||
InstanceCost: DefaultInstanceCost,
|
||||
CompileCost: DefaultCompileCost,
|
||||
GasMultiplier: DefaultGasMultiplier,
|
||||
EventPerAttributeCost: DefaultPerAttributeCost,
|
||||
CustomEventCost: DefaultPerCustomEventCost,
|
||||
EventAttributeDataCost: DefaultEventAttributeDataCost,
|
||||
EventAttributeDataFreeTier: DefaultEventAttributeDataFreeTier,
|
||||
ContractMessageDataCost: DefaultContractMessageDataCost,
|
||||
UncompressCost: DefaultPerByteUncompressCost(),
|
||||
}
|
||||
}
|
||||
|
||||
// WasmGasRegister implements GasRegister interface
|
||||
type WasmGasRegister struct {
|
||||
c WasmGasRegisterConfig
|
||||
}
|
||||
|
||||
// NewDefaultWasmGasRegister creates instance with default values
|
||||
func NewDefaultWasmGasRegister() WasmGasRegister {
|
||||
return NewWasmGasRegister(DefaultGasRegisterConfig())
|
||||
}
|
||||
|
||||
// NewWasmGasRegister constructor
|
||||
func NewWasmGasRegister(c WasmGasRegisterConfig) WasmGasRegister {
|
||||
if c.GasMultiplier == 0 {
|
||||
panic(sdkerrors.Wrap(sdkerrors.ErrLogic, "GasMultiplier can not be 0"))
|
||||
}
|
||||
return WasmGasRegister{
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
// NewContractInstanceCosts costs to crate a new contract instance from code
|
||||
func (g WasmGasRegister) NewContractInstanceCosts(pinned bool, msgLen int) storetypes.Gas {
|
||||
return g.InstantiateContractCosts(pinned, msgLen)
|
||||
}
|
||||
|
||||
// CompileCosts costs to persist and "compile" a new wasm contract
|
||||
func (g WasmGasRegister) CompileCosts(byteLength int) storetypes.Gas {
|
||||
if byteLength < 0 {
|
||||
panic(sdkerrors.Wrap(types.ErrInvalid, "negative length"))
|
||||
}
|
||||
return g.c.CompileCost * uint64(byteLength)
|
||||
}
|
||||
|
||||
// UncompressCosts costs to unpack a new wasm contract
|
||||
func (g WasmGasRegister) UncompressCosts(byteLength int) sdk.Gas {
|
||||
if byteLength < 0 {
|
||||
panic(sdkerrors.Wrap(types.ErrInvalid, "negative length"))
|
||||
}
|
||||
return g.c.UncompressCost.Mul(uint64(byteLength)).Floor()
|
||||
}
|
||||
|
||||
// InstantiateContractCosts costs when interacting with a wasm contract
|
||||
func (g WasmGasRegister) InstantiateContractCosts(pinned bool, msgLen int) sdk.Gas {
|
||||
if msgLen < 0 {
|
||||
panic(sdkerrors.Wrap(types.ErrInvalid, "negative length"))
|
||||
}
|
||||
dataCosts := sdk.Gas(msgLen) * g.c.ContractMessageDataCost
|
||||
if pinned {
|
||||
return dataCosts
|
||||
}
|
||||
return g.c.InstanceCost + dataCosts
|
||||
}
|
||||
|
||||
// ReplyCosts costs to to handle a message reply
|
||||
func (g WasmGasRegister) ReplyCosts(pinned bool, reply wasmvmtypes.Reply) sdk.Gas {
|
||||
var eventGas sdk.Gas
|
||||
msgLen := len(reply.Result.Err)
|
||||
if reply.Result.Ok != nil {
|
||||
msgLen += len(reply.Result.Ok.Data)
|
||||
var attrs []wasmvmtypes.EventAttribute
|
||||
for _, e := range reply.Result.Ok.Events {
|
||||
eventGas += sdk.Gas(len(e.Type)) * g.c.EventAttributeDataCost
|
||||
attrs = append(attrs, e.Attributes...)
|
||||
}
|
||||
// apply free tier on the whole set not per event
|
||||
eventGas += g.EventCosts(attrs, nil)
|
||||
}
|
||||
return eventGas + g.InstantiateContractCosts(pinned, msgLen)
|
||||
}
|
||||
|
||||
// EventCosts costs to persist an event
|
||||
func (g WasmGasRegister) EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) sdk.Gas {
|
||||
gas, remainingFreeTier := g.eventAttributeCosts(attrs, g.c.EventAttributeDataFreeTier)
|
||||
for _, e := range events {
|
||||
gas += g.c.CustomEventCost
|
||||
gas += sdk.Gas(len(e.Type)) * g.c.EventAttributeDataCost // no free tier with event type
|
||||
var attrCost sdk.Gas
|
||||
attrCost, remainingFreeTier = g.eventAttributeCosts(e.Attributes, remainingFreeTier)
|
||||
gas += attrCost
|
||||
}
|
||||
return gas
|
||||
}
|
||||
|
||||
func (g WasmGasRegister) eventAttributeCosts(attrs []wasmvmtypes.EventAttribute, freeTier uint64) (sdk.Gas, uint64) {
|
||||
if len(attrs) == 0 {
|
||||
return 0, freeTier
|
||||
}
|
||||
var storedBytes uint64
|
||||
for _, l := range attrs {
|
||||
storedBytes += uint64(len(l.Key)) + uint64(len(l.Value))
|
||||
}
|
||||
storedBytes, freeTier = calcWithFreeTier(storedBytes, freeTier)
|
||||
// total Length * costs + attribute count * costs
|
||||
r := sdk.NewIntFromUint64(g.c.EventAttributeDataCost).Mul(sdk.NewIntFromUint64(storedBytes)).
|
||||
Add(sdk.NewIntFromUint64(g.c.EventPerAttributeCost).Mul(sdk.NewIntFromUint64(uint64(len(attrs)))))
|
||||
if !r.IsUint64() {
|
||||
panic(sdk.ErrorOutOfGas{Descriptor: "overflow"})
|
||||
}
|
||||
return r.Uint64(), freeTier
|
||||
}
|
||||
|
||||
// apply free tier
|
||||
func calcWithFreeTier(storedBytes uint64, freeTier uint64) (uint64, uint64) {
|
||||
if storedBytes <= freeTier {
|
||||
return 0, freeTier - storedBytes
|
||||
}
|
||||
storedBytes -= freeTier
|
||||
return storedBytes, 0
|
||||
}
|
||||
|
||||
// ToWasmVMGas convert to wasmVM contract runtime gas unit
|
||||
func (g WasmGasRegister) ToWasmVMGas(source storetypes.Gas) uint64 {
|
||||
x := source * g.c.GasMultiplier
|
||||
if x < source {
|
||||
panic(sdk.ErrorOutOfGas{Descriptor: "overflow"})
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// FromWasmVMGas converts to SDK gas unit
|
||||
func (g WasmGasRegister) FromWasmVMGas(source uint64) sdk.Gas {
|
||||
return source / g.c.GasMultiplier
|
||||
}
|
||||
472
x/wasm/keeper/gas_register_test.go
Normal file
472
x/wasm/keeper/gas_register_test.go
Normal file
@ -0,0 +1,472 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCompileCosts(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
srcLen int
|
||||
srcConfig WasmGasRegisterConfig
|
||||
exp sdk.Gas
|
||||
expPanic bool
|
||||
}{
|
||||
"one byte": {
|
||||
srcLen: 1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(3), // DefaultCompileCost
|
||||
},
|
||||
"zero byte": {
|
||||
srcLen: 0,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(0),
|
||||
},
|
||||
"negative len": {
|
||||
srcLen: -1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
expPanic: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if spec.expPanic {
|
||||
assert.Panics(t, func() {
|
||||
NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen)
|
||||
})
|
||||
return
|
||||
}
|
||||
gotGas := NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen)
|
||||
assert.Equal(t, spec.exp, gotGas)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewContractInstanceCosts(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
srcLen int
|
||||
srcConfig WasmGasRegisterConfig
|
||||
pinned bool
|
||||
exp sdk.Gas
|
||||
expPanic bool
|
||||
}{
|
||||
"small msg - pinned": {
|
||||
srcLen: 1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: DefaultContractMessageDataCost,
|
||||
},
|
||||
"big msg - pinned": {
|
||||
srcLen: math.MaxUint32,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: DefaultContractMessageDataCost * sdk.Gas(math.MaxUint32),
|
||||
},
|
||||
"empty msg - pinned": {
|
||||
srcLen: 0,
|
||||
pinned: true,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(0),
|
||||
},
|
||||
"small msg - unpinned": {
|
||||
srcLen: 1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: DefaultContractMessageDataCost + DefaultInstanceCost,
|
||||
},
|
||||
"big msg - unpinned": {
|
||||
srcLen: math.MaxUint32,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultContractMessageDataCost*math.MaxUint32 + DefaultInstanceCost),
|
||||
},
|
||||
"empty msg - unpinned": {
|
||||
srcLen: 0,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultInstanceCost),
|
||||
},
|
||||
|
||||
"negative len": {
|
||||
srcLen: -1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
expPanic: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if spec.expPanic {
|
||||
assert.Panics(t, func() {
|
||||
NewWasmGasRegister(spec.srcConfig).NewContractInstanceCosts(spec.pinned, spec.srcLen)
|
||||
})
|
||||
return
|
||||
}
|
||||
gotGas := NewWasmGasRegister(spec.srcConfig).NewContractInstanceCosts(spec.pinned, spec.srcLen)
|
||||
assert.Equal(t, spec.exp, gotGas)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestContractInstanceCosts(t *testing.T) {
|
||||
// same as TestNewContractInstanceCosts currently
|
||||
specs := map[string]struct {
|
||||
srcLen int
|
||||
srcConfig WasmGasRegisterConfig
|
||||
pinned bool
|
||||
exp sdk.Gas
|
||||
expPanic bool
|
||||
}{
|
||||
"small msg - pinned": {
|
||||
srcLen: 1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: DefaultContractMessageDataCost,
|
||||
},
|
||||
"big msg - pinned": {
|
||||
srcLen: math.MaxUint32,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: sdk.Gas(DefaultContractMessageDataCost * math.MaxUint32),
|
||||
},
|
||||
"empty msg - pinned": {
|
||||
srcLen: 0,
|
||||
pinned: true,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(0),
|
||||
},
|
||||
"small msg - unpinned": {
|
||||
srcLen: 1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: DefaultContractMessageDataCost + DefaultInstanceCost,
|
||||
},
|
||||
"big msg - unpinned": {
|
||||
srcLen: math.MaxUint32,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultContractMessageDataCost*math.MaxUint32 + DefaultInstanceCost),
|
||||
},
|
||||
"empty msg - unpinned": {
|
||||
srcLen: 0,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultInstanceCost),
|
||||
},
|
||||
|
||||
"negative len": {
|
||||
srcLen: -1,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
expPanic: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if spec.expPanic {
|
||||
assert.Panics(t, func() {
|
||||
NewWasmGasRegister(spec.srcConfig).InstantiateContractCosts(spec.pinned, spec.srcLen)
|
||||
})
|
||||
return
|
||||
}
|
||||
gotGas := NewWasmGasRegister(spec.srcConfig).InstantiateContractCosts(spec.pinned, spec.srcLen)
|
||||
assert.Equal(t, spec.exp, gotGas)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplyCost(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src wasmvmtypes.Reply
|
||||
srcConfig WasmGasRegisterConfig
|
||||
pinned bool
|
||||
exp sdk.Gas
|
||||
expPanic bool
|
||||
}{
|
||||
"subcall response with events and data - pinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{
|
||||
Events: []wasmvmtypes.Event{
|
||||
{Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}},
|
||||
},
|
||||
Data: []byte{0x1},
|
||||
},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: sdk.Gas(3*DefaultEventAttributeDataCost + DefaultPerAttributeCost + DefaultContractMessageDataCost), // 3 == len("foo")
|
||||
},
|
||||
"subcall response with events - pinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{
|
||||
Events: []wasmvmtypes.Event{
|
||||
{Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: sdk.Gas(3*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo")
|
||||
},
|
||||
"subcall response with events exceeds free tier- pinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{
|
||||
Events: []wasmvmtypes.Event{
|
||||
{Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: strings.Repeat("x", DefaultEventAttributeDataFreeTier), Value: "myData"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: sdk.Gas((3+6)*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo"), 6 == len("myData")
|
||||
},
|
||||
"subcall response error - pinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Err: "foo",
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
pinned: true,
|
||||
exp: 3 * DefaultContractMessageDataCost,
|
||||
},
|
||||
"subcall response with events and data - unpinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{
|
||||
Events: []wasmvmtypes.Event{
|
||||
{Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}},
|
||||
},
|
||||
Data: []byte{0x1},
|
||||
},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultInstanceCost + 3*DefaultEventAttributeDataCost + DefaultPerAttributeCost + DefaultContractMessageDataCost),
|
||||
},
|
||||
"subcall response with events - unpinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{
|
||||
Events: []wasmvmtypes.Event{
|
||||
{Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultInstanceCost + 3*DefaultEventAttributeDataCost + DefaultPerAttributeCost),
|
||||
},
|
||||
"subcall response with events exceeds free tier- unpinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{
|
||||
Events: []wasmvmtypes.Event{
|
||||
{Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: strings.Repeat("x", DefaultEventAttributeDataFreeTier), Value: "myData"}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultInstanceCost + (3+6)*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo"), 6 == len("myData")
|
||||
},
|
||||
"subcall response error - unpinned": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Err: "foo",
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: sdk.Gas(DefaultInstanceCost + 3*DefaultContractMessageDataCost),
|
||||
},
|
||||
"subcall response with empty events": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{
|
||||
Events: make([]wasmvmtypes.Event, 10),
|
||||
},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: DefaultInstanceCost,
|
||||
},
|
||||
"subcall response with events unset": {
|
||||
src: wasmvmtypes.Reply{
|
||||
Result: wasmvmtypes.SubMsgResult{
|
||||
Ok: &wasmvmtypes.SubMsgResponse{},
|
||||
},
|
||||
},
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
exp: DefaultInstanceCost,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if spec.expPanic {
|
||||
assert.Panics(t, func() {
|
||||
NewWasmGasRegister(spec.srcConfig).ReplyCosts(spec.pinned, spec.src)
|
||||
})
|
||||
return
|
||||
}
|
||||
gotGas := NewWasmGasRegister(spec.srcConfig).ReplyCosts(spec.pinned, spec.src)
|
||||
assert.Equal(t, spec.exp, gotGas)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventCosts(t *testing.T) {
|
||||
// most cases are covered in TestReplyCost already. This ensures some edge cases
|
||||
specs := map[string]struct {
|
||||
srcAttrs []wasmvmtypes.EventAttribute
|
||||
srcEvents wasmvmtypes.Events
|
||||
expGas sdk.Gas
|
||||
}{
|
||||
"empty events": {
|
||||
srcEvents: make([]wasmvmtypes.Event, 1),
|
||||
expGas: DefaultPerCustomEventCost,
|
||||
},
|
||||
"empty attributes": {
|
||||
srcAttrs: make([]wasmvmtypes.EventAttribute, 1),
|
||||
expGas: DefaultPerAttributeCost,
|
||||
},
|
||||
"both nil": {
|
||||
expGas: 0,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
gotGas := NewDefaultWasmGasRegister().EventCosts(spec.srcAttrs, spec.srcEvents)
|
||||
assert.Equal(t, spec.expGas, gotGas)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToWasmVMGasConversion(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src storetypes.Gas
|
||||
srcConfig WasmGasRegisterConfig
|
||||
exp uint64
|
||||
expPanic bool
|
||||
}{
|
||||
"0": {
|
||||
src: 0,
|
||||
exp: 0,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
},
|
||||
"max": {
|
||||
srcConfig: WasmGasRegisterConfig{
|
||||
GasMultiplier: 1,
|
||||
},
|
||||
src: math.MaxUint64,
|
||||
exp: math.MaxUint64,
|
||||
},
|
||||
"overflow": {
|
||||
srcConfig: WasmGasRegisterConfig{
|
||||
GasMultiplier: 2,
|
||||
},
|
||||
src: math.MaxUint64,
|
||||
expPanic: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if spec.expPanic {
|
||||
assert.Panics(t, func() {
|
||||
r := NewWasmGasRegister(spec.srcConfig)
|
||||
_ = r.ToWasmVMGas(spec.src)
|
||||
})
|
||||
return
|
||||
}
|
||||
r := NewWasmGasRegister(spec.srcConfig)
|
||||
got := r.ToWasmVMGas(spec.src)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromWasmVMGasConversion(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src uint64
|
||||
exp storetypes.Gas
|
||||
srcConfig WasmGasRegisterConfig
|
||||
expPanic bool
|
||||
}{
|
||||
"0": {
|
||||
src: 0,
|
||||
exp: 0,
|
||||
srcConfig: DefaultGasRegisterConfig(),
|
||||
},
|
||||
"max": {
|
||||
srcConfig: WasmGasRegisterConfig{
|
||||
GasMultiplier: 1,
|
||||
},
|
||||
src: math.MaxUint64,
|
||||
exp: math.MaxUint64,
|
||||
},
|
||||
"missconfigured": {
|
||||
srcConfig: WasmGasRegisterConfig{
|
||||
GasMultiplier: 0,
|
||||
},
|
||||
src: 1,
|
||||
expPanic: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if spec.expPanic {
|
||||
assert.Panics(t, func() {
|
||||
r := NewWasmGasRegister(spec.srcConfig)
|
||||
_ = r.FromWasmVMGas(spec.src)
|
||||
})
|
||||
return
|
||||
}
|
||||
r := NewWasmGasRegister(spec.srcConfig)
|
||||
got := r.FromWasmVMGas(spec.src)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUncompressCosts(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
lenIn int
|
||||
exp sdk.Gas
|
||||
expPanic bool
|
||||
}{
|
||||
"0": {
|
||||
exp: 0,
|
||||
},
|
||||
"even": {
|
||||
lenIn: 100,
|
||||
exp: 15,
|
||||
},
|
||||
"round down when uneven": {
|
||||
lenIn: 19,
|
||||
exp: 2,
|
||||
},
|
||||
"max len": {
|
||||
lenIn: types.MaxWasmSize,
|
||||
exp: 122880,
|
||||
},
|
||||
"invalid len": {
|
||||
lenIn: -1,
|
||||
expPanic: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if spec.expPanic {
|
||||
assert.Panics(t, func() { NewDefaultWasmGasRegister().UncompressCosts(spec.lenIn) })
|
||||
return
|
||||
}
|
||||
got := NewDefaultWasmGasRegister().UncompressCosts(spec.lenIn)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
116
x/wasm/keeper/genesis.go
Normal file
116
x/wasm/keeper/genesis.go
Normal file
@ -0,0 +1,116 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// ValidatorSetSource is a subset of the staking keeper
|
||||
type ValidatorSetSource interface {
|
||||
ApplyAndReturnValidatorSetUpdates(sdk.Context) (updates []abci.ValidatorUpdate, err error)
|
||||
}
|
||||
|
||||
// InitGenesis sets supply information for genesis.
|
||||
//
|
||||
// CONTRACT: all types of accounts must have been already initialized/created
|
||||
func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) ([]abci.ValidatorUpdate, error) {
|
||||
contractKeeper := NewGovPermissionKeeper(keeper)
|
||||
keeper.SetParams(ctx, data.Params)
|
||||
var maxCodeID uint64
|
||||
for i, code := range data.Codes {
|
||||
err := keeper.importCode(ctx, code.CodeID, code.CodeInfo, code.CodeBytes)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(err, "code %d with id: %d", i, code.CodeID)
|
||||
}
|
||||
if code.CodeID > maxCodeID {
|
||||
maxCodeID = code.CodeID
|
||||
}
|
||||
if code.Pinned {
|
||||
if err := contractKeeper.PinCode(ctx, code.CodeID); err != nil {
|
||||
return nil, sdkerrors.Wrapf(err, "contract number %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var maxContractID int
|
||||
for i, contract := range data.Contracts {
|
||||
contractAddr, err := sdk.AccAddressFromBech32(contract.ContractAddress)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(err, "address in contract number %d", i)
|
||||
}
|
||||
err = keeper.importContract(ctx, contractAddr, &contract.ContractInfo, contract.ContractState, contract.ContractCodeHistory)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(err, "contract number %d", i)
|
||||
}
|
||||
maxContractID = i + 1 // not ideal but max(contractID) is not persisted otherwise
|
||||
}
|
||||
|
||||
for i, seq := range data.Sequences {
|
||||
err := keeper.importAutoIncrementID(ctx, seq.IDKey, seq.Value)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(err, "sequence number %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check seq values
|
||||
seqVal := keeper.PeekAutoIncrementID(ctx, types.KeyLastCodeID)
|
||||
if seqVal <= maxCodeID {
|
||||
return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastCodeID), seqVal, maxCodeID)
|
||||
}
|
||||
seqVal = keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID)
|
||||
if seqVal <= uint64(maxContractID) {
|
||||
return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastInstanceID), seqVal, maxContractID)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper.
|
||||
func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState {
|
||||
var genState types.GenesisState
|
||||
|
||||
genState.Params = keeper.GetParams(ctx)
|
||||
|
||||
keeper.IterateCodeInfos(ctx, func(codeID uint64, info types.CodeInfo) bool {
|
||||
bytecode, err := keeper.GetByteCode(ctx, codeID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
genState.Codes = append(genState.Codes, types.Code{
|
||||
CodeID: codeID,
|
||||
CodeInfo: info,
|
||||
CodeBytes: bytecode,
|
||||
Pinned: keeper.IsPinnedCode(ctx, codeID),
|
||||
})
|
||||
return false
|
||||
})
|
||||
|
||||
keeper.IterateContractInfo(ctx, func(addr sdk.AccAddress, contract types.ContractInfo) bool {
|
||||
var state []types.Model
|
||||
keeper.IterateContractState(ctx, addr, func(key, value []byte) bool {
|
||||
state = append(state, types.Model{Key: key, Value: value})
|
||||
return false
|
||||
})
|
||||
|
||||
contractCodeHistory := keeper.GetContractHistory(ctx, addr)
|
||||
|
||||
genState.Contracts = append(genState.Contracts, types.Contract{
|
||||
ContractAddress: addr.String(),
|
||||
ContractInfo: contract,
|
||||
ContractState: state,
|
||||
ContractCodeHistory: contractCodeHistory,
|
||||
})
|
||||
return false
|
||||
})
|
||||
|
||||
for _, k := range [][]byte{types.KeyLastCodeID, types.KeyLastInstanceID} {
|
||||
genState.Sequences = append(genState.Sequences, types.Sequence{
|
||||
IDKey: k,
|
||||
Value: keeper.PeekAutoIncrementID(ctx, k),
|
||||
})
|
||||
}
|
||||
|
||||
return &genState
|
||||
}
|
||||
671
x/wasm/keeper/genesis_test.go
Normal file
671
x/wasm/keeper/genesis_test.go
Normal file
@ -0,0 +1,671 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
||||
distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
|
||||
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
||||
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
wasmTypes "github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
const firstCodeID = 1
|
||||
|
||||
func TestGenesisExportImport(t *testing.T) {
|
||||
wasmKeeper, srcCtx, srcStoreKeys := setupKeeper(t)
|
||||
contractKeeper := NewGovPermissionKeeper(wasmKeeper)
|
||||
|
||||
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
|
||||
require.NoError(t, err)
|
||||
|
||||
// store some test data
|
||||
f := fuzz.New().Funcs(ModelFuzzers...)
|
||||
|
||||
wasmKeeper.SetParams(srcCtx, types.DefaultParams())
|
||||
|
||||
for i := 0; i < 25; i++ {
|
||||
var (
|
||||
codeInfo types.CodeInfo
|
||||
contract types.ContractInfo
|
||||
stateModels []types.Model
|
||||
history []types.ContractCodeHistoryEntry
|
||||
pinned bool
|
||||
contractExtension bool
|
||||
)
|
||||
f.Fuzz(&codeInfo)
|
||||
f.Fuzz(&contract)
|
||||
f.Fuzz(&stateModels)
|
||||
f.NilChance(0).Fuzz(&history)
|
||||
f.Fuzz(&pinned)
|
||||
f.Fuzz(&contractExtension)
|
||||
|
||||
creatorAddr, err := sdk.AccAddressFromBech32(codeInfo.Creator)
|
||||
require.NoError(t, err)
|
||||
codeID, _, err := contractKeeper.Create(srcCtx, creatorAddr, wasmCode, &codeInfo.InstantiateConfig)
|
||||
require.NoError(t, err)
|
||||
if pinned {
|
||||
contractKeeper.PinCode(srcCtx, codeID)
|
||||
}
|
||||
if contractExtension {
|
||||
anyTime := time.Now().UTC()
|
||||
var nestedType govtypes.TextProposal
|
||||
f.NilChance(0).Fuzz(&nestedType)
|
||||
myExtension, err := govtypes.NewProposal(&nestedType, 1, anyTime, anyTime)
|
||||
require.NoError(t, err)
|
||||
contract.SetExtension(&myExtension)
|
||||
}
|
||||
|
||||
contract.CodeID = codeID
|
||||
contractAddr := wasmKeeper.ClassicAddressGenerator()(srcCtx, codeID, nil)
|
||||
wasmKeeper.storeContractInfo(srcCtx, contractAddr, &contract)
|
||||
wasmKeeper.appendToContractHistory(srcCtx, contractAddr, history...)
|
||||
wasmKeeper.importContractState(srcCtx, contractAddr, stateModels)
|
||||
}
|
||||
var wasmParams types.Params
|
||||
f.NilChance(0).Fuzz(&wasmParams)
|
||||
wasmKeeper.SetParams(srcCtx, wasmParams)
|
||||
|
||||
// export
|
||||
exportedState := ExportGenesis(srcCtx, wasmKeeper)
|
||||
// order should not matter
|
||||
rand.Shuffle(len(exportedState.Codes), func(i, j int) {
|
||||
exportedState.Codes[i], exportedState.Codes[j] = exportedState.Codes[j], exportedState.Codes[i]
|
||||
})
|
||||
rand.Shuffle(len(exportedState.Contracts), func(i, j int) {
|
||||
exportedState.Contracts[i], exportedState.Contracts[j] = exportedState.Contracts[j], exportedState.Contracts[i]
|
||||
})
|
||||
rand.Shuffle(len(exportedState.Sequences), func(i, j int) {
|
||||
exportedState.Sequences[i], exportedState.Sequences[j] = exportedState.Sequences[j], exportedState.Sequences[i]
|
||||
})
|
||||
exportedGenesis, err := wasmKeeper.cdc.MarshalJSON(exportedState)
|
||||
require.NoError(t, err)
|
||||
|
||||
// setup new instances
|
||||
dstKeeper, dstCtx, dstStoreKeys := setupKeeper(t)
|
||||
|
||||
// reset contract code index in source DB for comparison with dest DB
|
||||
wasmKeeper.IterateContractInfo(srcCtx, func(address sdk.AccAddress, info wasmTypes.ContractInfo) bool {
|
||||
creatorAddress := sdk.MustAccAddressFromBech32(info.Creator)
|
||||
history := wasmKeeper.GetContractHistory(srcCtx, address)
|
||||
|
||||
wasmKeeper.addToContractCodeSecondaryIndex(srcCtx, address, history[len(history)-1])
|
||||
wasmKeeper.addToContractCreatorSecondaryIndex(srcCtx, creatorAddress, history[0].Updated, address)
|
||||
return false
|
||||
})
|
||||
|
||||
// re-import
|
||||
var importState wasmTypes.GenesisState
|
||||
err = dstKeeper.cdc.UnmarshalJSON(exportedGenesis, &importState)
|
||||
require.NoError(t, err)
|
||||
InitGenesis(dstCtx, dstKeeper, importState)
|
||||
|
||||
// compare whole DB
|
||||
for j := range srcStoreKeys {
|
||||
srcIT := srcCtx.KVStore(srcStoreKeys[j]).Iterator(nil, nil)
|
||||
dstIT := dstCtx.KVStore(dstStoreKeys[j]).Iterator(nil, nil)
|
||||
|
||||
for i := 0; srcIT.Valid(); i++ {
|
||||
require.True(t, dstIT.Valid(), "[%s] destination DB has less elements than source. Missing: %x", srcStoreKeys[j].Name(), srcIT.Key())
|
||||
require.Equal(t, srcIT.Key(), dstIT.Key(), i)
|
||||
require.Equal(t, srcIT.Value(), dstIT.Value(), "[%s] element (%d): %X", srcStoreKeys[j].Name(), i, srcIT.Key())
|
||||
dstIT.Next()
|
||||
srcIT.Next()
|
||||
}
|
||||
if !assert.False(t, dstIT.Valid()) {
|
||||
t.Fatalf("dest Iterator still has key :%X", dstIT.Key())
|
||||
}
|
||||
srcIT.Close()
|
||||
dstIT.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenesisInit(t *testing.T) {
|
||||
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
|
||||
require.NoError(t, err)
|
||||
|
||||
myCodeInfo := wasmTypes.CodeInfoFixture(wasmTypes.WithSHA256CodeHash(wasmCode))
|
||||
specs := map[string]struct {
|
||||
src types.GenesisState
|
||||
expSuccess bool
|
||||
}{
|
||||
"happy path: code info correct": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
expSuccess: true,
|
||||
},
|
||||
"happy path: code ids can contain gaps": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}, {
|
||||
CodeID: 3,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastCodeID, Value: 10},
|
||||
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
expSuccess: true,
|
||||
},
|
||||
"happy path: code order does not matter": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: 2,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}, {
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Contracts: nil,
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastCodeID, Value: 3},
|
||||
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
expSuccess: true,
|
||||
},
|
||||
"prevent code hash mismatch": {src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: wasmTypes.CodeInfoFixture(func(i *wasmTypes.CodeInfo) { i.CodeHash = make([]byte, sha256.Size) }),
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Params: types.DefaultParams(),
|
||||
}},
|
||||
"prevent duplicate codeIDs": {src: types.GenesisState{
|
||||
Codes: []types.Code{
|
||||
{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
},
|
||||
{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
}},
|
||||
"codes with same checksum can be pinned": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{
|
||||
{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
Pinned: true,
|
||||
},
|
||||
{
|
||||
CodeID: 2,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
Pinned: true,
|
||||
},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
},
|
||||
"happy path: code id in info and contract do match": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||
{IDKey: types.KeyLastInstanceID, Value: 2},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
expSuccess: true,
|
||||
},
|
||||
"happy path: code info with two contracts": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{}`),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
ContractAddress: BuildContractAddressClassic(1, 2).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{"foo":"bar"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||
{IDKey: types.KeyLastInstanceID, Value: 3},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
expSuccess: true,
|
||||
},
|
||||
"prevent contracts that points to non existing codeID": {
|
||||
src: types.GenesisState{
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{"foo":"bar"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
},
|
||||
"prevent duplicate contract address": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{"foo":"bar"}`),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{"other":"value"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
},
|
||||
"prevent duplicate contract model keys": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractState: []types.Model{
|
||||
{
|
||||
Key: []byte{0x1},
|
||||
Value: []byte("foo"),
|
||||
},
|
||||
{
|
||||
Key: []byte{0x1},
|
||||
Value: []byte("bar"),
|
||||
},
|
||||
},
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{"foo":"bar"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
},
|
||||
"prevent duplicate sequences": {
|
||||
src: types.GenesisState{
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: []byte("foo"), Value: 1},
|
||||
{IDKey: []byte("foo"), Value: 9999},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
},
|
||||
"prevent code id seq init value == max codeID used": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: 2,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastCodeID, Value: 1},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
},
|
||||
"prevent contract id seq init value == count contracts": {
|
||||
src: types.GenesisState{
|
||||
Codes: []types.Code{{
|
||||
CodeID: firstCodeID,
|
||||
CodeInfo: myCodeInfo,
|
||||
CodeBytes: wasmCode,
|
||||
}},
|
||||
Contracts: []types.Contract{
|
||||
{
|
||||
ContractAddress: BuildContractAddressClassic(1, 1).String(),
|
||||
ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields),
|
||||
ContractCodeHistory: []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: 1,
|
||||
Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()},
|
||||
Msg: []byte(`{}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Sequences: []types.Sequence{
|
||||
{IDKey: types.KeyLastCodeID, Value: 2},
|
||||
{IDKey: types.KeyLastInstanceID, Value: 1},
|
||||
},
|
||||
Params: types.DefaultParams(),
|
||||
},
|
||||
},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
keeper, ctx, _ := setupKeeper(t)
|
||||
|
||||
require.NoError(t, types.ValidateGenesis(spec.src))
|
||||
_, gotErr := InitGenesis(ctx, keeper, spec.src)
|
||||
if !spec.expSuccess {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
|
||||
for _, c := range spec.src.Codes {
|
||||
assert.Equal(t, c.Pinned, keeper.IsPinnedCode(ctx, c.CodeID))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportContractWithCodeHistoryPreserved(t *testing.T) {
|
||||
genesisTemplate := `
|
||||
{
|
||||
"params":{
|
||||
"code_upload_access": {
|
||||
"permission": "Everybody"
|
||||
},
|
||||
"instantiate_default_permission": "Everybody"
|
||||
},
|
||||
"codes": [
|
||||
{
|
||||
"code_id": "1",
|
||||
"code_info": {
|
||||
"code_hash": %q,
|
||||
"creator": "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx",
|
||||
"instantiate_config": {
|
||||
"permission": "OnlyAddress",
|
||||
"address": "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx"
|
||||
}
|
||||
},
|
||||
"code_bytes": %q
|
||||
}
|
||||
],
|
||||
"contracts": [
|
||||
{
|
||||
"contract_address": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
|
||||
"contract_info": {
|
||||
"code_id": "1",
|
||||
"creator": "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x",
|
||||
"admin": "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn",
|
||||
"label": "ȀĴnZV芢毤",
|
||||
"created": {
|
||||
"block_height" : "100",
|
||||
"tx_index" : "10"
|
||||
}
|
||||
},
|
||||
"contract_code_history": [
|
||||
{
|
||||
"operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT",
|
||||
"code_id": "1",
|
||||
"updated": {
|
||||
"block_height" : "100",
|
||||
"tx_index" : "10"
|
||||
},
|
||||
"msg": {"foo": "bar"}
|
||||
},
|
||||
{
|
||||
"operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE",
|
||||
"code_id": "1",
|
||||
"updated": {
|
||||
"block_height" : "200",
|
||||
"tx_index" : "10"
|
||||
},
|
||||
"msg": {"other": "msg"}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"sequences": [
|
||||
{"id_key": "BGxhc3RDb2RlSWQ=", "value": "2"},
|
||||
{"id_key": "BGxhc3RDb250cmFjdElk", "value": "3"}
|
||||
]
|
||||
}`
|
||||
keeper, ctx, _ := setupKeeper(t)
|
||||
|
||||
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
|
||||
require.NoError(t, err)
|
||||
|
||||
wasmCodeHash := sha256.Sum256(wasmCode)
|
||||
enc64 := base64.StdEncoding.EncodeToString
|
||||
genesisStr := fmt.Sprintf(genesisTemplate, enc64(wasmCodeHash[:]), enc64(wasmCode))
|
||||
|
||||
var importState wasmTypes.GenesisState
|
||||
err = keeper.cdc.UnmarshalJSON([]byte(genesisStr), &importState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, importState.ValidateBasic(), genesisStr)
|
||||
|
||||
ctx = ctx.WithBlockHeight(0).WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
|
||||
// when
|
||||
_, err = InitGenesis(ctx, keeper, importState)
|
||||
require.NoError(t, err)
|
||||
|
||||
// verify wasm code
|
||||
gotWasmCode, err := keeper.GetByteCode(ctx, 1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, wasmCode, gotWasmCode, "byte code does not match")
|
||||
|
||||
// verify code info
|
||||
gotCodeInfo := keeper.GetCodeInfo(ctx, 1)
|
||||
require.NotNil(t, gotCodeInfo)
|
||||
codeCreatorAddr := "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx"
|
||||
expCodeInfo := types.CodeInfo{
|
||||
CodeHash: wasmCodeHash[:],
|
||||
Creator: codeCreatorAddr,
|
||||
InstantiateConfig: wasmTypes.AccessConfig{
|
||||
Permission: types.AccessTypeOnlyAddress,
|
||||
Address: codeCreatorAddr,
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expCodeInfo, *gotCodeInfo)
|
||||
|
||||
// verify contract
|
||||
contractAddr, _ := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr")
|
||||
gotContractInfo := keeper.GetContractInfo(ctx, contractAddr)
|
||||
require.NotNil(t, gotContractInfo)
|
||||
contractCreatorAddr := "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x"
|
||||
adminAddr := "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn"
|
||||
|
||||
expContractInfo := types.ContractInfo{
|
||||
CodeID: firstCodeID,
|
||||
Creator: contractCreatorAddr,
|
||||
Admin: adminAddr,
|
||||
Label: "ȀĴnZV芢毤",
|
||||
Created: &types.AbsoluteTxPosition{BlockHeight: 100, TxIndex: 10},
|
||||
}
|
||||
assert.Equal(t, expContractInfo, *gotContractInfo)
|
||||
|
||||
expHistory := []types.ContractCodeHistoryEntry{
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeInit,
|
||||
CodeID: firstCodeID,
|
||||
Updated: &types.AbsoluteTxPosition{
|
||||
BlockHeight: 100,
|
||||
TxIndex: 10,
|
||||
},
|
||||
Msg: []byte(`{"foo": "bar"}`),
|
||||
},
|
||||
{
|
||||
Operation: types.ContractCodeHistoryOperationTypeMigrate,
|
||||
CodeID: firstCodeID,
|
||||
Updated: &types.AbsoluteTxPosition{
|
||||
BlockHeight: 200,
|
||||
TxIndex: 10,
|
||||
},
|
||||
Msg: []byte(`{"other": "msg"}`),
|
||||
},
|
||||
}
|
||||
assert.Equal(t, expHistory, keeper.GetContractHistory(ctx, contractAddr))
|
||||
assert.Equal(t, uint64(2), keeper.PeekAutoIncrementID(ctx, types.KeyLastCodeID))
|
||||
assert.Equal(t, uint64(3), keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID))
|
||||
}
|
||||
|
||||
func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) {
|
||||
t.Helper()
|
||||
tempDir, err := os.MkdirTemp("", "wasm")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { os.RemoveAll(tempDir) })
|
||||
var (
|
||||
keyParams = sdk.NewKVStoreKey(paramtypes.StoreKey)
|
||||
tkeyParams = sdk.NewTransientStoreKey(paramtypes.TStoreKey)
|
||||
keyWasm = sdk.NewKVStoreKey(wasmTypes.StoreKey)
|
||||
)
|
||||
|
||||
db := dbm.NewMemDB()
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(keyWasm, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||
require.NoError(t, ms.LoadLatestVersion())
|
||||
|
||||
ctx := sdk.NewContext(ms, tmproto.Header{
|
||||
Height: 1234567,
|
||||
Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC),
|
||||
}, false, log.NewNopLogger())
|
||||
|
||||
encodingConfig := MakeEncodingConfig(t)
|
||||
// register an example extension. must be protobuf
|
||||
encodingConfig.InterfaceRegistry.RegisterImplementations(
|
||||
(*types.ContractInfoExtension)(nil),
|
||||
&govtypes.Proposal{},
|
||||
)
|
||||
// also registering gov interfaces for nested Any type
|
||||
govtypes.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
||||
|
||||
wasmConfig := wasmTypes.DefaultWasmConfig()
|
||||
pk := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams, tkeyParams)
|
||||
|
||||
srcKeeper := NewKeeper(
|
||||
encodingConfig.Marshaler,
|
||||
keyWasm,
|
||||
pk.Subspace(wasmTypes.ModuleName),
|
||||
authkeeper.AccountKeeper{},
|
||||
&bankkeeper.BaseKeeper{},
|
||||
stakingkeeper.Keeper{},
|
||||
distributionkeeper.Keeper{},
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
tempDir,
|
||||
wasmConfig,
|
||||
AvailableCapabilities,
|
||||
)
|
||||
return &srcKeeper, ctx, []sdk.StoreKey{keyWasm, keyParams}
|
||||
}
|
||||
226
x/wasm/keeper/handler_plugin.go
Normal file
226
x/wasm/keeper/handler_plugin.go
Normal file
@ -0,0 +1,226 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
host "github.com/cosmos/ibc-go/v4/modules/core/24-host"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
// msgEncoder is an extension point to customize encodings
|
||||
type msgEncoder interface {
|
||||
// Encode converts wasmvm message to n cosmos message types
|
||||
Encode(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Msg, error)
|
||||
}
|
||||
|
||||
// MessageRouter ADR 031 request type routing
|
||||
type MessageRouter interface {
|
||||
Handler(msg sdk.Msg) baseapp.MsgServiceHandler
|
||||
}
|
||||
|
||||
// SDKMessageHandler can handles messages that can be encoded into sdk.Message types and routed.
|
||||
type SDKMessageHandler struct {
|
||||
router MessageRouter
|
||||
encoders msgEncoder
|
||||
}
|
||||
|
||||
func NewDefaultMessageHandler(
|
||||
router MessageRouter,
|
||||
channelKeeper types.ChannelKeeper,
|
||||
capabilityKeeper types.CapabilityKeeper,
|
||||
bankKeeper types.Burner,
|
||||
unpacker codectypes.AnyUnpacker,
|
||||
portSource types.ICS20TransferPortSource,
|
||||
customEncoders ...*MessageEncoders,
|
||||
) Messenger {
|
||||
encoders := DefaultEncoders(unpacker, portSource)
|
||||
for _, e := range customEncoders {
|
||||
encoders = encoders.Merge(e)
|
||||
}
|
||||
return NewMessageHandlerChain(
|
||||
NewSDKMessageHandler(router, encoders),
|
||||
NewIBCRawPacketHandler(channelKeeper, capabilityKeeper),
|
||||
NewBurnCoinMessageHandler(bankKeeper),
|
||||
)
|
||||
}
|
||||
|
||||
func NewSDKMessageHandler(router MessageRouter, encoders msgEncoder) SDKMessageHandler {
|
||||
return SDKMessageHandler{
|
||||
router: router,
|
||||
encoders: encoders,
|
||||
}
|
||||
}
|
||||
|
||||
func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
|
||||
sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, sdkMsg := range sdkMsgs {
|
||||
res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// append data
|
||||
data = append(data, res.Data)
|
||||
// append events
|
||||
sdkEvents := make([]sdk.Event, len(res.Events))
|
||||
for i := range res.Events {
|
||||
sdkEvents[i] = sdk.Event(res.Events[i])
|
||||
}
|
||||
events = append(events, sdkEvents...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) (*sdk.Result, error) {
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// make sure this account can send it
|
||||
for _, acct := range msg.GetSigners() {
|
||||
if !acct.Equals(contractAddr) {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission")
|
||||
}
|
||||
}
|
||||
|
||||
// find the handler and execute it
|
||||
if handler := h.router.Handler(msg); handler != nil {
|
||||
// ADR 031 request type routing
|
||||
msgResult, err := handler(ctx, msg)
|
||||
return msgResult, err
|
||||
}
|
||||
// legacy sdk.Msg routing
|
||||
// Assuming that the app developer has migrated all their Msgs to
|
||||
// proto messages and has registered all `Msg services`, then this
|
||||
// path should never be called, because all those Msgs should be
|
||||
// registered within the `msgServiceRouter` already.
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg)
|
||||
}
|
||||
|
||||
// MessageHandlerChain defines a chain of handlers that are called one by one until it can be handled.
|
||||
type MessageHandlerChain struct {
|
||||
handlers []Messenger
|
||||
}
|
||||
|
||||
func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandlerChain {
|
||||
r := &MessageHandlerChain{handlers: append([]Messenger{first}, others...)}
|
||||
for i := range r.handlers {
|
||||
if r.handlers[i] == nil {
|
||||
panic(fmt.Sprintf("handler must not be nil at position : %d", i))
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// DispatchMsg dispatch message and calls chained handlers one after another in
|
||||
// order to find the right one to process given message. If a handler cannot
|
||||
// process given message (returns ErrUnknownMsg), its result is ignored and the
|
||||
// next handler is executed.
|
||||
func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) {
|
||||
for _, h := range m.handlers {
|
||||
events, data, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg)
|
||||
switch {
|
||||
case err == nil:
|
||||
return events, data, nil
|
||||
case errors.Is(err, types.ErrUnknownMsg):
|
||||
continue
|
||||
default:
|
||||
return events, data, err
|
||||
}
|
||||
}
|
||||
return nil, nil, sdkerrors.Wrap(types.ErrUnknownMsg, "no handler found")
|
||||
}
|
||||
|
||||
// IBCRawPacketHandler handels IBC.SendPacket messages which are published to an IBC channel.
|
||||
type IBCRawPacketHandler struct {
|
||||
channelKeeper types.ChannelKeeper
|
||||
capabilityKeeper types.CapabilityKeeper
|
||||
}
|
||||
|
||||
func NewIBCRawPacketHandler(chk types.ChannelKeeper, cak types.CapabilityKeeper) IBCRawPacketHandler {
|
||||
return IBCRawPacketHandler{channelKeeper: chk, capabilityKeeper: cak}
|
||||
}
|
||||
|
||||
// DispatchMsg publishes a raw IBC packet onto the channel.
|
||||
func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
|
||||
if msg.IBC == nil || msg.IBC.SendPacket == nil {
|
||||
return nil, nil, types.ErrUnknownMsg
|
||||
}
|
||||
if contractIBCPortID == "" {
|
||||
return nil, nil, sdkerrors.Wrapf(types.ErrUnsupportedForContract, "ibc not supported")
|
||||
}
|
||||
contractIBCChannelID := msg.IBC.SendPacket.ChannelID
|
||||
if contractIBCChannelID == "" {
|
||||
return nil, nil, sdkerrors.Wrapf(types.ErrEmpty, "ibc channel")
|
||||
}
|
||||
|
||||
sequence, found := h.channelKeeper.GetNextSequenceSend(ctx, contractIBCPortID, contractIBCChannelID)
|
||||
if !found {
|
||||
return nil, nil, sdkerrors.Wrapf(channeltypes.ErrSequenceSendNotFound,
|
||||
"source port: %s, source channel: %s", contractIBCPortID, contractIBCChannelID,
|
||||
)
|
||||
}
|
||||
|
||||
channelInfo, ok := h.channelKeeper.GetChannel(ctx, contractIBCPortID, contractIBCChannelID)
|
||||
if !ok {
|
||||
return nil, nil, sdkerrors.Wrap(channeltypes.ErrInvalidChannel, "not found")
|
||||
}
|
||||
channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID))
|
||||
if !ok {
|
||||
return nil, nil, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability")
|
||||
}
|
||||
packet := channeltypes.NewPacket(
|
||||
msg.IBC.SendPacket.Data,
|
||||
sequence,
|
||||
contractIBCPortID,
|
||||
contractIBCChannelID,
|
||||
channelInfo.Counterparty.PortId,
|
||||
channelInfo.Counterparty.ChannelId,
|
||||
ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block),
|
||||
msg.IBC.SendPacket.Timeout.Timestamp,
|
||||
)
|
||||
return nil, nil, h.channelKeeper.SendPacket(ctx, channelCap, packet)
|
||||
}
|
||||
|
||||
var _ Messenger = MessageHandlerFunc(nil)
|
||||
|
||||
// MessageHandlerFunc is a helper to construct a function based message handler.
|
||||
type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error)
|
||||
|
||||
// DispatchMsg delegates dispatching of provided message into the MessageHandlerFunc.
|
||||
func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
|
||||
return m(ctx, contractAddr, contractIBCPortID, msg)
|
||||
}
|
||||
|
||||
// NewBurnCoinMessageHandler handles wasmvm.BurnMsg messages
|
||||
func NewBurnCoinMessageHandler(burner types.Burner) MessageHandlerFunc {
|
||||
return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
|
||||
if msg.Bank != nil && msg.Bank.Burn != nil {
|
||||
coins, err := ConvertWasmCoinsToSdkCoins(msg.Bank.Burn.Amount)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if coins.IsZero() {
|
||||
return nil, nil, types.ErrEmpty.Wrap("amount")
|
||||
}
|
||||
if err := burner.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, coins); err != nil {
|
||||
return nil, nil, sdkerrors.Wrap(err, "transfer to module")
|
||||
}
|
||||
if err := burner.BurnCoins(ctx, types.ModuleName, coins); err != nil {
|
||||
return nil, nil, sdkerrors.Wrap(err, "burn coins")
|
||||
}
|
||||
moduleLogger(ctx).Info("Burned", "amount", coins)
|
||||
return nil, nil, nil
|
||||
}
|
||||
return nil, nil, types.ErrUnknownMsg
|
||||
}
|
||||
}
|
||||
393
x/wasm/keeper/handler_plugin_encoders.go
Normal file
393
x/wasm/keeper/handler_plugin_encoders.go
Normal file
@ -0,0 +1,393 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"
|
||||
ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
type (
|
||||
BankEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error)
|
||||
CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error)
|
||||
DistributionEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error)
|
||||
StakingEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error)
|
||||
StargateEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error)
|
||||
WasmEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error)
|
||||
IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error)
|
||||
)
|
||||
|
||||
type MessageEncoders struct {
|
||||
Bank func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error)
|
||||
Custom func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error)
|
||||
Distribution func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error)
|
||||
IBC func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error)
|
||||
Staking func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error)
|
||||
Stargate func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error)
|
||||
Wasm func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error)
|
||||
Gov func(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error)
|
||||
}
|
||||
|
||||
func DefaultEncoders(unpacker codectypes.AnyUnpacker, portSource types.ICS20TransferPortSource) MessageEncoders {
|
||||
return MessageEncoders{
|
||||
Bank: EncodeBankMsg,
|
||||
Custom: NoCustomMsg,
|
||||
Distribution: EncodeDistributionMsg,
|
||||
IBC: EncodeIBCMsg(portSource),
|
||||
Staking: EncodeStakingMsg,
|
||||
Stargate: EncodeStargateMsg(unpacker),
|
||||
Wasm: EncodeWasmMsg,
|
||||
Gov: EncodeGovMsg,
|
||||
}
|
||||
}
|
||||
|
||||
func (e MessageEncoders) Merge(o *MessageEncoders) MessageEncoders {
|
||||
if o == nil {
|
||||
return e
|
||||
}
|
||||
if o.Bank != nil {
|
||||
e.Bank = o.Bank
|
||||
}
|
||||
if o.Custom != nil {
|
||||
e.Custom = o.Custom
|
||||
}
|
||||
if o.Distribution != nil {
|
||||
e.Distribution = o.Distribution
|
||||
}
|
||||
if o.IBC != nil {
|
||||
e.IBC = o.IBC
|
||||
}
|
||||
if o.Staking != nil {
|
||||
e.Staking = o.Staking
|
||||
}
|
||||
if o.Stargate != nil {
|
||||
e.Stargate = o.Stargate
|
||||
}
|
||||
if o.Wasm != nil {
|
||||
e.Wasm = o.Wasm
|
||||
}
|
||||
if o.Gov != nil {
|
||||
e.Gov = o.Gov
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Msg, error) {
|
||||
switch {
|
||||
case msg.Bank != nil:
|
||||
return e.Bank(contractAddr, msg.Bank)
|
||||
case msg.Custom != nil:
|
||||
return e.Custom(contractAddr, msg.Custom)
|
||||
case msg.Distribution != nil:
|
||||
return e.Distribution(contractAddr, msg.Distribution)
|
||||
case msg.IBC != nil:
|
||||
return e.IBC(ctx, contractAddr, contractIBCPortID, msg.IBC)
|
||||
case msg.Staking != nil:
|
||||
return e.Staking(contractAddr, msg.Staking)
|
||||
case msg.Stargate != nil:
|
||||
return e.Stargate(contractAddr, msg.Stargate)
|
||||
case msg.Wasm != nil:
|
||||
return e.Wasm(contractAddr, msg.Wasm)
|
||||
case msg.Gov != nil:
|
||||
return EncodeGovMsg(contractAddr, msg.Gov)
|
||||
}
|
||||
return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Wasm")
|
||||
}
|
||||
|
||||
func EncodeBankMsg(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error) {
|
||||
if msg.Send == nil {
|
||||
return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Bank")
|
||||
}
|
||||
if len(msg.Send.Amount) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
toSend, err := ConvertWasmCoinsToSdkCoins(msg.Send.Amount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sdkMsg := banktypes.MsgSend{
|
||||
FromAddress: sender.String(),
|
||||
ToAddress: msg.Send.ToAddress,
|
||||
Amount: toSend,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
}
|
||||
|
||||
func NoCustomMsg(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) {
|
||||
return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "custom variant not supported")
|
||||
}
|
||||
|
||||
func EncodeDistributionMsg(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) {
|
||||
switch {
|
||||
case msg.SetWithdrawAddress != nil:
|
||||
setMsg := distributiontypes.MsgSetWithdrawAddress{
|
||||
DelegatorAddress: sender.String(),
|
||||
WithdrawAddress: msg.SetWithdrawAddress.Address,
|
||||
}
|
||||
return []sdk.Msg{&setMsg}, nil
|
||||
case msg.WithdrawDelegatorReward != nil:
|
||||
withdrawMsg := distributiontypes.MsgWithdrawDelegatorReward{
|
||||
DelegatorAddress: sender.String(),
|
||||
ValidatorAddress: msg.WithdrawDelegatorReward.Validator,
|
||||
}
|
||||
return []sdk.Msg{&withdrawMsg}, nil
|
||||
default:
|
||||
return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Distribution")
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) {
|
||||
switch {
|
||||
case msg.Delegate != nil:
|
||||
coin, err := ConvertWasmCoinToSdkCoin(msg.Delegate.Amount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sdkMsg := stakingtypes.MsgDelegate{
|
||||
DelegatorAddress: sender.String(),
|
||||
ValidatorAddress: msg.Delegate.Validator,
|
||||
Amount: coin,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
|
||||
case msg.Redelegate != nil:
|
||||
coin, err := ConvertWasmCoinToSdkCoin(msg.Redelegate.Amount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sdkMsg := stakingtypes.MsgBeginRedelegate{
|
||||
DelegatorAddress: sender.String(),
|
||||
ValidatorSrcAddress: msg.Redelegate.SrcValidator,
|
||||
ValidatorDstAddress: msg.Redelegate.DstValidator,
|
||||
Amount: coin,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
case msg.Undelegate != nil:
|
||||
coin, err := ConvertWasmCoinToSdkCoin(msg.Undelegate.Amount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sdkMsg := stakingtypes.MsgUndelegate{
|
||||
DelegatorAddress: sender.String(),
|
||||
ValidatorAddress: msg.Undelegate.Validator,
|
||||
Amount: coin,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
default:
|
||||
return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Staking")
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeStargateMsg(unpacker codectypes.AnyUnpacker) StargateEncoder {
|
||||
return func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) {
|
||||
any := codectypes.Any{
|
||||
TypeUrl: msg.TypeURL,
|
||||
Value: msg.Value,
|
||||
}
|
||||
var sdkMsg sdk.Msg
|
||||
if err := unpacker.UnpackAny(&any, &sdkMsg); err != nil {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("Cannot unpack proto message with type URL: %s", msg.TypeURL))
|
||||
}
|
||||
if err := codectypes.UnpackInterfaces(sdkMsg, unpacker); err != nil {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("UnpackInterfaces inside msg: %s", err))
|
||||
}
|
||||
return []sdk.Msg{sdkMsg}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeWasmMsg(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) {
|
||||
switch {
|
||||
case msg.Execute != nil:
|
||||
coins, err := ConvertWasmCoinsToSdkCoins(msg.Execute.Funds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sdkMsg := types.MsgExecuteContract{
|
||||
Sender: sender.String(),
|
||||
Contract: msg.Execute.ContractAddr,
|
||||
Msg: msg.Execute.Msg,
|
||||
Funds: coins,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
case msg.Instantiate != nil:
|
||||
coins, err := ConvertWasmCoinsToSdkCoins(msg.Instantiate.Funds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sdkMsg := types.MsgInstantiateContract{
|
||||
Sender: sender.String(),
|
||||
CodeID: msg.Instantiate.CodeID,
|
||||
Label: msg.Instantiate.Label,
|
||||
Msg: msg.Instantiate.Msg,
|
||||
Admin: msg.Instantiate.Admin,
|
||||
Funds: coins,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
case msg.Instantiate2 != nil:
|
||||
coins, err := ConvertWasmCoinsToSdkCoins(msg.Instantiate2.Funds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sdkMsg := types.MsgInstantiateContract2{
|
||||
Sender: sender.String(),
|
||||
Admin: msg.Instantiate2.Admin,
|
||||
CodeID: msg.Instantiate2.CodeID,
|
||||
Label: msg.Instantiate2.Label,
|
||||
Msg: msg.Instantiate2.Msg,
|
||||
Funds: coins,
|
||||
Salt: msg.Instantiate2.Salt,
|
||||
// FixMsg is discouraged, see: https://medium.com/cosmwasm/dev-note-3-limitations-of-instantiate2-and-how-to-deal-with-them-a3f946874230
|
||||
FixMsg: false,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
case msg.Migrate != nil:
|
||||
sdkMsg := types.MsgMigrateContract{
|
||||
Sender: sender.String(),
|
||||
Contract: msg.Migrate.ContractAddr,
|
||||
CodeID: msg.Migrate.NewCodeID,
|
||||
Msg: msg.Migrate.Msg,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
case msg.ClearAdmin != nil:
|
||||
sdkMsg := types.MsgClearAdmin{
|
||||
Sender: sender.String(),
|
||||
Contract: msg.ClearAdmin.ContractAddr,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
case msg.UpdateAdmin != nil:
|
||||
sdkMsg := types.MsgUpdateAdmin{
|
||||
Sender: sender.String(),
|
||||
Contract: msg.UpdateAdmin.ContractAddr,
|
||||
NewAdmin: msg.UpdateAdmin.Admin,
|
||||
}
|
||||
return []sdk.Msg{&sdkMsg}, nil
|
||||
default:
|
||||
return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Wasm")
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) {
|
||||
return func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) {
|
||||
switch {
|
||||
case msg.CloseChannel != nil:
|
||||
return []sdk.Msg{&channeltypes.MsgChannelCloseInit{
|
||||
PortId: PortIDForContract(sender),
|
||||
ChannelId: msg.CloseChannel.ChannelID,
|
||||
Signer: sender.String(),
|
||||
}}, nil
|
||||
case msg.Transfer != nil:
|
||||
amount, err := ConvertWasmCoinToSdkCoin(msg.Transfer.Amount)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(err, "amount")
|
||||
}
|
||||
msg := &ibctransfertypes.MsgTransfer{
|
||||
SourcePort: portSource.GetPort(ctx),
|
||||
SourceChannel: msg.Transfer.ChannelID,
|
||||
Token: amount,
|
||||
Sender: sender.String(),
|
||||
Receiver: msg.Transfer.ToAddress,
|
||||
TimeoutHeight: ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.Transfer.Timeout.Block),
|
||||
TimeoutTimestamp: msg.Transfer.Timeout.Timestamp,
|
||||
}
|
||||
return []sdk.Msg{msg}, nil
|
||||
default:
|
||||
return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of IBC")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func EncodeGovMsg(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) {
|
||||
switch {
|
||||
case msg.Vote != nil:
|
||||
voteOption, err := convertVoteOption(msg.Vote.Vote)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(err, "vote option")
|
||||
}
|
||||
m := govtypes.NewMsgVote(sender, msg.Vote.ProposalId, voteOption)
|
||||
return []sdk.Msg{m}, nil
|
||||
case msg.VoteWeighted != nil:
|
||||
opts := make([]govtypes.WeightedVoteOption, len(msg.VoteWeighted.Options))
|
||||
for i, v := range msg.VoteWeighted.Options {
|
||||
weight, err := sdk.NewDecFromStr(v.Weight)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(err, "weight for vote %d", i+1)
|
||||
}
|
||||
voteOption, err := convertVoteOption(v.Option)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(err, "vote option")
|
||||
}
|
||||
opts[i] = govtypes.WeightedVoteOption{Option: voteOption, Weight: weight}
|
||||
}
|
||||
m := govtypes.NewMsgVoteWeighted(sender, msg.VoteWeighted.ProposalId, opts)
|
||||
return []sdk.Msg{m}, nil
|
||||
|
||||
default:
|
||||
return nil, types.ErrUnknownMsg.Wrap("unknown variant of gov")
|
||||
}
|
||||
}
|
||||
|
||||
func convertVoteOption(s interface{}) (govtypes.VoteOption, error) {
|
||||
var option govtypes.VoteOption
|
||||
switch s {
|
||||
case wasmvmtypes.Yes:
|
||||
option = govtypes.OptionYes
|
||||
case wasmvmtypes.No:
|
||||
option = govtypes.OptionNo
|
||||
case wasmvmtypes.NoWithVeto:
|
||||
option = govtypes.OptionNoWithVeto
|
||||
case wasmvmtypes.Abstain:
|
||||
option = govtypes.OptionAbstain
|
||||
default:
|
||||
return govtypes.OptionEmpty, types.ErrInvalid
|
||||
}
|
||||
return option, nil
|
||||
}
|
||||
|
||||
// ConvertWasmIBCTimeoutHeightToCosmosHeight converts a wasmvm type ibc timeout height to ibc module type height
|
||||
func ConvertWasmIBCTimeoutHeightToCosmosHeight(ibcTimeoutBlock *wasmvmtypes.IBCTimeoutBlock) ibcclienttypes.Height {
|
||||
if ibcTimeoutBlock == nil {
|
||||
return ibcclienttypes.NewHeight(0, 0)
|
||||
}
|
||||
return ibcclienttypes.NewHeight(ibcTimeoutBlock.Revision, ibcTimeoutBlock.Height)
|
||||
}
|
||||
|
||||
// ConvertWasmCoinsToSdkCoins converts the wasm vm type coins to sdk type coins
|
||||
func ConvertWasmCoinsToSdkCoins(coins []wasmvmtypes.Coin) (sdk.Coins, error) {
|
||||
var toSend sdk.Coins
|
||||
for _, coin := range coins {
|
||||
c, err := ConvertWasmCoinToSdkCoin(coin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
toSend = toSend.Add(c)
|
||||
}
|
||||
return toSend.Sort(), nil
|
||||
}
|
||||
|
||||
// ConvertWasmCoinToSdkCoin converts a wasm vm type coin to sdk type coin
|
||||
func ConvertWasmCoinToSdkCoin(coin wasmvmtypes.Coin) (sdk.Coin, error) {
|
||||
amount, ok := sdk.NewIntFromString(coin.Amount)
|
||||
if !ok {
|
||||
return sdk.Coin{}, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, coin.Amount+coin.Denom)
|
||||
}
|
||||
r := sdk.Coin{
|
||||
Denom: coin.Denom,
|
||||
Amount: amount,
|
||||
}
|
||||
return r, r.Validate()
|
||||
}
|
||||
932
x/wasm/keeper/handler_plugin_encoders_test.go
Normal file
932
x/wasm/keeper/handler_plugin_encoders_test.go
Normal file
@ -0,0 +1,932 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"
|
||||
clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
|
||||
channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting"
|
||||
"github.com/cerc-io/laconicd/x/wasm/types"
|
||||
)
|
||||
|
||||
func TestEncoding(t *testing.T) {
|
||||
var (
|
||||
addr1 = RandomAccountAddress(t)
|
||||
addr2 = RandomAccountAddress(t)
|
||||
addr3 = RandomAccountAddress(t)
|
||||
invalidAddr = "xrnd1d02kd90n38qvr3qb9qof83fn2d2"
|
||||
)
|
||||
valAddr := make(sdk.ValAddress, types.SDKAddrLen)
|
||||
valAddr[0] = 12
|
||||
valAddr2 := make(sdk.ValAddress, types.SDKAddrLen)
|
||||
valAddr2[1] = 123
|
||||
|
||||
jsonMsg := types.RawContractMessage(`{"foo": 123}`)
|
||||
|
||||
bankMsg := &banktypes.MsgSend{
|
||||
FromAddress: addr2.String(),
|
||||
ToAddress: addr1.String(),
|
||||
Amount: sdk.Coins{
|
||||
sdk.NewInt64Coin("uatom", 12345),
|
||||
sdk.NewInt64Coin("utgd", 54321),
|
||||
},
|
||||
}
|
||||
bankMsgBin, err := proto.Marshal(bankMsg)
|
||||
require.NoError(t, err)
|
||||
|
||||
content, err := codectypes.NewAnyWithValue(types.StoreCodeProposalFixture())
|
||||
require.NoError(t, err)
|
||||
|
||||
proposalMsg := &govtypes.MsgSubmitProposal{
|
||||
Proposer: addr1.String(),
|
||||
InitialDeposit: sdk.NewCoins(sdk.NewInt64Coin("uatom", 12345)),
|
||||
Content: content,
|
||||
}
|
||||
proposalMsgBin, err := proto.Marshal(proposalMsg)
|
||||
require.NoError(t, err)
|
||||
|
||||
cases := map[string]struct {
|
||||
sender sdk.AccAddress
|
||||
srcMsg wasmvmtypes.CosmosMsg
|
||||
srcContractIBCPort string
|
||||
transferPortSource types.ICS20TransferPortSource
|
||||
// set if valid
|
||||
output []sdk.Msg
|
||||
// set if expect mapping fails
|
||||
expError bool
|
||||
// set if sdk validate basic should fail
|
||||
expInvalid bool
|
||||
}{
|
||||
"simple send": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Bank: &wasmvmtypes.BankMsg{
|
||||
Send: &wasmvmtypes.SendMsg{
|
||||
ToAddress: addr2.String(),
|
||||
Amount: []wasmvmtypes.Coin{
|
||||
{
|
||||
Denom: "uatom",
|
||||
Amount: "12345",
|
||||
},
|
||||
{
|
||||
Denom: "usdt",
|
||||
Amount: "54321",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&banktypes.MsgSend{
|
||||
FromAddress: addr1.String(),
|
||||
ToAddress: addr2.String(),
|
||||
Amount: sdk.Coins{
|
||||
sdk.NewInt64Coin("uatom", 12345),
|
||||
sdk.NewInt64Coin("usdt", 54321),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid send amount": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Bank: &wasmvmtypes.BankMsg{
|
||||
Send: &wasmvmtypes.SendMsg{
|
||||
ToAddress: addr2.String(),
|
||||
Amount: []wasmvmtypes.Coin{
|
||||
{
|
||||
Denom: "uatom",
|
||||
Amount: "123.456",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expError: true,
|
||||
},
|
||||
"invalid address": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Bank: &wasmvmtypes.BankMsg{
|
||||
Send: &wasmvmtypes.SendMsg{
|
||||
ToAddress: invalidAddr,
|
||||
Amount: []wasmvmtypes.Coin{
|
||||
{
|
||||
Denom: "uatom",
|
||||
Amount: "7890",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expError: false, // addresses are checked in the handler
|
||||
expInvalid: true,
|
||||
output: []sdk.Msg{
|
||||
&banktypes.MsgSend{
|
||||
FromAddress: addr1.String(),
|
||||
ToAddress: invalidAddr,
|
||||
Amount: sdk.Coins{
|
||||
sdk.NewInt64Coin("uatom", 7890),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"wasm execute": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Wasm: &wasmvmtypes.WasmMsg{
|
||||
Execute: &wasmvmtypes.ExecuteMsg{
|
||||
ContractAddr: addr2.String(),
|
||||
Msg: jsonMsg,
|
||||
Funds: []wasmvmtypes.Coin{
|
||||
wasmvmtypes.NewCoin(12, "eth"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&types.MsgExecuteContract{
|
||||
Sender: addr1.String(),
|
||||
Contract: addr2.String(),
|
||||
Msg: jsonMsg,
|
||||
Funds: sdk.NewCoins(sdk.NewInt64Coin("eth", 12)),
|
||||
},
|
||||
},
|
||||
},
|
||||
"wasm instantiate": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Wasm: &wasmvmtypes.WasmMsg{
|
||||
Instantiate: &wasmvmtypes.InstantiateMsg{
|
||||
CodeID: 7,
|
||||
Msg: jsonMsg,
|
||||
Funds: []wasmvmtypes.Coin{
|
||||
wasmvmtypes.NewCoin(123, "eth"),
|
||||
},
|
||||
Label: "myLabel",
|
||||
Admin: addr2.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&types.MsgInstantiateContract{
|
||||
Sender: addr1.String(),
|
||||
CodeID: 7,
|
||||
Label: "myLabel",
|
||||
Msg: jsonMsg,
|
||||
Funds: sdk.NewCoins(sdk.NewInt64Coin("eth", 123)),
|
||||
Admin: addr2.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"wasm instantiate2": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Wasm: &wasmvmtypes.WasmMsg{
|
||||
Instantiate2: &wasmvmtypes.Instantiate2Msg{
|
||||
CodeID: 7,
|
||||
Msg: jsonMsg,
|
||||
Funds: []wasmvmtypes.Coin{
|
||||
wasmvmtypes.NewCoin(123, "eth"),
|
||||
},
|
||||
Label: "myLabel",
|
||||
Admin: addr2.String(),
|
||||
Salt: []byte("mySalt"),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&types.MsgInstantiateContract2{
|
||||
Sender: addr1.String(),
|
||||
Admin: addr2.String(),
|
||||
CodeID: 7,
|
||||
Label: "myLabel",
|
||||
Msg: jsonMsg,
|
||||
Funds: sdk.NewCoins(sdk.NewInt64Coin("eth", 123)),
|
||||
Salt: []byte("mySalt"),
|
||||
FixMsg: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
"wasm migrate": {
|
||||
sender: addr2,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Wasm: &wasmvmtypes.WasmMsg{
|
||||
Migrate: &wasmvmtypes.MigrateMsg{
|
||||
ContractAddr: addr1.String(),
|
||||
NewCodeID: 12,
|
||||
Msg: jsonMsg,
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&types.MsgMigrateContract{
|
||||
Sender: addr2.String(),
|
||||
Contract: addr1.String(),
|
||||
CodeID: 12,
|
||||
Msg: jsonMsg,
|
||||
},
|
||||
},
|
||||
},
|
||||
"wasm update admin": {
|
||||
sender: addr2,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Wasm: &wasmvmtypes.WasmMsg{
|
||||
UpdateAdmin: &wasmvmtypes.UpdateAdminMsg{
|
||||
ContractAddr: addr1.String(),
|
||||
Admin: addr3.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&types.MsgUpdateAdmin{
|
||||
Sender: addr2.String(),
|
||||
Contract: addr1.String(),
|
||||
NewAdmin: addr3.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"wasm clear admin": {
|
||||
sender: addr2,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Wasm: &wasmvmtypes.WasmMsg{
|
||||
ClearAdmin: &wasmvmtypes.ClearAdminMsg{
|
||||
ContractAddr: addr1.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&types.MsgClearAdmin{
|
||||
Sender: addr2.String(),
|
||||
Contract: addr1.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"staking delegate": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Staking: &wasmvmtypes.StakingMsg{
|
||||
Delegate: &wasmvmtypes.DelegateMsg{
|
||||
Validator: valAddr.String(),
|
||||
Amount: wasmvmtypes.NewCoin(777, "stake"),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&stakingtypes.MsgDelegate{
|
||||
DelegatorAddress: addr1.String(),
|
||||
ValidatorAddress: valAddr.String(),
|
||||
Amount: sdk.NewInt64Coin("stake", 777),
|
||||
},
|
||||
},
|
||||
},
|
||||
"staking delegate to non-validator": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Staking: &wasmvmtypes.StakingMsg{
|
||||
Delegate: &wasmvmtypes.DelegateMsg{
|
||||
Validator: addr2.String(),
|
||||
Amount: wasmvmtypes.NewCoin(777, "stake"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expError: false, // fails in the handler
|
||||
output: []sdk.Msg{
|
||||
&stakingtypes.MsgDelegate{
|
||||
DelegatorAddress: addr1.String(),
|
||||
ValidatorAddress: addr2.String(),
|
||||
Amount: sdk.NewInt64Coin("stake", 777),
|
||||
},
|
||||
},
|
||||
},
|
||||
"staking undelegate": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Staking: &wasmvmtypes.StakingMsg{
|
||||
Undelegate: &wasmvmtypes.UndelegateMsg{
|
||||
Validator: valAddr.String(),
|
||||
Amount: wasmvmtypes.NewCoin(555, "stake"),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&stakingtypes.MsgUndelegate{
|
||||
DelegatorAddress: addr1.String(),
|
||||
ValidatorAddress: valAddr.String(),
|
||||
Amount: sdk.NewInt64Coin("stake", 555),
|
||||
},
|
||||
},
|
||||
},
|
||||
"staking redelegate": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Staking: &wasmvmtypes.StakingMsg{
|
||||
Redelegate: &wasmvmtypes.RedelegateMsg{
|
||||
SrcValidator: valAddr.String(),
|
||||
DstValidator: valAddr2.String(),
|
||||
Amount: wasmvmtypes.NewCoin(222, "stake"),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&stakingtypes.MsgBeginRedelegate{
|
||||
DelegatorAddress: addr1.String(),
|
||||
ValidatorSrcAddress: valAddr.String(),
|
||||
ValidatorDstAddress: valAddr2.String(),
|
||||
Amount: sdk.NewInt64Coin("stake", 222),
|
||||
},
|
||||
},
|
||||
},
|
||||
"staking withdraw (explicit recipient)": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Distribution: &wasmvmtypes.DistributionMsg{
|
||||
WithdrawDelegatorReward: &wasmvmtypes.WithdrawDelegatorRewardMsg{
|
||||
Validator: valAddr2.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&distributiontypes.MsgWithdrawDelegatorReward{
|
||||
DelegatorAddress: addr1.String(),
|
||||
ValidatorAddress: valAddr2.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"staking set withdraw address": {
|
||||
sender: addr1,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Distribution: &wasmvmtypes.DistributionMsg{
|
||||
SetWithdrawAddress: &wasmvmtypes.SetWithdrawAddressMsg{
|
||||
Address: addr2.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&distributiontypes.MsgSetWithdrawAddress{
|
||||
DelegatorAddress: addr1.String(),
|
||||
WithdrawAddress: addr2.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
"stargate encoded bank msg": {
|
||||
sender: addr2,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Stargate: &wasmvmtypes.StargateMsg{
|
||||
TypeURL: "/cosmos.bank.v1beta1.MsgSend",
|
||||
Value: bankMsgBin,
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{bankMsg},
|
||||
},
|
||||
"stargate encoded msg with any type": {
|
||||
sender: addr2,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Stargate: &wasmvmtypes.StargateMsg{
|
||||
TypeURL: "/cosmos.gov.v1beta1.MsgSubmitProposal",
|
||||
Value: proposalMsgBin,
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{proposalMsg},
|
||||
},
|
||||
"stargate encoded invalid typeUrl": {
|
||||
sender: addr2,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Stargate: &wasmvmtypes.StargateMsg{
|
||||
TypeURL: "/cosmos.bank.v2.MsgSend",
|
||||
Value: bankMsgBin,
|
||||
},
|
||||
},
|
||||
expError: true,
|
||||
},
|
||||
"IBC transfer with block timeout": {
|
||||
sender: addr1,
|
||||
srcContractIBCPort: "myIBCPort",
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
IBC: &wasmvmtypes.IBCMsg{
|
||||
Transfer: &wasmvmtypes.TransferMsg{
|
||||
ChannelID: "myChanID",
|
||||
ToAddress: addr2.String(),
|
||||
Amount: wasmvmtypes.Coin{
|
||||
Denom: "ALX",
|
||||
Amount: "1",
|
||||
},
|
||||
Timeout: wasmvmtypes.IBCTimeout{
|
||||
Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string {
|
||||
return "myTransferPort"
|
||||
}},
|
||||
output: []sdk.Msg{
|
||||
&ibctransfertypes.MsgTransfer{
|
||||
SourcePort: "myTransferPort",
|
||||
SourceChannel: "myChanID",
|
||||
Token: sdk.Coin{
|
||||
Denom: "ALX",
|
||||
Amount: sdk.NewInt(1),
|
||||
},
|
||||
Sender: addr1.String(),
|
||||
Receiver: addr2.String(),
|
||||
TimeoutHeight: clienttypes.Height{RevisionNumber: 1, RevisionHeight: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
"IBC transfer with time timeout": {
|
||||
sender: addr1,
|
||||
srcContractIBCPort: "myIBCPort",
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
IBC: &wasmvmtypes.IBCMsg{
|
||||
Transfer: &wasmvmtypes.TransferMsg{
|
||||
ChannelID: "myChanID",
|
||||
ToAddress: addr2.String(),
|
||||
Amount: wasmvmtypes.Coin{
|
||||
Denom: "ALX",
|
||||
Amount: "1",
|
||||
},
|
||||
Timeout: wasmvmtypes.IBCTimeout{Timestamp: 100},
|
||||
},
|
||||
},
|
||||
},
|
||||
transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string {
|
||||
return "transfer"
|
||||
}},
|
||||
output: []sdk.Msg{
|
||||
&ibctransfertypes.MsgTransfer{
|
||||
SourcePort: "transfer",
|
||||
SourceChannel: "myChanID",
|
||||
Token: sdk.Coin{
|
||||
Denom: "ALX",
|
||||
Amount: sdk.NewInt(1),
|
||||
},
|
||||
Sender: addr1.String(),
|
||||
Receiver: addr2.String(),
|
||||
TimeoutTimestamp: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
"IBC transfer with time and height timeout": {
|
||||
sender: addr1,
|
||||
srcContractIBCPort: "myIBCPort",
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
IBC: &wasmvmtypes.IBCMsg{
|
||||
Transfer: &wasmvmtypes.TransferMsg{
|
||||
ChannelID: "myChanID",
|
||||
ToAddress: addr2.String(),
|
||||
Amount: wasmvmtypes.Coin{
|
||||
Denom: "ALX",
|
||||
Amount: "1",
|
||||
},
|
||||
Timeout: wasmvmtypes.IBCTimeout{Timestamp: 100, Block: &wasmvmtypes.IBCTimeoutBlock{Height: 1, Revision: 2}},
|
||||
},
|
||||
},
|
||||
},
|
||||
transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string {
|
||||
return "transfer"
|
||||
}},
|
||||
output: []sdk.Msg{
|
||||
&ibctransfertypes.MsgTransfer{
|
||||
SourcePort: "transfer",
|
||||
SourceChannel: "myChanID",
|
||||
Token: sdk.Coin{
|
||||
Denom: "ALX",
|
||||
Amount: sdk.NewInt(1),
|
||||
},
|
||||
Sender: addr1.String(),
|
||||
Receiver: addr2.String(),
|
||||
TimeoutTimestamp: 100,
|
||||
TimeoutHeight: clienttypes.NewHeight(2, 1),
|
||||
},
|
||||
},
|
||||
},
|
||||
"IBC close channel": {
|
||||
sender: addr1,
|
||||
srcContractIBCPort: "myIBCPort",
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
IBC: &wasmvmtypes.IBCMsg{
|
||||
CloseChannel: &wasmvmtypes.CloseChannelMsg{
|
||||
ChannelID: "channel-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&channeltypes.MsgChannelCloseInit{
|
||||
PortId: "wasm." + addr1.String(),
|
||||
ChannelId: "channel-1",
|
||||
Signer: addr1.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
encodingConfig := MakeEncodingConfig(t)
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var ctx sdk.Context
|
||||
encoder := DefaultEncoders(encodingConfig.Marshaler, tc.transferPortSource)
|
||||
res, err := encoder.Encode(ctx, tc.sender, tc.srcContractIBCPort, tc.srcMsg)
|
||||
if tc.expError {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.output, res)
|
||||
}
|
||||
// and valid sdk message
|
||||
for _, v := range res {
|
||||
gotErr := v.ValidateBasic()
|
||||
if tc.expInvalid {
|
||||
assert.Error(t, gotErr)
|
||||
} else {
|
||||
assert.NoError(t, gotErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeGovMsg(t *testing.T) {
|
||||
myAddr := RandomAccountAddress(t)
|
||||
|
||||
cases := map[string]struct {
|
||||
sender sdk.AccAddress
|
||||
srcMsg wasmvmtypes.CosmosMsg
|
||||
transferPortSource types.ICS20TransferPortSource
|
||||
// set if valid
|
||||
output []sdk.Msg
|
||||
// set if expect mapping fails
|
||||
expError bool
|
||||
// set if sdk validate basic should fail
|
||||
expInvalid bool
|
||||
}{
|
||||
"Gov vote: yes": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.Yes},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVote{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Option: govtypes.OptionYes,
|
||||
},
|
||||
},
|
||||
},
|
||||
"Gov vote: No": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.No},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVote{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Option: govtypes.OptionNo,
|
||||
},
|
||||
},
|
||||
},
|
||||
"Gov vote: Abstain": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
Vote: &wasmvmtypes.VoteMsg{ProposalId: 10, Vote: wasmvmtypes.Abstain},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVote{
|
||||
ProposalId: 10,
|
||||
Voter: myAddr.String(),
|
||||
Option: govtypes.OptionAbstain,
|
||||
},
|
||||
},
|
||||
},
|
||||
"Gov vote: No with veto": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.NoWithVeto},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVote{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Option: govtypes.OptionNoWithVeto,
|
||||
},
|
||||
},
|
||||
},
|
||||
"Gov vote: unset option": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
Vote: &wasmvmtypes.VoteMsg{ProposalId: 1},
|
||||
},
|
||||
},
|
||||
expError: true,
|
||||
},
|
||||
"Gov weighted vote: single vote": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
VoteWeighted: &wasmvmtypes.VoteWeightedMsg{
|
||||
ProposalId: 1,
|
||||
Options: []wasmvmtypes.WeightedVoteOption{
|
||||
{Option: wasmvmtypes.Yes, Weight: "1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVoteWeighted{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Options: []govtypes.WeightedVoteOption{
|
||||
{Option: govtypes.OptionYes, Weight: sdk.NewDec(1)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Gov weighted vote: splitted": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
VoteWeighted: &wasmvmtypes.VoteWeightedMsg{
|
||||
ProposalId: 1,
|
||||
Options: []wasmvmtypes.WeightedVoteOption{
|
||||
{Option: wasmvmtypes.Yes, Weight: "0.23"},
|
||||
{Option: wasmvmtypes.No, Weight: "0.24"},
|
||||
{Option: wasmvmtypes.Abstain, Weight: "0.26"},
|
||||
{Option: wasmvmtypes.NoWithVeto, Weight: "0.27"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVoteWeighted{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Options: []govtypes.WeightedVoteOption{
|
||||
{Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(23, 2)},
|
||||
{Option: govtypes.OptionNo, Weight: sdk.NewDecWithPrec(24, 2)},
|
||||
{Option: govtypes.OptionAbstain, Weight: sdk.NewDecWithPrec(26, 2)},
|
||||
{Option: govtypes.OptionNoWithVeto, Weight: sdk.NewDecWithPrec(27, 2)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Gov weighted vote: duplicate option": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
VoteWeighted: &wasmvmtypes.VoteWeightedMsg{
|
||||
ProposalId: 1,
|
||||
Options: []wasmvmtypes.WeightedVoteOption{
|
||||
{Option: wasmvmtypes.Yes, Weight: "0.5"},
|
||||
{Option: wasmvmtypes.Yes, Weight: "0.5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVoteWeighted{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Options: []govtypes.WeightedVoteOption{
|
||||
{Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(5, 1)},
|
||||
{Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(5, 1)},
|
||||
},
|
||||
},
|
||||
},
|
||||
expInvalid: true,
|
||||
},
|
||||
"Gov weighted vote: weight sum exceeds 1": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
VoteWeighted: &wasmvmtypes.VoteWeightedMsg{
|
||||
ProposalId: 1,
|
||||
Options: []wasmvmtypes.WeightedVoteOption{
|
||||
{Option: wasmvmtypes.Yes, Weight: "0.51"},
|
||||
{Option: wasmvmtypes.No, Weight: "0.5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVoteWeighted{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Options: []govtypes.WeightedVoteOption{
|
||||
{Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(51, 2)},
|
||||
{Option: govtypes.OptionNo, Weight: sdk.NewDecWithPrec(5, 1)},
|
||||
},
|
||||
},
|
||||
},
|
||||
expInvalid: true,
|
||||
},
|
||||
"Gov weighted vote: weight sum less than 1": {
|
||||
sender: myAddr,
|
||||
srcMsg: wasmvmtypes.CosmosMsg{
|
||||
Gov: &wasmvmtypes.GovMsg{
|
||||
VoteWeighted: &wasmvmtypes.VoteWeightedMsg{
|
||||
ProposalId: 1,
|
||||
Options: []wasmvmtypes.WeightedVoteOption{
|
||||
{Option: wasmvmtypes.Yes, Weight: "0.49"},
|
||||
{Option: wasmvmtypes.No, Weight: "0.5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: []sdk.Msg{
|
||||
&govtypes.MsgVoteWeighted{
|
||||
ProposalId: 1,
|
||||
Voter: myAddr.String(),
|
||||
Options: []govtypes.WeightedVoteOption{
|
||||
{Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(49, 2)},
|
||||
{Option: govtypes.OptionNo, Weight: sdk.NewDecWithPrec(5, 1)},
|
||||
},
|
||||
},
|
||||
},
|
||||
expInvalid: true,
|
||||
},
|
||||
}
|
||||
encodingConfig := MakeEncodingConfig(t)
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var ctx sdk.Context
|
||||
encoder := DefaultEncoders(encodingConfig.Marshaler, tc.transferPortSource)
|
||||
res, gotEncErr := encoder.Encode(ctx, tc.sender, "myIBCPort", tc.srcMsg)
|
||||
if tc.expError {
|
||||
assert.Error(t, gotEncErr)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, gotEncErr)
|
||||
assert.Equal(t, tc.output, res)
|
||||
}
|
||||
// and valid sdk message
|
||||
for _, v := range res {
|
||||
gotErr := v.ValidateBasic()
|
||||
if tc.expInvalid {
|
||||
assert.Error(t, gotErr)
|
||||
} else {
|
||||
assert.NoError(t, gotErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertWasmCoinToSdkCoin(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src wasmvmtypes.Coin
|
||||
expErr bool
|
||||
expVal sdk.Coin
|
||||
}{
|
||||
"all good": {
|
||||
src: wasmvmtypes.Coin{
|
||||
Denom: "foo",
|
||||
Amount: "1",
|
||||
},
|
||||
expVal: sdk.NewCoin("foo", sdk.NewIntFromUint64(1)),
|
||||
},
|
||||
"negative amount": {
|
||||
src: wasmvmtypes.Coin{
|
||||
Denom: "foo",
|
||||
Amount: "-1",
|
||||
},
|
||||
expErr: true,
|
||||
},
|
||||
"denom to short": {
|
||||
src: wasmvmtypes.Coin{
|
||||
Denom: "f",
|
||||
Amount: "1",
|
||||
},
|
||||
expErr: true,
|
||||
},
|
||||
"invalid demum char": {
|
||||
src: wasmvmtypes.Coin{
|
||||
Denom: "&fff",
|
||||
Amount: "1",
|
||||
},
|
||||
expErr: true,
|
||||
},
|
||||
"not a number amount": {
|
||||
src: wasmvmtypes.Coin{
|
||||
Denom: "foo",
|
||||
Amount: "bar",
|
||||
},
|
||||
expErr: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
gotVal, gotErr := ConvertWasmCoinToSdkCoin(spec.src)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
assert.Equal(t, spec.expVal, gotVal)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertWasmCoinsToSdkCoins(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src []wasmvmtypes.Coin
|
||||
exp sdk.Coins
|
||||
expErr bool
|
||||
}{
|
||||
"empty": {
|
||||
src: []wasmvmtypes.Coin{},
|
||||
exp: nil,
|
||||
},
|
||||
"single coin": {
|
||||
src: []wasmvmtypes.Coin{{Denom: "foo", Amount: "1"}},
|
||||
exp: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1))),
|
||||
},
|
||||
"multiple coins": {
|
||||
src: []wasmvmtypes.Coin{
|
||||
{Denom: "foo", Amount: "1"},
|
||||
{Denom: "bar", Amount: "2"},
|
||||
},
|
||||
exp: sdk.NewCoins(
|
||||
sdk.NewCoin("bar", sdk.NewInt(2)),
|
||||
sdk.NewCoin("foo", sdk.NewInt(1)),
|
||||
),
|
||||
},
|
||||
"sorted": {
|
||||
src: []wasmvmtypes.Coin{
|
||||
{Denom: "foo", Amount: "1"},
|
||||
{Denom: "other", Amount: "1"},
|
||||
{Denom: "bar", Amount: "1"},
|
||||
},
|
||||
exp: []sdk.Coin{
|
||||
sdk.NewCoin("bar", sdk.NewInt(1)),
|
||||
sdk.NewCoin("foo", sdk.NewInt(1)),
|
||||
sdk.NewCoin("other", sdk.NewInt(1)),
|
||||
},
|
||||
},
|
||||
"zero amounts dropped": {
|
||||
src: []wasmvmtypes.Coin{
|
||||
{Denom: "foo", Amount: "1"},
|
||||
{Denom: "bar", Amount: "0"},
|
||||
},
|
||||
exp: sdk.NewCoins(
|
||||
sdk.NewCoin("foo", sdk.NewInt(1)),
|
||||
),
|
||||
},
|
||||
"duplicate denoms merged": {
|
||||
src: []wasmvmtypes.Coin{
|
||||
{Denom: "foo", Amount: "1"},
|
||||
{Denom: "foo", Amount: "1"},
|
||||
},
|
||||
exp: []sdk.Coin{sdk.NewCoin("foo", sdk.NewInt(2))},
|
||||
},
|
||||
"duplicate denoms with one 0 amount does not fail": {
|
||||
src: []wasmvmtypes.Coin{
|
||||
{Denom: "foo", Amount: "0"},
|
||||
{Denom: "foo", Amount: "1"},
|
||||
},
|
||||
exp: []sdk.Coin{sdk.NewCoin("foo", sdk.NewInt(1))},
|
||||
},
|
||||
"empty denom rejected": {
|
||||
src: []wasmvmtypes.Coin{{Denom: "", Amount: "1"}},
|
||||
expErr: true,
|
||||
},
|
||||
"invalid denom rejected": {
|
||||
src: []wasmvmtypes.Coin{{Denom: "!%&", Amount: "1"}},
|
||||
expErr: true,
|
||||
},
|
||||
}
|
||||
for name, spec := range specs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
gotCoins, gotErr := ConvertWasmCoinsToSdkCoins(spec.src)
|
||||
if spec.expErr {
|
||||
require.Error(t, gotErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, gotErr)
|
||||
assert.Equal(t, spec.exp, gotCoins)
|
||||
assert.NoError(t, gotCoins.Validate())
|
||||
})
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user