diff --git a/.gitattributes b/.gitattributes index f97533361f..ec32a6f30a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ tortoise/data/*.json filter=lfs diff=lfs merge=lfs -text vm/templates/wallet/wallet.bin filter=lfs diff=lfs merge=lfs -text +vm/templates/multisig/elf/multisig filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d22b97bdc5..596b5ff4f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,8 +88,31 @@ jobs: make test-fmt make test-tidy make test-generate - - name: Check for vulnerabilities - run: make vulncheck + + # The contracts are written in Rust and require a + # specific toolchain to build for Athena (Risc-V). + test-contracts: + runs-on: ubuntu-22.04 + needs: filter-changes + if: ${{ needs.filter-changes.outputs.nondocchanges == 'true' }} + timeout-minutes: 10 + env: + ATHENA_DIR: "${{ github.workspace }}/.athena" + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Setup Rust toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: Install Athena CLI & toolchain + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # for authorization to have higher rate-limit. + run: | + cargo install athena-cli --git https://github.com/athenavm/athena --tag v0.6.2 + cargo athena install-toolchain + - name: test contracts + run: cargo t --manifest-path vm/templates/multisig/Cargo.toml lint: runs-on: ubuntu-22.04 @@ -309,6 +332,7 @@ jobs: - lint - build - unittests + - test-contracts runs-on: ubuntu-22.04 env: # short-circuit success if no non-doc files were modified diff --git a/.gitignore b/.gitignore index 39dd2382c9..476d8c080d 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ database/data vendor/* systest/vendor/* .run/* + +target diff --git a/Makefile b/Makefile index c10e0dbd8d..4b7fa805d0 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) GOLANGCI_LINT_VERSION := v1.61.0 GOTESTSUM_VERSION := v1.12.0 -GOVULNCHECK_VERSION := v1.1.3 GOSCALE_VERSION := v1.2.0 MOCKGEN_VERSION := v0.5.0 @@ -69,7 +68,6 @@ install: go install github.com/spacemeshos/go-scale/scalegen@$(GOSCALE_VERSION) go install go.uber.org/mock/mockgen@$(MOCKGEN_VERSION) go install gotest.tools/gotestsum@$(GOTESTSUM_VERSION) - go install golang.org/x/vuln/cmd/govulncheck@$(GOVULNCHECK_VERSION) .PHONY: install build: go-spacemesh get-profiler get-postrs-service @@ -148,10 +146,6 @@ cover: get-libs @$(ULIMIT) ATHENA_LIB_PATH="$(ATHENA_LIB_PATH)" CGO_LDFLAGS="$(CGO_TEST_LDFLAGS)" gotestsum --junitfile junit.xml -- -coverprofile=cover.out -p 1 -timeout 30m -coverpkg=./... $(UNIT_TESTS) .PHONY: cover -vulncheck: get-libs - govulncheck ./... -.PHONY: vulncheck - list-versions: @echo "Latest 5 tagged versions:\n" @git for-each-ref --sort=-creatordate --count=5 --format '%(creatordate:short): %(refname:short)' refs/tags diff --git a/Makefile-libs.Inc b/Makefile-libs.Inc index 9f4763a513..81be8c0e56 100644 --- a/Makefile-libs.Inc +++ b/Makefile-libs.Inc @@ -56,8 +56,8 @@ POSTRS_PROFILER_URL ?= https://github.com/spacemeshos/post-rs/releases/download/ POSTRS_SERVICE_ZIP = post-service-$(platform)-v$(POSTRS_SETUP_REV).zip POSTRS_SERVICE_URL ?= https://github.com/spacemeshos/post-rs/releases/download/v$(POSTRS_SETUP_REV)/$(POSTRS_SERVICE_ZIP) -ATHENA_SETUP_REV = v0.6.1 -ATHENA_SETUP_RELEASE = v0.6.1 +ATHENA_SETUP_REV = v0.6.2 +ATHENA_SETUP_RELEASE = v0.6.2 ATHENA_SETUP_ARTIFACT = athena_vmlib_$(ATHENA_SETUP_REV)_$(GOOS)_$(GOARCH).tar.gz ATHENA_SETUP_ARTIFACT_URL ?= https://github.com/athenavm/athena/releases/download/$(ATHENA_SETUP_RELEASE)/$(ATHENA_SETUP_ARTIFACT) @@ -121,7 +121,7 @@ $(BINDIR_ATHENA_SETUP_LIBS): $(BIN_DIR).athena.version.$(ATHENA_SETUP_REV) ATHENA_LIB_RENAMED := libathenavmwrapper$(suffix $(ATHENA_LIB)) ATHENA_LIB_PATH := $(BIN_DIR)$(ATHENA_LIB_RENAMED) $(ATHENA_LIB_PATH): $(BIN_DIR)$(ATHENA_LIB) - mv $(BIN_DIR)$(ATHENA_LIB) $@ + cp $(BIN_DIR)$(ATHENA_LIB) $@ $(PROJ_DIR)$(POSTRS_SETUP_ZIP): curl -sSL $(CURL_OPTIONS) $(POSTRS_SETUP_URL_ZIP) -o $(PROJ_DIR)$(POSTRS_SETUP_ZIP) diff --git a/go.mod b/go.mod index f14396c1ae..1a7cd15781 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/spacemeshos/go-spacemesh -go 1.23.2 +go 1.23.4 require ( cloud.google.com/go/storage v1.47.0 github.com/ALTree/bigfloat v0.2.0 github.com/ChainSafe/gossamer v0.9.0 - github.com/athenavm/athena/ffi/athcon/bindings/go v0.6.1 - github.com/chaos-mesh/chaos-mesh/api v0.0.0-20241021021428-64a7a81821a0 + github.com/athenavm/athena/ffi/athcon/bindings/go v0.6.2 + github.com/chaos-mesh/chaos-mesh/api v0.0.0-20241204110417-3c631bce206f github.com/cosmos/btcutil v1.0.5 github.com/go-llsqlite/crawshaw v0.5.5 github.com/gofrs/flock v0.12.1 @@ -59,10 +59,10 @@ require ( github.com/zeebo/blake3 v0.2.4 go.uber.org/mock v0.5.0 go.uber.org/zap v1.27.0 - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f - golang.org/x/sync v0.9.0 + golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d + golang.org/x/sync v0.10.0 golang.org/x/time v0.8.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 + google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a google.golang.org/grpc v1.68.1 google.golang.org/protobuf v1.35.2 k8s.io/api v0.31.3 @@ -239,14 +239,14 @@ require ( go.uber.org/dig v1.18.0 // indirect go.uber.org/fx v1.23.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.29.0 // indirect + golang.org/x/crypto v0.30.0 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.31.0 // indirect + golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.27.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/tools v0.28.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect gonum.org/v1/gonum v0.15.0 // indirect google.golang.org/api v0.203.0 // indirect diff --git a/go.sum b/go.sum index f95e00c8ac..0cf0ac97b2 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,8 @@ github.com/anacrolix/sync v0.3.0 h1:ZPjTrkqQWEfnYVGTQHh5qNjokWaXnjsyXTJSMsKY0TA= github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/athenavm/athena/ffi/athcon/bindings/go v0.6.1 h1:APmcx/Qiejq2CHA/X0vkCiPO/RvdcjJ+iDNfqLQlJw8= -github.com/athenavm/athena/ffi/athcon/bindings/go v0.6.1/go.mod h1:dgoxFG6b5kBESS03ZC4WSi3vzLcmTTchqwPOVFYiFTc= +github.com/athenavm/athena/ffi/athcon/bindings/go v0.6.2 h1:tpHsZsmcjJNdaKx+0lXgcOSdfwHva1/BfPy3CVpK8Cw= +github.com/athenavm/athena/ffi/athcon/bindings/go v0.6.2/go.mod h1:dgoxFG6b5kBESS03ZC4WSi3vzLcmTTchqwPOVFYiFTc= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -82,8 +82,8 @@ github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMr github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chaos-mesh/chaos-mesh/api v0.0.0-20241021021428-64a7a81821a0 h1:FUdG3FIIawOSaSWgl3cnisayGJyI3lKhC5ptbluffRM= -github.com/chaos-mesh/chaos-mesh/api v0.0.0-20241021021428-64a7a81821a0/go.mod h1:x11iCbZV6hzzSQWMq610B6Wl5Lg1dhwqcVfeiWQQnQQ= +github.com/chaos-mesh/chaos-mesh/api v0.0.0-20241204110417-3c631bce206f h1:N6vSz68L9EguQPpPNcbRRb8JkEuhE3T4OckRxgM49xE= +github.com/chaos-mesh/chaos-mesh/api v0.0.0-20241204110417-3c631bce206f/go.mod h1:x11iCbZV6hzzSQWMq610B6Wl5Lg1dhwqcVfeiWQQnQQ= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -778,11 +778,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0= +golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -823,8 +823,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -842,8 +842,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -877,8 +877,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -886,8 +886,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= 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= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -897,8 +897,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 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.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= @@ -923,8 +923,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= -golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -954,8 +954,8 @@ google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+Ji google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= diff --git a/vm/core/gas.go b/vm/core/gas.go index 7c363289f8..f34495b5d3 100644 --- a/vm/core/gas.go +++ b/vm/core/gas.go @@ -17,11 +17,7 @@ const ( // Hardcoded Athena gas costs // TODO(lane): remove hardcoded gas costs. - ATHENA_MAX_GAS = 20_000 - ATHENA_GAS_SPAWN = 4472 - ATHENA_GAS_DEPLOY = 10000 - ATHENA_GAS_SPEND = 6184 - ATHENA_GAS_VERIFY = 9820 + ATHENA_GAS_VERIFY = 12_000 ) const ( @@ -47,5 +43,5 @@ func TxDataGas(size int) uint64 { } func MaxGas(inputSize int) uint64 { - return ATHENA_MAX_GAS + uint64(inputSize)*100 + return 10_000 + uint64(inputSize)*150 } diff --git a/vm/rewards_test.go b/vm/rewards_test.go index 12d8ea4dd9..1e8a10623b 100644 --- a/vm/rewards_test.go +++ b/vm/rewards_test.go @@ -16,7 +16,7 @@ func TestRewards(t *testing.T) { applyGenesis() } ref := genTester(t) - spawnFee := ref.estimateSpawnGas(0, 0) + spawnFee := ref.estimateSpawnGas(0) // this is hardcoded so that you can see which number is divided without reminder // and pick correct fractions for tests expected := []int{ diff --git a/vm/sdk/multisig/address.go b/vm/sdk/multisig/address.go new file mode 100644 index 0000000000..2d3b3efb63 --- /dev/null +++ b/vm/sdk/multisig/address.go @@ -0,0 +1,16 @@ +package multisig + +import ( + "github.com/spacemeshos/go-spacemesh/common/types" + "github.com/spacemeshos/go-spacemesh/vm/core" +) + +// Address computes wallet address from spawn arguments. +func Address(template types.Address, required uint8, pubkeys []core.PublicKey) types.Address { + if len(pubkeys) < int(required) { + panic("cannot require more than available public keys") + } + + args := EncodeSpawnArgs(required, pubkeys) + return core.ComputePrincipalFromBlob(template, args) +} diff --git a/vm/sdk/multisig/tx.go b/vm/sdk/multisig/tx.go new file mode 100644 index 0000000000..a20eebe2e1 --- /dev/null +++ b/vm/sdk/multisig/tx.go @@ -0,0 +1,146 @@ +package multisig + +import ( + "bytes" + "maps" + "slices" + + // FIXME: use go-scale when we add a tag to encode uint8 non-compact. + "github.com/ChainSafe/gossamer/pkg/scale" + athcon "github.com/athenavm/athena/ffi/athcon/bindings/go" + + "github.com/spacemeshos/go-spacemesh/codec" + "github.com/spacemeshos/go-spacemesh/common/types" + "github.com/spacemeshos/go-spacemesh/vm/core" + "github.com/spacemeshos/go-spacemesh/vm/sdk" +) + +// SpawnArguments contains a collection with PublicKeys. +type SpawnArguments struct { + Required uint8 + PublicKeys []core.PublicKey +} + +type SpendArguments struct { + To types.Address + Amount uint64 +} + +// part contains a reference to public key and signature from private key counterpart. +type part struct { + Ref uint8 + Sig core.Signature +} + +func NewSignatureAggregator(unsigned []byte) *SignatureAggregator { + return &SignatureAggregator{unsigned: unsigned, parts: map[uint8]part{}} +} + +// SignatureAggregator is a signature accumulator. +type SignatureAggregator struct { + unsigned []byte + parts map[uint8]part +} + +// Add signature and reference to the public key counterpart. +func (a *SignatureAggregator) Add(ref uint8, sig core.Signature) { + if _, exists := a.parts[ref]; exists { + panic("signature already exists") + } + a.parts[ref] = part{ + Ref: ref, + Sig: sig, + } +} + +// Raw returns full raw transaction including payload and signatures. +func (a *SignatureAggregator) Raw() []byte { + var buf bytes.Buffer + enc := scale.NewEncoder(&buf) + keys := slices.Sorted(maps.Keys(a.parts)) + for _, ref := range keys { + if err := enc.Encode(a.parts[ref]); err != nil { + panic(err) + } + } + rawTxBuf := bytes.NewBuffer(a.unsigned) + enc = scale.NewEncoder(rawTxBuf) + if err := enc.Encode(buf.Bytes()); err != nil { + panic(err) + } + return rawTxBuf.Bytes() +} + +func EncodeSpawnArgs(required uint8, pubkeys []core.PublicKey) []byte { + args := SpawnArguments{ + Required: required, + PublicKeys: pubkeys, + } + return scale.MustMarshal(args) +} + +func EncodeSpendArgs(to types.Address, amount uint64) []byte { + args := SpendArguments{ + To: to, + Amount: amount, + } + return scale.MustMarshal(args) +} + +// Spawn creates a raw SPAWN transaction, which needs to be signed by the required +// number of signers. +func Spawn( + template types.Address, + required uint8, + pubkeys []core.PublicKey, + nonce core.Nonce, + opts ...sdk.Opt, +) ([]byte, error) { + options := sdk.Defaults() + for _, opt := range opts { + opt(options) + } + encodedArgs := EncodeSpawnArgs(required, pubkeys) + selector, _ := athcon.FromString("athexp_spawn") + payload := athcon.Payload{ + Selector: &selector, + Input: encodedArgs, + } + tx := core.Tx{ + Version: 1, + Principal: core.ComputePrincipalFromBlob(template, encodedArgs), + Template: &template, + Metadata: core.Metadata{ + Nonce: nonce, + GasPrice: options.GasPrice, + }, + Payload: scale.MustMarshal(payload), + } + return codec.Encode(&tx) +} + +// Spend creates a raw SPEND transaction, which needs to be signed by the required +// number of signers. +func Spend(principal, to types.Address, amount uint64, nonce types.Nonce, opts ...sdk.Opt) ([]byte, error) { + options := sdk.Defaults() + for _, opt := range opts { + opt(options) + } + + selector, _ := athcon.FromString("athexp_spend") + payload := athcon.Payload{ + Selector: &selector, + Input: EncodeSpendArgs(to, amount), + } + + tx := core.Tx{ + Version: uint8(sdk.TxVersion), + Principal: principal, + Metadata: core.Metadata{ + Nonce: nonce, + GasPrice: options.GasPrice, + }, + Payload: scale.MustMarshal(payload), + } + return codec.Encode(&tx) +} diff --git a/vm/sdk/wallet/tx.go b/vm/sdk/wallet/tx.go index e13146f965..94d710faa1 100644 --- a/vm/sdk/wallet/tx.go +++ b/vm/sdk/wallet/tx.go @@ -21,7 +21,6 @@ func Deploy(pk signing.PrivateKey, nonce core.Nonce, blob []byte, opts ...sdk.Op for _, opt := range opts { opt(options) } - principal := Address(signing.Public(pk)) var blobEncoded bytes.Buffer if _, err := codec.EncodeByteSlice(&blobEncoded, blob); err != nil { return nil, fmt.Errorf("encoding code blob: %w", err) @@ -35,9 +34,14 @@ func Deploy(pk signing.PrivateKey, nonce core.Nonce, blob []byte, opts ...sdk.Op if err != nil { return nil, fmt.Errorf("encoding tx payload: %w", err) } + + template := options.Template + if template == nil { + template = &wallet.TemplateAddress + } tx := core.Tx{ Version: uint8(sdk.TxVersion), - Principal: principal, + Principal: core.ComputePrincipalFromBlob(*template, signing.Public(pk)), Metadata: core.Metadata{ Nonce: nonce, GasPrice: options.GasPrice, @@ -105,9 +109,14 @@ func Spend(pk signing.PrivateKey, to types.Address, amount uint64, nonce types.N } defer vmlib.Close() + template := options.Template + if template == nil { + template = &wallet.TemplateAddress + } + tx := core.Tx{ Version: uint8(sdk.TxVersion), - Principal: Address(signing.Public(pk)), + Principal: core.ComputePrincipalFromBlob(*template, signing.Public(pk)), Metadata: core.Metadata{ Nonce: nonce, GasPrice: options.GasPrice, diff --git a/vm/templates/multisig/Cargo.lock b/vm/templates/multisig/Cargo.lock new file mode 100644 index 0000000000..270368afbe --- /dev/null +++ b/vm/templates/multisig/Cargo.lock @@ -0,0 +1,1990 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "athena-builder" +version = "0.6.1" +source = "git+https://github.com/athenavm/athena?tag=v0.6.1#a7212092b944477e1132d365b456c96f53e3f750" +dependencies = [ + "anyhow", + "cargo_metadata", + "clap", +] + +[[package]] +name = "athena-builder" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "anyhow", + "cargo_metadata", + "clap", +] + +[[package]] +name = "athena-core" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "athena-helper 0.6.2", + "athena-interface", + "bincode", + "ed25519-dalek", + "elf", + "gdbstub", + "hex", + "mockall", + "nohash-hasher", + "rrs-lib", + "serde", + "strum", + "strum_macros", + "thiserror", + "tracing", +] + +[[package]] +name = "athena-helper" +version = "0.6.1" +source = "git+https://github.com/athenavm/athena?tag=v0.6.1#a7212092b944477e1132d365b456c96f53e3f750" +dependencies = [ + "athena-builder 0.6.1", + "cargo_metadata", +] + +[[package]] +name = "athena-helper" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "athena-builder 0.6.2", + "cargo_metadata", +] + +[[package]] +name = "athena-interface" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "blake3", + "bytemuck", + "hex", + "mockall", + "parity-scale-codec", + "serde", + "tracing", +] + +[[package]] +name = "athena-runner" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "athena-core", + "athena-helper 0.6.2", + "athena-interface", + "athena-sdk", + "bincode", + "hex", + "tracing", +] + +[[package]] +name = "athena-sdk" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "anyhow", + "athena-core", + "athena-interface", + "vergen-git2", +] + +[[package]] +name = "athena-vm" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "athena-interface", + "bincode", + "bytemuck", + "cfg-if", + "getrandom", + "parity-scale-codec", + "rand", + "serde", +] + +[[package]] +name = "athena-vm-declare" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "quote", + "syn 2.0.90", +] + +[[package]] +name = "athena-vm-sdk" +version = "0.6.2" +source = "git+https://github.com/athenavm/athena?tag=v0.6.2#c99a7e39983aef7a5bfd06d56707d4424e549cbc" +dependencies = [ + "athena-interface", + "athena-vm", + "cfg-if", + "parity-scale-codec", + "serde", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytemuck" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.90", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.90", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "gdbstub" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c683a9f13de31432e6097131d5f385898c7f0635c0f392b9d0fa165063c8ac" +dependencies = [ + "bitflags", + "cfg-if", + "log", + "managed", + "num-traits", + "paste", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "git2" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.167" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" + +[[package]] +name = "libgit2-sys" +version = "0.17.0+1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mockall" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "multisig" +version = "0.1.0" +dependencies = [ + "athena-helper 0.6.1", + "athena-interface", + "athena-runner", + "athena-sdk", + "athena-vm", + "athena-vm-declare", + "athena-vm-sdk", + "ed25519-dalek", + "multisig", + "parity-scale-codec", + "rand", + "tracing-subscriber", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" + +[[package]] +name = "predicates-tree" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rrs-lib" +version = "0.1.0" +source = "git+https://github.com/GregAC/rrs.git#b23afc16b4e6a1fb5c4a73eb1e337e9400816507" +dependencies = [ + "downcast-rs", + "num_enum", + "paste", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.90", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.6.20", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vergen" +version = "9.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f25fc8f8f05df455c7941e87f093ad22522a9ff33d7a027774815acf6f0639" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", + "time", + "vergen-lib", +] + +[[package]] +name = "vergen-git2" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e63e069d8749fead1e3bab7a9d79e8fb90516b2ec66fc2243a798ecdc1a31d7" +dependencies = [ + "anyhow", + "derive_builder", + "git2", + "rustversion", + "time", + "vergen", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0c767e6751c09fc85cde58722cf2f1007e80e4c8d5a4321fc90d83dc54ca147" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] diff --git a/vm/templates/multisig/Cargo.toml b/vm/templates/multisig/Cargo.toml new file mode 100644 index 0000000000..9229569ddb --- /dev/null +++ b/vm/templates/multisig/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "multisig" +version = "0.1.0" +edition = "2021" + +[dependencies] +parity-scale-codec = { version = "3.6.12", features = ["derive"] } +athena-interface = { git = "https://github.com/athenavm/athena", tag = "v0.6.2" } +athena-vm = { git = "https://github.com/athenavm/athena", tag = "v0.6.2" } +athena-vm-declare = { git = "https://github.com/athenavm/athena", tag = "v0.6.2" } +athena-vm-sdk = { git = "https://github.com/athenavm/athena", tag = "v0.6.2" } + +[dev-dependencies] +multisig = { path = ".", features = ["unittest"] } +athena-sdk = { git = "https://github.com/athenavm/athena", tag = "v0.6.2" } +athena-runner = { git = "https://github.com/athenavm/athena", tag = "v0.6.2" } +ed25519-dalek = { version = "2.1.1", features = ["rand_core"] } +rand = "0.8.5" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } + +[build-dependencies] +athena-helper = { git = "https://github.com/athenavm/athena", tag = "v0.6.1" } + +[features] +unittest = [] diff --git a/vm/templates/multisig/build.rs b/vm/templates/multisig/build.rs new file mode 100644 index 0000000000..312fa75e73 --- /dev/null +++ b/vm/templates/multisig/build.rs @@ -0,0 +1,10 @@ +#[cfg(feature = "unittest")] +fn build_programs_for_tests() { + use athena_helper::build_program; + build_program("."); +} + +fn main() { + #[cfg(feature = "unittest")] + build_programs_for_tests() +} diff --git a/vm/templates/multisig/elf/multisig b/vm/templates/multisig/elf/multisig new file mode 100755 index 0000000000..88cfc4e122 --- /dev/null +++ b/vm/templates/multisig/elf/multisig @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e26436b4649990ec584a2922ecbea6ebcbe5adb4ef7935b2ed6000fa8a0ddb0 +size 154300 diff --git a/vm/templates/multisig/program.go b/vm/templates/multisig/program.go new file mode 100644 index 0000000000..96538c013c --- /dev/null +++ b/vm/templates/multisig/program.go @@ -0,0 +1,6 @@ +package multisig + +import _ "embed" + +//go:embed elf/multisig +var PROGRAM []byte diff --git a/vm/templates/multisig/src/contract.rs b/vm/templates/multisig/src/contract.rs new file mode 100644 index 0000000000..61943b211a --- /dev/null +++ b/vm/templates/multisig/src/contract.rs @@ -0,0 +1,86 @@ +//! The Spacemesh standard multi-signature wallet template. +extern crate alloc; + +use athena_interface::Address; +use athena_vm_declare::{callable, template}; +use athena_vm_sdk::wallet::SpendArguments; +use athena_vm_sdk::{call, spawn, Pubkey}; +use parity_scale_codec::{Decode, Encode, IoReader}; + +#[derive(Encode, Decode)] +struct Contract { + required: u8, + keys: alloc::vec::Vec, +} + +#[derive(Decode)] +struct SpawnArguments { + required: u8, + keys: alloc::vec::Vec, +} + +#[derive(Encode, Decode)] +struct Signature { + id: u8, + sig: [u8; 64], +} + +#[template] +impl Contract { + #[callable] + fn spawn(args: SpawnArguments) -> Address { + let wallet = Contract { + required: args.required, + keys: args.keys, + }; + let serialized = wallet.encode(); + spawn(&serialized) + } + + #[callable] + fn spend(&self, args: SpendArguments) { + call(args.recipient, None, None, args.amount); + } + + #[callable] + fn deploy(&self, code: alloc::vec::Vec) -> Address { + athena_vm_sdk::deploy(&code) + } + + #[callable] + fn max_spend(&self, args: SpendArguments) -> u64 { + args.amount + } + + #[callable] + fn verify() -> bool { + let mut io = IoReader(athena_vm::io::Io::default()); + let state = Contract::decode(&mut io).unwrap(); + let tx = alloc::vec::Vec::::decode(&mut io).unwrap(); + + let mut last_id = None; + for _ in 0..state.required { + let sig = if let Ok(s) = Signature::decode(&mut io) { + s + } else { + return false; + }; + + if state.keys.len() < sig.id as usize { + return false; + } + if let Some(last) = last_id { + if sig.id <= last { + return false; + } + } + last_id = Some(sig.id); + let pubkey = &state.keys[sig.id as usize]; + + if !athena_vm_sdk::precompiles::ed25519::verify(&tx, &pubkey.0, &sig.sig) { + return false; + } + } + return true; + } +} diff --git a/vm/templates/multisig/src/main.rs b/vm/templates/multisig/src/main.rs new file mode 100644 index 0000000000..04f604bb00 --- /dev/null +++ b/vm/templates/multisig/src/main.rs @@ -0,0 +1,12 @@ +#![cfg_attr(target_os = "zkvm", no_main)] + +#[cfg(target_os = "zkvm")] +mod contract; + +#[cfg(target_os = "zkvm")] +use athena_vm::entrypoint; +#[cfg(target_os = "zkvm")] +athena_vm::entrypoint!(); + +#[cfg(not(target_os = "zkvm"))] +pub fn main() {} diff --git a/vm/templates/multisig/tests/test.rs b/vm/templates/multisig/tests/test.rs new file mode 100644 index 0000000000..4694bafdec --- /dev/null +++ b/vm/templates/multisig/tests/test.rs @@ -0,0 +1,154 @@ +use std::error::Error; + +use athena_interface::{Address, MethodSelector}; +use athena_sdk::{AthenaStdin, ExecutionClient}; +use athena_vm_sdk::Pubkey; +use parity_scale_codec::Encode; + +use ed25519_dalek::ed25519::signature::Signer; +use rand::rngs::OsRng; + +pub const PROGRAM: &[u8] = include_bytes!("../elf/multisig"); +pub const ADDRESS_ALICE: [u8; 24] = [1u8; 24]; + +#[derive(Encode)] +struct SpawnArguments { + required: u8, + keys: Vec, +} + +#[derive(Clone)] +struct SigningKey { + id: u8, + key: ed25519_dalek::SigningKey, +} + +fn spawn(required: u8, keys: Vec) -> Result<(Address, Vec), Box> { + let mut stdin = AthenaStdin::new(); + let (state_w, state_r) = std::sync::mpsc::channel(); + let mut host = athena_interface::MockHostInterface::new(); + host.expect_spawn().returning_st(move |s| { + state_w.send(s).unwrap(); + Address::from(ADDRESS_ALICE) + }); + + let args = SpawnArguments { required, keys }; + stdin.write_vec(args.encode()); + + let method_selector = MethodSelector::from("athexp_spawn"); + + let client = ExecutionClient::new(); + let (mut result, _) = client.execute_function( + PROGRAM, + &method_selector, + stdin, + Some(&mut host), + None, + None, + )?; + + let state = state_r.recv().unwrap(); + Ok((result.read(), state)) +} + +fn verify(state: Vec, keys: &[SigningKey]) -> bool { + let tx = b"some really bad tx"; + + let mut stdin = AthenaStdin::new(); + stdin.write_vec(state); + stdin.write_vec(tx.as_slice().encode()); + + for key in keys.iter() { + let signature = key.key.sign(tx); + stdin.write_vec(key.id.encode()); + stdin.write_vec(signature.to_bytes().encode()); + } + + let result = ExecutionClient::new().execute_function( + PROGRAM, + &MethodSelector::from("athexp_verify"), + stdin, + None, + Some(100000), + None, + ); + let (mut result, _) = result.unwrap(); + result.read::() +} + +fn create_keys(count: u8) -> (Vec, Vec) { + let keys: Vec<_> = (0..count) + .map(|id| SigningKey { + id, + key: ed25519_dalek::SigningKey::generate(&mut OsRng), + }) + .collect(); + let pubkeys = keys + .iter() + .map(|k| Pubkey(k.key.verifying_key().to_bytes())) + .collect(); + + (keys, pubkeys) +} + +fn setup_logger() { + let _ = tracing_subscriber::fmt() + .with_test_writer() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .try_init(); +} + +#[test] +fn spawning() { + setup_logger(); + let signing_key = ed25519_dalek::SigningKey::generate(&mut OsRng); + + let (address, state) = spawn(1, vec![Pubkey(signing_key.verifying_key().to_bytes())]).unwrap(); + + assert_eq!(Address::from(ADDRESS_ALICE), address); + assert!(!state.is_empty()); +} + +#[test] +fn verify_with_all_keys() { + setup_logger(); + let (keys, pubkeys) = create_keys(5); + let (_, state) = spawn(keys.len() as u8, pubkeys).unwrap(); + + let valid = verify(state, &keys); + assert!(valid); +} + +#[test] +fn verify_with_required_keys() { + setup_logger(); + let (keys, pubkeys) = create_keys(5); + let (_, state) = spawn(2, pubkeys).unwrap(); + + let valid = verify(state.clone(), &[keys[0].clone(), keys[2].clone()]); + assert!(valid); + + // signatures must be ordered by ID + let valid = verify(state, &[keys[2].clone(), keys[0].clone()]); + assert!(!valid); +} + +#[test] +fn verify_fails_when_insufficient_keys() { + setup_logger(); + let (keys, pubkeys) = create_keys(5); + let (_, state) = spawn(5, pubkeys).unwrap(); + + let valid = verify(state, &keys[..4]); + assert!(!valid); +} + +#[test] +fn verify_must_be_signed_with_different_keys() { + setup_logger(); + let (keys, pubkeys) = create_keys(5); + let (_, state) = spawn(2, pubkeys).unwrap(); + + let valid = verify(state, &[keys[0].clone(), keys[0].clone()]); + assert!(!valid); +} diff --git a/vm/templates/wallet/wallet.bin b/vm/templates/wallet/wallet.bin index bf2c9f977d..b0366cf71e 100755 --- a/vm/templates/wallet/wallet.bin +++ b/vm/templates/wallet/wallet.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8daf2bd314b9bb263139c4e9d8e9e22f28ddfef8771cd1b4e2792ff32a6254c4 -size 147924 +oid sha256:ccb6f4503d4a5af90db28578a8f91b0768260e526c22a1712d8cdc2b634120ac +size 143472 diff --git a/vm/vm.go b/vm/vm.go index 860e10ce1b..74dc5a84b9 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -330,7 +330,7 @@ func (v *VM) execute( continue } balance := ctx.Balance() - intrinsic := core.IntrinsicGas(ctx.PrincipalTemplate.BaseGas(), len(tx.GetRaw().Raw)) + intrinsic := core.IntrinsicGas(ctx.PrincipalTemplate.BaseGas(), 0) // we don't charge for TX storage yet logger.Info("intrinsic gas check", zap.Uint64("balance", balance), zap.Uint64("intrinsic gas", intrinsic)) if balance < intrinsic { logger.Warn("ineffective transaction. intrinsic gas not covered", @@ -563,10 +563,12 @@ func parse( // is passed not explicitly as part of the tx, but implicitly in the args. This simplifies the // logic here considerably. + var estimatedStateSize int if ctx.PrincipalAccount.TemplateAddress == nil { if tx.Template == nil { return nil, nil, core.ErrNotSpawned } + estimatedStateSize = max(len(tx.Payload), 6) - 6 ctx.SpawnTx = true ctx.Header.TemplateAddress = *tx.Template // in case of a self-spawn, we need to check that the calculated principal matches. @@ -587,6 +589,7 @@ func parse( if tx.Template != nil { return nil, nil, fmt.Errorf("%w: principal account already spawned", core.ErrMalformed) } + estimatedStateSize = len(ctx.PrincipalAccount.State) ctx.Header.TemplateAddress = *ctx.PrincipalAccount.TemplateAddress } @@ -610,7 +613,14 @@ func parse( } // FIXME: How to obtain a max gas? Should it be returned from Verify()? - ctx.Header.MaxGas = core.MaxGas(max(len(tx.Payload), 6) - 6) // skip bytes for method selector + logger.Debug( + "calculating max gas", + zap.Int("payload len", len(tx.Payload)), + zap.Int("witness data len", len(witnessData)), + ) + ctx.Header.MaxGas = core.MaxGas( + estimatedStateSize + max(len(tx.Payload), 6) - 6 + len(witnessData), + ) // skip bytes for method selector ctx.Header.Principal = tx.Principal ctx.Header.GasPrice = tx.Metadata.GasPrice ctx.Header.Nonce = tx.Metadata.Nonce diff --git a/vm/vm_test.go b/vm/vm_test.go index d1ae332259..c100b99d70 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -1,6 +1,7 @@ package vm import ( + "bytes" "math" "math/big" "math/rand" @@ -20,12 +21,15 @@ import ( "github.com/spacemeshos/go-spacemesh/codec" "github.com/spacemeshos/go-spacemesh/common/types" "github.com/spacemeshos/go-spacemesh/hash" + "github.com/spacemeshos/go-spacemesh/signing" "github.com/spacemeshos/go-spacemesh/sql/accounts" "github.com/spacemeshos/go-spacemesh/sql/layers" "github.com/spacemeshos/go-spacemesh/sql/statesql" "github.com/spacemeshos/go-spacemesh/vm/core" "github.com/spacemeshos/go-spacemesh/vm/sdk" + sdkmultisig "github.com/spacemeshos/go-spacemesh/vm/sdk/multisig" sdkwallet "github.com/spacemeshos/go-spacemesh/vm/sdk/wallet" + "github.com/spacemeshos/go-spacemesh/vm/templates/multisig" "github.com/spacemeshos/go-spacemesh/vm/templates/wallet" ) @@ -48,8 +52,11 @@ type testAccount interface { spawn(t *tester, nonce core.Nonce, opts ...sdk.Opt) []byte deploy(t *tester, nonce core.Nonce, blob []byte, opts ...sdk.Opt) []byte - baseGas() int - loadGas() int + selfSpawnGas() int + spendGas() int + + selfSpawnMaxGas() int + spendMaxGas() int } type singlesigAccount struct { @@ -89,12 +96,133 @@ func (a *singlesigAccount) spawn( return addr } -func (a *singlesigAccount) baseGas() int { - return int(wallet.BaseGas()) +func (a *singlesigAccount) spendGas() int { + return 6276 + 9200 +} + +func (a *singlesigAccount) selfSpawnGas() int { + return 3488 + 9200 } -func (a *singlesigAccount) loadGas() int { - return int(wallet.LoadGas()) +func (a *singlesigAccount) spendMaxGas() int { + return int(core.MaxGas(32 + 32 + 64)) +} + +func (a *singlesigAccount) selfSpawnMaxGas() int { + return int(core.MaxGas(32 + 32 + 64)) +} + +type multisigAccount struct { + required uint8 + pks []ed25519.PrivateKey + address core.Address + template core.Address +} + +func (a *multisigAccount) getAddress() core.Address { + return a.address +} + +func (a *multisigAccount) spend(t *tester, to core.Address, amount uint64, nonce core.Nonce, opts ...sdk.Opt) []byte { + tx, err := sdkmultisig.Spend(a.address, to, amount, nonce, opts...) + require.NoError(t, err) + + agg := sdkmultisig.NewSignatureAggregator(tx) + for i := range a.required { + pk := a.pks[i] + sig := core.SignRawTx(tx, t.cfg.GenesisID, pk) + agg.Add(uint8(i), core.Signature(sig)) + } + return agg.Raw() +} + +func (a *multisigAccount) spawn( + t *tester, + nonce core.Nonce, + opts ...sdk.Opt, +) []byte { + panic("not implemented") +} + +func (a *multisigAccount) selfSpawn(t *tester, nonce core.Nonce, opts ...sdk.Opt) []byte { + var pubs []core.PublicKey + for _, pk := range a.pks { + pubs = append(pubs, [32]byte(signing.Public(signing.PrivateKey(pk)))) + } + tx, err := sdkmultisig.Spawn(a.template, a.required, pubs, nonce, opts...) + require.NoError(t, err) + agg := sdkmultisig.NewSignatureAggregator(tx) + for i := range a.required { + pk := a.pks[i] + sig := core.SignRawTx(tx, t.cfg.GenesisID, pk) + agg.Add(uint8(i), core.Signature(sig)) + } + raw := agg.Raw() + return raw +} + +func (a *multisigAccount) deploy(t *tester, nonce core.Nonce, blob []byte, opts ...sdk.Opt) []byte { + panic("not implemented") +} + +// verify gas depends on the length of witness data, +// which depends on the number of required signatures. +func (a *multisigAccount) verifyGas() int { + switch a.required { + case 1: + return 17828 + case 2: + return 23832 + case 5: + return 49176 + } + panic("unknown") +} + +// spend + verify, both depend on: +// - arguments size (state and witness data sizes) +// - instructions executed (will change when code changes). +func (a *multisigAccount) spendGas() int { + switch len(a.pks) { + case 3: + return 13792 + a.verifyGas() + case 7: + return 24432 + a.verifyGas() + } + panic("unknown") +} + +// spawn + verify, both depend on: +// - arguments size (state and witness data sizes) +// - instructions executed (will change when code changes). +func (a *multisigAccount) selfSpawnGas() int { + switch len(a.pks) { + case 3: + return 12420 + a.verifyGas() + case 7: + return 25220 + a.verifyGas() + } + panic("unknown") +} + +func (a *multisigAccount) spendMaxGas() int { + pubs := make([]core.PublicKey, len(a.pks)) + state := sdkmultisig.EncodeSpawnArgs(a.required, pubs) + args := sdkmultisig.EncodeSpendArgs(types.Address{}, 0) + var buf bytes.Buffer + argsSize, _ := scale.EncodeByteSlice(scale.NewEncoder(&buf), args) + // total input is state + args + witness data + return int(core.MaxGas(len(state) + argsSize + int(a.required)*(64+1))) +} + +func (a *multisigAccount) selfSpawnMaxGas() int { + pubs := make([]core.PublicKey, len(a.pks)) + args := sdkmultisig.EncodeSpawnArgs(a.required, pubs) + stateSize := len(args) + var buf bytes.Buffer + argsSize, _ := scale.EncodeByteSlice(scale.NewEncoder(&buf), args) + // total input is state + args + witness data + return int(core.MaxGas(stateSize + argsSize + int(a.required)*(64+1))) } type testTemplate struct { @@ -134,11 +262,21 @@ func (t *tester) addAccount(account testAccount, balance uint64) { t.balances = append(t.balances, balance) } -func (t *tester) addWalletTemplate() *tester { - t.templates = append(t.templates, testTemplate{address: wallet.TemplateAddress, state: wallet.PROGRAM}) +func (t *tester) addTemplate(address types.Address, code []byte) *tester { + t.templates = append(t.templates, testTemplate{address: address, state: code}) return t } +func (t *tester) addWalletTemplate() *tester { + return t.addTemplate(wallet.TemplateAddress, wallet.PROGRAM) +} + +var multiSigWalletTemplateAddress = types.Address{2} + +func (t *tester) addMultiSigWalletTemplate() *tester { + return t.addTemplate(multiSigWalletTemplateAddress, multisig.PROGRAM) +} + func (t *tester) addSingleSig(n int) *tester { for i := 0; i < n; i++ { pub, pk, err := ed25519.GenerateKey(t.rng) @@ -149,6 +287,30 @@ func (t *tester) addSingleSig(n int) *tester { return t } +func (t *tester) createMultisig(required, total uint8, template core.Address) *multisigAccount { + var pks []ed25519.PrivateKey + var pubs []core.PublicKey + for range total { + pub, pk, err := ed25519.GenerateKey(t.rng) + require.NoError(t, err) + pks = append(pks, pk) + pubs = append(pubs, core.PublicKey(pub)) + } + return &multisigAccount{ + required: required, + pks: pks, + address: sdkmultisig.Address(template, required, pubs), + template: template, + } +} + +func (t *tester) addMultisig(template types.Address, total int, required, numKeys uint8) *tester { + for range total { + t.addAccount(t.createMultisig(required, numKeys, template), 1_000_000_000) + } + return t +} + func (t *tester) applyGenesis() *tester { return t.applyGenesisWithBalance() } @@ -250,25 +412,20 @@ func (t *tester) rewards(all ...reward) []types.CoinbaseReward { return rst } -func (t *tester) estimateSpawnGas(principal, target int) int { - // TODO(lane): improve gas arithmetic and gas estimation - return core.ATHENA_GAS_SPAWN + core.ATHENA_GAS_VERIFY - // tx := t.accounts[principal].spawn(t, 0) - // gas := t.accounts[principal].baseGas() + - // int(core.TxDataGas(len(tx))) - // if principal != target { - // gas += t.accounts[principal].loadGas() - // } - // return gas +func (t *tester) estimateSpendMaxGas(principal int) int { + return t.accounts[principal].spendMaxGas() +} + +func (t *tester) estimateSelfSpawnMaxGas(principal int) int { + return t.accounts[principal].selfSpawnMaxGas() +} + +func (t *tester) estimateSpawnGas(principal int) int { + return t.accounts[principal].selfSpawnGas() } -func (t *tester) estimateSpendGas(principal, to, amount int, nonce core.Nonce) int { - // TODO(lane): improve gas arithmetic and gas estimation - return core.ATHENA_GAS_SPEND + core.ATHENA_GAS_VERIFY - // tx := t.accounts[principal].spend(t, t.accounts[to].getAddress(), uint64(amount), nonce) - // return t.accounts[principal].baseGas() + - // t.accounts[principal].loadGas() + - // int(core.TxDataGas(len(tx))) +func (t *tester) estimateSpendGas(principal int) int { + return t.accounts[principal].spendGas() } func encodeTx(tb testing.TB, tx core.Tx) types.RawTx { @@ -467,12 +624,12 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test }, { txs: []testTx{ - &spendTx{0, 10, 100_000}, + &spendTx{0, 10, 500_000}, }, expected: map[int]change{ - 0: spent{amount: 100_000 + defaultGasPrice*ref.estimateSpendGas(0, 10, 100, 1)}, + 0: spent{amount: 500_000 + ref.estimateSpendGas(0)}, 1: same{}, - 10: earned{amount: 100_000}, + 10: earned{amount: 500_000}, }, }, { @@ -482,7 +639,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test expected: map[int]change{ 0: same{}, 1: same{}, - 10: spent{amount: ref.estimateSpawnGas(10, 10)}, + 10: spent{amount: ref.estimateSpawnGas(10)}, }, }, }, @@ -513,10 +670,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test expected: map[int]change{ 0: spawned{ template: template, - change: spent{amount: 100 + - defaultGasPrice* - (ref.estimateSpawnGas(0, 0)+ - ref.estimateSpendGas(0, 10, 100, 1))}, + change: spent{amount: 100 + ref.estimateSpawnGas(0) + ref.estimateSpendGas(0)}, }, 10: earned{amount: 100}, }, @@ -558,10 +712,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test &spendTx{0, 12, 100}, }, expected: map[int]change{ - 0: spent{amount: 100*3 + defaultGasPrice* - (ref.estimateSpendGas(0, 10, 100, 1)+ - ref.estimateSpendGas(0, 11, 100, 2)+ - ref.estimateSpendGas(0, 12, 100, 3))}, + 0: spent{amount: 3 * (100 + ref.estimateSpendGas(0))}, 10: earned{amount: 100}, 11: earned{amount: 100}, 12: earned{amount: 100}, @@ -584,12 +735,12 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test &spendTx{10, 11, 100}, }, expected: map[int]change{ - 0: spent{amount: 2_000_000 + defaultGasPrice* - ref.estimateSpendGas(0, 10, 200_000, 1)}, + 0: spent{amount: 2_000_000 + ref.estimateSpendGas(0)}, 10: spawned{ template: template, - change: earned{amount: 2_000_000 - 100 - defaultGasPrice*(ref.estimateSpawnGas(10, 10)+ - ref.estimateSpendGas(10, 11, 100, 1))}, + change: earned{ + amount: 2_000_000 - 100 - ref.estimateSpawnGas(10) - ref.estimateSpendGas(10), + }, }, 11: earned{amount: 100}, }, @@ -600,9 +751,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test &spendTx{10, 12, 100}, }, expected: map[int]change{ - 10: spent{amount: 2*100 + defaultGasPrice* - (ref.estimateSpendGas(10, 11, 100, 2)+ - ref.estimateSpendGas(10, 12, 100, 3))}, + 10: spent{amount: 2 * (100 + ref.estimateSpendGas(10))}, 11: earned{amount: 100}, 12: earned{amount: 100}, }, @@ -625,10 +774,10 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test }, expected: map[int]change{ 0: spent{ - amount: defaultGasPrice * ref.estimateSpendGas(0, 10, 1000, 1), + amount: ref.estimateSpendGas(0), change: nonce{increased: 1}, }, - 1: spent{amount: 1000 + defaultGasPrice*ref.estimateSpendGas(1, 0, 1000, 1)}, + 1: spent{amount: 1000 + ref.estimateSpendGas(1)}, 10: earned{amount: 1000}, }, }, @@ -639,10 +788,10 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test }, expected: map[int]change{ 0: spent{ - amount: defaultGasPrice * ref.estimateSpendGas(0, 10, 1000, 1), + amount: ref.estimateSpendGas(0), change: nonce{increased: 1}, }, - 1: spent{amount: 1000 + defaultGasPrice*ref.estimateSpendGas(1, 0, 1000, 1)}, + 1: spent{amount: 1000 + ref.estimateSpendGas(1)}, 10: earned{amount: 1000}, }, }, @@ -662,7 +811,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test }, expected: map[int]change{ 0: spent{ - amount: defaultGasPrice * ref.estimateSpendGas(0, 0, 1000, 1), + amount: defaultGasPrice * ref.estimateSpendGas(0), change: nonce{increased: 1}, }, }, @@ -700,7 +849,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test txs: []testTx{ &selfSpawnTx{0}, // cover intrinsic gas but not execution gas - &spendTx{0, 11, core.IntrinsicGas(core.ATHENA_MAX_GAS, 0)}, + &spendTx{0, 11, core.IntrinsicGas(core.ATHENA_GAS_VERIFY, 0)}, &selfSpawnTx{11}, }, failed: map[int]error{2: core.ErrOutOfGas}, @@ -718,21 +867,20 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test { txs: []testTx{ &selfSpawnTx{0}, - // the account needs to have 'max gas + gas for TX data' to start execution - &spendTx{0, 11, core.MaxGas(32)}, + // the account needs to have 'max gas' to start execution + &spendTx{0, 11, uint64(ref.estimateSelfSpawnMaxGas(0))}, &selfSpawnTx{11}, - &spendTx{11, 12, core.ATHENA_MAX_GAS}, + &spendTx{11, 12, 10_000}, }, - ineffective: []int{3}, + failed: map[int]error{3: core.ErrOutOfGas}, expected: map[int]change{ - 11: spawned{template: template, change: nonce{increased: 1}}, + 11: spawned{template: template, change: nonce{increased: 2}}, 12: same{}, }, }, { txs: []testTx{ &spendTx{0, 11, 12_000}, - // send enough funds to cover spawn, but no spend &spendTx{11, 12, 1}, }, failed: map[int]error{1: core.ErrOutOfGas}, @@ -752,10 +900,10 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test &spendTx{0, 11, 100}, &spendTx{0, 12, 100}, }, - gasLimit: uint64(ref.estimateSpawnGas(0, 0)) + uint64(ref.estimateSpendGas(0, 10, 100, 0))*2, + gasLimit: uint64(ref.estimateSpawnGas(0)) + uint64(ref.estimateSpendGas(0))*2, ineffective: []int{2, 3}, expected: map[int]change{ - 0: spent{amount: 100 + ref.estimateSpawnGas(0, 0) + ref.estimateSpendGas(0, 10, 100, 1)}, + 0: spent{amount: 100 + ref.estimateSpawnGas(0) + ref.estimateSpendGas(0)}, 10: earned{amount: 100}, 11: same{}, 12: same{}, @@ -770,19 +918,19 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test txs: []testTx{ &selfSpawnTx{0}, // send enough to cover intrinsic cost but not whole transaction - &spendTx{0, 10, uint64(ref.estimateSpawnGas(10, 10)) - 1}, + &spendTx{0, 10, uint64(ref.estimateSpawnGas(10)) - 1}, &selfSpawnTx{10}, &spendTx{0, 11, 100}, }, gasLimit: uint64( - ref.estimateSpawnGas(0, 0)+ref.estimateSpendGas(0, 10, 100, 1), - ) + core.MaxGas(32), + ref.estimateSpawnGas(0) + ref.estimateSpendGas(0) + ref.estimateSelfSpawnMaxGas(10), + ), failed: map[int]error{2: core.ErrOutOfGas}, ineffective: []int{3}, expected: map[int]change{ - 0: spent{amount: ref.estimateSpawnGas(10, 10) - 1 + - ref.estimateSpawnGas(0, 0) + - ref.estimateSpendGas(0, 10, ref.estimateSpawnGas(10, 10)-1, 1)}, + 0: spent{amount: ref.estimateSpawnGas(10) - 1 + + ref.estimateSpawnGas(0) + + ref.estimateSpendGas(0)}, 10: nonce{increased: 1}, 11: same{}, }, @@ -806,8 +954,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test 0: spawned{ template: template, change: spent{ - amount: 100 + defaultGasPrice*(ref.estimateSpawnGas(0, 0)+ - ref.estimateSpendGas(0, 11, 100, 2)), + amount: 100 + ref.estimateSpawnGas(0) + ref.estimateSpendGas(0), }, }, 10: same{}, @@ -820,8 +967,8 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test spendTx{0, 12, 100}.withNonce(6), }, expected: map[int]change{ - 0: spent{amount: 2*100 + defaultGasPrice*(ref.estimateSpendGas(0, 10, 100, 3)+ - ref.estimateSpendGas(0, 10, 100, 6))}, + 0: spent{amount: 2*100 + defaultGasPrice*(ref.estimateSpendGas(0)+ + ref.estimateSpendGas(0))}, 10: earned{amount: 100}, 12: earned{amount: 100}, }, @@ -837,7 +984,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test }, rewards: []reward{{address: 10, share: 1}}, expected: map[int]change{ - 10: earned{amount: int(rewards.TotalSubsidyAtLayer(0)) + ref.estimateSpawnGas(0, 0)}, + 10: earned{amount: int(rewards.TotalSubsidyAtLayer(0)) + ref.estimateSpawnGas(0)}, }, }, { @@ -867,8 +1014,8 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test }, rewards: []reward{{address: 10, share: 0.5}, {address: 11, share: 0.5}}, expected: map[int]change{ - 10: earned{amount: (int(rewards.TotalSubsidyAtLayer(1)) + ref.estimateSpawnGas(10, 10)) / 2}, - 11: earned{amount: (int(rewards.TotalSubsidyAtLayer(1)) + ref.estimateSpawnGas(11, 11)) / 2}, + 10: earned{amount: (int(rewards.TotalSubsidyAtLayer(1)) + ref.estimateSpawnGas(10)) / 2}, + 11: earned{amount: (int(rewards.TotalSubsidyAtLayer(1)) + ref.estimateSpawnGas(11)) / 2}, }, }, }, @@ -921,7 +1068,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test &spendTx{ 0, 11, - uint64(ref.estimateSpawnGas(11, 11)) + core.MaxGas(32), + uint64(ref.estimateSpawnGas(11) + ref.estimateSelfSpawnMaxGas(0)), }, &selfSpawnTx{11}, &spendTx{11, 12, 1_000_000}, @@ -939,7 +1086,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test }, expected: map[int]change{ 0: spent{ - amount: ref.estimateSpendGas(0, 11, 200_000, 2) + 200_000, + amount: ref.estimateSpendGas(0) + 200_000, change: nonce{increased: 1}, }, 11: nonce{increased: 1}, @@ -954,41 +1101,31 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test { txs: []testTx{ &selfSpawnTx{0}, - &spendTx{0, 11, core.ATHENA_MAX_GAS - 1}, + &spendTx{0, 11, core.IntrinsicGas(core.ATHENA_GAS_VERIFY, 0)}, &selfSpawnTx{11}, }, failed: map[int]error{2: core.ErrOutOfGas}, expected: map[int]change{ 0: spent{ amount: ref.estimateSpawnGas( - 11, - 11, - ) - 1 + ref.estimateSpendGas( 0, - 11, - core.ATHENA_MAX_GAS, - 1, - ) + core.ATHENA_MAX_GAS, + ) + ref.estimateSpendGas( + 0, + ) + int( + core.IntrinsicGas(core.ATHENA_GAS_VERIFY, 0), + ), }, 11: nonce{increased: 1}, }, }, { txs: []testTx{ - &spendTx{0, 11, uint64(ref.estimateSpawnGas(11, 11)) + core.ATHENA_MAX_GAS}, + &spendTx{0, 11, uint64(ref.estimateSelfSpawnMaxGas(11))}, &selfSpawnTx{11}, }, expected: map[int]change{ 0: spent{ - amount: ref.estimateSpendGas( - 0, - 11, - 0, - 0, - ) + ref.estimateSpawnGas( - 11, - 11, - ) + core.ATHENA_MAX_GAS, + amount: ref.estimateSelfSpawnMaxGas(11) + ref.estimateSpendGas(0), }, 11: spawned{template: template, change: nonce{increased: 1}}, }, @@ -1013,7 +1150,7 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test change: nonce{ increased: 1, // increased: 2, - change: spent{amount: ref.estimateSpawnGas(0, 0)}, + change: spent{amount: ref.estimateSpawnGas(0)}, // change: spent{amount: 2 * ref.estimateSpawnGas(0, 0)}, }, }, @@ -1028,21 +1165,21 @@ func singleWalletTestCases(defaultGasPrice int, template core.Address, ref *test txs: []testTx{ &selfSpawnTx{0}, // gas will be higher than fixed, but less than max gas - &spendTx{0, 11, uint64(ref.estimateSpawnGas(11, 11)) - 1}, + &spendTx{0, 11, uint64(ref.estimateSpawnGas(11)) - 1}, // it will cause this transaction to fail &selfSpawnTx{11}, }, failed: map[int]error{2: core.ErrOutOfGas}, rewards: []reward{{address: 20, share: 1}}, expected: map[int]change{ - 0: spent{amount: ref.estimateSpawnGas(0, 0) + - ref.estimateSpendGas(0, 11, ref.estimateSpawnGas(11, 11)-1, 1) + - ref.estimateSpawnGas(11, 11) - 1}, + 0: spent{amount: ref.estimateSpawnGas(0) + + ref.estimateSpendGas(0) + + ref.estimateSpawnGas(11) - 1}, 11: nonce{increased: 1}, // fees from every transaction (including failed) + testBaseReward - 20: earned{amount: ref.estimateSpawnGas(0, 0) + - ref.estimateSpendGas(0, 11, ref.estimateSpawnGas(11, 11)-1, 1) + - ref.estimateSpawnGas(11, 11) - 1 + + 20: earned{amount: ref.estimateSpawnGas(0) + + ref.estimateSpendGas(0) + + ref.estimateSpawnGas(11) - 1 + int(rewards.TotalSubsidyAtLayer(0))}, }, }, @@ -1273,27 +1410,48 @@ func TestWallets(t *testing.T) { addSingleSig(total - funded) }) }) + t.Run("MultiSig13", func(t *testing.T) { + testWallet(t, defaultGasPrice, multiSigWalletTemplateAddress, func(t *testing.T) *tester { + return newTester(t). + addMultiSigWalletTemplate(). + addMultisig(multiSigWalletTemplateAddress, funded, 1, 3). + applyGenesisWithBalance(). + addMultisig(multiSigWalletTemplateAddress, total-funded, 1, 3) + }) + }) + t.Run("MultiSig23", func(t *testing.T) { + testWallet(t, defaultGasPrice, multiSigWalletTemplateAddress, func(t *testing.T) *tester { + return newTester(t). + addMultiSigWalletTemplate(). + addMultisig(multiSigWalletTemplateAddress, funded, 2, 3). + applyGenesisWithBalance(). + addMultisig(multiSigWalletTemplateAddress, total-funded, 2, 3) + }) + }) + t.Run("MultiSig57", func(t *testing.T) { + testWallet(t, defaultGasPrice, multiSigWalletTemplateAddress, func(t *testing.T) *tester { + return newTester(t). + addMultiSigWalletTemplate(). + addMultisig(multiSigWalletTemplateAddress, funded, 5, 7). + applyGenesisWithBalance(). + addMultisig(multiSigWalletTemplateAddress, total-funded, 5, 7) + }) + }) } func TestSingleSigWalletDeploy(t *testing.T) { - tt := newTester(t).addWalletTemplate().addSingleSig(1) - - // FIXME: The test will deploy singleSig wallet template again at a different address - // (`wallet.TemplateAddress` is hardcoded), because we don't have another template yet. - // Fix this test once we have more than 1 program. - code := wallet.PROGRAM - newTemplateAddress := core.TemplateAddress(code) - require.NotEqual(t, wallet.TemplateAddress, newTemplateAddress, "update the test to use another template") - pub, pk, err := ed25519.GenerateKey(tt.rng) - require.NoError(t, err) - principal := core.ComputePrincipalFromBlob(newTemplateAddress, pub) - tt.addAccount(&singlesigAccount{pk, principal}, 1_000_000_000) - - tt.applyGenesisWithBalance() + code := multisig.PROGRAM + templateAddress := core.TemplateAddress(code) + tt := newTester( + t, + ).addWalletTemplate(). + addSingleSig(1). + addMultisig(templateAddress, 1, 1, 3). + applyGenesisWithBalance() // 1. Spawn an account to pay for deploying account := tt.accounts[0] - _, _, err = tt.Apply(types.GetEffectiveGenesis(), []types.Transaction{{RawTx: tt.selfSpawn(0)}}, nil) + _, _, err := tt.Apply(types.GetEffectiveGenesis(), []types.Transaction{{RawTx: tt.selfSpawn(0)}}, nil) require.NoError(t, err) exists, err := tt.AccountExists(account.getAddress()) @@ -1310,13 +1468,13 @@ func TestSingleSigWalletDeploy(t *testing.T) { require.Empty(t, skipped) require.Empty(t, results[0].Message) require.Equal(t, types.TransactionSuccess, results[0].Status) - require.Contains(t, results[0].Addresses, newTemplateAddress) + require.Contains(t, results[0].Addresses, templateAddress) - deployedAccount, err := accounts.Latest(tt.db, newTemplateAddress) + deployedAccount, err := accounts.Latest(tt.db, templateAddress) require.NoError(t, err) logger := zaptest.NewLogger(t) - logger.Debug("new template", zap.Stringer("address", newTemplateAddress), zap.Inline(&deployedAccount)) + logger.Debug("new template", zap.Stringer("address", templateAddress), zap.Inline(&deployedAccount)) require.Equal(t, code, deployedAccount.State) pAccount1, err := accounts.Latest(tt.db, account.getAddress()) @@ -1339,7 +1497,7 @@ func TestSingleSigWalletDeploy(t *testing.T) { // 3. Spawn the new template using the 2nd prefunded account _, _, err = tt.Apply( types.GetEffectiveGenesis(), - []types.Transaction{{RawTx: tt.selfSpawn(1, sdk.WithTemplate(newTemplateAddress))}}, + []types.Transaction{{RawTx: tt.selfSpawn(1, sdk.WithTemplate(templateAddress))}}, nil, ) require.NoError(t, err) @@ -1350,7 +1508,7 @@ func TestSingleSigWalletDeploy(t *testing.T) { a, err := accounts.Latest(tt.db, tt.accounts[1].getAddress()) require.NoError(t, err) - require.Equal(t, &newTemplateAddress, a.TemplateAddress) + require.Equal(t, &templateAddress, a.TemplateAddress) } func testValidation(t *testing.T, tt *tester, template core.Address) { @@ -1373,7 +1531,7 @@ func testValidation(t *testing.T, tt *tester, template core.Address) { Principal: tt.accounts[1].getAddress(), TemplateAddress: template, GasPrice: 1, - MaxGas: core.MaxGas(32), + MaxGas: uint64(tt.estimateSelfSpawnMaxGas(1)), }, verified: true, }, @@ -1391,7 +1549,7 @@ func testValidation(t *testing.T, tt *tester, template core.Address) { GasPrice: 1, Nonce: 1, MaxSpend: 100, - MaxGas: core.MaxGas(32), + MaxGas: uint64(tt.estimateSpendMaxGas(1)), }, verified: true, },