release: v0.20-rc3 changelog (#1517)

* deps(sdk): bump to v0.46.4 (#1423)

* deps(sdk): bump to v0.46.4

* deps(sdk): add IAVLDisableFastNode flag with false default

* imp: reduce integration test block time to 2s (#1428)

* build(deps): bump github.com/onsi/gomega from 1.23.0 to 1.24.0 (#1429)

Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.23.0 to 1.24.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.23.0...v1.24.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(rpc): different result from `eth_getProof` comparing with Ethereum (#1431)

* align with eth_getProof

for more info, see https://eips.ethereum.org/EIPS/eip-1186

* add GetHexProofs

* add change doc

* keep default res

* fix lint

* add e2e test

* Apply suggestions from code review

* fix lint

* nix run -f ./nix gomod2nix

* Refactor EIP-712 signature verification (#1397)

* [WIP] EIP-712 Signature Refactor

* Debug and add ante tests

* Add tests for failure cases

* Add changelog entry

* Code cleanup

* Add tests for MsgDelegate and MsgWithdrawDelegationReward

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Code cleanup

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Minor codefix

* Update ethereum/eip712/encoding.go

* Minor code revision updates

* Refactor EIP712 unit tests to use test suite

* Address import cycle and implement minor refactors

* Fix lint issues

* Add EIP712 unit suite test function

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/eip712/encoding.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Add minor refactors; increase test coverage

* Correct ante_test for change in payload

* Add single-signer util and tests

* Update ethereum/eip712/encoding.go

* Update ethereum/eip712/encoding.go

* fix build

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>

* fix: build test on mac by updating to python3.10 (#1437)

* build(deps): bump loader-utils from 1.4.0 to 1.4.1 in /tests/solidity (#1445)

Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.1/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* imp(evm): improve performance of EstimateGas (#1444)

* imp(evm): improve performance of EstimateGas

* changelog

* fix(rpc): decode `finalized` block number (#1442)

* fix(rpc): decode 'finalized' block number

* changelog

Co-authored-by: Freddy Caceres <facs95@gmail.com>

* build(deps): bump github.com/onsi/gomega from 1.24.0 to 1.24.1 (#1449)

Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.24.0 to 1.24.1.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.24.0...v1.24.1)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump github.com/spf13/viper from 1.13.0 to 1.14.0 (#1439)

Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.13.0...v1.14.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: 4rgon4ut <59182467+4rgon4ut@users.noreply.github.com>
Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* fix: unstable tx_priority test (#1440)

* fix unstable tx_priority test

* Update tests/integration_tests/test_priority.py

Co-authored-by: yihuang <huang@crypto.com>

* Update tests/integration_tests/test_priority.py

Co-authored-by: yihuang <huang@crypto.com>

Co-authored-by: yihuang <huang@crypto.com>
Co-authored-by: Adi Saravanan <59209660+adisaran64@users.noreply.github.com>
Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* build(deps): bump github.com/cosmos/ibc-go/v5 from 5.0.1 to 5.1.0 (#1450)

Bumps [github.com/cosmos/ibc-go/v5](https://github.com/cosmos/ibc-go) from 5.0.1 to 5.1.0.
- [Release notes](https://github.com/cosmos/ibc-go/releases)
- [Changelog](https://github.com/cosmos/ibc-go/blob/v5.1.0/CHANGELOG.md)
- [Commits](https://github.com/cosmos/ibc-go/compare/v5.0.1...v5.1.0)

---
updated-dependencies:
- dependency-name: github.com/cosmos/ibc-go/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump golangci/golangci-lint-action from 3.3.0 to 3.3.1 (#1454)

Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v3.3.0...v3.3.1)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* refactor(all): refactor errors import to use cosmossdk.io (#1456)

* refactor (errors) refactor errors import to use cosmossdk.io instead of cosmos-sdk/types/errors

* refactor (errors) refactor errors import in ethsecp256k1 file

* refactor (errors) add changes to changelog

* build(deps): bump alpine from 3.16.2 to 3.16.3 (#1453)

Bumps alpine from 3.16.2 to 3.16.3.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Empty KV gas config (#1460)

* update sdk version

* setup empty gas config

* fix lint

* fix integration tests

* add Ante unit test

* update changelog

* test: remove unused integration tests (#1462)

* fix: remove e2e github action (#1463)

* remove unused tests

* imp: remove e2e github action

* build(deps): bump loader-utils from 1.4.1 to 1.4.2 in /tests/solidity (#1464)

Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore (deps): Update geth version to v1.10.25 (#1413)

* build(deps): bump github.com/ethereum/go-ethereum

Bumps [github.com/ethereum/go-ethereum](https://github.com/ethereum/go-ethereum) from 1.10.19 to 1.10.25.
- [Release notes](https://github.com/ethereum/go-ethereum/releases)
- [Commits](https://github.com/ethereum/go-ethereum/compare/v1.10.19...v1.10.25)

---
updated-dependencies:
- dependency-name: github.com/ethereum/go-ethereum
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* wip geth update

* fix geth init flag order

* add chainId to getTransaction. fix types comparison. update expected values on tests

* wip add tracer config

* tracers test

* update tests

* update to v1.10.25

* fix linter python

* ignore error

* fix lint

* additional changes from diff

* fix issues

* solve lint issues

* fix tests

* fix flake

* wrap types comparison in integration tests

* fix integration tests

* fix flake

* update changelog

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>

* Add EIP-712 encoding support type for any array (#1430)

* Add EIP-712 encoding support type for any array

* Refactor implementation + add tests

* Refactor unpacking implementation; refactor test case

* Fix lint issue

* Add MsgExec test case

* Update comment for clarity

* Add changelog entry

* Refactor `sdkerrors` to `errorsmod`

Co-authored-by: Freddy Caceres <facs95@gmail.com>

* fix: extend geth config on integration tests (#1467)

* changing git config and adding tests

* removing print statements

* remove unneccessary imports

* fix flake

* remove geth setup test

Co-authored-by: Freddy Caceres <facs95@gmail.com>

* tests: Add unit tests for rpc client endpoints (#1409)

* test: add preliminary unit tests and additional mocks for chain_info, account_info and filters

* tests: added additional mocked client calls

* tests: bumped coverage of call_tx to 56% and chain_info to 77%

* tests: bumped call_tx coverage to 70.2% and added additional mock client calls

* tests: tx_info preliminary tests added for debugging.

* tests: added test coverage for sign_tx and additional mocks

* tests: tx_info test coverage bumped to 60.3%

* test: coverage for tracing_tests now at 72%

* tests: added fee makert query client mocks and bumped chain_info to 87.6% coverage.

* tests: failing Cosmos auth module account query.

* tests: added FeeMarket Params mock to call_tx_test

* cleanup some unused code

* tests: added helper function to test suite for signing a Tx and bumped coverage of tx_info to 71.2%

* test: commented GetAccount error case and bumped chain_info to 90.3% coverage

* test: cleanup of tests in node_info, sign_tx and account_info

* Clean up print

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Apply suggestions from code review

* fix import issues

Co-authored-by: Vladislav Varadinov <vlad@evmos.org>
Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>

* Refactor to omit empty optionals from EIP-712 type generation (#1459)

* Refactor to omit empty values from type creation; add test for v1.vote

* Add test for createValidator with optional fields left blank

* Add changelog entry

* Update changelog entry

Co-authored-by: Freddy Caceres <facs95@gmail.com>

* fix: protogen scripts were not correctly implemented (#1466)

* Delete local copy of third party proto files

* Update protocgen script and buf yaml files to mirror cosmos-sdk

* Update makefile commands for proto-gen and proto-swagger-gen to correctly use docker

* Commit changed .pb.go files after updating the protogen scripts

* Adjust grep in proto-tools-installer script to look for correct gogoproto replacement

* address reviews - remove unnecessary ignore in buf.yaml and cosmos-sdk download in the protocgen script

* remove proto-update-deps from makefile as we don't store local copies of third party protofiles anymore

* Add changelog entry

* Update protoc-swagger-gen.sh

* Remove third party queries from swagger-ui config (for now)

* fix integrations tests

* fix dead changelog links (markdown-link-check)

Co-authored-by: Freddy Caceres <facs95@gmail.com>
Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* added gas consumption test (#1474)

* build(deps): bump github.com/cosmos/cosmos-proto (#1475)

Bumps [github.com/cosmos/cosmos-proto](https://github.com/cosmos/cosmos-proto) from 1.0.0-alpha7 to 1.0.0-alpha8.
- [Release notes](https://github.com/cosmos/cosmos-proto/releases)
- [Commits](https://github.com/cosmos/cosmos-proto/compare/v1.0.0-alpha7...v1.0.0-alpha8)

---
updated-dependencies:
- dependency-name: github.com/cosmos/cosmos-proto
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: chain-id in grpc query is not initialized without abci event (#1405)

* fix: chain-id in grpc query is not initialized without abci event

Closes: #1404

Solution:
- pass the chain-id from caller.

* Update CHANGELOG.md

* only override if input is not empty

* add comment to chain id

* pass chain-id to state transition

* Update x/evm/keeper/grpc_query.go

* Apply suggestions from code review

* fix golang lint

* update gomod2nix.toml

* fix unit tests

* update gomod2nix

* api breaking changelog

* add unit tests, and fix TraceBlock by the way

* Update CHANGELOG.md

* test --grpc-only mode in integration tests

* remove tmp var

* Update tests/integration_tests/test_grpc_only.py

* Update x/evm/keeper/grpc_query_test.go

Co-authored-by: mmsqe <tqd0800210105@gmail.com>

* fix linters

* fix nil pointer in tests

* fix conflicts

* fix conflicts

* fixes

* fix lint

* fix unit test

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: mmsqe <tqd0800210105@gmail.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>

* fix(evm): Simplify Gas Math (#1452)

* fix math

* changelog

* imp(ante): refactor `AnteHandler` (#1455)

* fix(ante): block gas check

* refactor

* rename

* use gas wanted

* remove consume gas logic on ante handler

* comment

* c++

* move min gas price

* comment

* Update app/ante/eth.go

Co-authored-by: Vladislav Varadinov <vladislav.varadinov@gmail.com>

* fix build

* fix integration test script

Co-authored-by: Vladislav Varadinov <vladislav.varadinov@gmail.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>

* tests: add additional gas consumption tests (#1477)

* split existing gas test

* added contract call test

* fix flake issues, update gomod2nix

* isort imports

* add stateful contract calls

* chore: update proto make commands (#1471)

* Update proto make commands to use cosmos docker image and add notes for possible problems

* Apply make proto-all with new docker container

* Remove stale DOCKER_BUF variable

* Revert to using the tendermintdev/sdk-proto-gen docker image

* remove '@' in proto-lint and proto-check-breaking for consistency with other commands

* Remove unnecessary go get from protocgen.sh (only works after adding --network host to docker run)

* Add --network host to docker run for compatibility on linux

* use cosmos/proto-builder docker image for proto-format because clang-format is not installed on tendermintdev/sdk-proto-gen

* update swagger docs after recent additions to evm.proto in #1413

Co-authored-by: Tomas Guerra <54514587+GAtom22@users.noreply.github.com>

* Remove unbound labels from added custom tendermint metrics (#1434)

* Remove unbound labels from added custom tendermint metrics

* Add entry to changelog

* deps: bump SDK to v0.46.6 (#1486)

* deps: bump SDK to v0.46.6

* changelog

* Update CHANGELOG.md

Co-authored-by: Tomas Guerra <54514587+GAtom22@users.noreply.github.com>

Co-authored-by: Tomas Guerra <54514587+GAtom22@users.noreply.github.com>

* fear(eip712): Add EIP-712 encoding for multiple messages of the same type (#1483)

* Add EIP-712 encoding for multiple messages of the same type

* Fix Protobuf encoding bug

* Add ante tests

* Refactor naming and minor implementation details

* Test empty transaction coverage

* Address revisions for code clarity

* Move aminoMessage type definition

* fix: enable `fixIssue172` flag for non-deterministic keyring test (#1447)

* enable fixIssue172 flag for test

for more info, https://github.com/btcsuite/btcutil/pull/182/files

* fix import

* Apply suggestions from code review

* Apply suggestions from code review

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Adi Saravanan <59209660+adisaran64@users.noreply.github.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>

* fix(tests): Delete inconsistent test (#1481)

* Delete inconsistent test

* delete test

* build(deps): bump alpine from 3.16.3 to 3.17.0 (#1492)

Bumps alpine from 3.16.3 to 3.17.0.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump google.golang.org/grpc from 1.50.1 to 1.51.0 (#1490)

Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.50.1 to 1.51.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.50.1...v1.51.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump github.com/onsi/ginkgo/v2 from 2.5.0 to 2.5.1 (#1489)

Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.5.0 to 2.5.1.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.5.0...v2.5.1)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore: refactor imports naming for clarity (#1491)

* chore: refactor imports naming for clarity

* Merge main and fix conflicts

* fix: align empty account result for old blocks as ethereum (#1484)

* align result account as ethereum

* add test_get_transaction_count

* add change doc

* sync gomod2nix

* Apply suggestions from code review

* crosscheck with ws & geth

* sync gomod2nix

* Update rpc/backend/utils.go

* use session provider

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* imp(ante): refactor AnteHandler (#1479)

* imp(ante): refactor AnteHandler

* fix test

* test

* Adjust deprecated sdkerrors import (#1493)

* refactor test files

* Apply suggestions from code review

Co-authored-by: 4rgon4ut <59182467+4rgon4ut@users.noreply.github.com>

* lint

* prioritization comment

* fix test

Co-authored-by: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com>
Co-authored-by: 4rgon4ut <59182467+4rgon4ut@users.noreply.github.com>

* chore: Update linter and protogen configuration (#1478)

* add protolint yaml

* Update .protolint.yml with Evmos settings

* Add super-linter.yml for GH action

* Copy .markdownlint.yml settings from Evmos

* Sort proto imports

* address protolint error in all Protobuf files

* update Makefile to mirror Proto commands for Evmos

* remove unnecessary go get command in protocgen.sh when using cosmos docker image

* copy .clang-format from Evmos repo

* apply make proto-format

* Execute make proto-all after changes to config are complete

* address last linter comment

* fix(server): telemetry setup (#1497)

* fix(server): telemetry setup

* more fixes

* fix

* changelog

* update standalone process

* chore(evm) - Delete deprecated store migrations (#1498)

* (fix): Delete deprecated migrations

* Update x/evm/module.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* fix(evm): Added Cancun and Shanghai blocks to ChainConfig (#1499)

* (refactor): Added Cancun and Shanghai blocks to ChainConfig

* (tests): Added test for invalid Shanghai and Cancun block

* (fix): ran proto linter

* Applied changes from code review

* Added CHANGELOG entry

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* chore(app): add store listener to Ethermint app (#1501)

* add store listener to Ethermint app

* add changelog entry

* build(deps): bump cosmossdk.io/math from 1.0.0-beta.3 to 1.0.0-beta.4 (#1502)

Bumps [cosmossdk.io/math](https://github.com/cosmos/cosmos-sdk) from 1.0.0-beta.3 to 1.0.0-beta.4.
- [Release notes](https://github.com/cosmos/cosmos-sdk/releases)
- [Changelog](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md)
- [Commits](https://github.com/cosmos/cosmos-sdk/compare/math/v1.0.0-beta.3...math/v1.0.0-beta.4)

---
updated-dependencies:
- dependency-name: cosmossdk.io/math
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(app): register node service (#1505)

* fix(app): register node service

* changelog

* fix(cmd): add missing GetAuxToFeeCommand (#1504)

Co-authored-by: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com>

* chore(feemarket): Delete deprecated migration logic (#1508)

* (refactor): Remove old migration code

* (fix): Lint and add CHANGELOG entry

* Remove simulation checks (#1507)

* Add cli rollback command

it's useful in app-hash mismatch situation.

* Update CHANGELOG.md

* (refactor): removed old sim tests logic

* (fix): removed tests from CI

* (fix): fix test.yml

* (fix): format and lint

* (fix): fix linter issue

* (fix): fix linter issues v2

* (fix): linter

* (fix): removed sim-test references

* Applied changes from code review

Co-authored-by: HuangYi <huang@crypto.com>

* chore: verify fees refactor (#1496)

* chore: verify fees refactor

* adjust call structure in rest of repo after splitting up DeductTxCostsFromUserBalance

* adjust test logic after splitting DeductTxCostsFromUserBalance up

* remove outdated TODO

* address PR comments - remove import name for evm keeper

* remove misleading comment

* address review comments - only handover boolean instead of context

* remove TODO

Co-authored-by: MalteHerrmann <malteherrmann.mail@web.de>
Co-authored-by: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com>

* json-rpc(filters) fix block hash on newBlock filter (#1503)

* tests(filters) add block hash check on newBlock filter

* tests(filters) fix linting errors

* fix(filters): fix newBlock filter response

* fix(filters): add changes on CHANGELOG file

* fix(ci): add gitleaks config (#1513)

* fix(ci): add gitleaks config to ignore init.sh

* make ci lint init.sh

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* tests(filters): add/improve integration tests for JSON-RPC methods (#1480)

* tests(filters) add block hash check on newBlock filter

* tests(filters) add getLogs test cases

* tests(filters) add eth_newFilter multiple filters test cases

* tests(filters) add eth_newFilter and eth_eth_uninstallFilter test case

* tests(filters) fix linting errors

* tests(filters) fix linting error on imports

* tests(filters) add test case: register filter before contract deploy

* tests(filters) refactor logs topics assertion

* tests(filters) add topics filter test cases

* tests(filters) fix linting errors

* tests(filters) remove unnecessary package.json file

* tests(filters) update based on PR comments

* tests(filters) separate getNewBlocks failing test to a separate PR

* tests(filters) add retry on send_tx to avoid Timeout error

* tests(filters) add logs by topic and block range test case

* update gomod2nix

* tests(filters) remove test elapsed time log

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>

* add dragonberry update changelog entry again

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Daniel Burckhardt <daniel.m.burckhardt@gmail.com>
Co-authored-by: Freddy Caceres <facs95@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mmsqe <mavis@crypto.com>
Co-authored-by: Austin Chandra <austinchandra@berkeley.edu>
Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: 4rgon4ut <59182467+4rgon4ut@users.noreply.github.com>
Co-authored-by: yihuang <huang@crypto.com>
Co-authored-by: Adi Saravanan <59209660+adisaran64@users.noreply.github.com>
Co-authored-by: Tomas Guerra <54514587+GAtom22@users.noreply.github.com>
Co-authored-by: Ramiro Carlucho <ramirocarlucho@gmail.com>
Co-authored-by: Vladislav Varadinov <vladislav.varadinov@gmail.com>
Co-authored-by: Vladislav Varadinov <vlad@evmos.org>
Co-authored-by: mmsqe <tqd0800210105@gmail.com>
Co-authored-by: Devon Bear <itsdevbear@berachain.com>
Co-authored-by: v-homsi <110708931+v-homsi@users.noreply.github.com>
This commit is contained in:
MalteHerrmann 2022-11-30 18:00:19 +01:00 committed by GitHub
parent 4b676b603f
commit 55b292f179
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
305 changed files with 13550 additions and 41018 deletions

View File

@ -1,115 +1,6 @@
---
Language: Proto
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
RawStringFormats:
- Delimiters:
- pb
Language: TextProto
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
Language: Proto
BasedOnStyle: google
ColumnLimit: 120
IndentWidth: 2
...

View File

@ -25,7 +25,7 @@ jobs:
**/**.go
go.mod
go.sum
- uses: golangci/golangci-lint-action@v3.3.0
- uses: golangci/golangci-lint-action@v3.3.1
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: latest

38
.github/workflows/super-linter.yml vendored Normal file
View File

@ -0,0 +1,38 @@
# This workflow executes several linters on changed files based on languages used in your code base whenever
# you push a code or open a pull request.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/github/super-linter
---
name: Lint Code Base
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
run-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
# Full git history is needed to get a proper list of changed files within `super-linter`
fetch-depth: 0
- name: Lint Code Base
uses: github/super-linter@v4
env:
LINTER_RULES_PATH: /
YAML_CONFIG_FILE: .yamllint
VALIDATE_ALL_CODEBASE: false
MARKDOWN_CONFIG_FILE: .markdownlint.yml
PROTOBUF_CONFIG_FILE: .protolint.yml
VALIDATE_NATURAL_LANGUAGE: false
VALIDATE_OPENAPI: false
VALIDATE_JSCPD: false
VALIDATE_GO: false
DEFAULT_BRANCH: "main"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -82,27 +82,6 @@ jobs:
make test-rpc
if: env.GIT_DIFF
test-e2e:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.sol
**/**.go
go.mod
go.sum
- name: Test e2e
run: |
make test-integration
if: env.GIT_DIFF
integration_tests:
runs-on: ubuntu-latest
steps:
@ -148,84 +127,4 @@ jobs:
name: ethermint
signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}"
- name: 'instantiate integration test env'
run: nix-store -r $(nix-instantiate tests/integration_tests/shell.nix)
test-sim-nondeterminism:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test simulation nondeterminism
run: |
make test-sim-nondeterminism
if: env.GIT_DIFF
test-sim-random-genesis-fast:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test simulation with random genesis
run: |
make test-sim-random-genesis-fast
if: env.GIT_DIFF
test-sim-import-export:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Simulation of import and export genesis
run: |
make test-sim-import-export
if: env.GIT_DIFF
test-sim-after-import:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test simulation after import
run: |
make test-sim-after-import
if: env.GIT_DIFF
run: nix-store -r "$(nix-instantiate tests/integration_tests/shell.nix)"

2766
.gitleaks.toml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
"default": true
"MD001": false
"MD004": false
"MD007":
"MD007":
"indent": 4
"MD013": false
"MD024":
"MD024":
"siblings_only": true
"MD025": false
"MD026":
"MD026":
"punctuation": ".;:"
"MD029": false
"MD033": false
@ -15,6 +15,7 @@
"MD036": false
"MD040": false
"MD041": false
"MD049":
"MD051": false
"MD049":
"style": "asterisk"
"no-hard-tabs": false

174
.protolint.yml Normal file
View File

@ -0,0 +1,174 @@
---
# Lint directives.
lint:
# # Linter files to ignore.
# ignores:
# - id: MESSAGE_NAMES_UPPER_CAMEL_CASE
# files:
# # NOTE: UNIX paths will be properly accepted by both UNIX and Windows.
# - _example/proto/simple.proto
# - id: ENUM_NAMES_UPPER_CAMEL_CASE
# files:
# - path/to/foo.proto
# # Linter files to walk.
# files:
# # The specific files to exclude.
# exclude:
# # NOTE: UNIX paths will be properly accepted by both UNIX and Windows.
# - path/to/file
# # Linter directories to walk.
# directories:
# # The specific directories to exclude.
# exclude:
# # NOTE: UNIX paths will be properly accepted by both UNIX and Windows.
# - path/to/dir
# Linter rules.
# Run `protolint list` to see all available rules.
rules:
# Determines whether or not to include the default set of linters.
no_default: true
# Set the default to all linters. This option works the other way around as no_default does.
# If you want to enable this option, delete the comment out below and no_default.
# all_default: true
# The specific linters to add.
add:
- FIELD_NAMES_LOWER_SNAKE_CASE
- MESSAGE_NAMES_UPPER_CAMEL_CASE
- MAX_LINE_LENGTH
- INDENT
# - SERVICE_NAMES_END_WITH
- FIELD_NAMES_EXCLUDE_PREPOSITIONS
- MESSAGE_NAMES_EXCLUDE_PREPOSITIONS
- FILE_NAMES_LOWER_SNAKE_CASE
- IMPORTS_SORTED
- PACKAGE_NAME_LOWER_CASE
- ORDER
- MESSAGES_HAVE_COMMENT
- SERVICES_HAVE_COMMENT
- RPCS_HAVE_COMMENT
- FIELDS_HAVE_COMMENT
- PROTO3_FIELDS_AVOID_REQUIRED
- PROTO3_GROUPS_AVOID
# - REPEATED_FIELD_NAMES_PLURALIZED
- ENUMS_HAVE_COMMENT
- ENUM_FIELDS_HAVE_COMMENT
- SYNTAX_CONSISTENT
- RPC_NAMES_UPPER_CAMEL_CASE
# - FILE_HAS_COMMENT
- QUOTE_CONSISTENT
# # The specific linters to remove.
# remove:
# - RPC_NAMES_UPPER_CAMEL_CASE
# Linter rules option.
rules_option:
# MAX_LINE_LENGTH rule option.
max_line_length:
# Enforces a maximum line length
max_chars: 120
# Specifies the character count for tab characters
tab_chars: 2
# INDENT rule option.
indent:
# Available styles are 4(4-spaces), 2(2-spaces) or tab.
style: 2
# Specifies if it should stop considering and inserting new lines at the appropriate positions
# when the inner elements are on the same line. Default is false.
not_insert_newline: true
# # FILE_NAMES_LOWER_SNAKE_CASE rule option.
# file_names_lower_snake_case:
# excludes:
# - ../proto/invalidFileName.proto
# QUOTE_CONSISTENT rule option.
quote_consistent:
# Available quote are "double" or "single".
quote: double
# ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH rule option.
enum_field_names_zero_value_end_with:
suffix: INVALID
# # SERVICE_NAMES_END_WITH rule option.
# service_names_end_with:
# text: Service
# FIELD_NAMES_EXCLUDE_PREPOSITIONS rule option.
field_names_exclude_prepositions:
# The specific prepositions to determine if the field name includes.
prepositions:
- for
- at
- of
# The specific keywords including prepositions to ignore. E.g. end_of_support is a term you would like to use, and skip checking.
excludes:
- duration_of_decay
# # REPEATED_FIELD_NAMES_PLURALIZED rule option.
# ## The spec for each rules follows the implementation of https://github.com/gertd/go-pluralize.
# ## Plus, you can refer to this rule's test code.
# repeated_field_names_pluralized:
# uncountable_rules:
# - paper
# irregular_rules:
# Irregular: Regular
# MESSAGE_NAMES_EXCLUDE_PREPOSITIONS rule option.
message_names_exclude_prepositions:
# The specific prepositions to determine if the message name includes.
prepositions:
- With
- For
- Of
# # The specific keywords including prepositions to ignore. E.g. EndOfSupport is a term you would like to use, and skip checking.
# excludes:
# - EndOfSupport
# # RPC_NAMES_CASE rule option.
# rpc_names_case:
# # The specific convention the name should conforms to.
# ## Available conventions are "lower_camel_case", "upper_snake_case", or "lower_snake_case".
# convention: upper_snake_case
# MESSAGES_HAVE_COMMENT rule option.
messages_have_comment:
# Comments need to begin with the name of the thing being described. default is false.
should_follow_golang_style: true
# SERVICES_HAVE_COMMENT rule option.
services_have_comment:
# Comments need to begin with the name of the thing being described. default is false.
should_follow_golang_style: true
# RPCS_HAVE_COMMENT rule option.
rpcs_have_comment:
# Comments need to begin with the name of the thing being described. default is false.
should_follow_golang_style: true
# FIELDS_HAVE_COMMENT rule option.
fields_have_comment:
# Comments need to begin with the name of the thing being described. default is false.
should_follow_golang_style: true
# ENUMS_HAVE_COMMENT rule option.
enums_have_comment:
# Comments need to begin with the name of the thing being described. default is false.
should_follow_golang_style: true
# ENUM_FIELDS_HAVE_COMMENT rule option.
enum_fields_have_comment:
# Comments need to begin with the name of the thing being described. default is false.
should_follow_golang_style: true
# # SYNTAX_CONSISTENT rule option.
# syntax_consistent:
# # Default is proto3.
# version: proto2

View File

@ -36,41 +36,61 @@ Ref: https://keepachangelog.com/en/1.0.0/
# Changelog
## [v0.20.0-rc2] - 2022-11-02
## [v0.20.0-rc3] - 2022-11-30
### State Machine Breaking
* (deps) [#1423](https://github.com/evmos/ethermint/pull/1423) Bump Cosmos SDK to `v0.46.4`
* (deps) [#1419](https://github.com/evmos/ethermint/pull/1419) Add ics23 patch for dragonberry and bump iavl to v0.19.4
* (deps) [#1361](https://github.com/evmos/ethermint/pull/1361) Bump ibc-go to [`v5.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v5.0.0)
* (deps) [#1361](https://github.com/evmos/ethermint/pull/1361) Bump ibc-go to [`v5.1.0`](https://github.com/cosmos/ibc-go/releases/tag/v5.1.0)
* (evm) [\#1272](https://github.com/evmos/ethermint/pull/1272) Implement modular interface for the EVM.
* (deps) [#1168](https://github.com/evmos/ethermint/pull/1168) Upgrade Cosmos SDK to `v0.46`.
* (deps) [#1168](https://github.com/evmos/ethermint/pull/1168) Upgrade Cosmos SDK to [`v0.46.6`](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.6).
* (feemarket) [#1194](https://github.com/evmos/ethermint/pull/1194) Apply feemarket to native cosmos tx.
* (eth) [#1346](https://github.com/evmos/ethermint/pull/1346) Added support for `sdk.Dec` and `ed25519` type on eip712.
* (evm) [#1452](https://github.com/evmos/ethermint/pull/1452) Simplify Gas Math in `ApplyTransaction`.
* (eth) [#1430](https://github.com/evmos/ethermint/pull/1430) Added support for array of type `Any` on eip712. 
* (ante) [1460](https://github.com/evmos/ethermint/pull/1460) Add KV Gas config on ethereum Txs.
* (eth) [#1459](https://github.com/evmos/ethermint/pull/1459) Added support for messages with optional types omitted on eip712.
* (geth) [#1413](https://github.com/evmos/ethermint/pull/1413) Update go-ethereum version to [`v1.10.26`](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.26).
### API Breaking
* (ante) [#1214](https://github.com/evmos/ethermint/pull/1214) Set mempool priority to EVM transactions.
* (evm) [#1405](https://github.com/evmos/ethermint/pull/1405) Add parameter `chainID` to evm keeper's `EVMConfig` method, so caller can choose to not use the cached `eip155ChainID`.
### Features
- (app) [#1501](https://github.com/evmos/ethermint/pull/1501) Set default File store listener for application from [ADR38](https://docs.cosmos.network/v0.47/architecture/adr-038-state-listening)
### Improvements
* (tests) [#1507](https://github.com/evmos/ethermint/pull/1507) Remove legacy sim tests
* (feemarket) [#1508](https://github.com/evmos/ethermint/pull/1508) Remove old x/params migration logic
* (evm) [#1499](https://github.com/evmos/ethermint/pull/1499) Add Shanghai and Cancun block
* (ante) [#1455](https://github.com/evmos/ethermint/pull/1455) Refactor `AnteHandler` logic
* (evm) [#1444](https://github.com/evmos/ethermint/pull/1444) Improve performance of `eth_estimateGas`
* (ante) [\#1388](https://github.com/evmos/ethermint/pull/1388) Optimize AnteHandler gas consumption
* (lint) [#1298](https://github.com/evmos/ethermint/pull/1298) 150 character line length limit, `gofumpt`, and linting
* (feemarket) [\#1165](https://github.com/evmos/ethermint/pull/1165) Add hint in specs about different gas terminology in Cosmos and Ethereum.
* (cli) [#1226](https://github.com/evmos/ethermint/pull/1226) Add custom app db backend flag.
* (ante) [#1289](https://github.com/evmos/ethermint/pull/1289) Change the fallback tx priority mechanism to be based on gas price.
* (test) [#1311](https://github.com/evmos/ethermint/pull/1311) Add integration test for the `rollback` cmd
* (ledger) [#1277](https://github.com/evmos/ethermint/pull/1277) Add Ledger preprocessing transaction hook for EIP-712-signed Cosmos payloads.
* (rpc) [#1296](https://github.com/evmos/ethermint/pull/1296) Add RPC Backend unit tests.
* (rpc) [#1352](https://github.com/evmos/ethermint/pull/1352) Make the grpc queries run concurrently, don't block the consensus state machine.
* (cli) [#1360](https://github.com/evmos/ethermint/pull/1360) Introduce a new `grpc-only` flag, such that when enabled, will start the node in a query-only mode. Note, gRPC MUST be enabled with this flag.
* (rpc) [#1378](https://github.com/evmos/ethermint/pull/1378) Add support for EVM RPC metrics
* (ante) [#1390](https://github.com/evmos/ethermint/pull/1390) Added multisig tx support.
* (test) [#1396](https://github.com/evmos/ethermint/pull/1396) Increase test coverage for the EVM module `keeper`
* (ante) [#1397](https://github.com/evmos/ethermint/pull/1397) Refactor EIP-712 signature verification to support EIP-712 multi-signing.
* (deps) [#1416](https://github.com/evmos/ethermint/pull/1416) Bump Go version to `1.19`
* (cmd) [\#1417](https://github.com/evmos/ethermint/pull/1417) Apply Google CLI Syntax for required and optional args.
* (deps) [#1456](https://github.com/evmos/ethermint/pull/1456) Migrate errors-related functionality from "github.com/cosmos/cosmos-sdk/types/errors" (deprecated) to "cosmossdk.io/errors"
### Bug Fixes
* (app) [#1505](https://github.com/evmos/ethermint/pull/1505) Setup gRPC node service with the application.
* (server) [#1497](https://github.com/evmos/ethermint/pull/1497) Fix telemetry server setup for observability
* (rpc) [#1442](https://github.com/evmos/ethermint/pull/1442) Fix decoding of `finalized` block number.
* (rpc) [#1179](https://github.com/evmos/ethermint/pull/1179) Fix gas used in traceTransaction response.
* (rpc) [#1284](https://github.com/evmos/ethermint/pull/1284) Fix internal trace response upon incomplete `eth_sendTransaction` call.
* (rpc) [#1340](https://github.com/evmos/ethermint/pull/1340) Fix error response when `eth_estimateGas` height provided is not found.
@ -78,6 +98,13 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (cli) [#1362](https://github.com/evmos/ethermint/pull/1362) Fix `index-eth-tx` error when the indexer db is empty.
* (state) [#1320](https://github.com/evmos/ethermint/pull/1320) Fix codehash check mismatch when the code has been deleted in the evm state.
* (rpc) [#1392](https://github.com/evmos/ethermint/pull/1392) Allow fill the proposer address in json-rpc through tendermint api, and pass explicitly to grpc query handler.
* (rpc) [#1431](https://github.com/evmos/ethermint/pull/1431) Align hex-strings proof fields in `eth_getProof` as Ethereum.
* (proto) [#1466](https://github.com/evmos/ethermint/pull/1466) Fix proto scripts and upgrade them to mirror current cosmos-sdk scripts
* (rpc) [#1405](https://github.com/evmos/ethermint/pull/1405) Fix uninitialized chain ID field in gRPC requests.
* (analytics) [#1434](https://github.com/evmos/ethermint/pull/1434) Remove unbound labels from custom tendermint metrics.
* (rpc) [#1484](https://github.com/evmos/ethermint/pull/1484) Align empty account result for old blocks as ethereum instead of return account not found error.
* (rpc) [#1503](https://github.com/evmos/ethermint/pull/1503) Fix block hashes returned on JSON-RPC filter `eth_newBlockFilter`.
## [v0.19.3] - 2022-10-14
@ -211,7 +238,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (evm) [tharsis#1088](https://github.com/evmos/ethermint/pull/1088) Fix ability to append log in tx post processing.
* (rpc) [tharsis#1081](https://github.com/evmos/ethermint/pull/1081) fix `debug_getBlockRlp`/`debug_printBlock` don't filter failed transactions.
* (ante) [tharsis#1111](https://github.com/evmos/ethermint/pull/1111) Move CanTransfer decorator before GasConsume decorator
* (types) [tharsis#1112](https://github.com/cosmos/ethermint/pull/1112) Add `GetBaseAccount` to avoid invalid account error when create vesting account.
* (types) [tharsis#1112](https://github.com/evmos/ethermint/pull/1112) Add `GetBaseAccount` to avoid invalid account error when create vesting account.
## [v0.15.0] - 2022-05-09
@ -647,7 +674,7 @@ the Tracer type used to collect execution traces from the EVM transaction execut
### Improvements
* (deps) [tharsis#615](https://github.com/cosmos/ethermint/pull/615) Bump Cosmos SDK version to [v0.39.2](https://github.com/cosmos/cosmos-sdk/tag/v0.39.2)
* (deps) [tharsis#615](https://github.com/cosmos/ethermint/pull/615) Bump Cosmos SDK version to [v0.39.2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.39.2)
* (deps) [tharsis#610](https://github.com/cosmos/ethermint/pull/610) Update Go dependency to 1.15+.
* (evm) [tharsis#603](https://github.com/cosmos/ethermint/pull/603) Add state transition params that enable or disable the EVM `Call` and `Create` operations.
* (deps) [tharsis#602](https://github.com/cosmos/ethermint/pull/602) Bump tendermint version to [v0.33.9](https://github.com/tendermint/tendermint/releases/tag/v0.33.9)

View File

@ -17,7 +17,7 @@ COPY . .
RUN make build
# Final image
FROM alpine:3.16.2
FROM alpine:3.17.0
# Install ca-certificates
RUN apk add --update ca-certificates jq

141
Makefile Executable file → Normal file
View File

@ -14,7 +14,6 @@ SIMAPP = ./app
HTTPS_GIT := https://github.com/evmos/ethermint.git
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
DOCKER := $(shell which docker)
DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf:1.0.0-rc8
# RocksDB is a native dependency, so we don't assume the library is installed.
# Instead, it must be explicitly enabled and we warn when it is not.
ENABLE_ROCKSDB ?= false
@ -328,9 +327,6 @@ test-import:
test-rpc:
./scripts/integration-test-all.sh -t "rpc" -q 1 -z 1 -s 2 -m "rpc" -r "true"
test-integration:
./scripts/integration-test-all.sh -t "integration" -q 1 -z 1 -s 2 -m "integration" -r "true"
run-integration-tests:
@nix-shell ./tests/integration_tests/shell.nix --run ./scripts/run-integration-tests.sh
@ -347,51 +343,6 @@ test-solidity:
.PHONY: run-tests test test-all test-import test-rpc test-contract test-solidity $(TEST_TARGETS)
test-sim-nondeterminism:
@echo "Running non-determinism test..."
@go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \
-NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h
test-sim-random-genesis-fast:
@echo "Running random genesis simulation..."
@go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation \
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h
test-sim-import-export: runsim
@echo "Running application import/export simulation. This may take several minutes..."
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport
test-sim-after-import: runsim
@echo "Running application simulation-after-import. This may take several minutes..."
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppSimulationAfterImport
test-sim-random-genesis-multi-seed: runsim
@echo "Running multi-seed custom genesis simulation..."
@$(BINDIR)/runsim -SimAppPkg=$(SIMAPP) -ExitOnFail 400 5 TestFullAppSimulation
test-sim-multi-seed-long: runsim
@echo "Running long multi-seed application simulation. This may take awhile!"
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation
test-sim-multi-seed-short: runsim
@echo "Running short multi-seed application simulation. This may take awhile!"
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation
test-sim-benchmark-invariants:
@echo "Running simulation invariant benchmarks..."
@go test -mod=readonly $(SIMAPP) -benchmem -bench=BenchmarkInvariants -run=^$ \
-Enabled=true -NumBlocks=1000 -BlockSize=200 \
-Period=1 -Commit=true -Seed=57 -v -timeout 24h
.PHONY: \
test-sim-nondeterminism \
test-sim-custom-genesis-fast \
test-sim-import-export \
test-sim-after-import \
test-sim-custom-genesis-multi-seed \
test-sim-multi-seed-short \
test-sim-multi-seed-long \
test-sim-benchmark-invariants
benchmark:
@go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION)
@ -425,74 +376,62 @@ format-fix:
### Protobuf ###
###############################################################################
protoVer=v0.2
# ------
# NOTE: Link to the tendermintdev/sdk-proto-gen docker images:
# https://hub.docker.com/r/tendermintdev/sdk-proto-gen/tags
#
protoVer=v0.7
protoImageName=tendermintdev/sdk-proto-gen:$(protoVer)
containerProtoGen=$(PROJECT_NAME)-proto-gen-$(protoVer)
containerProtoGenAny=$(PROJECT_NAME)-proto-gen-any-$(protoVer)
containerProtoGenSwagger=$(PROJECT_NAME)-proto-gen-swagger-$(protoVer)
containerProtoFmt=$(PROJECT_NAME)-proto-fmt-$(protoVer)
protoImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)
# ------
# NOTE: cosmos/proto-builder image is needed because clang-format is not installed
# on the tendermintdev/sdk-proto-gen docker image.
# Link to the cosmos/proto-builder docker images:
# https://github.com/cosmos/cosmos-sdk/pkgs/container/proto-builder
#
protoCosmosVer=0.11.2
protoCosmosName=ghcr.io/cosmos/proto-builder:$(protoCosmosVer)
protoCosmosImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protoCosmosName)
# ------
# NOTE: Link to the yoheimuta/protolint docker images:
# https://hub.docker.com/r/yoheimuta/protolint/tags
#
protolintVer=0.42.2
protolintName=yoheimuta/protolint:$(protolintVer)
protolintImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protolintName)
# ------
# NOTE: If you are experiencing problems running these commands, try deleting
# the docker images and execute the desired command again.
#
proto-all: proto-format proto-lint proto-gen
proto-gen:
@echo "Generating Protobuf files"
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
sh ./scripts/protocgen.sh; fi
$(protoImage) sh ./scripts/protocgen.sh
proto-swagger-gen:
@echo "Generating Protobuf Swagger"
@./scripts/proto-tools-installer.sh
@./scripts/protoc-swagger-gen.sh
# TODO: Rethink API docs generation
# proto-swagger-gen:
# @echo "Generating Protobuf Swagger"
# $(protoImage) sh ./scripts/protoc-swagger-gen.sh
proto-format:
@echo "Formatting Protobuf files"
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \
find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi
$(protoCosmosImage) find ./ -name *.proto -exec clang-format -i {} \;
# NOTE: The linter configuration lives in .protolint.yaml
proto-lint:
@$(DOCKER_BUF) lint --error-format=json
@echo "Linting Protobuf files"
$(protolintImage) lint ./proto
proto-check-breaking:
@$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main
@echo "Checking Protobuf files for breaking changes"
$(protoImage) buf breaking --against $(HTTPS_GIT)#branch=main
TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.12/proto/tendermint
GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos
COSMOS_SDK_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/v0.43.0
COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master
TM_CRYPTO_TYPES = third_party/proto/tendermint/crypto
TM_ABCI_TYPES = third_party/proto/tendermint/abci
TM_TYPES = third_party/proto/tendermint/types
GOGO_PROTO_TYPES = third_party/proto/gogoproto
COSMOS_PROTO_TYPES = third_party/proto/cosmos_proto
proto-update-deps:
@mkdir -p $(GOGO_PROTO_TYPES)
@curl -sSL $(GOGO_PROTO_URL)/gogoproto/gogo.proto > $(GOGO_PROTO_TYPES)/gogo.proto
@mkdir -p $(COSMOS_PROTO_TYPES)
@curl -sSL $(COSMOS_PROTO_URL)/cosmos.proto > $(COSMOS_PROTO_TYPES)/cosmos.proto
## Importing of tendermint protobuf definitions currently requires the
## use of `sed` in order to build properly with cosmos-sdk's proto file layout
## (which is the standard Buf.build FILE_LAYOUT)
## Issue link: https://github.com/tendermint/tendermint/issues/5021
@mkdir -p $(TM_ABCI_TYPES)
@curl -sSL $(TM_URL)/abci/types.proto > $(TM_ABCI_TYPES)/types.proto
@mkdir -p $(TM_TYPES)
@curl -sSL $(TM_URL)/types/types.proto > $(TM_TYPES)/types.proto
@mkdir -p $(TM_CRYPTO_TYPES)
@curl -sSL $(TM_URL)/crypto/proof.proto > $(TM_CRYPTO_TYPES)/proof.proto
@curl -sSL $(TM_URL)/crypto/keys.proto > $(TM_CRYPTO_TYPES)/keys.proto
.PHONY: proto-all proto-gen proto-gen-any proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps
.PHONY: proto-all proto-gen proto-gen-any proto-format proto-lint proto-check-breaking
###############################################################################
### Localnet ###

View File

@ -6,9 +6,10 @@ import (
tmlog "github.com/tendermint/tendermint/libs/log"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@ -51,8 +52,8 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
// cosmos-sdk tx with dynamic fee extension
anteHandler = newCosmosAnteHandler(options)
default:
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrUnknownExtensionOptions,
return ctx, errorsmod.Wrapf(
errortypes.ErrUnknownExtensionOptions,
"rejecting tx with unsupported extension option: %s", typeURL,
)
}
@ -66,7 +67,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
case sdk.Tx:
anteHandler = newCosmosAnteHandler(options)
default:
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid transaction type: %T", tx)
}
return anteHandler(ctx, tx, sim)
@ -75,7 +76,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
func Recover(logger tmlog.Logger, err *error) {
if r := recover(); r != nil {
*err = sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)
*err = errorsmod.Wrapf(errortypes.ErrPanic, "%v", r)
if e, ok := r.(error); ok {
logger.Error(

View File

@ -31,6 +31,7 @@ import (
evmtypes "github.com/evmos/ethermint/x/evm/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)
func (suite AnteTestSuite) TestAnteHandler() {
@ -348,6 +349,17 @@ func (suite AnteTestSuite) TestAnteHandler() {
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 create validator (with blank fields)",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgCreateValidator2(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 MsgSubmitProposal",
func() sdk.Tx {
@ -375,7 +387,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
from, grantee, &banktypes.SendAuthorization{SpendLimit: gasAmount}, &expiresAt,
)
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, privKey, "ethermint_9000-1", gas, gasAmount, msg).GetTx()
return suite.CreateTestEIP712SingleMessageTxBuilder(from, privKey, "ethermint_9000-1", gas, gasAmount, msg).GetTx()
}, false, false, true,
},
@ -408,10 +420,65 @@ func (suite AnteTestSuite) TestAnteHandler() {
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgEditValidator(from, privKey, "ethermint_9000-1", gas, amount)
txBuilder := suite.CreateTestEIP712MsgSubmitEvidence(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 submit proposal v1",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712SubmitProposalV1(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 MsgExec",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgExec(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 MsgVoteV1",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgVoteV1(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 Multiple MsgSend",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MultipleMsgSend(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"fails - DeliverTx EIP712 Multiple Signers",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MultipleSignerMsgs(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, false,
},
{
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
func() sdk.Tx {
@ -507,6 +574,301 @@ func (suite AnteTestSuite) TestAnteHandler() {
return tx
}, true, false, false,
},
{
"passes - Single-signer EIP-712",
func() sdk.Tx {
msg := banktypes.NewMsgSend(
sdk.AccAddress(privKey.PubKey().Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSingleSignedTx(
privKey,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"EIP-712",
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"passes - EIP-712 multi-key",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"EIP-712",
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"passes - Mixed multi-key",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"mixed", // Combine EIP-712 and standard signatures
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"passes - Mixed multi-key with MsgVote",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := govtypes.NewMsgVote(
sdk.AccAddress(pk.Address()),
1,
govtypes.OptionYes,
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"mixed", // Combine EIP-712 and standard signatures
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"Fails - Multi-Key with incorrect Chain ID",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9005-1",
2000000,
"mixed",
)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with incorrect sign mode",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000000,
"mixed",
)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with too little gas",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"mixed", // Combine EIP-712 and standard signatures
)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with different payload than one signed",
func() sdk.Tx {
numKeys := 1
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"EIP-712",
)
msg.Amount[0].Amount = sdk.NewInt(5)
txBuilder.SetMsgs(msg)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with messages added after signing",
func() sdk.Tx {
numKeys := 1
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"EIP-712",
)
// Duplicate
txBuilder.SetMsgs(msg, msg)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Single-Signer EIP-712 with messages added after signing",
func() sdk.Tx {
msg := banktypes.NewMsgSend(
sdk.AccAddress(privKey.PubKey().Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSingleSignedTx(
privKey,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"EIP-712",
)
txBuilder.SetMsgs(msg, msg)
return txBuilder.GetTx()
}, false, false, false,
},
}
for _, tc := range testCases {
@ -939,7 +1301,7 @@ func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() {
multisigKey1 := kmultisig.NewLegacyAminoPubKey(2, pkSet1)
multisignature1 := multisig.NewMultisig(len(pkSet1))
expectedCost1 := expectedGasCostByKeys(pkSet1)
for i := 0; i < len(pkSet1); i++ {
stdSig := legacytx.StdSignature{PubKey: pkSet1[i], Signature: sigSet1[i]}
sigV2, err := legacytx.StdSignatureToSignatureV2(cdc, stdSig)

View File

@ -3,11 +3,12 @@ package ante
import (
"fmt"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
@ -15,9 +16,11 @@ import (
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/evmos/ethermint/ethereum/eip712"
ethermint "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
)
@ -61,12 +64,12 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", tx)
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", tx)
}
authSignTx, ok := tx.(authsigning.Tx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", tx)
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", tx)
}
// stdSigs contains the sequence number, account number, and signatures.
@ -80,12 +83,16 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
// EIP712 allows just one signature
if len(sigs) != 1 {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signers (%d); EIP712 signatures allows just one signature", len(sigs))
return ctx, errorsmod.Wrapf(
errortypes.ErrTooManySignatures,
"invalid number of signers (%d); EIP712 signatures allows just one signature",
len(sigs),
)
}
// check that signer length and signature length are the same
if len(sigs) != len(signerAddrs) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
return ctx, errorsmod.Wrapf(errortypes.ErrorInvalidSigner, "invalid number of signers; expected: %d, got %d", len(signerAddrs), len(sigs))
}
// EIP712 has just one signature, avoid looping here and only read index 0
@ -100,13 +107,13 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
// retrieve pubkey
pubKey := acc.GetPubKey()
if !simulate && pubKey == nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
return ctx, errorsmod.Wrap(errortypes.ErrInvalidPubKey, "pubkey on account is not set")
}
// Check account sequence number.
if sig.Sequence != acc.GetSequence() {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrWrongSequence,
return ctx, errorsmod.Wrapf(
errortypes.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}
@ -132,7 +139,7 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
if err := VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx); err != nil {
errMsg := fmt.Errorf("signature verification failed; please verify account number (%d) and chain-id (%s): %w", accNum, chainID, err)
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg.Error())
return ctx, errorsmod.Wrap(errortypes.ErrUnauthorized, errMsg.Error())
}
return next(ctx, tx, simulate)
@ -150,12 +157,12 @@ func VerifySignature(
switch data := sigData.(type) {
case *signing.SingleSignatureData:
if data.SignMode != signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON {
return sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "unexpected SignatureData %T: wrong SignMode", sigData)
return errorsmod.Wrapf(errortypes.ErrNotSupported, "unexpected SignatureData %T: wrong SignMode", sigData)
}
// Note: this prevents the user from sending thrash data in the signature field
// Note: this prevents the user from sending trash data in the signature field
if len(data.Signature) != 0 {
return sdkerrors.Wrap(sdkerrors.ErrTooManySignatures, "invalid signature value; EIP712 must have the cosmos transaction signature empty")
return errorsmod.Wrap(errortypes.ErrTooManySignatures, "invalid signature value; EIP712 must have the cosmos transaction signature empty")
}
// @contract: this code is reached only when Msg has Web3Tx extension (so this custom Ante handler flow),
@ -163,7 +170,7 @@ func VerifySignature(
msgs := tx.GetMsgs()
if len(msgs) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrNoSignatures, "tx doesn't contain any msgs to verify signature")
return errorsmod.Wrap(errortypes.ErrNoSignatures, "tx doesn't contain any msgs to verify signature")
}
txBytes := legacytx.StdSignBytes(
@ -180,33 +187,33 @@ func VerifySignature(
signerChainID, err := ethermint.ParseChainID(signerData.ChainID)
if err != nil {
return sdkerrors.Wrapf(err, "failed to parse chainID: %s", signerData.ChainID)
return errorsmod.Wrapf(err, "failed to parse chain-id: %s", signerData.ChainID)
}
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
if !ok {
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "tx doesnt contain any extensions")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "tx doesnt contain any extensions")
}
opts := txWithExtensions.GetExtensionOptions()
if len(opts) != 1 {
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "tx doesnt contain expected amount of extension options")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "tx doesnt contain expected amount of extension options")
}
extOpt, ok := opts[0].GetCachedValue().(*ethermint.ExtensionOptionsWeb3Tx)
if !ok {
return sdkerrors.Wrap(sdkerrors.ErrInvalidChainID, "unknown extension option")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "unknown extension option")
}
if extOpt.TypedDataChainID != signerChainID.Uint64() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidChainID, "invalid chainID")
return errorsmod.Wrap(errortypes.ErrInvalidChainID, "invalid chain-id")
}
if len(extOpt.FeePayer) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "no feePayer on ExtensionOptionsWeb3Tx")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "no feePayer on ExtensionOptionsWeb3Tx")
}
feePayer, err := sdk.AccAddressFromBech32(extOpt.FeePayer)
if err != nil {
return sdkerrors.Wrap(err, "failed to parse feePayer from ExtensionOptionsWeb3Tx")
return errorsmod.Wrap(err, "failed to parse feePayer from ExtensionOptionsWeb3Tx")
}
feeDelegation := &eip712.FeeDelegationOptions{
@ -215,17 +222,17 @@ func VerifySignature(
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
if err != nil {
return sdkerrors.Wrap(err, "failed to pack tx data in EIP712 object")
return errorsmod.Wrap(err, "failed to create EIP-712 typed data from tx")
}
sigHash, err := eip712.ComputeTypedDataHash(typedData)
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
if err != nil {
return err
}
feePayerSig := extOpt.FeePayerSig
if len(feePayerSig) != ethcrypto.SignatureLength {
return sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, "signature length doesn't match typical [R||S||V] signature 65 bytes")
return errorsmod.Wrap(errortypes.ErrorInvalidSigner, "signature length doesn't match typical [R||S||V] signature 65 bytes")
}
// Remove the recovery offset if needed (ie. Metamask eip712 signature)
@ -235,12 +242,12 @@ func VerifySignature(
feePayerPubkey, err := secp256k1.RecoverPubkey(sigHash, feePayerSig)
if err != nil {
return sdkerrors.Wrap(err, "failed to recover delegated fee payer from sig")
return errorsmod.Wrap(err, "failed to recover delegated fee payer from sig")
}
ecPubKey, err := ethcrypto.UnmarshalPubkey(feePayerPubkey)
if err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal recovered fee payer pubkey")
return errorsmod.Wrap(err, "failed to unmarshal recovered fee payer pubkey")
}
pk := &ethsecp256k1.PubKey{
@ -248,23 +255,23 @@ func VerifySignature(
}
if !pubKey.Equals(pk) {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "feePayer pubkey %s is different from transaction pubkey %s", pubKey, pk)
return errorsmod.Wrapf(errortypes.ErrInvalidPubKey, "feePayer pubkey %s is different from transaction pubkey %s", pubKey, pk)
}
recoveredFeePayerAcc := sdk.AccAddress(pk.Address().Bytes())
if !recoveredFeePayerAcc.Equals(feePayer) {
return sdkerrors.Wrapf(sdkerrors.ErrorInvalidSigner, "failed to verify delegated fee payer %s signature", recoveredFeePayerAcc)
return errorsmod.Wrapf(errortypes.ErrorInvalidSigner, "failed to verify delegated fee payer %s signature", recoveredFeePayerAcc)
}
// VerifySignature of ethsecp256k1 accepts 64 byte signature [R||S]
// WARNING! Under NO CIRCUMSTANCES try to use pubKey.VerifySignature there
if !secp256k1.VerifySignature(pubKey.Bytes(), sigHash, feePayerSig[:len(feePayerSig)-1]) {
return sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, "unable to verify signer signature of EIP712 typed data")
return errorsmod.Wrap(errortypes.ErrorInvalidSigner, "unable to verify signer signature of EIP712 typed data")
}
return nil
default:
return sdkerrors.Wrapf(sdkerrors.ErrTooManySignatures, "unexpected SignatureData %T", sigData)
return errorsmod.Wrapf(errortypes.ErrTooManySignatures, "unexpected SignatureData %T", sigData)
}
}

View File

@ -1,19 +1,17 @@
package ante
import (
"errors"
"math"
"math/big"
"strconv"
errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
ethermint "github.com/evmos/ethermint/types"
evmkeeper "github.com/evmos/ethermint/x/evm/keeper"
"github.com/evmos/ethermint/x/evm/keeper"
"github.com/evmos/ethermint/x/evm/statedb"
evmtypes "github.com/evmos/ethermint/x/evm/types"
@ -21,60 +19,6 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// EthSigVerificationDecorator validates an ethereum signatures
type EthSigVerificationDecorator struct {
evmKeeper EVMKeeper
}
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
return EthSigVerificationDecorator{
evmKeeper: ek,
}
}
// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
// that the signer address matches the one defined on the message.
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
// won't see the error message.
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
chainID := esvd.evmKeeper.ChainID()
chainCfg := esvd.evmKeeper.GetChainConfig(ctx)
ethCfg := chainCfg.EthereumConfig(chainID)
blockNum := big.NewInt(ctx.BlockHeight())
signer := ethtypes.MakeSigner(ethCfg, blockNum)
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
allowUnprotectedTxs := esvd.evmKeeper.GetAllowUnprotectedTxs(ctx)
ethTx := msgEthTx.AsTransaction()
if !allowUnprotectedTxs && !ethTx.Protected() {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrNotSupported,
"rejected unprotected Ethereum txs. Please EIP155 sign your transaction to protect it against replay-attacks")
}
sender, err := signer.Sender(ethTx)
if err != nil {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrorInvalidSigner,
"couldn't retrieve sender address from the ethereum transaction: %s",
err.Error(),
)
}
// set up the sender to the transaction field if not already
msgEthTx.From = sender.Hex()
}
return next(ctx, tx, simulate)
}
// EthAccountVerificationDecorator validates an account balance checks
type EthAccountVerificationDecorator struct {
ak evmtypes.AccountKeeper
@ -108,18 +52,18 @@ func (avd EthAccountVerificationDecorator) AnteHandle(
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data any for tx %d", i)
return ctx, errorsmod.Wrapf(err, "failed to unpack tx data any for tx %d", i)
}
// sender address should be in the tx cache from the previous AnteHandle call
from := msgEthTx.GetFrom()
if from.Empty() {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "from address cannot be empty")
return ctx, errorsmod.Wrap(errortypes.ErrInvalidAddress, "from address cannot be empty")
}
// check whether the sender address is EOA
@ -131,12 +75,12 @@ func (avd EthAccountVerificationDecorator) AnteHandle(
avd.ak.SetAccount(ctx, acc)
acct = statedb.NewEmptyAccount()
} else if acct.IsContract() {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType,
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
}
if err := evmkeeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
return ctx, sdkerrors.Wrap(err, "failed to check sender balance")
if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
return ctx, errorsmod.Wrap(err, "failed to check sender balance")
}
}
return next(ctx, tx, simulate)
@ -164,7 +108,7 @@ func NewEthGasConsumeDecorator(
// (during CheckTx only) and that the sender has enough balance to pay for the gas cost.
//
// Intrinsic gas for a transaction is the amount of gas that the transaction uses before the
// transaction is executed. The gas is a constant value plus any cost inccured by additional bytes
// transaction is executed. The gas is a constant value plus any cost incurred by additional bytes
// of data supplied with the transaction.
//
// This AnteHandler decorator will fail if:
@ -174,29 +118,36 @@ func NewEthGasConsumeDecorator(
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
// - transaction or block gas meter runs out of gas
// - sets the gas meter limit
// - gas limit is greater than the block gas meter limit
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// gas consumption limit already checked during CheckTx so there's no need to
// verify it again during ReCheckTx
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
chainCfg := egcd.evmKeeper.GetChainConfig(ctx)
ethCfg := chainCfg.EthereumConfig(egcd.evmKeeper.ChainID())
blockHeight := big.NewInt(ctx.BlockHeight())
homestead := ethCfg.IsHomestead(blockHeight)
istanbul := ethCfg.IsIstanbul(blockHeight)
london := ethCfg.IsLondon(blockHeight)
gasWanted := uint64(0)
var events sdk.Events
// Use the lowest priority of all the messages as the final one.
minPriority := int64(math.MaxInt64)
baseFee := egcd.evmKeeper.GetBaseFee(ctx, ethCfg)
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
return ctx, errorsmod.Wrap(err, "failed to unpack tx data")
}
if ctx.IsCheckTx() && egcd.maxGasWanted != 0 {
@ -211,45 +162,58 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
}
evmDenom := egcd.evmKeeper.GetEVMDenom(ctx)
fees, priority, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
ctx,
*msgEthTx,
txData,
evmDenom,
homestead,
istanbul,
london,
)
fees, err := keeper.VerifyFee(txData, evmDenom, baseFee, homestead, istanbul, ctx.IsCheckTx())
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance")
return ctx, errorsmod.Wrapf(err, "failed to verify the fees")
}
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
err = egcd.evmKeeper.DeductTxCostsFromUserBalance(ctx, fees, common.HexToAddress(msgEthTx.From))
if err != nil {
return ctx, errorsmod.Wrapf(err, "failed to deduct transaction costs from user balance")
}
events = append(events,
sdk.NewEvent(
sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeyFee, fees.String()),
),
)
priority := evmtypes.GetTxPriority(txData, baseFee)
if priority < minPriority {
minPriority = priority
}
}
// TODO: change to typed events
ctx.EventManager().EmitEvents(events)
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
blockGasLimit := ethermint.BlockGasLimit(ctx)
// NOTE: safety check
if blockGasLimit > 0 {
// generate a copy of the gas pool (i.e block gas meter) to see if we've run out of gas for this block
// if current gas consumed is greater than the limit, this funcion panics and the error is recovered on the Baseapp
gasPool := sdk.NewGasMeter(blockGasLimit)
gasPool.ConsumeGas(ctx.GasMeter().GasConsumedToLimit(), "gas pool check")
// return error if the tx gas is greater than the block limit (max gas)
// NOTE: it's important here to use the gas wanted instead of the gas consumed
// from the tx gas pool. The later only has the value so far since the
// EthSetupContextDecorator so it will never exceed the block gas limit.
if gasWanted > blockGasLimit {
return ctx, errorsmod.Wrapf(
errortypes.ErrOutOfGas,
"tx gas (%d) exceeds block gas limit (%d)",
gasWanted,
blockGasLimit,
)
}
// Set ctx.GasMeter with a limit of GasWanted (gasLimit)
gasConsumed := ctx.GasMeter().GasConsumed()
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
// Set tx GasMeter with a limit of GasWanted (i.e gas limit from the Ethereum tx).
// The gas consumed will be then reset to the gas used by the state transition
// in the EVM.
newCtx := ctx.WithPriority(minPriority)
// FIXME: use a custom gas configuration that doesn't add any additional gas and only
// takes into account the gas consumed at the end of the EVM transaction.
newCtx := ctx.
WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted)).
WithPriority(minPriority)
// we know that we have enough gas on the pool to cover the intrinsic gas
return next(newCtx, tx, simulate)
@ -278,19 +242,35 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
baseFee := ctd.evmKeeper.GetBaseFee(ctx, ethCfg)
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
if err != nil {
return ctx, sdkerrors.Wrapf(
return ctx, errorsmod.Wrapf(
err,
"failed to create an ethereum core.Message from signer %T", signer,
)
}
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
if baseFee == nil {
return ctx, errorsmod.Wrap(
evmtypes.ErrInvalidBaseFee,
"base fee is supported but evm block context value is nil",
)
}
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
return ctx, errorsmod.Wrapf(
errortypes.ErrInsufficientFee,
"max fee per gas less than block base fee (%s < %s)",
coreMsg.GasFeeCap(), baseFee,
)
}
}
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
cfg := &evmtypes.EVMConfig{
ChainConfig: ethCfg,
@ -304,29 +284,13 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
// check that caller has enough balance to cover asset transfer for **topmost** call
// NOTE: here the gas consumed is from the context with the infinite gas meter
if coreMsg.Value().Sign() > 0 && !evm.Context().CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFunds,
return ctx, errorsmod.Wrapf(
errortypes.ErrInsufficientFunds,
"failed to transfer %s from address %s using the EVM block context transfer function",
coreMsg.Value(),
coreMsg.From(),
)
}
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
if baseFee == nil {
return ctx, sdkerrors.Wrap(
evmtypes.ErrInvalidBaseFee,
"base fee is supported but evm block context value is nil",
)
}
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFee,
"max fee per gas less than block base fee (%s < %s)",
coreMsg.GasFeeCap(), baseFee,
)
}
}
}
return next(ctx, tx, simulate)
@ -351,19 +315,19 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
return ctx, errorsmod.Wrap(err, "failed to unpack tx data")
}
// increase sequence of sender
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
if acc == nil {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrUnknownAddress,
return ctx, errorsmod.Wrapf(
errortypes.ErrUnknownAddress,
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
)
}
@ -372,14 +336,14 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
// we merged the nonce verification to nonce increment, so when tx includes multiple messages
// with same sender, they'll be accepted.
if txData.GetNonce() != nonce {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInvalidSequence,
return ctx, errorsmod.Wrapf(
errortypes.ErrInvalidSequence,
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
)
}
if err := acc.SetSequence(nonce + 1); err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
return ctx, errorsmod.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
}
issd.ak.SetAccount(ctx, acc)
@ -387,220 +351,3 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
return next(ctx, tx, simulate)
}
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
type EthValidateBasicDecorator struct {
evmKeeper EVMKeeper
}
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
func NewEthValidateBasicDecorator(ek EVMKeeper) EthValidateBasicDecorator {
return EthValidateBasicDecorator{
evmKeeper: ek,
}
}
// AnteHandle handles basic validation of tx
func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// no need to validate basic on recheck tx, call next antehandler
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
err := tx.ValidateBasic()
// ErrNoSignatures is fine with eth tx
if err != nil && !errors.Is(err, sdkerrors.ErrNoSignatures) {
return ctx, sdkerrors.Wrap(err, "tx basic validation failed")
}
// For eth type cosmos tx, some fields should be veified as zero values,
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
wrapperTx, ok := tx.(protoTxProvider)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid tx type %T, didn't implement interface protoTxProvider", tx)
}
protoTx := wrapperTx.GetProtoTx()
body := protoTx.Body
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
}
if len(body.ExtensionOptions) != 1 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
}
txFee := sdk.Coins{}
txGasLimit := uint64(0)
chainCfg := vbd.evmKeeper.GetChainConfig(ctx)
chainID := vbd.evmKeeper.ChainID()
ethCfg := chainCfg.EthereumConfig(chainID)
baseFee := vbd.evmKeeper.GetBaseFee(ctx, ethCfg)
enableCreate := vbd.evmKeeper.GetEnableCreate(ctx)
enableCall := vbd.evmKeeper.GetEnableCall(ctx)
evmDenom := vbd.evmKeeper.GetEVMDenom(ctx)
for _, msg := range protoTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
// Validate `From` field
if msgEthTx.From != "" {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid From %s, expect empty string", msgEthTx.From)
}
txGasLimit += msgEthTx.GetGas()
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data")
}
// return error if contract creation or call are disabled through governance
if !enableCreate && txData.GetTo() == nil {
return ctx, sdkerrors.Wrap(evmtypes.ErrCreateDisabled, "failed to create new contract")
} else if !enableCall && txData.GetTo() != nil {
return ctx, sdkerrors.Wrap(evmtypes.ErrCallDisabled, "failed to call contract")
}
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
return ctx, sdkerrors.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
}
txFee = txFee.Add(sdk.NewCoin(evmDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
}
authInfo := protoTx.AuthInfo
if len(authInfo.SignerInfos) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
}
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
}
if !authInfo.Fee.Amount.IsEqual(txFee) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
}
if authInfo.Fee.GasLimit != txGasLimit {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
}
sigs := protoTx.Signatures
if len(sigs) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty")
}
return next(ctx, tx, simulate)
}
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
// by setting the gas meter to infinite
type EthSetupContextDecorator struct {
evmKeeper EVMKeeper
}
func NewEthSetUpContextDecorator(evmKeeper EVMKeeper) EthSetupContextDecorator {
return EthSetupContextDecorator{
evmKeeper: evmKeeper,
}
}
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// all transactions must implement GasTx
_, ok := tx.(authante.GasTx)
if !ok {
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
// Reset transient gas used to prepare the execution of current cosmos tx.
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
esc.evmKeeper.ResetTransientGasUsed(ctx)
return next(newCtx, tx, simulate)
}
// EthMempoolFeeDecorator will check if the transaction's effective fee is at least as large
// as the local validator's minimum gasFee (defined in validator config).
// If fee is too low, decorator returns error and tx is rejected from mempool.
// Note this only applies when ctx.CheckTx = true
// If fee is high enough or not CheckTx, then call next AnteHandler
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
type EthMempoolFeeDecorator struct {
evmKeeper EVMKeeper
}
func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
return EthMempoolFeeDecorator{
evmKeeper: ek,
}
}
// AnteHandle ensures that the provided fees meet a minimum threshold for the validator,
// if this is a CheckTx. This is only for local mempool purposes, and thus
// is only ran on check tx.
// It only do the check if london hardfork not enabled or feemarket not enabled, because in that case feemarket will take over the task.
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if ctx.IsCheckTx() && !simulate {
chainCfg := mfd.evmKeeper.GetChainConfig(ctx)
ethCfg := chainCfg.EthereumConfig(mfd.evmKeeper.ChainID())
baseFee := mfd.evmKeeper.GetBaseFee(ctx, ethCfg)
evmDenom := mfd.evmKeeper.GetEVMDenom(ctx)
if baseFee == nil {
for _, msg := range tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
feeAmt := ethMsg.GetFee()
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeAmt, requiredFee)
}
}
}
}
return next(ctx, tx, simulate)
}
// EthEmitEventDecorator emit events in ante handler in case of tx execution failed (out of block gas limit).
type EthEmitEventDecorator struct {
evmKeeper EVMKeeper
}
// NewEthEmitEventDecorator creates a new EthEmitEventDecorator
func NewEthEmitEventDecorator(evmKeeper EVMKeeper) EthEmitEventDecorator {
return EthEmitEventDecorator{evmKeeper}
}
// AnteHandle emits some basic events for the eth messages
func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// After eth tx passed ante handler, the fee is deducted and nonce increased, it shouldn't be ignored by json-rpc,
// we need to emit some basic events at the very end of ante handler to be indexed by tendermint.
txIndex := eeed.evmKeeper.GetTxIndexTransient(ctx)
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
// emit ethereum tx hash as event, should be indexed by tm tx indexer for query purpose.
// it's emitted in ante handler so we can query failed transaction (out of block gas limit).
ctx.EventManager().EmitEvent(sdk.NewEvent(
evmtypes.EventTypeEthereumTx,
sdk.NewAttribute(evmtypes.AttributeKeyEthereumTxHash, msgEthTx.Hash),
sdk.NewAttribute(evmtypes.AttributeKeyTxIndex, strconv.FormatUint(txIndex+uint64(i), 10)),
))
}
return next(ctx, tx, simulate)
}

View File

@ -15,59 +15,6 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
addr, privKey := tests.NewAddrKey()
signedTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
signedTx.From = addr.Hex()
err := signedTx.Sign(suite.ethSigner, tests.NewSigner(privKey))
suite.Require().NoError(err)
unprotectedTx := evmtypes.NewTxContract(nil, 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
unprotectedTx.From = addr.Hex()
err = unprotectedTx.Sign(ethtypes.HomesteadSigner{}, tests.NewSigner(privKey))
suite.Require().NoError(err)
testCases := []struct {
name string
tx sdk.Tx
allowUnprotectedTxs bool
reCheckTx bool
expPass bool
}{
{"ReCheckTx", &invalidTx{}, false, true, false},
{"invalid transaction type", &invalidTx{}, false, false, false},
{
"invalid sender",
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &addr, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
true,
false,
false,
},
{"successful signature verification", signedTx, false, false, true},
{"invalid, reject unprotected txs", unprotectedTx, false, false, false},
{"successful, allow unprotected txs", unprotectedTx, true, false, true},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.evmParamsOption = func(params *evmtypes.Params) {
params.AllowUnprotectedTxs = tc.allowUnprotectedTxs
}
suite.SetupTest()
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
suite.evmParamsOption = nil
}
func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
dec := ante.NewEthAccountVerificationDecorator(
suite.app.AccountKeeper, suite.app.EvmKeeper,
@ -521,33 +468,3 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
})
}
}
func (suite AnteTestSuite) TestEthSetupContextDecorator() {
dec := ante.NewEthSetUpContextDecorator(suite.app.EvmKeeper)
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
testCases := []struct {
name string
tx sdk.Tx
expPass bool
}{
{"invalid transaction type - does not implement GasTx", &invalidTx{}, false},
{
"success - transaction implement GasTx",
tx,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -4,10 +4,11 @@ import (
"fmt"
"math"
errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
ethermint "github.com/evmos/ethermint/types"
"github.com/evmos/ethermint/x/evm/types"
@ -64,7 +65,7 @@ func NewDynamicFeeChecker(k DynamicFeeEVMKeeper) authante.TxFeeChecker {
baseFeeInt := sdkmath.NewIntFromBigInt(baseFee)
if feeCap.LT(baseFeeInt) {
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient gas prices; got: %s required: %s", feeCap, baseFeeInt)
return nil, 0, errorsmod.Wrapf(errortypes.ErrInsufficientFee, "insufficient gas prices; got: %s required: %s", feeCap, baseFeeInt)
}
// calculate the effective gas price using the EIP-1559 logic.
@ -112,7 +113,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coi
}
if !feeCoins.IsAnyGTE(requiredFees) {
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
return nil, 0, errorsmod.Wrapf(errortypes.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
}
}

View File

@ -3,8 +3,8 @@ package ante
import (
"math/big"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// GasWantedDecorator keeps track of the gasWanted amount on the current block in transient store
@ -44,7 +44,7 @@ func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
// Add total gasWanted to cumulative in block transientStore in FeeMarket module
if isBaseFeeEnabled {
if _, err := gwd.feeMarketKeeper.AddTransientGasWanted(ctx, gasWanted); err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to add gas wanted to transient store")
return ctx, errorsmod.Wrapf(err, "failed to add gas wanted to transient store")
}
}

View File

@ -3,8 +3,9 @@ package ante
import (
"math/big"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
ethtypes "github.com/ethereum/go-ethereum/core/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
@ -20,14 +21,50 @@ type MinGasPriceDecorator struct {
evmKeeper EVMKeeper
}
// EthMinGasPriceDecorator will check if the transaction's fee is at least as large
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
// is rejected. This applies to both CheckTx and DeliverTx and regardless
// if London hard fork or fee market params (EIP-1559) are enabled.
// If fee is high enough, then call next AnteHandler
type EthMinGasPriceDecorator struct {
feesKeeper FeeMarketKeeper
evmKeeper EVMKeeper
}
// EthMempoolFeeDecorator will check if the transaction's effective fee is at least as large
// as the local validator's minimum gasFee (defined in validator config).
// If fee is too low, decorator returns error and tx is rejected from mempool.
// Note this only applies when ctx.CheckTx = true
// If fee is high enough or not CheckTx, then call next AnteHandler
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
type EthMempoolFeeDecorator struct {
evmKeeper EVMKeeper
}
// NewMinGasPriceDecorator creates a new MinGasPriceDecorator instance used only for
// Cosmos transactions.
func NewMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) MinGasPriceDecorator {
return MinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
}
// NewEthMinGasPriceDecorator creates a new MinGasPriceDecorator instance used only for
// Ethereum transactions.
func NewEthMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) EthMinGasPriceDecorator {
return EthMinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
}
// NewEthMempoolFeeDecorator creates a new NewEthMempoolFeeDecorator instance used only for
// Ethereum transactions.
func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
return EthMempoolFeeDecorator{
evmKeeper: ek,
}
}
func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "invalid transaction type %T, expected sdk.FeeTx", tx)
}
minGasPrice := mpd.feesKeeper.GetParams(ctx).MinGasPrice
@ -62,7 +99,7 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
}
if !feeCoins.IsAnyGTE(requiredFees) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee,
return ctx, errorsmod.Wrapf(errortypes.ErrInsufficientFee,
"provided fee < minimum global fee (%s < %s). Please increase the gas price.",
feeCoins,
requiredFees)
@ -71,20 +108,8 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
return next(ctx, tx, simulate)
}
// EthMinGasPriceDecorator will check if the transaction's fee is at least as large
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
// is rejected. This applies to both CheckTx and DeliverTx and regardless
// if London hard fork or fee market params (EIP-1559) are enabled.
// If fee is high enough, then call next AnteHandler
type EthMinGasPriceDecorator struct {
feesKeeper FeeMarketKeeper
evmKeeper EVMKeeper
}
func NewEthMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) EthMinGasPriceDecorator {
return EthMinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
}
// AnteHandle ensures that the that the effective fee from the transaction is greater than the
// minimum global fee, which is defined by the MinGasPrice (parameter) * GasLimit (tx argument).
func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
minGasPrice := empd.feesKeeper.GetParams(ctx).MinGasPrice
@ -100,8 +125,8 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
for _, msg := range tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrUnknownRequest,
return ctx, errorsmod.Wrapf(
errortypes.ErrUnknownRequest,
"invalid message type %T, expected %T",
msg, (*evmtypes.MsgEthereumTx)(nil),
)
@ -120,7 +145,7 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
txData, err := evmtypes.UnpackTxData(ethMsg.Data)
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data %s", ethMsg.Hash)
return ctx, errorsmod.Wrapf(err, "failed to unpack tx data %s", ethMsg.Hash)
}
if txData.TxType() != ethtypes.LegacyTxType {
@ -133,8 +158,8 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
fee := sdk.NewDecFromBigInt(feeAmt)
if fee.LT(requiredFee) {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFee,
return ctx, errorsmod.Wrapf(
errortypes.ErrInsufficientFee,
"provided fee < minimum global fee (%d < %d). Please increase the priority tip (for EIP-1559 txs) or the gas prices (for access list or legacy txs)", //nolint:lll
fee.TruncateInt().Int64(), requiredFee.TruncateInt().Int64(),
)
@ -143,3 +168,44 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
return next(ctx, tx, simulate)
}
// AnteHandle ensures that the provided fees meet a minimum threshold for the validator.
// This check only for local mempool purposes, and thus it is only run on (Re)CheckTx.
// The logic is also skipped if the London hard fork and EIP-1559 are enabled.
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if !ctx.IsCheckTx() || simulate {
return next(ctx, tx, simulate)
}
chainCfg := mfd.evmKeeper.GetChainConfig(ctx)
ethCfg := chainCfg.EthereumConfig(mfd.evmKeeper.ChainID())
baseFee := mfd.evmKeeper.GetBaseFee(ctx, ethCfg)
// skip check as the London hard fork and EIP-1559 are enabled
if baseFee != nil {
return next(ctx, tx, simulate)
}
evmDenom := mfd.evmKeeper.GetEVMDenom(ctx)
minGasPrice := ctx.MinGasPrices().AmountOf(evmDenom)
for _, msg := range tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
fee := sdk.NewDecFromBigInt(ethMsg.GetFee())
gasLimit := sdk.NewDecFromBigInt(new(big.Int).SetUint64(ethMsg.GetGas()))
requiredFee := minGasPrice.Mul(gasLimit)
if fee.LT(requiredFee) {
return ctx, errorsmod.Wrapf(
errortypes.ErrInsufficientFee,
"insufficient fee; got: %s required: %s",
fee, requiredFee,
)
}
}
return next(ctx, tx, simulate)
}

View File

@ -42,7 +42,7 @@ func (s AnteTestSuite) TestMinGasPriceDecorator() {
return &invalidTx{}
},
false,
"must be a FeeTx",
"invalid transaction type",
false,
},
{
@ -345,3 +345,7 @@ func (s AnteTestSuite) TestEthMinGasPriceDecorator() {
}
}
}
func (suite AnteTestSuite) TestEthMempoolFeeDecorator() {
// TODO: add test
}

View File

@ -1,8 +1,9 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
@ -32,19 +33,19 @@ type HandlerOptions struct {
func (options HandlerOptions) validate() error {
if options.AccountKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler")
return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler")
}
if options.BankKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler")
return errorsmod.Wrap(errortypes.ErrLogic, "bank keeper is required for AnteHandler")
}
if options.SignModeHandler == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
return errorsmod.Wrap(errortypes.ErrLogic, "sign mode handler is required for ante builder")
}
if options.FeeMarketKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "fee market keeper is required for AnteHandler")
return errorsmod.Wrap(errortypes.ErrLogic, "fee market keeper is required for AnteHandler")
}
if options.EvmKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for AnteHandler")
return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler")
}
return nil
}

View File

@ -28,9 +28,7 @@ type EVMKeeper interface {
DynamicFeeEVMKeeper
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
DeductTxCostsFromUserBalance(
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
) (fees sdk.Coins, priority int64, err error)
DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
ResetTransientGasUsed(ctx sdk.Context)
GetTxIndexTransient(ctx sdk.Context) uint64

View File

@ -1,8 +1,9 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
evmtypes "github.com/evmos/ethermint/x/evm/types"
)
@ -15,8 +16,8 @@ type RejectMessagesDecorator struct{}
func (rmd RejectMessagesDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
for _, msg := range tx.GetMsgs() {
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInvalidType,
return ctx, errorsmod.Wrapf(
errortypes.ErrInvalidType,
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
)
}

189
app/ante/setup.go Normal file
View File

@ -0,0 +1,189 @@
package ante
import (
"errors"
"strconv"
errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
ethtypes "github.com/ethereum/go-ethereum/core/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
)
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
// by setting the gas meter to infinite
type EthSetupContextDecorator struct {
evmKeeper EVMKeeper
}
func NewEthSetUpContextDecorator(evmKeeper EVMKeeper) EthSetupContextDecorator {
return EthSetupContextDecorator{
evmKeeper: evmKeeper,
}
}
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// all transactions must implement GasTx
_, ok := tx.(authante.GasTx)
if !ok {
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "invalid transaction type %T, expected GasTx", tx)
}
// We need to setup an empty gas config so that the gas is consistent with Ethereum.
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()).
WithKVGasConfig(storetypes.GasConfig{}).
WithTransientKVGasConfig(storetypes.GasConfig{})
// Reset transient gas used to prepare the execution of current cosmos tx.
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
esc.evmKeeper.ResetTransientGasUsed(ctx)
return next(newCtx, tx, simulate)
}
// EthEmitEventDecorator emit events in ante handler in case of tx execution failed (out of block gas limit).
type EthEmitEventDecorator struct {
evmKeeper EVMKeeper
}
// NewEthEmitEventDecorator creates a new EthEmitEventDecorator
func NewEthEmitEventDecorator(evmKeeper EVMKeeper) EthEmitEventDecorator {
return EthEmitEventDecorator{evmKeeper}
}
// AnteHandle emits some basic events for the eth messages
func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// After eth tx passed ante handler, the fee is deducted and nonce increased, it shouldn't be ignored by json-rpc,
// we need to emit some basic events at the very end of ante handler to be indexed by tendermint.
txIndex := eeed.evmKeeper.GetTxIndexTransient(ctx)
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
// emit ethereum tx hash as an event so that it can be indexed by Tendermint for query purposes
// it's emitted in ante handler, so we can query failed transaction (out of block gas limit).
ctx.EventManager().EmitEvent(sdk.NewEvent(
evmtypes.EventTypeEthereumTx,
sdk.NewAttribute(evmtypes.AttributeKeyEthereumTxHash, msgEthTx.Hash),
sdk.NewAttribute(evmtypes.AttributeKeyTxIndex, strconv.FormatUint(txIndex+uint64(i), 10)),
))
}
return next(ctx, tx, simulate)
}
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
type EthValidateBasicDecorator struct {
evmKeeper EVMKeeper
}
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
func NewEthValidateBasicDecorator(ek EVMKeeper) EthValidateBasicDecorator {
return EthValidateBasicDecorator{
evmKeeper: ek,
}
}
// AnteHandle handles basic validation of tx
func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// no need to validate basic on recheck tx, call next antehandler
if ctx.IsReCheckTx() {
return next(ctx, tx, simulate)
}
err := tx.ValidateBasic()
// ErrNoSignatures is fine with eth tx
if err != nil && !errors.Is(err, errortypes.ErrNoSignatures) {
return ctx, errorsmod.Wrap(err, "tx basic validation failed")
}
// For eth type cosmos tx, some fields should be verified as zero values,
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
wrapperTx, ok := tx.(protoTxProvider)
if !ok {
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid tx type %T, didn't implement interface protoTxProvider", tx)
}
protoTx := wrapperTx.GetProtoTx()
body := protoTx.Body
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest,
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
}
if len(body.ExtensionOptions) != 1 {
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
}
authInfo := protoTx.AuthInfo
if len(authInfo.SignerInfos) > 0 {
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
}
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
}
sigs := protoTx.Signatures
if len(sigs) > 0 {
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx Signatures should be empty")
}
txFee := sdk.Coins{}
txGasLimit := uint64(0)
chainCfg := vbd.evmKeeper.GetChainConfig(ctx)
chainID := vbd.evmKeeper.ChainID()
ethCfg := chainCfg.EthereumConfig(chainID)
baseFee := vbd.evmKeeper.GetBaseFee(ctx, ethCfg)
enableCreate := vbd.evmKeeper.GetEnableCreate(ctx)
enableCall := vbd.evmKeeper.GetEnableCall(ctx)
evmDenom := vbd.evmKeeper.GetEVMDenom(ctx)
for _, msg := range protoTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
// Validate `From` field
if msgEthTx.From != "" {
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid From %s, expect empty string", msgEthTx.From)
}
txGasLimit += msgEthTx.GetGas()
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, errorsmod.Wrap(err, "failed to unpack MsgEthereumTx Data")
}
// return error if contract creation or call are disabled through governance
if !enableCreate && txData.GetTo() == nil {
return ctx, errorsmod.Wrap(evmtypes.ErrCreateDisabled, "failed to create new contract")
} else if !enableCall && txData.GetTo() != nil {
return ctx, errorsmod.Wrap(evmtypes.ErrCallDisabled, "failed to call contract")
}
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
return ctx, errorsmod.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
}
txFee = txFee.Add(sdk.Coin{Denom: evmDenom, Amount: sdkmath.NewIntFromBigInt(txData.Fee())})
}
if !authInfo.Fee.Amount.IsEqual(txFee) {
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
}
if authInfo.Fee.GasLimit != txGasLimit {
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
}
return next(ctx, tx, simulate)
}

42
app/ante/setup_test.go Normal file
View File

@ -0,0 +1,42 @@
package ante_test
import (
"math/big"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/evmos/ethermint/app/ante"
evmtypes "github.com/evmos/ethermint/x/evm/types"
)
func (suite AnteTestSuite) TestEthSetupContextDecorator() {
dec := ante.NewEthSetUpContextDecorator(suite.app.EvmKeeper)
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
testCases := []struct {
name string
tx sdk.Tx
expPass bool
}{
{"invalid transaction type - does not implement GasTx", &invalidTx{}, false},
{
"success - transaction implement GasTx",
tx,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
ctx, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
if tc.expPass {
suite.Require().NoError(err)
suite.Equal(storetypes.GasConfig{}, ctx.KVGasConfig())
suite.Equal(storetypes.GasConfig{}, ctx.TransientKVGasConfig())
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -0,0 +1,64 @@
package ante_test
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/evmos/ethermint/app/ante"
"github.com/evmos/ethermint/tests"
evmtypes "github.com/evmos/ethermint/x/evm/types"
)
func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
addr, privKey := tests.NewAddrKey()
signedTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
signedTx.From = addr.Hex()
err := signedTx.Sign(suite.ethSigner, tests.NewSigner(privKey))
suite.Require().NoError(err)
unprotectedTx := evmtypes.NewTxContract(nil, 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
unprotectedTx.From = addr.Hex()
err = unprotectedTx.Sign(ethtypes.HomesteadSigner{}, tests.NewSigner(privKey))
suite.Require().NoError(err)
testCases := []struct {
name string
tx sdk.Tx
allowUnprotectedTxs bool
reCheckTx bool
expPass bool
}{
{"ReCheckTx", &invalidTx{}, false, true, false},
{"invalid transaction type", &invalidTx{}, false, false, false},
{
"invalid sender",
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &addr, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
true,
false,
false,
},
{"successful signature verification", signedTx, false, false, true},
{"invalid, reject unprotected txs", unprotectedTx, false, false, false},
{"successful, allow unprotected txs", unprotectedTx, true, false, true},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.evmParamsOption = func(params *evmtypes.Params) {
params.AllowUnprotectedTxs = tc.allowUnprotectedTxs
}
suite.SetupTest()
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
suite.evmParamsOption = nil
}

65
app/ante/sigverify.go Normal file
View File

@ -0,0 +1,65 @@
package ante
import (
"math/big"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
ethtypes "github.com/ethereum/go-ethereum/core/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
)
// EthSigVerificationDecorator validates an ethereum signatures
type EthSigVerificationDecorator struct {
evmKeeper EVMKeeper
}
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
return EthSigVerificationDecorator{
evmKeeper: ek,
}
}
// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
// that the signer address matches the one defined on the message.
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
// won't see the error message.
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
chainID := esvd.evmKeeper.ChainID()
chainCfg := esvd.evmKeeper.GetChainConfig(ctx)
ethCfg := chainCfg.EthereumConfig(chainID)
blockNum := big.NewInt(ctx.BlockHeight())
signer := ethtypes.MakeSigner(ethCfg, blockNum)
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
allowUnprotectedTxs := esvd.evmKeeper.GetAllowUnprotectedTxs(ctx)
ethTx := msgEthTx.AsTransaction()
if !allowUnprotectedTxs && !ethTx.Protected() {
return ctx, errorsmod.Wrapf(
errortypes.ErrNotSupported,
"rejected unprotected Ethereum transaction. Please EIP155 sign your transaction to protect it against replay-attacks")
}
sender, err := signer.Sender(ethTx)
if err != nil {
return ctx, errorsmod.Wrapf(
errortypes.ErrorInvalidSigner,
"couldn't retrieve sender address from the ethereum transaction: %s",
err.Error(),
)
}
// set up the sender to the transaction field if not already
msgEthTx.From = sender.Hex()
}
return next(ctx, tx, simulate)
}

View File

@ -13,9 +13,10 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
types2 "github.com/cosmos/cosmos-sdk/x/bank/types"
types3 "github.com/cosmos/cosmos-sdk/x/staking/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/evmos/ethermint/ethereum/eip712"
"github.com/evmos/ethermint/types"
@ -25,21 +26,27 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
sdkante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
authz "github.com/cosmos/cosmos-sdk/x/authz"
cryptocodec "github.com/evmos/ethermint/crypto/codec"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
"github.com/cosmos/cosmos-sdk/x/feegrant"
types5 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
"github.com/evmos/ethermint/app"
ante "github.com/evmos/ethermint/app/ante"
"github.com/evmos/ethermint/encoding"
@ -92,6 +99,8 @@ func (suite *AnteTestSuite) SetupTest() {
evmGenesis.Params.ChainConfig.ArrowGlacierBlock = &maxInt
evmGenesis.Params.ChainConfig.GrayGlacierBlock = &maxInt
evmGenesis.Params.ChainConfig.MergeNetsplitBlock = &maxInt
evmGenesis.Params.ChainConfig.ShanghaiBlock = &maxInt
evmGenesis.Params.ChainConfig.CancunBlock = &maxInt
}
if suite.evmParamsOption != nil {
suite.evmParamsOption(&evmGenesis.Params)
@ -111,6 +120,7 @@ func (suite *AnteTestSuite) SetupTest() {
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
// We're using TestMsg amino encoding in some tests, so register it here.
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
eip712.SetEncodingConfig(encodingConfig)
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
@ -263,41 +273,57 @@ func (suite *AnteTestSuite) CreateTestCosmosTxBuilder(gasPrice sdkmath.Int, deno
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build MsgSend
recipient := sdk.AccAddress(common.Address{}.Bytes())
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
}
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build MsgSend
valEthAddr := tests.GenerateAddress()
valAddr := sdk.ValAddress(valEthAddr.Bytes())
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
msgSend := stakingtypes.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
}
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build MsgCreateValidator
valAddr := sdk.ValAddress(from.Bytes())
privEd := ed25519.GenPrivKey()
msgCreate, err := types3.NewMsgCreateValidator(
msgCreate, err := stakingtypes.NewMsgCreateValidator(
valAddr,
privEd.PubKey(),
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
// TODO: can this values be empty strings?
types3.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
types3.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
stakingtypes.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
sdk.OneInt(),
)
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
}
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator2(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build MsgCreateValidator
valAddr := sdk.ValAddress(from.Bytes())
privEd := ed25519.GenPrivKey()
msgCreate, err := stakingtypes.NewMsgCreateValidator(
valAddr,
privEd.PubKey(),
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
// Ensure optional fields can be left blank
stakingtypes.NewDescription("moniker", "indentity", "", "", ""),
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
sdk.OneInt(),
)
suite.Require().NoError(err)
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
}
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposal(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, deposit sdk.Coins) client.TxBuilder {
proposal, ok := types5.ContentFromProposalType("My proposal", "My description", types5.ProposalTypeText)
proposal, ok := govtypes.ContentFromProposalType("My proposal", "My description", govtypes.ProposalTypeText)
suite.Require().True(ok)
msgSubmit, err := types5.NewMsgSubmitProposal(proposal, deposit, from)
msgSubmit, err := govtypes.NewMsgSubmitProposal(proposal, deposit, from)
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSubmit)
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSubmit)
}
func (suite *AnteTestSuite) CreateTestEIP712GrantAllowance(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@ -311,18 +337,18 @@ func (suite *AnteTestSuite) CreateTestEIP712GrantAllowance(from sdk.AccAddress,
grantedAddr := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, granted.Bytes())
msgGrant, err := feegrant.NewMsgGrantAllowance(basic, from, grantedAddr.GetAddress())
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgGrant)
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgGrant)
}
func (suite *AnteTestSuite) CreateTestEIP712MsgEditValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
valAddr := sdk.ValAddress(from.Bytes())
msgEdit := types3.NewMsgEditValidator(
msgEdit := stakingtypes.NewMsgEditValidator(
valAddr,
types3.NewDescription("moniker", "identity", "website", "security_contract", "details"),
stakingtypes.NewDescription("moniker", "identity", "website", "security_contract", "details"),
nil,
nil,
)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEdit)
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgEdit)
}
func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@ -335,7 +361,72 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddres
})
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
}
func (suite *AnteTestSuite) CreateTestEIP712MsgVoteV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
msgVote := govtypesv1.NewMsgVote(from, 1, govtypesv1.VoteOption_VOTE_OPTION_YES, "")
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgVote)
}
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposalV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build V1 proposal messages. Must all be same-type, since EIP-712
// does not support arrays of variable type.
authAcc := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx)
proposal1, ok := govtypes.ContentFromProposalType("My proposal 1", "My description 1", govtypes.ProposalTypeText)
suite.Require().True(ok)
content1, err := govtypesv1.NewLegacyContent(
proposal1,
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()),
)
suite.Require().NoError(err)
proposal2, ok := govtypes.ContentFromProposalType("My proposal 2", "My description 2", govtypes.ProposalTypeText)
suite.Require().True(ok)
content2, err := govtypesv1.NewLegacyContent(
proposal2,
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()),
)
suite.Require().NoError(err)
proposalMsgs := []sdk.Msg{
content1,
content2,
}
// Build V1 proposal
msgProposal, err := govtypesv1.NewMsgSubmitProposal(
proposalMsgs,
sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100))),
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), from.Bytes()),
"Metadata",
)
suite.Require().NoError(err)
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgProposal)
}
func (suite *AnteTestSuite) CreateTestEIP712MsgExec(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
recipient := sdk.AccAddress(common.Address{}.Bytes())
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
msgExec := authz.NewMsgExec(from, []sdk.Msg{msgSend})
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, &msgExec)
}
func (suite *AnteTestSuite) CreateTestEIP712MultipleMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
recipient := sdk.AccAddress(common.Address{}.Bytes())
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend, msgSend, msgSend})
}
// Fails
func (suite *AnteTestSuite) CreateTestEIP712MultipleSignerMsgs(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
recipient := sdk.AccAddress(common.Address{}.Bytes())
msgSend1 := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
msgSend2 := banktypes.NewMsgSend(recipient, from, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend1, msgSend2})
}
// StdSignBytes returns the bytes to sign for a transaction.
@ -376,8 +467,14 @@ func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequenc
return sdk.MustSortJSON(bz)
}
func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
func (suite *AnteTestSuite) CreateTestEIP712SingleMessageTxBuilder(
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
) client.TxBuilder {
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msg})
}
func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msgs []sdk.Msg,
) client.TxBuilder {
var err error
@ -398,13 +495,13 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
fee := legacytx.NewStdFee(gas, gasAmount)
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "", nil)
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, msgs, "", nil)
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msgs[0], data, &eip712.FeeDelegationOptions{
FeePayer: from,
})
suite.Require().NoError(err)
sigHash, err := eip712.ComputeTypedDataHash(typedData)
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
suite.Require().NoError(err)
// Sign typedData
@ -442,12 +539,189 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
err = builder.SetSignatures(sigsV2)
suite.Require().NoError(err)
err = builder.SetMsgs(msg)
err = builder.SetMsgs(msgs...)
suite.Require().NoError(err)
return builder
}
// Generate a set of pub/priv keys to be used in creating multi-keys
func (suite *AnteTestSuite) GenerateMultipleKeys(n int) ([]cryptotypes.PrivKey, []cryptotypes.PubKey) {
privKeys := make([]cryptotypes.PrivKey, n)
pubKeys := make([]cryptotypes.PubKey, n)
for i := 0; i < n; i++ {
privKey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
privKeys[i] = privKey
pubKeys[i] = privKey.PubKey()
}
return privKeys, pubKeys
}
// generateSingleSignature signs the given sign doc bytes using the given signType (EIP-712 or Standard)
func (suite *AnteTestSuite) generateSingleSignature(signMode signing.SignMode, privKey cryptotypes.PrivKey, signDocBytes []byte, signType string) (signature signing.SignatureV2) {
var (
msg []byte
err error
)
msg = signDocBytes
if signType == "EIP-712" {
msg, err = eip712.GetEIP712HashForMsg(signDocBytes)
suite.Require().NoError(err)
}
sigBytes, _ := privKey.Sign(msg)
sigData := &signing.SingleSignatureData{
SignMode: signMode,
Signature: sigBytes,
}
return signing.SignatureV2{
PubKey: privKey.PubKey(),
Data: sigData,
}
}
// generateMultikeySignatures signs a set of messages using each private key within a given multi-key
func (suite *AnteTestSuite) generateMultikeySignatures(signMode signing.SignMode, privKeys []cryptotypes.PrivKey, signDocBytes []byte, signType string) (signatures []signing.SignatureV2) {
n := len(privKeys)
signatures = make([]signing.SignatureV2, n)
for i := 0; i < n; i++ {
privKey := privKeys[i]
currentType := signType
// If mixed type, alternate signing type on each iteration
if signType == "mixed" {
if i%2 == 0 {
currentType = "EIP-712"
} else {
currentType = "Standard"
}
}
signatures[i] = suite.generateSingleSignature(
signMode,
privKey,
signDocBytes,
currentType,
)
}
return signatures
}
// RegisterAccount creates an account with the keeper and populates the initial balance
func (suite *AnteTestSuite) RegisterAccount(pubKey cryptotypes.PubKey, balance *big.Int) {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, sdk.AccAddress(pubKey.Address()))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.EvmKeeper.SetBalance(suite.ctx, common.BytesToAddress(pubKey.Address()), balance)
}
// createSignerBytes generates sign doc bytes using the given parameters
func (suite *AnteTestSuite) createSignerBytes(chainId string, signMode signing.SignMode, pubKey cryptotypes.PubKey, txBuilder client.TxBuilder) []byte {
acc, err := sdkante.GetSignerAcc(suite.ctx, suite.app.AccountKeeper, sdk.AccAddress(pubKey.Address()))
suite.Require().NoError(err)
signerInfo := authsigning.SignerData{
Address: sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), acc.GetAddress().Bytes()),
ChainID: chainId,
AccountNumber: acc.GetAccountNumber(),
Sequence: acc.GetSequence(),
PubKey: pubKey,
}
signerBytes, err := suite.clientCtx.TxConfig.SignModeHandler().GetSignBytes(
signMode,
signerInfo,
txBuilder.GetTx(),
)
suite.Require().NoError(err)
return signerBytes
}
// createBaseTxBuilder creates a TxBuilder to be used for Single- or Multi-signing
func (suite *AnteTestSuite) createBaseTxBuilder(msg sdk.Msg, gas uint64) client.TxBuilder {
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
txBuilder.SetGasLimit(gas)
txBuilder.SetFeeAmount(sdk.NewCoins(
sdk.NewCoin("aphoton", sdk.NewInt(10000)),
))
err := txBuilder.SetMsgs(msg)
suite.Require().NoError(err)
txBuilder.SetMemo("")
return txBuilder
}
// CreateTestSignedMultisigTx creates and sign a multi-signed tx for the given message. `signType` indicates whether to use standard signing ("Standard"),
// EIP-712 signing ("EIP-712"), or a mix of the two ("mixed").
func (suite *AnteTestSuite) CreateTestSignedMultisigTx(privKeys []cryptotypes.PrivKey, signMode signing.SignMode, msg sdk.Msg, chainId string, gas uint64, signType string) client.TxBuilder {
pubKeys := make([]cryptotypes.PubKey, len(privKeys))
for i, privKey := range privKeys {
pubKeys[i] = privKey.PubKey()
}
// Re-derive multikey
numKeys := len(privKeys)
multiKey := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
suite.RegisterAccount(multiKey, big.NewInt(10000000000))
txBuilder := suite.createBaseTxBuilder(msg, gas)
// Prepare signature field
sig := multisig.NewMultisig(len(pubKeys))
txBuilder.SetSignatures(signing.SignatureV2{
PubKey: multiKey,
Data: sig,
})
signerBytes := suite.createSignerBytes(chainId, signMode, multiKey, txBuilder)
// Sign for each key and update signature field
sigs := suite.generateMultikeySignatures(signMode, privKeys, signerBytes, signType)
for _, pkSig := range sigs {
err := multisig.AddSignatureV2(sig, pkSig, pubKeys)
suite.Require().NoError(err)
}
txBuilder.SetSignatures(signing.SignatureV2{
PubKey: multiKey,
Data: sig,
})
return txBuilder
}
func (suite *AnteTestSuite) CreateTestSingleSignedTx(privKey cryptotypes.PrivKey, signMode signing.SignMode, msg sdk.Msg, chainId string, gas uint64, signType string) client.TxBuilder {
pubKey := privKey.PubKey()
suite.RegisterAccount(pubKey, big.NewInt(10000000000))
txBuilder := suite.createBaseTxBuilder(msg, gas)
// Prepare signature field
sig := signing.SingleSignatureData{}
txBuilder.SetSignatures(signing.SignatureV2{
PubKey: pubKey,
Data: &sig,
})
signerBytes := suite.createSignerBytes(chainId, signMode, pubKey, txBuilder)
sigData := suite.generateSingleSignature(signMode, privKey, signerBytes, signType)
txBuilder.SetSignatures(sigData)
return txBuilder
}
func NextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
return ctx, nil
}

View File

@ -2,6 +2,7 @@ package app
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
@ -18,6 +19,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/grpc/node"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
@ -26,6 +28,7 @@ import (
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/store/streaming"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
@ -179,8 +182,6 @@ var (
}
)
var _ simapp.App = (*EthermintApp)(nil)
// var _ server.Application (*EthermintApp)(nil)
// EthermintApp implements an extended ABCI application. It is an application
@ -230,9 +231,6 @@ type EthermintApp struct {
// the module manager
mm *module.Manager
// simulation manager
sm *module.SimulationManager
// the configurator
configurator module.Configurator
}
@ -283,6 +281,12 @@ func NewEthermintApp(
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
// load state streaming if enabled
if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil {
fmt.Printf("failed to load state streaming: %s", err)
os.Exit(1)
}
app := &EthermintApp{
BaseApp: bApp,
cdc: cdc,
@ -591,17 +595,6 @@ func NewEthermintApp(
// add test gRPC service for testing gRPC queries in isolation
// testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{})
// create the simulation manager and define the order of the modules for deterministic simulations
//
// NOTE: this is not required apps that don't use the simulator for fuzz testing
// transactions
overrideModules := map[string]module.AppModuleSimulation{
authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
}
app.sm = module.NewSimulationManagerFromAppModules(app.mm.Modules, overrideModules)
app.sm.RegisterStoreDecoders()
// initialize stores
app.MountKVStores(keys)
app.MountTransientStores(tkeys)
@ -771,11 +764,6 @@ func (app *EthermintApp) GetSubspace(moduleName string) paramstypes.Subspace {
return subspace
}
// SimulationManager implements the SimulationApp interface
func (app *EthermintApp) SimulationManager() *module.SimulationManager {
return app.sm
}
// RegisterAPIRoutes registers all application module routes with the provided
// API server.
func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
@ -784,6 +772,8 @@ func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register new tendermint queries routes from grpc-gateway.
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register node gRPC service for grpc-gateway.
node.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register grpc-gateway routes for all modules.
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
@ -809,6 +799,12 @@ func (app *EthermintApp) RegisterTendermintService(clientCtx client.Context) {
)
}
// RegisterNodeService registers the node gRPC service on the provided
// application gRPC query router.
func (app *EthermintApp) RegisterNodeService(clientCtx client.Context) {
node.RegisterNodeService(clientCtx, app.GRPCQueryRouter())
}
// RegisterSwaggerAPI registers swagger route with API Server
func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) {
statikFS, err := fs.New()

View File

@ -1,403 +0,0 @@
package app
// TODO: COsmos SDK fix for the simulator issue for custom keys
import (
"encoding/json"
"fmt"
"math/rand"
"os"
"runtime/debug"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cosmos/cosmos-sdk/x/simulation"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
ibchost "github.com/cosmos/ibc-go/v5/modules/core/24-host"
"github.com/evmos/ethermint/app/ante"
evmenc "github.com/evmos/ethermint/encoding"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
)
// MakeEncodingConfig creates the EncodingConfig
func MakeEncodingConfig() params.EncodingConfig {
return evmenc.MakeConfig(ModuleBasics)
}
func init() {
simapp.GetSimulatorFlags()
}
const SimAppChainID = "simulation_777-1"
type storeKeysPrefixes struct {
A storetypes.StoreKey
B storetypes.StoreKey
Prefixes [][]byte
}
// fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
// an IAVLStore for faster simulation speed.
func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
bapp.SetFauxMerkleMode()
}
// NewSimApp disable feemarket on native tx, otherwise the cosmos-sdk simulation tests will fail.
func NewSimApp(logger log.Logger, db dbm.DB) (*EthermintApp, error) {
encodingConfig := MakeEncodingConfig()
app := NewEthermintApp(logger, db, nil, false, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, encodingConfig, simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
// disable feemarket on native tx
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
IBCKeeper: app.IBCKeeper,
EvmKeeper: app.EvmKeeper,
FeeMarketKeeper: app.FeeMarketKeeper,
MaxTxGasWanted: 0,
})
if err != nil {
return nil, err
}
app.SetAnteHandler(anteHandler)
if err := app.LoadLatestVersion(); err != nil {
return nil, err
}
return app, nil
}
// interBlockCacheOpt returns a BaseApp option function that sets the persistent
// inter-block write-through cache.
func interBlockCacheOpt() func(*baseapp.BaseApp) {
return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
}
func TestFullAppSimulation(t *testing.T) {
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping application simulation")
}
require.NoError(t, err, "simulation setup failed")
config.ChainID = SimAppChainID
defer func() {
require.NoError(t, db.Close())
require.NoError(t, os.RemoveAll(dir))
}()
app, err := NewSimApp(logger, db)
require.Equal(t, appName, app.Name())
require.NoError(t, err)
// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simapp.SimulationOperations(app, app.AppCodec(), config),
app.ModuleAccountAddrs(),
config,
app.AppCodec(),
)
// export state and simParams before the simulation error is checked
err = simapp.CheckExportSimulation(app, config, simParams)
require.NoError(t, err)
require.NoError(t, simErr)
if config.Commit {
simapp.PrintStats(db)
}
}
func TestAppImportExport(t *testing.T) {
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping application import/export simulation")
}
require.NoError(t, err, "simulation setup failed")
config.ChainID = SimAppChainID
defer func() {
require.NoError(t, db.Close())
require.NoError(t, os.RemoveAll(dir))
}()
app, err := NewSimApp(logger, db)
require.NoError(t, err)
require.Equal(t, appName, app.Name())
// Run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simapp.SimulationOperations(app, app.AppCodec(), config),
app.ModuleAccountAddrs(),
config,
app.AppCodec(),
)
// export state and simParams before the simulation error is checked
err = simapp.CheckExportSimulation(app, config, simParams)
require.NoError(t, err)
require.NoError(t, simErr)
if config.Commit {
simapp.PrintStats(db)
}
fmt.Printf("exporting genesis...\n")
exported, err := app.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err)
fmt.Printf("importing genesis...\n")
//nolint: dogsled
_, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
require.NoError(t, err, "simulation setup failed")
defer func() {
require.NoError(t, newDB.Close())
require.NoError(t, os.RemoveAll(newDir))
}()
newApp, err := NewSimApp(log.NewNopLogger(), newDB)
require.Equal(t, appName, newApp.Name())
require.NoError(t, err)
var genesisState simapp.GenesisState
err = json.Unmarshal(exported.AppState, &genesisState)
require.NoError(t, err)
defer func() {
if r := recover(); r != nil {
err := fmt.Sprintf("%v", r)
if !strings.Contains(err, "validator set is empty after InitGenesis") {
panic(r)
}
logger.Info("Skipping simulation as all validators have been unbonded")
logger.Info("err", err, "stacktrace", string(debug.Stack()))
}
}()
ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight(), ChainID: SimAppChainID})
ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight(), ChainID: SimAppChainID})
newApp.mm.InitGenesis(ctxB, app.AppCodec(), genesisState)
newApp.StoreConsensusParams(ctxB, exported.ConsensusParams)
fmt.Printf("comparing stores...\n")
storeKeysPrefixes := []storeKeysPrefixes{
{app.keys[authtypes.StoreKey], newApp.keys[authtypes.StoreKey], [][]byte{}},
{
app.keys[stakingtypes.StoreKey], newApp.keys[stakingtypes.StoreKey],
[][]byte{
stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey,
stakingtypes.HistoricalInfoKey,
},
}, // ordering may change but it doesn't matter
{app.keys[slashingtypes.StoreKey], newApp.keys[slashingtypes.StoreKey], [][]byte{}},
{app.keys[minttypes.StoreKey], newApp.keys[minttypes.StoreKey], [][]byte{}},
{app.keys[distrtypes.StoreKey], newApp.keys[distrtypes.StoreKey], [][]byte{}},
{app.keys[banktypes.StoreKey], newApp.keys[banktypes.StoreKey], [][]byte{banktypes.BalancesPrefix}},
{app.keys[paramtypes.StoreKey], newApp.keys[paramtypes.StoreKey], [][]byte{}},
{app.keys[govtypes.StoreKey], newApp.keys[govtypes.StoreKey], [][]byte{}},
{app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}},
{app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
{app.keys[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{authzkeeper.GrantKey, authzkeeper.GrantQueuePrefix}},
{app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}},
{app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
}
for _, skp := range storeKeysPrefixes {
storeA := ctxA.KVStore(skp.A)
storeB := ctxB.KVStore(skp.B)
failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes)
require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare")
fmt.Printf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B)
require.Equal(t, len(failedKVAs), 0, simapp.GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, failedKVAs, failedKVBs))
}
}
func TestAppSimulationAfterImport(t *testing.T) {
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping application simulation after import")
}
require.NoError(t, err, "simulation setup failed")
config.ChainID = SimAppChainID
defer func() {
require.NoError(t, db.Close())
require.NoError(t, os.RemoveAll(dir))
}()
app, err := NewSimApp(logger, db)
require.Equal(t, appName, app.Name())
require.NoError(t, err)
// Run randomized simulation
stopEarly, simParams, simErr := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simapp.SimulationOperations(app, app.AppCodec(), config),
app.ModuleAccountAddrs(),
config,
app.AppCodec(),
)
// export state and simParams before the simulation error is checked
err = simapp.CheckExportSimulation(app, config, simParams)
require.NoError(t, err)
require.NoError(t, simErr)
if config.Commit {
simapp.PrintStats(db)
}
if stopEarly {
fmt.Println("can't export or import a zero-validator genesis, exiting test...")
return
}
fmt.Printf("exporting genesis...\n")
exported, err := app.ExportAppStateAndValidators(true, []string{})
require.NoError(t, err)
fmt.Printf("importing genesis...\n")
_, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
require.NoError(t, err, "simulation setup failed")
defer func() {
require.NoError(t, newDB.Close())
require.NoError(t, os.RemoveAll(newDir))
}()
newApp, err := NewSimApp(log.NewNopLogger(), newDB)
require.Equal(t, appName, newApp.Name())
require.NoError(t, err)
newApp.InitChain(abci.RequestInitChain{
ChainId: SimAppChainID,
AppStateBytes: exported.AppState,
})
_, _, err = simulation.SimulateFromSeed(
t,
os.Stdout,
newApp.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simapp.SimulationOperations(newApp, newApp.AppCodec(), config),
app.ModuleAccountAddrs(),
config,
app.AppCodec(),
)
require.NoError(t, err)
}
// TODO: Make another test for the fuzzer itself, which just has noOp txs
// and doesn't depend on the application.
func TestAppStateDeterminism(t *testing.T) {
if !simapp.FlagEnabledValue {
t.Skip("skipping application simulation")
}
config := simapp.NewConfigFromFlags()
config.InitialBlockHeight = 1
config.ExportParamsPath = ""
config.OnOperation = false
config.AllInvariants = false
config.ChainID = SimAppChainID
numSeeds := 3
numTimesToRunPerSeed := 5
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
for i := 0; i < numSeeds; i++ {
config.Seed = rand.Int63()
for j := 0; j < numTimesToRunPerSeed; j++ {
var logger log.Logger
if simapp.FlagVerboseValue {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
db := dbm.NewMemDB()
app, err := NewSimApp(logger, db)
require.NoError(t, err)
fmt.Printf(
"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
)
_, _, err = simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
simapp.SimulationOperations(app, app.AppCodec(), config),
app.ModuleAccountAddrs(),
config,
app.AppCodec(),
)
require.NoError(t, err)
if config.Commit {
simapp.PrintStats(db)
}
appHash := app.LastCommitID().Hash
appHashList[j] = appHash
if j != 0 {
require.Equal(
t, string(appHashList[0]), string(appHashList[j]),
"non-determinism in seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
)
}
}
}
}

View File

@ -2,7 +2,6 @@ package app
import (
"encoding/json"
"math/rand"
"time"
"github.com/cosmos/cosmos-sdk/codec"
@ -11,21 +10,12 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/mock"
"github.com/cosmos/cosmos-sdk/types/module"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/evmos/ethermint/encoding"
ethermint "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/evmos/ethermint/encoding"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
@ -94,96 +84,6 @@ func SetupWithDB(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.Genesis
return app
}
// RandomGenesisAccounts is used by the auth module to create random genesis accounts in simulation when a genesis.json is not specified.
// In contrast, the default auth module's RandomGenesisAccounts implementation creates only base accounts and vestings accounts.
func RandomGenesisAccounts(simState *module.SimulationState) authtypes.GenesisAccounts {
emptyCodeHash := crypto.Keccak256(nil)
genesisAccs := make(authtypes.GenesisAccounts, len(simState.Accounts))
for i, acc := range simState.Accounts {
bacc := authtypes.NewBaseAccountWithAddress(acc.Address)
ethacc := &ethermint.EthAccount{
BaseAccount: bacc,
CodeHash: common.BytesToHash(emptyCodeHash).String(),
}
genesisAccs[i] = ethacc
}
return genesisAccs
}
// RandomAccounts creates random accounts with an ethsecp256k1 private key
// TODO: replace secp256k1.GenPrivKeyFromSecret() with similar function in go-ethereum
func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
accs := make([]simtypes.Account, n)
for i := 0; i < n; i++ {
// don't need that much entropy for simulation
privkeySeed := make([]byte, 15)
_, _ = r.Read(privkeySeed)
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
ethPrv := &ethsecp256k1.PrivKey{}
_ = ethPrv.UnmarshalAmino(prv.Bytes()) // UnmarshalAmino simply copies the bytes and assigns them to ethPrv.Key
accs[i].PrivKey = ethPrv
accs[i].PubKey = accs[i].PrivKey.PubKey()
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
}
return accs
}
// StateFn returns the initial application state using a genesis or the simulation parameters.
// It is a wrapper of simapp.AppStateFn to replace evm param EvmDenom with staking param BondDenom.
func StateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn {
return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config,
) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) {
appStateFn := simapp.AppStateFn(cdc, simManager)
appState, simAccs, chainID, genesisTimestamp = appStateFn(r, accs, config)
rawState := make(map[string]json.RawMessage)
err := json.Unmarshal(appState, &rawState)
if err != nil {
panic(err)
}
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
if !ok {
panic("staking genesis state is missing")
}
stakingState := new(stakingtypes.GenesisState)
cdc.MustUnmarshalJSON(stakingStateBz, stakingState)
// we should get the BondDenom and make it the evmdenom.
// thus simulation accounts could have positive amount of gas token.
bondDenom := stakingState.Params.BondDenom
evmStateBz, ok := rawState[evmtypes.ModuleName]
if !ok {
panic("evm genesis state is missing")
}
evmState := new(evmtypes.GenesisState)
cdc.MustUnmarshalJSON(evmStateBz, evmState)
// we should replace the EvmDenom with BondDenom
evmState.Params.EvmDenom = bondDenom
// change appState back
rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState)
// replace appstate
appState, err = json.Marshal(rawState)
if err != nil {
panic(err)
}
return appState, simAccs, chainID, genesisTimestamp
}
}
// NewTestGenesisState generate genesis state with single validator
func NewTestGenesisState(codec codec.Codec) simapp.GenesisState {
privVal := mock.NewPV()

View File

@ -1,113 +0,0 @@
package app
import (
"encoding/json"
"math/rand"
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
ethermint "github.com/evmos/ethermint/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var (
maxTestingAccounts = 100
seed = int64(233)
)
func TestRandomGenesisAccounts(t *testing.T) {
r := rand.New(rand.NewSource(seed))
accs := RandomAccounts(r, rand.Intn(maxTestingAccounts))
encodingConfig := MakeEncodingConfig()
appCodec := encodingConfig.Codec
cdc := encodingConfig.Amino
paramsKeeper := initParamsKeeper(appCodec, cdc, sdk.NewKVStoreKey(paramstypes.StoreKey), sdk.NewTransientStoreKey(paramstypes.StoreKey))
subSpace, find := paramsKeeper.GetSubspace(authtypes.ModuleName)
require.True(t, find)
accountKeeper := authkeeper.NewAccountKeeper(
appCodec, sdk.NewKVStoreKey(authtypes.StoreKey), subSpace, ethermint.ProtoAccount, maccPerms, sdk.GetConfig().GetBech32AccountAddrPrefix(),
)
authModule := auth.NewAppModule(appCodec, accountKeeper, RandomGenesisAccounts)
genesisState := simapp.NewDefaultGenesisState(appCodec)
simState := &module.SimulationState{Accounts: accs, Cdc: appCodec, Rand: r, GenState: genesisState}
authModule.GenerateGenesisState(simState)
authStateBz, find := genesisState[authtypes.ModuleName]
require.True(t, find)
authState := new(authtypes.GenesisState)
appCodec.MustUnmarshalJSON(authStateBz, authState)
accounts, err := authtypes.UnpackAccounts(authState.Accounts)
require.NoError(t, err)
for _, acc := range accounts {
_, ok := acc.(ethermint.EthAccountI)
require.True(t, ok)
}
}
func TestStateFn(t *testing.T) {
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping AppStateFn testing")
}
require.NoError(t, err, "simulation setup failed")
config.ChainID = SimAppChainID
config.Commit = true
defer func() {
db.Close()
require.NoError(t, os.RemoveAll(dir))
}()
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
require.Equal(t, appName, app.Name())
appStateFn := StateFn(app.AppCodec(), app.SimulationManager())
r := rand.New(rand.NewSource(seed))
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
appState, _, _, _ := appStateFn(r, accounts, config)
rawState := make(map[string]json.RawMessage)
err = json.Unmarshal(appState, &rawState)
require.NoError(t, err)
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
require.True(t, ok)
stakingState := new(stakingtypes.GenesisState)
app.AppCodec().MustUnmarshalJSON(stakingStateBz, stakingState)
bondDenom := stakingState.Params.BondDenom
evmStateBz, ok := rawState[evmtypes.ModuleName]
require.True(t, ok)
evmState := new(evmtypes.GenesisState)
app.AppCodec().MustUnmarshalJSON(evmStateBz, evmState)
require.Equal(t, bondDenom, evmState.Params.EvmDenom)
}
func TestRandomAccounts(t *testing.T) {
r := rand.New(rand.NewSource(seed))
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
for _, acc := range accounts {
_, ok := acc.PrivKey.(*ethsecp256k1.PrivKey)
require.True(t, ok)
}
}

View File

@ -1,4 +1,3 @@
version: v1
directories:
- proto
- third_party/proto

View File

@ -13,57 +13,6 @@
"Params": "EvmParams"
}
}
},
{
"url": "./tmp-swagger-gen/cosmos/auth/v1beta1/query.swagger.json",
"operationIds": {
"rename": {
"Account": "AuthAccount",
"Params": "AuthParams"
}
}
},
{
"url": "./tmp-swagger-gen/cosmos/bank/v1beta1/query.swagger.json",
"operationIds": {
"rename": {
"Balance": "BankBalance",
"Params": "BankParams"
}
}
},
{
"url": "./tmp-swagger-gen/cosmos/distribution/v1beta1/query.swagger.json",
"operationIds": {
"rename": {
"Params": "DistributionParams",
"DelegatorValidators": "DistDelegatorValidators"
}
}
},
{
"url": "./tmp-swagger-gen/cosmos/mint/v1beta1/query.swagger.json",
"operationIds": {
"rename": {
"Params": "MintParams"
}
}
},
{
"url": "./tmp-swagger-gen/cosmos/gov/v1beta1/query.swagger.json",
"operationIds": {
"rename": {
"Params": "GovParams"
}
}
},
{
"url": "./tmp-swagger-gen/cosmos/staking/v1beta1/query.swagger.json",
"operationIds": {
"rename": {
"Params": "StakingParams"
}
}
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@ import (
"github.com/evmos/ethermint/client/debug"
"github.com/evmos/ethermint/crypto/hd"
"github.com/evmos/ethermint/encoding"
"github.com/evmos/ethermint/ethereum/eip712"
"github.com/evmos/ethermint/server"
servercfg "github.com/evmos/ethermint/server/config"
srvflags "github.com/evmos/ethermint/server/flags"
@ -61,6 +62,8 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
WithKeyringOptions(hd.EthSecp256k1Option()).
WithViper(EnvPrefix)
eip712.SetEncodingConfig(encodingConfig)
rootCmd := &cobra.Command{
Use: "ethermintd",
Short: "Ethermint Daemon",
@ -179,6 +182,7 @@ func txCommand() *cobra.Command {
authcmd.GetBroadcastCommand(),
authcmd.GetEncodeCommand(),
authcmd.GetDecodeCommand(),
authcmd.GetAuxToFeeCommand(),
)
app.ModuleBasics.AddTxCommands(cmd)

View File

@ -6,11 +6,12 @@ import (
"crypto/subtle"
"fmt"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/crypto"
"github.com/evmos/ethermint/ethereum/eip712"
tmcrypto "github.com/tendermint/tendermint/crypto"
)
@ -182,7 +183,7 @@ func (pubKey PubKey) MarshalAmino() ([]byte, error) {
// UnmarshalAmino overrides Amino binary marshaling.
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
if len(bz) != PubKeySize {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "invalid pubkey size, expected %d, got %d", PubKeySize, len(bz))
return errorsmod.Wrapf(errortypes.ErrInvalidPubKey, "invalid pubkey size, expected %d, got %d", PubKeySize, len(bz))
}
pubKey.Key = bz
@ -203,10 +204,28 @@ func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error {
// VerifySignature verifies that the ECDSA public key created a given signature over
// the provided message. It will calculate the Keccak256 hash of the message
// prior to verification.
// prior to verification and approve verification if the signature can be verified
// from either the original message or its EIP-712 representation.
//
// CONTRACT: The signature should be in [R || S] format.
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
return pubKey.verifySignatureECDSA(msg, sig) || pubKey.verifySignatureAsEIP712(msg, sig)
}
// Verifies the signature as an EIP-712 signature by first converting the message payload
// to an EIP-712 hashed object, performing ECDSA verification on the hash. This is to support
// signing a Cosmos payload using EIP-712.
func (pubKey PubKey) verifySignatureAsEIP712(msg, sig []byte) bool {
eip712Hash, err := eip712.GetEIP712HashForMsg(msg)
if err != nil {
return false
}
return pubKey.verifySignatureECDSA(eip712Hash, sig)
}
// Perform standard ECDSA signature verification for the given raw bytes and signature.
func (pubKey PubKey) verifySignatureECDSA(msg, sig []byte) bool {
if len(sig) == crypto.SignatureLength {
// remove recovery ID (V) if contained in the signature
sig = sig[:len(sig)-1]

View File

@ -5,7 +5,7 @@ package ethsecp256k1
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
_ "github.com/cosmos/gogoproto/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
@ -27,6 +27,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// Tendermint's PubKey interface. It represents the 33-byte compressed public
// key format.
type PubKey struct {
// key is the public key in byte form
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
}
@ -72,6 +73,7 @@ func (m *PubKey) GetKey() []byte {
// PrivKey defines a type alias for an ecdsa.PrivateKey that implements
// Tendermint's PrivateKey interface.
type PrivKey struct {
// key is the private key in byte form
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
}

View File

@ -1,6 +1,7 @@
package hd
import (
"os"
"strings"
"testing"
@ -10,7 +11,6 @@ import (
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
"github.com/cosmos/cosmos-sdk/codec"
amino "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
@ -20,10 +20,10 @@ import (
ethermint "github.com/evmos/ethermint/types"
)
var TestCodec codec.Codec
var TestCodec amino.Codec
func init() {
cdc := codec.NewLegacyAmino()
cdc := amino.NewLegacyAmino()
cryptocodec.RegisterCrypto(cdc)
interfaceRegistry := types.NewInterfaceRegistry()
@ -31,12 +31,18 @@ func init() {
enccodec.RegisterInterfaces(interfaceRegistry)
}
const mnemonic = "picnic rent average infant boat squirrel federal assault mercy purity very motor fossil wheel verify upset box fresh horse vivid copy predict square regret"
const (
mnemonic = "picnic rent average infant boat squirrel federal assault mercy purity very motor fossil wheel verify upset box fresh horse vivid copy predict square regret"
// hdWalletFixEnv defines whether the standard (correct) bip39
// derivation path was used, or if derivation was affected by
// https://github.com/btcsuite/btcutil/issues/172
hdWalletFixEnv = "GO_ETHEREUM_HDWALLET_FIX_ISSUE_179"
)
func TestKeyring(t *testing.T) {
dir := t.TempDir()
mockIn := strings.NewReader("")
kr, err := keyring.New("ethermint", keyring.BackendTest, dir, mockIn, TestCodec, EthSecp256k1Option())
require.NoError(t, err)
@ -68,7 +74,9 @@ func TestKeyring(t *testing.T) {
privkey := EthSecp256k1.Generate()(bz)
addr := common.BytesToAddress(privkey.PubKey().Address().Bytes())
os.Setenv(hdWalletFixEnv, "true")
wallet, err := hdwallet.NewFromMnemonic(mnemonic)
os.Setenv(hdWalletFixEnv, "")
require.NoError(t, err)
path := hdwallet.MustParseDerivationPath(hdPath)

View File

@ -275,6 +275,7 @@ TraceConfig holds extra parameters to trace functions.
| `overrides` | [ChainConfig](#ethermint.evm.v1.ChainConfig) | | Chain overrides, can be used to execute a trace using future fork rules |
| `enable_memory` | [bool](#bool) | | enable memory capture |
| `enable_return_data` | [bool](#bool) | | enable return data capture |
| `tracer_json_config` | [string](#string) | | tracer config |
@ -563,6 +564,7 @@ EthCallRequest defines EthCall request
| `args` | [bytes](#bytes) | | same json format as the json rpc api. |
| `gas_cap` | [uint64](#uint64) | | the default gas cap to be used |
| `proposer_address` | [bytes](#bytes) | | the proposer of the requested block |
| `chain_id` | [int64](#int64) | | the eip155 chain id parsed from the requested block header |
@ -793,6 +795,7 @@ QueryTraceBlockRequest defines TraceTx request
| `block_hash` | [string](#string) | | block hex hash |
| `block_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | block time |
| `proposer_address` | [bytes](#bytes) | | the proposer of the requested block |
| `chain_id` | [int64](#int64) | | the eip155 chain id parsed from the requested block header |
@ -829,6 +832,7 @@ QueryTraceTxRequest defines TraceTx request
| `block_hash` | [string](#string) | | block hex hash of requested transaction |
| `block_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | block time of requested transaction |
| `proposer_address` | [bytes](#bytes) | | the proposer of the requested block |
| `chain_id` | [int64](#int64) | | the eip155 chain id parsed from the requested block header |

View File

@ -14,34 +14,16 @@ import (
"golang.org/x/text/cases"
"golang.org/x/text/language"
errorsmod "cosmossdk.io/errors"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
)
// ComputeTypedDataHash computes keccak hash of typed data for signing.
func ComputeTypedDataHash(typedData apitypes.TypedData) ([]byte, error) {
domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
if err != nil {
err = sdkerrors.Wrap(err, "failed to pack and hash typedData EIP712Domain")
return nil, err
}
typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
if err != nil {
err = sdkerrors.Wrap(err, "failed to pack and hash typedData primary type")
return nil, err
}
rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
return crypto.Keccak256(rawData), nil
}
// WrapTxToTypedData is an ultimate method that wraps Amino-encoded Cosmos Tx JSON data
// into an EIP712-compatible TypedData request.
func WrapTxToTypedData(
@ -54,7 +36,7 @@ func WrapTxToTypedData(
txData := make(map[string]interface{})
if err := json.Unmarshal(data, &txData); err != nil {
return apitypes.TypedData{}, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, "failed to JSON unmarshal data")
return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrJSONUnmarshal, "failed to JSON unmarshal data")
}
domain := apitypes.TypedDataDomain{
@ -73,7 +55,7 @@ func WrapTxToTypedData(
if feeDelegation != nil {
feeInfo, ok := txData["fee"].(map[string]interface{})
if !ok {
return apitypes.TypedData{}, sdkerrors.Wrap(sdkerrors.ErrInvalidType, "cannot parse fee from tx data")
return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrInvalidType, "cannot parse fee from tx data")
}
feeInfo["feePayer"] = feeDelegation.FeePayer.String()
@ -206,7 +188,11 @@ func traverseFields(
}
for i := 0; i < n; i++ {
var field reflect.Value
var (
field reflect.Value
err error
)
if v.IsValid() {
field = v.Field(i)
}
@ -215,27 +201,14 @@ func traverseFields(
fieldName := jsonNameFromTag(t.Field(i).Tag)
if fieldType == cosmosAnyType {
any, ok := field.Interface().(*codectypes.Any)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "%T", field.Interface())
// Unpack field, value as Any
if fieldType, field, err = unpackAny(cdc, field); err != nil {
return err
}
anyWrapper := &cosmosAnyWrapper{
Type: any.TypeUrl,
}
if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
return sdkerrors.Wrap(err, "failed to unpack Any in msg struct")
}
fieldType = reflect.TypeOf(anyWrapper)
field = reflect.ValueOf(anyWrapper)
// then continue as normal
}
// If its a nil pointer, do not include in types
if fieldType.Kind() == reflect.Ptr && field.IsNil() {
// If field is an empty value, do not include in types, since it will not be present in the object
if field.IsZero() {
continue
}
@ -273,6 +246,12 @@ func traverseFields(
fieldType = fieldType.Elem()
field = field.Index(0)
isCollection = true
if fieldType == cosmosAnyType {
if fieldType, field, err = unpackAny(cdc, field); err != nil {
return err
}
}
}
for {
@ -363,6 +342,27 @@ func jsonNameFromTag(tag reflect.StructTag) string {
return parts[0]
}
// Unpack the given Any value with Type/Value deconstruction
func unpackAny(cdc codectypes.AnyUnpacker, field reflect.Value) (reflect.Type, reflect.Value, error) {
any, ok := field.Interface().(*codectypes.Any)
if !ok {
return nil, reflect.Value{}, errorsmod.Wrapf(errortypes.ErrPackAny, "%T", field.Interface())
}
anyWrapper := &cosmosAnyWrapper{
Type: any.TypeUrl,
}
if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
return nil, reflect.Value{}, errorsmod.Wrap(err, "failed to unpack Any in msg struct")
}
fieldType := reflect.TypeOf(anyWrapper)
field = reflect.ValueOf(anyWrapper)
return fieldType, field, nil
}
// _.foo_bar.baz -> TypeFooBarBaz
//
// this is needed for Geth's own signing code which doesn't
@ -465,7 +465,7 @@ func typToEth(typ reflect.Type) string {
func doRecover(err *error) {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
e = sdkerrors.Wrap(e, "panicked with error")
e = errorsmod.Wrap(e, "panicked with error")
*err = e
return
}

View File

@ -0,0 +1,433 @@
package eip712_test
import (
"testing"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/ethereum/go-ethereum/crypto"
"github.com/evmos/ethermint/ethereum/eip712"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/evmos/ethermint/app"
"github.com/evmos/ethermint/encoding"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/suite"
)
// Unit tests for single-signer EIP-712 signature verification. Multi-signer verification tests are included
// in ante_test.go.
type EIP712TestSuite struct {
suite.Suite
config params.EncodingConfig
clientCtx client.Context
}
func TestEIP712TestSuite(t *testing.T) {
suite.Run(t, &EIP712TestSuite{})
}
// Set up test env to replicate prod. environment
func (suite *EIP712TestSuite) SetupTest() {
suite.config = encoding.MakeConfig(app.ModuleBasics)
suite.clientCtx = client.Context{}.WithTxConfig(suite.config.TxConfig)
sdk.GetConfig().SetBech32PrefixForAccount("ethm", "")
eip712.SetEncodingConfig(suite.config)
}
// Helper to create random test addresses for messages
func (suite *EIP712TestSuite) createTestAddress() sdk.AccAddress {
privkey, _ := ethsecp256k1.GenerateKey()
key, err := privkey.ToECDSA()
suite.Require().NoError(err)
addr := crypto.PubkeyToAddress(key.PublicKey)
return addr.Bytes()
}
// Helper to create random keypair for signing + verification
func (suite *EIP712TestSuite) createTestKeyPair() (*ethsecp256k1.PrivKey, *ethsecp256k1.PubKey) {
privKey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
pubKey := &ethsecp256k1.PubKey{
Key: privKey.PubKey().Bytes(),
}
suite.Require().Implements((*cryptotypes.PubKey)(nil), pubKey)
return privKey, pubKey
}
// Helper to create instance of sdk.Coins[] with single coin
func (suite *EIP712TestSuite) makeCoins(denom string, amount math.Int) sdk.Coins {
return sdk.NewCoins(
sdk.NewCoin(
denom,
amount,
),
)
}
func (suite *EIP712TestSuite) TestEIP712SignatureVerification() {
suite.SetupTest()
signModes := []signing.SignMode{
signing.SignMode_SIGN_MODE_DIRECT,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
}
// Fixed test address
testAddress := suite.createTestAddress()
testCases := []struct {
title string
chainId string
fee txtypes.Fee
memo string
msgs []sdk.Msg
accountNumber uint64
sequence uint64
timeoutHeight uint64
expectSuccess bool
}{
{
title: "Succeeds - Standard MsgSend",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
banktypes.NewMsgSend(
suite.createTestAddress(),
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(1)),
),
},
accountNumber: 8,
sequence: 5,
expectSuccess: true,
},
{
title: "Succeeds - Standard MsgVote",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Succeeds - Standard MsgDelegate",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
stakingtypes.NewMsgDelegate(
suite.createTestAddress(),
sdk.ValAddress(suite.createTestAddress()),
suite.makeCoins("photon", math.NewInt(1))[0],
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Succeeds - Standard MsgWithdrawDelegationReward",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
distributiontypes.NewMsgWithdrawDelegatorReward(
suite.createTestAddress(),
sdk.ValAddress(suite.createTestAddress()),
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Succeeds - Two Single-Signer MsgDelegate",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
stakingtypes.NewMsgDelegate(
testAddress,
sdk.ValAddress(suite.createTestAddress()),
suite.makeCoins("photon", math.NewInt(1))[0],
),
stakingtypes.NewMsgDelegate(
testAddress,
sdk.ValAddress(suite.createTestAddress()),
suite.makeCoins("photon", math.NewInt(5))[0],
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Fails - Two MsgVotes with Different Signers",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
govtypes.NewMsgVote(
suite.createTestAddress(),
25,
govtypes.OptionAbstain,
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Empty transaction",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Single-Signer MsgSend + MsgVote",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
testAddress,
5,
govtypes.OptionNo,
),
banktypes.NewMsgSend(
testAddress,
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Invalid ChainID",
chainId: "invalidchainid",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Includes TimeoutHeight",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
},
accountNumber: 25,
sequence: 78,
timeoutHeight: 1000,
expectSuccess: false,
},
{
title: "Fails - Single Message / Multi-Signer",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
banktypes.NewMsgMultiSend(
[]banktypes.Input{
banktypes.NewInput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
banktypes.NewInput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
},
[]banktypes.Output{
banktypes.NewOutput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
banktypes.NewOutput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
},
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
}
for _, tc := range testCases {
for _, signMode := range signModes {
suite.Run(tc.title, func() {
privKey, pubKey := suite.createTestKeyPair()
// Init tx builder
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
// Set gas and fees
txBuilder.SetGasLimit(tc.fee.GasLimit)
txBuilder.SetFeeAmount(tc.fee.Amount)
// Set messages
err := txBuilder.SetMsgs(tc.msgs...)
suite.Require().NoError(err)
// Set memo
txBuilder.SetMemo(tc.memo)
// Prepare signature field
txSigData := signing.SingleSignatureData{
SignMode: signMode,
Signature: nil,
}
txSig := signing.SignatureV2{
PubKey: pubKey,
Data: &txSigData,
Sequence: tc.sequence,
}
err = txBuilder.SetSignatures([]signing.SignatureV2{txSig}...)
suite.Require().NoError(err)
chainId := "ethermint_9000-1"
if tc.chainId != "" {
chainId = tc.chainId
}
if tc.timeoutHeight != 0 {
txBuilder.SetTimeoutHeight(tc.timeoutHeight)
}
// Declare signerData
signerData := authsigning.SignerData{
ChainID: chainId,
AccountNumber: tc.accountNumber,
Sequence: tc.sequence,
PubKey: pubKey,
Address: sdk.MustBech32ifyAddressBytes("ethm", pubKey.Bytes()),
}
bz, err := suite.clientCtx.TxConfig.SignModeHandler().GetSignBytes(
signMode,
signerData,
txBuilder.GetTx(),
)
suite.Require().NoError(err)
suite.verifyEIP712SignatureVerification(tc.expectSuccess, *privKey, *pubKey, bz)
})
}
}
}
// Verify that the payload passes signature verification if signed as its EIP-712 representation.
func (suite *EIP712TestSuite) verifyEIP712SignatureVerification(expectedSuccess bool, privKey ethsecp256k1.PrivKey, pubKey ethsecp256k1.PubKey, signBytes []byte) {
// Convert to EIP712 hash and sign
eip712Hash, err := eip712.GetEIP712HashForMsg(signBytes)
if !expectedSuccess {
// Expect failure generating EIP-712 hash
suite.Require().Error(err)
return
}
suite.Require().NoError(err)
sigHash := crypto.Keccak256Hash(eip712Hash)
sig, err := privKey.Sign(sigHash.Bytes())
suite.Require().NoError(err)
// Verify against original payload bytes. This should pass, even though it is not
// the original message that was signed.
res := pubKey.VerifySignature(signBytes, sig)
suite.Require().True(res)
// Verify against the signed EIP-712 bytes. This should pass, since it is the message signed.
res = pubKey.VerifySignature(eip712Hash, sig)
suite.Require().True(res)
// Verify against random bytes to ensure it does not pass unexpectedly (sanity check).
randBytes := make([]byte, len(signBytes))
copy(randBytes, signBytes)
// Change the first element of signBytes to a different value
randBytes[0] = (signBytes[0] + 10) % 128
res = pubKey.VerifySignature(randBytes, sig)
suite.Require().False(res)
}

285
ethereum/eip712/encoding.go Normal file
View File

@ -0,0 +1,285 @@
package eip712
import (
"encoding/json"
"errors"
"fmt"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
sdk "github.com/cosmos/cosmos-sdk/types"
txTypes "github.com/cosmos/cosmos-sdk/types/tx"
apitypes "github.com/ethereum/go-ethereum/signer/core/apitypes"
ethermint "github.com/evmos/ethermint/types"
"github.com/cosmos/cosmos-sdk/codec"
)
type aminoMessage struct {
Type string `json:"type"`
Value interface{} `json:"value"`
}
var (
protoCodec codec.ProtoCodecMarshaler
aminoCodec *codec.LegacyAmino
)
// SetEncodingConfig set the encoding config to the singleton codecs (Amino and Protobuf).
// The process of unmarshaling SignDoc bytes into a SignDoc object requires having a codec
// populated with all relevant message types. As a result, we must call this method on app
// initialization with the app's encoding config.
func SetEncodingConfig(cfg params.EncodingConfig) {
aminoCodec = cfg.Amino
protoCodec = codec.NewProtoCodec(cfg.InterfaceRegistry)
}
// Get the EIP-712 object hash for the given SignDoc bytes by first decoding the bytes into
// an EIP-712 object, then hashing the EIP-712 object to create the bytes to be signed.
// See https://eips.ethereum.org/EIPS/eip-712 for more.
func GetEIP712HashForMsg(signDocBytes []byte) ([]byte, error) {
typedData, err := GetEIP712TypedDataForMsg(signDocBytes)
if err != nil {
return nil, err
}
domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
if err != nil {
return nil, fmt.Errorf("could not hash EIP-712 domain: %w", err)
}
typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
if err != nil {
return nil, fmt.Errorf("could not hash EIP-712 primary type: %w", err)
}
rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
return rawData, nil
}
// GetEIP712TypedDataForMsg returns the EIP-712 TypedData representation for either
// Amino or Protobuf encoded signature doc bytes.
func GetEIP712TypedDataForMsg(signDocBytes []byte) (apitypes.TypedData, error) {
// Attempt to decode as both Amino and Protobuf since the message format is unknown.
// If either decode works, we can move forward with the corresponding typed data.
typedDataAmino, errAmino := decodeAminoSignDoc(signDocBytes)
if errAmino == nil && isValidEIP712Payload(typedDataAmino) {
return typedDataAmino, nil
}
typedDataProtobuf, errProtobuf := decodeProtobufSignDoc(signDocBytes)
if errProtobuf == nil && isValidEIP712Payload(typedDataProtobuf) {
return typedDataProtobuf, nil
}
return apitypes.TypedData{}, fmt.Errorf("could not decode sign doc as either Amino or Protobuf.\n amino: %v\n protobuf: %v", errAmino, errProtobuf)
}
// isValidEIP712Payload ensures that the given TypedData does not contain empty fields from
// an improper initialization.
func isValidEIP712Payload(typedData apitypes.TypedData) bool {
return len(typedData.Message) != 0 && len(typedData.Types) != 0 && typedData.PrimaryType != "" && typedData.Domain != apitypes.TypedDataDomain{}
}
// decodeAminoSignDoc attempts to decode the provided sign doc (bytes) as an Amino payload
// and returns a signable EIP-712 TypedData object.
func decodeAminoSignDoc(signDocBytes []byte) (apitypes.TypedData, error) {
var aminoDoc legacytx.StdSignDoc
if err := aminoCodec.UnmarshalJSON(signDocBytes, &aminoDoc); err != nil {
return apitypes.TypedData{}, err
}
var fees legacytx.StdFee
if err := aminoCodec.UnmarshalJSON(aminoDoc.Fee, &fees); err != nil {
return apitypes.TypedData{}, err
}
// Validate payload messages
msgs := make([]sdk.Msg, len(aminoDoc.Msgs))
for i, jsonMsg := range aminoDoc.Msgs {
var m sdk.Msg
if err := aminoCodec.UnmarshalJSON(jsonMsg, &m); err != nil {
return apitypes.TypedData{}, fmt.Errorf("failed to unmarshal sign doc message: %w", err)
}
msgs[i] = m
}
if err := validatePayloadMessages(msgs); err != nil {
return apitypes.TypedData{}, err
}
// Use first message for fee payer and type inference
msg := msgs[0]
// By convention, the fee payer is the first address in the list of signers.
feePayer := msg.GetSigners()[0]
feeDelegation := &FeeDelegationOptions{
FeePayer: feePayer,
}
chainID, err := ethermint.ParseChainID(aminoDoc.ChainID)
if err != nil {
return apitypes.TypedData{}, errors.New("invalid chain ID passed as argument")
}
typedData, err := WrapTxToTypedData(
protoCodec,
chainID.Uint64(),
msg,
signDocBytes,
feeDelegation,
)
if err != nil {
return apitypes.TypedData{}, fmt.Errorf("could not convert to EIP712 representation: %w", err)
}
return typedData, nil
}
// decodeProtobufSignDoc attempts to decode the provided sign doc (bytes) as a Protobuf payload
// and returns a signable EIP-712 TypedData object.
func decodeProtobufSignDoc(signDocBytes []byte) (apitypes.TypedData, error) {
signDoc := &txTypes.SignDoc{}
if err := signDoc.Unmarshal(signDocBytes); err != nil {
return apitypes.TypedData{}, err
}
authInfo := &txTypes.AuthInfo{}
if err := authInfo.Unmarshal(signDoc.AuthInfoBytes); err != nil {
return apitypes.TypedData{}, err
}
body := &txTypes.TxBody{}
if err := body.Unmarshal(signDoc.BodyBytes); err != nil {
return apitypes.TypedData{}, err
}
// Until support for these fields is added, throw an error at their presence
if body.TimeoutHeight != 0 || len(body.ExtensionOptions) != 0 || len(body.NonCriticalExtensionOptions) != 0 {
return apitypes.TypedData{}, errors.New("body contains unsupported fields: TimeoutHeight, ExtensionOptions, or NonCriticalExtensionOptions")
}
if len(authInfo.SignerInfos) != 1 {
return apitypes.TypedData{}, fmt.Errorf("invalid number of signer infos provided, expected 1 got %v", len(authInfo.SignerInfos))
}
// Validate payload messages
msgs := make([]sdk.Msg, len(body.Messages))
for i, protoMsg := range body.Messages {
var m sdk.Msg
if err := protoCodec.UnpackAny(protoMsg, &m); err != nil {
return apitypes.TypedData{}, fmt.Errorf("could not unpack message object with error %w", err)
}
msgs[i] = m
}
if err := validatePayloadMessages(msgs); err != nil {
return apitypes.TypedData{}, err
}
// Use first message for fee payer and type inference
msg := msgs[0]
signerInfo := authInfo.SignerInfos[0]
chainID, err := ethermint.ParseChainID(signDoc.ChainId)
if err != nil {
return apitypes.TypedData{}, fmt.Errorf("invalid chain ID passed as argument: %w", err)
}
stdFee := &legacytx.StdFee{
Amount: authInfo.Fee.Amount,
Gas: authInfo.Fee.GasLimit,
}
feePayer := msg.GetSigners()[0]
feeDelegation := &FeeDelegationOptions{
FeePayer: feePayer,
}
tip := authInfo.Tip
// WrapTxToTypedData expects the payload as an Amino Sign Doc
signBytes := legacytx.StdSignBytes(
signDoc.ChainId,
signDoc.AccountNumber,
signerInfo.Sequence,
body.TimeoutHeight,
*stdFee,
msgs,
body.Memo,
tip,
)
typedData, err := WrapTxToTypedData(
protoCodec,
chainID.Uint64(),
msg,
signBytes,
feeDelegation,
)
if err != nil {
return apitypes.TypedData{}, err
}
return typedData, nil
}
// validatePayloadMessages ensures that the transaction messages can be represented in an EIP-712
// encoding by checking that messages exist, are of the same type, and share a single signer.
func validatePayloadMessages(msgs []sdk.Msg) error {
if len(msgs) == 0 {
return errors.New("unable to build EIP-712 payload: transaction does contain any messages")
}
var msgType string
var msgSigner sdk.AccAddress
for i, m := range msgs {
t, err := getMsgType(m)
if err != nil {
return err
}
if len(m.GetSigners()) != 1 {
return errors.New("unable to build EIP-712 payload: expect exactly 1 signer")
}
if i == 0 {
msgType = t
msgSigner = m.GetSigners()[0]
continue
}
if t != msgType {
return errors.New("unable to build EIP-712 payload: different types of messages detected")
}
if !msgSigner.Equals(m.GetSigners()[0]) {
return errors.New("unable to build EIP-712 payload: multiple signers detected")
}
}
return nil
}
// getMsgType returns the message type prefix for the given Cosmos SDK Msg
func getMsgType(msg sdk.Msg) (string, error) {
jsonBytes, err := aminoCodec.MarshalJSON(msg)
if err != nil {
return "", err
}
var jsonMsg aminoMessage
if err := json.Unmarshal(jsonBytes, &jsonMsg); err != nil {
return "", err
}
// Verify Type was successfully filled in
if jsonMsg.Type == "" {
return "", errors.New("could not decode message: type is missing")
}
return jsonMsg.Type, nil
}

63
go.mod
View File

@ -3,15 +3,18 @@ module github.com/evmos/ethermint
go 1.19
require (
cosmossdk.io/math v1.0.0-beta.3
cosmossdk.io/errors v1.0.0-beta.7
cosmossdk.io/math v1.0.0-beta.4
github.com/armon/go-metrics v0.4.1
github.com/btcsuite/btcd v0.22.1
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
github.com/cosmos/cosmos-sdk v0.46.4
github.com/cosmos/cosmos-proto v1.0.0-alpha8
github.com/cosmos/cosmos-sdk v0.46.6
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/ibc-go/v5 v5.0.1
github.com/cosmos/gogoproto v1.4.3
github.com/cosmos/ibc-go/v5 v5.1.0
github.com/davecgh/go-spew v1.1.1
github.com/ethereum/go-ethereum v1.10.19
github.com/ethereum/go-ethereum v1.10.25
github.com/gogo/protobuf v1.3.3
github.com/golang/protobuf v1.5.2
github.com/gorilla/mux v1.8.0
@ -20,34 +23,32 @@ require (
github.com/holiman/uint256 v1.2.1
github.com/improbable-eng/grpc-web v0.15.0
github.com/miguelmota/go-ethereum-hdwallet v0.1.1
github.com/onsi/ginkgo/v2 v2.4.0
github.com/onsi/gomega v1.23.0
github.com/onsi/ginkgo/v2 v2.5.1
github.com/onsi/gomega v1.24.1
github.com/pkg/errors v0.9.1
github.com/rakyll/statik v0.1.7
github.com/regen-network/cosmos-proto v0.3.1
github.com/rs/cors v1.8.2
github.com/spf13/cast v1.5.0
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.13.0
github.com/spf13/viper v1.14.0
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969
github.com/stretchr/testify v1.8.1
github.com/tendermint/tendermint v0.34.22
github.com/tendermint/tendermint v0.34.23
github.com/tendermint/tm-db v0.6.7
github.com/tyler-smith/go-bip39 v1.1.0
golang.org/x/net v0.1.0
golang.org/x/net v0.2.0
golang.org/x/text v0.4.0
google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55
google.golang.org/grpc v1.50.1
google.golang.org/protobuf v1.28.1
google.golang.org/genproto v0.0.0-20221116193143-41c2ba794472
google.golang.org/grpc v1.51.0
sigs.k8s.io/yaml v1.3.0
)
require (
cloud.google.com/go v0.102.1 // indirect
cloud.google.com/go/compute v1.7.0 // indirect
cloud.google.com/go/iam v0.4.0 // indirect
cloud.google.com/go/storage v1.22.1 // indirect
cosmossdk.io/errors v1.0.0-beta.7 // indirect
cloud.google.com/go v0.105.0 // indirect
cloud.google.com/go/compute v1.12.1 // indirect
cloud.google.com/go/compute/metadata v0.2.1 // indirect
cloud.google.com/go/iam v0.7.0 // indirect
cloud.google.com/go/storage v1.27.0 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/keyring v1.2.1 // indirect
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
@ -68,7 +69,6 @@ require (
github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect
github.com/confio/ics23/go v0.7.0 // indirect
github.com/cosmos/btcutil v1.0.4 // indirect
github.com/cosmos/cosmos-proto v1.0.0-alpha7 // indirect
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/iavl v0.19.4 // indirect
github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect
@ -87,7 +87,7 @@ require (
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
@ -105,9 +105,8 @@ require (
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
github.com/googleapis/go-type-adapters v1.0.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
github.com/googleapis/gax-go/v2 v2.6.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
@ -128,7 +127,7 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
@ -151,9 +150,10 @@ require (
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.34.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/prometheus/tsdb v0.7.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/regen-network/cosmos-proto v0.3.1 // indirect
github.com/rjeczalik/notify v0.9.1 // indirect
github.com/rs/zerolog v1.27.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
@ -173,15 +173,16 @@ require (
github.com/zondax/hid v0.9.1-0.20220302062450-5552068d2266 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/crypto v0.3.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/term v0.1.0 // indirect
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/term v0.2.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.93.0 // indirect
google.golang.org/api v0.102.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect

317
go.sum
View File

@ -19,21 +19,8 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go v0.102.1 h1:vpK6iQWv/2uUeFJth4/cBHsQAGjn1iIE6AAlxipRaA0=
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -41,18 +28,15 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0=
cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48=
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
cloud.google.com/go/iam v0.4.0 h1:YBYU00SCDzZJdHqVc4I5d6lsklcYIjQZa1YmEz4jlSE=
cloud.google.com/go/iam v0.4.0/go.mod h1:cbaZxyScUhxl7ZAkNWiALgihfP75wS/fUsVNaa1r3vA=
cloud.google.com/go/iam v0.7.0 h1:k4MuwOsS7zGJJ+QfZ5vBK8SgHBAvYN/23BWsiihJ1vs=
cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -63,13 +47,13 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.22.1 h1:F6IlQJZrZM++apn9V5/VfS3gbTUYg98PS3EMQAzqtfg=
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ=
cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w=
cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE=
cosmossdk.io/math v1.0.0-beta.3 h1:TbZxSopz2LqjJ7aXYfn7nJSb8vNaBklW6BLpcei1qwM=
cosmossdk.io/math v1.0.0-beta.3/go.mod h1:3LYasri3Zna4XpbrTNdKsWmD5fHHkaNAod/mNT9XdE4=
cosmossdk.io/math v1.0.0-beta.4 h1:JtKedVLGzA0vv84xjYmZ75RKG35Kf2WwcFu8IjRkIIw=
cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
@ -100,7 +84,7 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -222,12 +206,6 @@ github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3h
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E=
github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
@ -248,29 +226,33 @@ github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44=
github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU=
github.com/cosmos/cosmos-proto v1.0.0-alpha7 h1:yqYUOHF2jopwZh4dVQp3xgqwftE5/2hkrwIV6vkUbO0=
github.com/cosmos/cosmos-proto v1.0.0-alpha7/go.mod h1:dosO4pSAbJF8zWCzCoTWP7nNsjcvSUBQmniFxDg5daw=
github.com/cosmos/cosmos-sdk v0.46.4 h1:I4CPfnz7lAPM7cEvvyTxL1h3M/ugbhTNr5ZRcnW8WsU=
github.com/cosmos/cosmos-sdk v0.46.4/go.mod h1:b5usG7aBEEvhaatYCdV6orFbDUsj4BG1V6UtKwNcJeQ=
github.com/cosmos/cosmos-proto v1.0.0-alpha8 h1:d3pCRuMYYvGA5bM0ZbbjKn+AoQD4A7dyNG2wzwWalUw=
github.com/cosmos/cosmos-proto v1.0.0-alpha8/go.mod h1:6/p+Bc4O8JKeZqe0VqUGTX31eoYqemTT4C1hLCWsO7I=
github.com/cosmos/cosmos-sdk v0.46.6 h1:K9EZsqOZ2jQX3bIQUpn7Hk/YCoaJWRLU56PzvpX8INk=
github.com/cosmos/cosmos-sdk v0.46.6/go.mod h1:JNklMfXo7MhDF1j/jxZCmDyOYyqhVoKB22e8p1ATEqA=
github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k=
github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
github.com/cosmos/gogoproto v1.4.3 h1:RP3yyVREh9snv/lsOvmsAPQt8f44LgL281X0IOIhhcI=
github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU=
github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y=
github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw=
github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok=
github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw=
github.com/cosmos/ibc-go/v5 v5.0.1 h1:ZI5xCi6RDOL+hyu6Wx/w6JoAYFlOoK5hijsRTVWo+RA=
github.com/cosmos/ibc-go/v5 v5.0.1/go.mod h1:LX0DHLW3dfi/1e4BJzi8MGLWmQ4DSraPEgVjyo3VzAo=
github.com/cosmos/ibc-go/v5 v5.1.0 h1:m1NHXFkwwvNeJegZqtyox1WLinh+PMy4ivU/Cs9KjeA=
github.com/cosmos/ibc-go/v5 v5.1.0/go.mod h1:H6sV0/CkNRDtvSrhbsIgiog1WnSwhguGfg8x34MOVEk=
github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 h1:DdzS1m6o/pCqeZ8VOAit/gyATedRgjvkVI+UCrLpyuU=
github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76/go.mod h1:0mkLWIoZuQ7uBoospo5Q9zIpqq6rYCPJDSUdeCJvPM8=
github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY=
github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI=
github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM=
github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk=
@ -316,7 +298,7 @@ github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ=
@ -340,15 +322,11 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=
github.com/ethereum/go-ethereum v1.10.19 h1:EOR5JbL4MD5yeOqv8W2iC1s4NximrTjqFccUz8lyBRA=
github.com/ethereum/go-ethereum v1.10.19/go.mod h1:IJBNMtzKcNHPtllYihy6BL2IgK1u+32JriaTbdt4v+w=
github.com/ethereum/go-ethereum v1.10.25 h1:5dFrKJDnYf8L6/5o42abCE6a9yJm9cs4EJVRyYMr55s=
github.com/ethereum/go-ethereum v1.10.25/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
@ -365,8 +343,8 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
@ -450,9 +428,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -469,7 +445,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@ -494,9 +469,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
@ -508,7 +480,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ=
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us=
github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -521,11 +492,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -534,19 +500,12 @@ github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw=
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs=
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk=
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU=
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
@ -698,8 +657,8 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
@ -830,17 +789,17 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
github.com/onsi/ginkgo/v2 v2.5.1 h1:auzK7OI497k6x4OvWq+TKAcpcSAlod0doAH72oIN0Jw=
github.com/onsi/ginkgo/v2 v2.5.1/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@ -918,8 +877,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
@ -937,15 +897,17 @@ github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRr
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
@ -989,8 +951,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 h1:Oo2KZNP70KE0+IUJSidPj/BFS/RXNHmKIJOdckzml2E=
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
@ -1025,8 +987,8 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RM
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
github.com/tendermint/tendermint v0.34.22 h1:XMhtC8s8QqJO4l/dn+TkQvevTRSow3Vixjclr41o+2Q=
github.com/tendermint/tendermint v0.34.22/go.mod h1:YpP5vBEAKUT4g6oyfjKgFeZmdB/GjkJAxfF+cgmJg6Y=
github.com/tendermint/tendermint v0.34.23 h1:JZYsdc59aOiT5efou+BHILJv8x6FlRyvlor84Xq9Tb0=
github.com/tendermint/tendermint v0.34.23/go.mod h1:rXVrl4OYzmIa1I91av3iLv2HS0fGSiucyW9J4aMTpKI=
github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8=
github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@ -1057,8 +1019,10 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
@ -1068,6 +1032,7 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -1091,7 +1056,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@ -1123,8 +1087,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1155,7 +1119,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@ -1167,6 +1130,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1215,9 +1179,7 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -1225,13 +1187,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1241,19 +1198,10 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1265,9 +1213,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc=
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1331,55 +1278,35 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1397,7 +1324,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -1456,18 +1383,12 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
@ -1496,28 +1417,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
google.golang.org/api v0.93.0 h1:T2xt9gi0gHdxdnRkVQhT8mIvPaXKNsDNWz+L696M66M=
google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/api v0.102.0 h1:JxJl2qQ85fRMPNvlZY/enexbxpCjLwGhZUtgfGeQ51I=
google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1570,54 +1471,9 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 h1:U1u4KB2kx6KR/aJDjQ97hZ15wQs8ZPvDcGcRynBhkvg=
google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55/go.mod h1:45EK0dUbEZ2NHjCeAd2LXmyjAgGUGrpGROgjhC3ADck=
google.golang.org/genproto v0.0.0-20221116193143-41c2ba794472 h1:kIfItBRE5gkUKpH4H5lNGciZbka1JrmRli3ArqrKFkA=
google.golang.org/genproto v0.0.0-20221116193143-41c2ba794472/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@ -1642,23 +1498,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -1671,10 +1512,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk=
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -1695,7 +1534,6 @@ gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJ
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@ -1724,8 +1562,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g=
pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
pgregory.net/rapid v0.5.3 h1:163N50IHFqr1phZens4FQOdPgfJscR7a562mjQqeo4M=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

View File

@ -2,23 +2,26 @@ schema = 3
[mod]
[mod."cloud.google.com/go"]
version = "v0.102.1"
hash = "sha256-rv3MHFvIrN6AcrmWcWGSQwgaZLbjJMmJFi3bsfHoiO4="
version = "v0.105.0"
hash = "sha256-2nYtHjuN9ghGcM6aPlOxyNNarHebHtj0Xec48sWwdaI="
[mod."cloud.google.com/go/compute"]
version = "v1.7.0"
hash = "sha256-g+n7L36LC+NP4KaiEu9fCMn6S9fkxjp4PCLOp/oXV38="
version = "v1.12.1"
hash = "sha256-mMsdL+6R1KuFeAFqEJv8oq/cmRc9hSluEisCpGP0GTc="
[mod."cloud.google.com/go/compute/metadata"]
version = "v0.2.1"
hash = "sha256-gqjkb6y5POkTWXGQtCvgygvXqoLkESB+cykKp7Mp3jI="
[mod."cloud.google.com/go/iam"]
version = "v0.4.0"
hash = "sha256-sPtj6QPPC/QrkDXJW4Y7rMIHk5l1y9XV/DgM47eEtvg="
version = "v0.7.0"
hash = "sha256-2UTJ/BbZ+YMGJhyo3HRPUYVDXW6+B5znFdqiutboYtA="
[mod."cloud.google.com/go/storage"]
version = "v1.22.1"
hash = "sha256-YZt05wru0kacyi6moTgvocavActKpXx7FlLh+o0HGDs="
version = "v1.27.0"
hash = "sha256-V4B6A1Ms8cemB5Cs6nAtUe1N1ldaI9oqTdzGU2FUhrc="
[mod."cosmossdk.io/errors"]
version = "v1.0.0-beta.7"
hash = "sha256-XblGvIx6Wvvq6wggXjp+KbeJGXoe7AZH7hXEdauCezU="
[mod."cosmossdk.io/math"]
version = "v1.0.0-beta.3"
hash = "sha256-lTQ27ZlL+kWlc+S//sJmyiOwaf9qS+YLv61I4OXi9XE="
version = "v1.0.0-beta.4"
hash = "sha256-UYdq/46EubyjxkldGike8FlwJLWGCB576VB7th285ao="
[mod."filippo.io/edwards25519"]
version = "v1.0.0-rc.1"
hash = "sha256-3DboBqby2ejRU33FG96Z8JF5AJ8HP2rC/v++VyoQ2LQ="
@ -91,14 +94,17 @@ schema = 3
version = "v1.0.4"
hash = "sha256-JvcBXBdjdmnaW/nyf/tw/uaOAGn1b78yxrtl2/Rs3kA="
[mod."github.com/cosmos/cosmos-proto"]
version = "v1.0.0-alpha7"
hash = "sha256-2wCH+toTF2A6MfFjOa13muEH5oBCcxAhZEqirNOrBA0="
version = "v1.0.0-alpha8"
hash = "sha256-iXzXoS5Kfh5DBy+PhdFWraDWXda/3M4j7j4VECjv4CA="
[mod."github.com/cosmos/cosmos-sdk"]
version = "v0.46.4"
hash = "sha256-YjrhZsGKMH7kxCS9Lhbvt7YjJs/B+9aSS+l042oBhAw="
version = "v0.46.6"
hash = "sha256-H1VZxZUWXhpXiY3A9smLp09MEGpXmh+XvX6YUiXPcpQ="
[mod."github.com/cosmos/go-bip39"]
version = "v1.0.0"
hash = "sha256-Qm2aC2vaS8tjtMUbHmlBSagOSqbduEEDwc51qvQaBmA="
[mod."github.com/cosmos/gogoproto"]
version = "v1.4.3"
hash = "sha256-Y/NL76ay/oAl8mS3skkK5ula0/xudqbwW1o22lZjKRg="
[mod."github.com/cosmos/gorocksdb"]
version = "v1.2.0"
hash = "sha256-209TcVuXc5s/TcOvNlaQ1HEJAUDTEK3nxPhs+d8TEcY="
@ -106,8 +112,8 @@ schema = 3
version = "v0.19.4"
hash = "sha256-EmpRZ48pjPFq/fIHneut9Vyo5QJATfb3ZO7KzWnqs9g="
[mod."github.com/cosmos/ibc-go/v5"]
version = "v5.0.1"
hash = "sha256-44Vyj9i4gh6U0BGNsEFqRsHAYdxfuJmLGdtPWxcBfWQ="
version = "v5.1.0"
hash = "sha256-9ZwGw6XqYkBtj+vTQ2IodNb7VcGesTFnVsxjd+G1I6Q="
[mod."github.com/cosmos/ledger-cosmos-go"]
version = "v0.11.1"
hash = "sha256-yli+VvVtZmHo2LPvCY6lYVUfcCDn3sBLDL+a8KIlqDA="
@ -157,14 +163,14 @@ schema = 3
version = "v1.0.0"
hash = "sha256-k1DYvCqO3BKNcGEve/nMW0RxzMkK2tGfXbUbycqcVSo="
[mod."github.com/ethereum/go-ethereum"]
version = "v1.10.19"
hash = "sha256-7FPnTGcCb8Xd1QVR+6PmGTaHdTY1mm/8osFTW1JLuG8="
version = "v1.10.25"
hash = "sha256-tNlI2XyuTXjGuBoe5vlYDcaGN2Sub7yltVtI6TeLLSc="
[mod."github.com/felixge/httpsnoop"]
version = "v1.0.1"
hash = "sha256-TNXnnC/ZGNY9lInAcES1cBGqIdEljKuh5LH/khVFjVk="
[mod."github.com/fsnotify/fsnotify"]
version = "v1.5.4"
hash = "sha256-iPuInpDAJvDeSTr6to713J/fTOWdQIWlLXWAuWIs2Bw="
version = "v1.6.0"
hash = "sha256-DQesOCweQPEwmAn6s7DCP/Dwy8IypC+osbpfsvpkdP0="
[mod."github.com/gballet/go-libpcsclite"]
version = "v0.0.0-20190607065134-2772fd86a8ff"
hash = "sha256-Nr5ocU9s1F2Lhx/Zq6/nIo+KkKEqMjDYOEs3yWRC48g="
@ -224,14 +230,11 @@ schema = 3
version = "v1.3.0"
hash = "sha256-QoR55eBtA94T2tBszyxfDtO7/pjZZSGb5vm7U0Xhs0Y="
[mod."github.com/googleapis/enterprise-certificate-proxy"]
version = "v0.1.0"
hash = "sha256-fxaElfiGGh1mLmltkFpVFdiuaagrLZLTW9btVpK13wg="
version = "v0.2.0"
hash = "sha256-5gxsS5kDLqNFBkQ4eK6GS/sNn+aFknm6jjfteO+6jl4="
[mod."github.com/googleapis/gax-go/v2"]
version = "v2.4.0"
hash = "sha256-zzat4+3iF2XBTQ6RZAUgsCbfK0HgO0nYhM4utA5dqz0="
[mod."github.com/googleapis/go-type-adapters"]
version = "v1.0.0"
hash = "sha256-u3ajruRV/EN2E1WKet/zoe3zmRrAy4C5F2Dx8bpQwoc="
version = "v2.6.0"
hash = "sha256-sSsncbJmv0n5jB3G7tHY1Zr2ucCusIeTrXZH4A8QqYI="
[mod."github.com/gorilla/handlers"]
version = "v1.5.1"
hash = "sha256-GnBAARgOx1E+hDMQ63SI17hdhGtLQxb31lZOmn5j/pU="
@ -308,8 +311,8 @@ schema = 3
version = "v0.0.0-20190712205309-48d3d31d256d"
hash = "sha256-bn04wkDnhQ0tb/YzmPf7MNJlApOl+z6+EAbUqH7Ti5Q="
[mod."github.com/klauspost/compress"]
version = "v1.15.9"
hash = "sha256-ctPxlVq0c/SoNPVsP66RjxUjTHys3diW2Apxjyc9WdE="
version = "v1.15.11"
hash = "sha256-9MXm0TObg6DyqnYMIw3IChrorHc2ILf5djZYoM0e1J0="
[mod."github.com/lib/pq"]
version = "v1.10.6"
hash = "sha256-8EhFwY/9YH5L/fd6l2beOnC3VvpegRAmCCsnDVJBqBM="
@ -359,11 +362,11 @@ schema = 3
version = "v0.0.5"
hash = "sha256-/5i70IkH/qSW5KjGzv8aQNKh9tHoz98tqtL0K2DMFn4="
[mod."github.com/onsi/ginkgo/v2"]
version = "v2.4.0"
hash = "sha256-Z+bch118Akc5wGkOM7ZePNqw7vW5euXE7ec4Y297HNw="
version = "v2.5.1"
hash = "sha256-VB29+H9k7l6il63oXJvsjamSUhsw/e99iI/BeTCderA="
[mod."github.com/onsi/gomega"]
version = "v1.23.0"
hash = "sha256-g5FaFLUK8ZAR9VgFTTH0ax0t45tZkYbIHbq/gANIOTM="
version = "v1.24.1"
hash = "sha256-REfxQTDRcO23GnmJfOW8/MmPJf9oE2grVvvGiC1eSbo="
[mod."github.com/pelletier/go-toml"]
version = "v1.9.5"
hash = "sha256-RJ9K1BTId0Mled7S66iGgxHkZ5JKEIsrrNaEfM8aImc="
@ -389,8 +392,8 @@ schema = 3
version = "v0.34.0"
hash = "sha256-M+v+7DntUBmiQNzfNmG3aLLufbl0XBQOubtYoNTzJDA="
[mod."github.com/prometheus/procfs"]
version = "v0.7.3"
hash = "sha256-ik0WpnpSjMwifPYfQTfu/eb5ilNj+eLJF0d5Dftp8A8="
version = "v0.8.0"
hash = "sha256-hgrilokQsXCOCCvwgOSfuErxoFAQpXM/+zNJKcMVHyM="
[mod."github.com/prometheus/tsdb"]
version = "v0.7.1"
hash = "sha256-BPz7YJbfMZgeR+u9YaeWeipVzHIS73EdgXD7VSJSLbA="
@ -434,8 +437,8 @@ schema = 3
version = "v1.0.5"
hash = "sha256-w9LLYzxxP74WHT4ouBspH/iQZXjuAh2WQCHsuvyEjAw="
[mod."github.com/spf13/viper"]
version = "v1.13.0"
hash = "sha256-yHviS3lMo1hB6jwyiU3zpyGtxP6v9AsyZUKiLeCVz+k="
version = "v1.14.0"
hash = "sha256-qn3VzD339HZIub5QP4aWVciSufAfVb9llbmQZ8pfDEs="
[mod."github.com/status-im/keycard-go"]
version = "v0.0.0-20200402102358-957c09536969"
hash = "sha256-yddXXuu6mEFEO2/K6c1tWymeBKzOcvLQnNsFGRjtfXk="
@ -461,8 +464,8 @@ schema = 3
version = "v0.16.0"
hash = "sha256-JW4zO/0vMzf1dXLePOqaMtiLUZgNbuIseh9GV+jQlf0="
[mod."github.com/tendermint/tendermint"]
version = "v0.34.22"
hash = "sha256-4p4cpyCWjBbNQUpYN2gDJvnyj+Pov9hw5uRjHrrO++Y="
version = "v0.34.23"
hash = "sha256-eir0vr8lQOG+FTPo+ZUeDidAIACfyUq2ie3XRE8rIa4="
[mod."github.com/tendermint/tm-db"]
version = "v0.6.7"
hash = "sha256-hl/3RrBrpkk2zA6dmrNlIYKs1/GfqegSscDSkA5Pjlo="
@ -488,26 +491,26 @@ schema = 3
version = "v0.23.0"
hash = "sha256-R3O9GyNtv6j0ic7s+2xkLLaLzbJEop0Otj1nJDFBjsg="
[mod."golang.org/x/crypto"]
version = "v0.1.0"
hash = "sha256-0oZWBSiW5Pd/2a1p2beuoelDe0CpfXZhrg/qPduJlYs="
version = "v0.3.0"
hash = "sha256-Un9wPqz8u/xpV98T4IqE6RMXIPhGCIm2prsNkHP3cjg="
[mod."golang.org/x/exp"]
version = "v0.0.0-20220722155223-a9213eeb770e"
hash = "sha256-kNgzydWRpjm0sZl4uXEs3LX5L0xjJtJRAFf/CTlYUN4="
[mod."golang.org/x/net"]
version = "v0.1.0"
hash = "sha256-SrThFBg6sqGYpiN1E3d1SilJxbKkQhSZXPmAFoMAA/I="
version = "v0.2.0"
hash = "sha256-0MqnHDdLkkau6k7hlWD9MzIoAFROvxulyT+KzZkSXOs="
[mod."golang.org/x/oauth2"]
version = "v0.0.0-20220622183110-fd043fe589d2"
hash = "sha256-VLffpTpx3DlUzXB8mKiJfFzm4ZmgnLSUuLB5Ir0WQUg="
version = "v0.0.0-20221014153046-6fdb5e3db783"
hash = "sha256-IoygidVNqyAZmN+3macDeIefK8hhJToygpcqlwehdYQ="
[mod."golang.org/x/sync"]
version = "v0.0.0-20220819030929-7fc1605a5dde"
hash = "sha256-5EOxO8FRdaLW9v/DhwBmWiT2G34A2ofxSCaC7ovvpb0="
version = "v0.1.0"
hash = "sha256-Hygjq9euZ0qz6TvHYQwOZEjNiTbTh1nSLRAWZ6KFGR8="
[mod."golang.org/x/sys"]
version = "v0.1.0"
hash = "sha256-nZbEJ/2PuWrDLD4ujeVvcFGoIsfVoIH/Lcp4FjD7hpU="
version = "v0.2.0"
hash = "sha256-N6yfQH7R2gfcvyWTQZbxWuSNyVy6hAxiab2WFzgAykI="
[mod."golang.org/x/term"]
version = "v0.1.0"
hash = "sha256-UWnNsJIj5nXsuzlPWQ1NyHQuHStaDacMVkFbJ4pnxXk="
version = "v0.2.0"
hash = "sha256-azcllZ0o/9TurqX9udaJ0o9yxqSoI0/bSJsvQQLYIQc="
[mod."golang.org/x/text"]
version = "v0.4.0"
hash = "sha256-JvyMygdmTvWg7xhbnUB9MMk6WcYXJt8DAj4DYl82Pys="
@ -515,20 +518,20 @@ schema = 3
version = "v0.0.0-20220907171357-04be3eba64a2"
hash = "sha256-6+zueutgefIYmgXinOflz8qGDDDj0Zhv+2OkGhBTKno="
[mod."google.golang.org/api"]
version = "v0.93.0"
hash = "sha256-W17B79osAhObMbrCHlgywEPg9yIPx0ZISDhp9JwFE5A="
version = "v0.102.0"
hash = "sha256-q8t08Wu0qzOQOmhY4GSoUrhqLTW/TeXiKhio+5ONfe4="
[mod."google.golang.org/appengine"]
version = "v1.6.7"
hash = "sha256-zIxGRHiq4QBvRqkrhMGMGCaVL4iM4TtlYpAi/hrivS4="
[mod."google.golang.org/genproto"]
version = "v0.0.0-20221018160656-63c7b68cfc55"
hash = "sha256-Z4ynOw+3NkSkWVOrNaeuQC3G9Q6+joNbTLVoF2HegrU="
version = "v0.0.0-20221116193143-41c2ba794472"
hash = "sha256-uQuxuOvWRsdMii5M5QresisVd1E+Ss8s2WfR2n7QSXk="
[mod."google.golang.org/grpc"]
version = "v1.50.1"
hash = "sha256-38nk4qIme+fE57SsCqNxtCZnc8fyzzi4Sb60uDTT2KE="
version = "v1.51.0"
hash = "sha256-RzH5DU13D/ulxxOouIKpdNt8eHdff7mrEnB+JUupbLU="
[mod."google.golang.org/protobuf"]
version = "v1.28.1"
hash = "sha256-sTJYgvlv5is7vHNxcuigF2lNASp0QonhUgnrguhfHSU="
version = "v1.28.2-0.20220831092852-f930b1dc76e8"
hash = "sha256-li5hXlXwTJ5LIZ8bVki1AZ6UFI2gXHl33JwdX1dOrtM="
[mod."gopkg.in/ini.v1"]
version = "v1.67.0"
hash = "sha256-V10ahGNGT+NLRdKUyRg1dos5RxLBXBk1xutcnquc/+4="

View File

@ -3,10 +3,10 @@ package indexer
import (
"fmt"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/ethereum/go-ethereum/common"
rpctypes "github.com/evmos/ethermint/rpc/types"
@ -110,12 +110,12 @@ func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.Response
ethTxIndex++
if err := saveTxResult(kv.clientCtx.Codec, batch, txHash, &txResult); err != nil {
return sdkerrors.Wrapf(err, "IndexBlock %d", height)
return errorsmod.Wrapf(err, "IndexBlock %d", height)
}
}
}
if err := batch.Write(); err != nil {
return sdkerrors.Wrapf(err, "IndexBlock %d, write batch", block.Height)
return errorsmod.Wrapf(err, "IndexBlock %d, write batch", block.Height)
}
return nil
}
@ -134,14 +134,14 @@ func (kv *KVIndexer) FirstIndexedBlock() (int64, error) {
func (kv *KVIndexer) GetByTxHash(hash common.Hash) (*ethermint.TxResult, error) {
bz, err := kv.db.Get(TxHashKey(hash))
if err != nil {
return nil, sdkerrors.Wrapf(err, "GetByTxHash %s", hash.Hex())
return nil, errorsmod.Wrapf(err, "GetByTxHash %s", hash.Hex())
}
if len(bz) == 0 {
return nil, fmt.Errorf("tx not found, hash: %s", hash.Hex())
}
var txKey ethermint.TxResult
if err := kv.clientCtx.Codec.Unmarshal(bz, &txKey); err != nil {
return nil, sdkerrors.Wrapf(err, "GetByTxHash %s", hash.Hex())
return nil, errorsmod.Wrapf(err, "GetByTxHash %s", hash.Hex())
}
return &txKey, nil
}
@ -150,7 +150,7 @@ func (kv *KVIndexer) GetByTxHash(hash common.Hash) (*ethermint.TxResult, error)
func (kv *KVIndexer) GetByBlockAndIndex(blockNumber int64, txIndex int32) (*ethermint.TxResult, error) {
bz, err := kv.db.Get(TxIndexKey(blockNumber, txIndex))
if err != nil {
return nil, sdkerrors.Wrapf(err, "GetByBlockAndIndex %d %d", blockNumber, txIndex)
return nil, errorsmod.Wrapf(err, "GetByBlockAndIndex %d %d", blockNumber, txIndex)
}
if len(bz) == 0 {
return nil, fmt.Errorf("tx not found, block: %d, eth-index: %d", blockNumber, txIndex)
@ -174,7 +174,7 @@ func TxIndexKey(blockNumber int64, txIndex int32) []byte {
func LoadLastBlock(db dbm.DB) (int64, error) {
it, err := db.ReverseIterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
if err != nil {
return 0, sdkerrors.Wrap(err, "LoadLastBlock")
return 0, errorsmod.Wrap(err, "LoadLastBlock")
}
defer it.Close()
if !it.Valid() {
@ -187,7 +187,7 @@ func LoadLastBlock(db dbm.DB) (int64, error) {
func LoadFirstBlock(db dbm.DB) (int64, error) {
it, err := db.Iterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
if err != nil {
return 0, sdkerrors.Wrap(err, "LoadFirstBlock")
return 0, errorsmod.Wrap(err, "LoadFirstBlock")
}
defer it.Close()
if !it.Valid() {
@ -213,10 +213,10 @@ func isEthTx(tx sdk.Tx) bool {
func saveTxResult(codec codec.Codec, batch dbm.Batch, txHash common.Hash, txResult *ethermint.TxResult) error {
bz := codec.MustMarshal(txResult)
if err := batch.Set(TxHashKey(txHash), bz); err != nil {
return sdkerrors.Wrap(err, "set tx-hash key")
return errorsmod.Wrap(err, "set tx-hash key")
}
if err := batch.Set(TxIndexKey(txResult.Height, txResult.EthTxIndex), txHash.Bytes()); err != nil {
return sdkerrors.Wrap(err, "set tx-index key")
return errorsmod.Wrap(err, "set tx-index key")
}
return nil
}

View File

@ -6,7 +6,7 @@ MONIKER="localtestnet"
KEYRING="test"
KEYALGO="eth_secp256k1"
LOGLEVEL="info"
# to trace evm
# trace evm
TRACE="--trace"
# TRACE=""

View File

@ -27,7 +27,7 @@ import sources.nixpkgs {
dotenv = builtins.path { name = "dotenv"; path = ../scripts/.env; };
};
})
(_: pkgs: { test-env = import ./testenv.nix { inherit pkgs; }; })
(_: pkgs: { test-env = pkgs.callPackage ./testenv.nix { }; })
(_: pkgs: {
cosmovisor = pkgs.buildGo118Module rec {
name = "cosmovisor";

View File

@ -1,4 +1,4 @@
{ lib, stdenv, buildGoModule, fetchFromGitHub, libobjc, IOKit }:
{ lib, stdenv, buildGoModule, fetchFromGitHub, libobjc, IOKit, nixosTests }:
let
# A list of binaries to put into separate outputs
@ -7,19 +7,18 @@ let
"clef"
];
in
buildGoModule rec {
in buildGoModule rec {
pname = "go-ethereum";
version = "1.10.19";
version = "1.10.25";
src = fetchFromGitHub {
owner = "ethereum";
repo = pname;
rev = "v${version}";
sha256 = "0f6n9rg42ph47mvykc9f0lf99yzwqy4jm7mlzyks4l6i6fl1g3q1";
sha256 = "sha256-mnf0kMfQEEQMricZJfyF7ZB/2F1dyPBx9iT2v/rGh1U=";
};
vendorSha256 = "1s5yfpk2yn7f3zwjl2fdrh6c63ki2b8rlmnlss27yxibsidaj0yd";
vendorSha256 = "sha256-Dj+xN8lr98LJyYr2FwJ7yUIJkUeUrr1fkcbj4hShJI0=";
doCheck = false;
@ -47,14 +46,19 @@ buildGoModule rec {
"cmd/utils"
];
# Following upstream: https://github.com/ethereum/go-ethereum/blob/v1.10.25/build/ci.go#L218
tags = [ "urfave_cli_no_docs" ];
# Fix for usb-related segmentation faults on darwin
propagatedBuildInputs =
lib.optionals stdenv.isDarwin [ libobjc IOKit ];
passthru.tests = { inherit (nixosTests) geth; };
meta = with lib; {
homepage = "https://geth.ethereum.org/";
description = "Official golang implementation of the Ethereum protocol";
license = with licenses; [ lgpl3Plus gpl3Plus ];
maintainers = with maintainers; [ adisbladis lionello RaghavSood ];
maintainers = with maintainers; [ adisbladis RaghavSood ];
};
}
}

View File

@ -41,10 +41,10 @@
"homepage": "",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f904e3562aabca382d12f8471ca2330b3f82899a",
"sha256": "1lsa3sjwp1v3nv2jjpkl5lf9dncplwihmavasalg9fq1217pmzmb",
"rev": "ea2c6a6dda1aa35a80139a512a9dee375b0946e7",
"sha256": "0nd4nn9ryqa80ssw3j2kmr8wa73p2xz1hyxp280cdzqlmdfgw1lm",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/f904e3562aabca382d12f8471ca2330b3f82899a.tar.gz",
"url": "https://github.com/NixOS/nixpkgs/archive/ea2c6a6dda1aa35a80139a512a9dee375b0946e7.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}

View File

@ -1,18 +1,38 @@
{ pkgs }:
pkgs.poetry2nix.mkPoetryEnv {
{ poetry2nix, lib, python310 }:
poetry2nix.mkPoetryEnv {
projectDir = ../tests/integration_tests;
python = pkgs.python39;
overrides = pkgs.poetry2nix.overrides.withDefaults (self: super: {
eth-bloom = super.eth-bloom.overridePythonAttrs {
preConfigure = ''
substituteInPlace setup.py --replace \'setuptools-markdown\' ""
'';
};
pystarport = super.pystarport.overridePythonAttrs (
old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ self.poetry ];
}
);
});
python = python310;
overrides = poetry2nix.overrides.withDefaults (lib.composeManyExtensions [
(self: super:
let
buildSystems = {
eth-bloom = [ "setuptools" ];
pystarport = [ "poetry" ];
durations = [ "setuptools" ];
multitail2 = [ "setuptools" ];
pytest-github-actions-annotate-failures = [ "setuptools" ];
flake8-black = [ "setuptools" ];
multiaddr = [ "setuptools" ];
};
in
lib.mapAttrs
(attr: systems: super.${attr}.overridePythonAttrs
(old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ map (a: self.${a}) systems;
}))
buildSystems
)
(self: super: {
eth-bloom = super.eth-bloom.overridePythonAttrs {
preConfigure = ''
substituteInPlace setup.py --replace \'setuptools-markdown\' ""
'';
};
pyyaml-include = super.pyyaml-include.overridePythonAttrs {
preConfigure = ''
substituteInPlace setup.py --replace "setup()" "setup(version=\"1.3\")"
'';
};
})
]);
}

8
proto/buf.gen.gogo.yaml Normal file
View File

@ -0,0 +1,8 @@
version: v1
plugins:
- name: gocosmos
out: .
opt: plugins=grpc,Mgoogle/protobuf/duration.proto=Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1alpha1/orm.proto=github.com/cosmos/cosmos-sdk/api/cosmos/orm/v1alpha1
- name: grpc-gateway
out: .
opt: logtostderr=true,allow_colon_final_segments=true

View File

@ -0,0 +1,15 @@
version: v1
plugins:
- name: gocosmos
out: .
opt: plugins=grpc,Mgoogle/protobuf/duration.proto=Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1alpha1/orm.proto=github.com/cosmos/cosmos-sdk/api/cosmos/orm/v1alpha1
- name: grpc-gateway
out: .
opt: logtostderr=true
- name: swagger
out: ./tmp-swagger-gen
opt:
- logtostderr=true
- fqn_for_swagger_name=true
- simple_operation_ids=true
strategy: all

19
proto/buf.lock Normal file
View File

@ -0,0 +1,19 @@
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: cosmos
repository: cosmos-proto
commit: 1935555c206d4afb9e94615dfd0fad31
- remote: buf.build
owner: cosmos
repository: cosmos-sdk
commit: 508e19f5f37549e3a471a2a59b903c00
- remote: buf.build
owner: cosmos
repository: gogo-proto
commit: 34d970b699f84aa382f3c29773a60836
- remote: buf.build
owner: googleapis
repository: googleapis
commit: 783e4b5374fa488ab068d08af9658438

View File

@ -1,4 +1,10 @@
version: v1
name: buf.build/evmos/ethermint
deps:
- buf.build/cosmos/cosmos-sdk
- buf.build/cosmos/cosmos-proto
- buf.build/cosmos/gogo-proto
- buf.build/googleapis/googleapis
lint:
use:
- DEFAULT

View File

@ -11,11 +11,13 @@ option go_package = "github.com/evmos/ethermint/crypto/ethsecp256k1";
message PubKey {
option (gogoproto.goproto_stringer) = false;
// key is the public key in byte form
bytes key = 1;
}
// PrivKey defines a type alias for an ecdsa.PrivateKey that implements
// Tendermint's PrivateKey interface.
message PrivKey {
// key is the private key in byte form
bytes key = 1;
}

View File

@ -7,18 +7,18 @@ option go_package = "github.com/evmos/ethermint/x/evm/types";
// Params defines the EVM module parameters
message Params {
// evm denom represents the token denomination used to run the EVM state
// evm_denom represents the token denomination used to run the EVM state
// transitions.
string evm_denom = 1 [(gogoproto.moretags) = "yaml:\"evm_denom\""];
// enable create toggles state transitions that use the vm.Create function
// enable_create toggles state transitions that use the vm.Create function
bool enable_create = 2 [(gogoproto.moretags) = "yaml:\"enable_create\""];
// enable call toggles state transitions that use the vm.Call function
// enable_call toggles state transitions that use the vm.Call function
bool enable_call = 3 [(gogoproto.moretags) = "yaml:\"enable_call\""];
// extra eips defines the additional EIPs for the vm.Config
// extra_eips defines the additional EIPs for the vm.Config
repeated int64 extra_eips = 4 [(gogoproto.customname) = "ExtraEIPs", (gogoproto.moretags) = "yaml:\"extra_eips\""];
// chain config defines the EVM chain configuration parameters
// chain_config defines the EVM chain configuration parameters
ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false];
// Allow unprotected transactions defines if replay-protected (i.e non EIP155
// allow_unprotected_txs defines if replay-protected (i.e non EIP155
// signed) transactions can be executed on the state machine.
bool allow_unprotected_txs = 6;
}
@ -26,102 +26,115 @@ message Params {
// ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int values
// instead of *big.Int.
message ChainConfig {
// Homestead switch block (nil no fork, 0 = already homestead)
// homestead_block switch (nil no fork, 0 = already homestead)
string homestead_block = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"homestead_block\""
(gogoproto.moretags) = "yaml:\"homestead_block\""
];
// TheDAO hard-fork switch block (nil no fork)
// dao_fork_block corresponds to TheDAO hard-fork switch block (nil no fork)
string dao_fork_block = 2 [
(gogoproto.customname) = "DAOForkBlock",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"dao_fork_block\""
(gogoproto.moretags) = "yaml:\"dao_fork_block\""
];
// Whether the nodes supports or opposes the DAO hard-fork
// dao_fork_support defines whether the nodes supports or opposes the DAO hard-fork
bool dao_fork_support = 3
[(gogoproto.customname) = "DAOForkSupport", (gogoproto.moretags) = "yaml:\"dao_fork_support\""];
// EIP150 implements the Gas price changes
[(gogoproto.customname) = "DAOForkSupport", (gogoproto.moretags) = "yaml:\"dao_fork_support\""];
// eip150_block: EIP150 implements the Gas price changes
// (https://github.com/ethereum/EIPs/issues/150) EIP150 HF block (nil no fork)
string eip150_block = 4 [
(gogoproto.customname) = "EIP150Block",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"eip150_block\""
(gogoproto.moretags) = "yaml:\"eip150_block\""
];
// EIP150 HF hash (needed for header only clients as only gas pricing changed)
// eip150_hash: EIP150 HF hash (needed for header only clients as only gas pricing changed)
string eip150_hash = 5 [(gogoproto.customname) = "EIP150Hash", (gogoproto.moretags) = "yaml:\"byzantium_block\""];
// EIP155Block HF block
// eip155_block: EIP155Block HF block
string eip155_block = 6 [
(gogoproto.customname) = "EIP155Block",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"eip155_block\""
(gogoproto.moretags) = "yaml:\"eip155_block\""
];
// EIP158 HF block
// eip158_block: EIP158 HF block
string eip158_block = 7 [
(gogoproto.customname) = "EIP158Block",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"eip158_block\""
(gogoproto.moretags) = "yaml:\"eip158_block\""
];
// Byzantium switch block (nil no fork, 0 = already on byzantium)
// byzantium_block: Byzantium switch block (nil no fork, 0 = already on byzantium)
string byzantium_block = 8 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"byzantium_block\""
(gogoproto.moretags) = "yaml:\"byzantium_block\""
];
// Constantinople switch block (nil no fork, 0 = already activated)
// constantinople_block: Constantinople switch block (nil no fork, 0 = already activated)
string constantinople_block = 9 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"constantinople_block\""
(gogoproto.moretags) = "yaml:\"constantinople_block\""
];
// Petersburg switch block (nil same as Constantinople)
// petersburg_block: Petersburg switch block (nil same as Constantinople)
string petersburg_block = 10 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"petersburg_block\""
(gogoproto.moretags) = "yaml:\"petersburg_block\""
];
// Istanbul switch block (nil no fork, 0 = already on istanbul)
// istanbul_block: Istanbul switch block (nil no fork, 0 = already on istanbul)
string istanbul_block = 11 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"istanbul_block\""
(gogoproto.moretags) = "yaml:\"istanbul_block\""
];
// Eip-2384 (bomb delay) switch block (nil no fork, 0 = already activated)
// muir_glacier_block: Eip-2384 (bomb delay) switch block (nil no fork, 0 = already activated)
string muir_glacier_block = 12 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"muir_glacier_block\""
(gogoproto.moretags) = "yaml:\"muir_glacier_block\""
];
// Berlin switch block (nil = no fork, 0 = already on berlin)
// berlin_block: Berlin switch block (nil = no fork, 0 = already on berlin)
string berlin_block = 13 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"berlin_block\""
(gogoproto.moretags) = "yaml:\"berlin_block\""
];
// DEPRECATED: EWASM, YOLOV3 and Catalyst block have been deprecated
reserved 14, 15, 16;
reserved "yolo_v3_block", "ewasm_block", "catalyst_block";
// London switch block (nil = no fork, 0 = already on london)
// london_block: London switch block (nil = no fork, 0 = already on london)
string london_block = 17 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"london_block\""
(gogoproto.moretags) = "yaml:\"london_block\""
];
// Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
// arrow_glacier_block: Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
string arrow_glacier_block = 18 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"arrow_glacier_block\""
(gogoproto.moretags) = "yaml:\"arrow_glacier_block\""
];
// DEPRECATED: merge fork block was deprecated: https://github.com/ethereum/go-ethereum/pull/24904
reserved 19;
reserved "merge_fork_block";
// EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
// gray_glacier_block: EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
string gray_glacier_block = 20 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"gray_glacier_block\""
(gogoproto.moretags) = "yaml:\"gray_glacier_block\""
];
// Virtual fork after The Merge to use as a network splitter
// merge_netsplit_block: Virtual fork after The Merge to use as a network splitter
string merge_netsplit_block = 21 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"merge_netsplit_block\""
(gogoproto.moretags) = "yaml:\"merge_netsplit_block\""
];
// shanghai_block switch block (nil = no fork, 0 = already on shanghai)
string shanghai_block = 22 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"shanghai_block\""
];
// cancun_block switch block (nil = no fork, 0 = already on cancun)
string cancun_block = 23 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"cancun_block\""
];
}
// State represents a single Storage key value pair item.
message State {
string key = 1;
// key is the stored key
string key = 1;
// value is the stored value for the given key
string value = 2;
}
@ -129,38 +142,38 @@ message State {
// with a given hash. It it used for import/export data as transactions are not
// persisted on blockchain state after an upgrade.
message TransactionLogs {
string hash = 1;
// hash of the transaction
string hash = 1;
// logs is an array of Logs for the given transaction hash
repeated Log logs = 2;
}
// Log represents an protobuf compatible Ethereum Log that defines a contract
// log event. These events are generated by the LOG opcode and stored/indexed by
// the node.
//
// NOTE: address, topics and data are consensus fields. The rest of the fields
// are derived, i.e. filled in by the nodes, but not secured by consensus.
message Log {
// Consensus fields:
// address of the contract that generated the event
string address = 1;
// list of topics provided by the contract.
// topics is a list of topics provided by the contract.
repeated string topics = 2;
// supplied by the contract, usually ABI-encoded
// data which is supplied by the contract, usually ABI-encoded
bytes data = 3;
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
// block in which the transaction was included
// block_number of the block in which the transaction was included
uint64 block_number = 4 [(gogoproto.jsontag) = "blockNumber"];
// hash of the transaction
// tx_hash is the transaction hash
string tx_hash = 5 [(gogoproto.jsontag) = "transactionHash"];
// index of the transaction in the block
// tx_index of the transaction in the block
uint64 tx_index = 6 [(gogoproto.jsontag) = "transactionIndex"];
// hash of the block in which the transaction was included
// block_hash of the block in which the transaction was included
string block_hash = 7 [(gogoproto.jsontag) = "blockHash"];
// index of the log in the block
uint64 index = 8 [(gogoproto.jsontag) = "logIndex"];
// The Removed field is true if this log was reverted due to a chain
// removed is true if this log was reverted due to a chain
// reorganisation. You must pay attention to this field if you receive logs
// through a filter query.
bool removed = 9;
@ -191,9 +204,9 @@ message TxResult {
message AccessTuple {
option (gogoproto.goproto_getters) = false;
// hex formatted ethereum address
// address is a hex formatted ethereum address
string address = 1;
// hex formatted hashes of the storage keys
// storage_keys are hex formatted hashes of the storage keys
repeated string storage_keys = 2 [(gogoproto.jsontag) = "storageKeys"];
}
@ -204,25 +217,27 @@ message TraceConfig {
reserved 4, 7;
reserved "disable_memory", "disable_return_data";
// custom javascript tracer
// tracer is a custom javascript tracer
string tracer = 1;
// overrides the default timeout of 5 seconds for JavaScript-based tracing
// timeout overrides the default timeout of 5 seconds for JavaScript-based tracing
// calls
string timeout = 2;
// number of blocks the tracer is willing to go back
// reexec defines the number of blocks the tracer is willing to go back
uint64 reexec = 3;
// disable stack capture
// disable_stack switches stack capture
bool disable_stack = 5 [(gogoproto.jsontag) = "disableStack"];
// disable storage capture
// disable_storage switches storage capture
bool disable_storage = 6 [(gogoproto.jsontag) = "disableStorage"];
// print output during capture end
// debug can be used to print output during capture end
bool debug = 8;
// maximum length of output, but zero means unlimited
// limit defines the maximum length of output, but zero means unlimited
int32 limit = 9;
// Chain overrides, can be used to execute a trace using future fork rules
// overrides can be used to execute a trace using future fork rules
ChainConfig overrides = 10;
// enable memory capture
// enable_memory switches memory capture
bool enable_memory = 11 [(gogoproto.jsontag) = "enableMemory"];
// enable return data capture
// enable_return_data switches the capture of return data
bool enable_return_data = 12 [(gogoproto.jsontag) = "enableReturnData"];
// tracer_json_config configures the tracer using a JSON string
string tracer_json_config = 13 [(gogoproto.jsontag) = "tracerConfig"];
}

View File

@ -1,8 +1,8 @@
syntax = "proto3";
package ethermint.evm.v1;
import "gogoproto/gogo.proto";
import "ethermint/evm/v1/evm.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/evmos/ethermint/x/evm/types";

View File

@ -1,11 +1,11 @@
syntax = "proto3";
package ethermint.evm.v1;
import "gogoproto/gogo.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "google/api/annotations.proto";
import "ethermint/evm/v1/evm.proto";
import "ethermint/evm/v1/tx.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
option go_package = "github.com/evmos/ethermint/x/evm/types";
@ -78,7 +78,7 @@ service Query {
// QueryAccountRequest is the request type for the Query/Account RPC method.
message QueryAccountRequest {
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// address is the ethereum hex address to query the account for.
@ -89,7 +89,7 @@ message QueryAccountRequest {
message QueryAccountResponse {
// balance is the balance of the EVM denomination.
string balance = 1;
// code hash is the hex-formatted code bytes from the EOA.
// code_hash is the hex-formatted code bytes from the EOA.
string code_hash = 2;
// nonce is the account's sequence number.
uint64 nonce = 3;
@ -98,7 +98,7 @@ message QueryAccountResponse {
// QueryCosmosAccountRequest is the request type for the Query/CosmosAccount RPC
// method.
message QueryCosmosAccountRequest {
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// address is the ethereum hex address to query the account for.
@ -112,14 +112,14 @@ message QueryCosmosAccountResponse {
string cosmos_address = 1;
// sequence is the account's sequence number.
uint64 sequence = 2;
// account_number is the account numbert
// account_number is the account number
uint64 account_number = 3;
}
// QueryValidatorAccountRequest is the request type for the
// Query/ValidatorAccount RPC method.
message QueryValidatorAccountRequest {
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// cons_address is the validator cons address to query the account for.
@ -139,7 +139,7 @@ message QueryValidatorAccountResponse {
// QueryBalanceRequest is the request type for the Query/Balance RPC method.
message QueryBalanceRequest {
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// address is the ethereum hex address to query the balance for.
@ -154,10 +154,10 @@ message QueryBalanceResponse {
// QueryStorageRequest is the request type for the Query/Storage RPC method.
message QueryStorageRequest {
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
/// address is the ethereum hex address to query the storage state for.
// address is the ethereum hex address to query the storage state for.
string address = 1;
// key defines the key of the storage state
@ -167,13 +167,13 @@ message QueryStorageRequest {
// QueryStorageResponse is the response type for the Query/Storage RPC
// method.
message QueryStorageResponse {
// key defines the storage state value hash associated with the given key.
// value defines the storage state value hash associated with the given key.
string value = 1;
}
// QueryCodeRequest is the request type for the Query/Code RPC method.
message QueryCodeRequest {
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// address is the ethereum hex address to query the code for.
@ -189,7 +189,7 @@ message QueryCodeResponse {
// QueryTxLogsRequest is the request type for the Query/TxLogs RPC method.
message QueryTxLogsRequest {
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// hash is the ethereum transaction hex hash to query the logs for.
@ -198,7 +198,7 @@ message QueryTxLogsRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}
// QueryTxLogs is the response type for the Query/TxLogs RPC method.
// QueryTxLogsResponse is the response type for the Query/TxLogs RPC method.
message QueryTxLogsResponse {
// logs represents the ethereum logs generated from the given transaction.
repeated Log logs = 1;
@ -217,66 +217,73 @@ message QueryParamsResponse {
// EthCallRequest defines EthCall request
message EthCallRequest {
// same json format as the json rpc api.
// args uses the same json format as the json rpc api.
bytes args = 1;
// the default gas cap to be used
// gas_cap defines the default gas cap to be used
uint64 gas_cap = 2;
// the proposer of the requested block
// proposer_address of the requested block in hex format
bytes proposer_address = 3 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
// chain_id is the eip155 chain id parsed from the requested block header
int64 chain_id = 4;
}
// EstimateGasResponse defines EstimateGas response
message EstimateGasResponse {
// the estimated gas
// gas returns the estimated gas
uint64 gas = 1;
}
// QueryTraceTxRequest defines TraceTx request
message QueryTraceTxRequest {
// msgEthereumTx for the requested transaction
// msg is the MsgEthereumTx for the requested transaction
MsgEthereumTx msg = 1;
// tx_index is not necessary anymore
reserved 2;
reserved "tx_index";
// TraceConfig holds extra parameters to trace functions.
// trace_config holds extra parameters to trace functions.
TraceConfig trace_config = 3;
// the predecessor transactions included in the same block
// predecessors is an array of transactions included in the same block
// need to be replayed first to get correct context for tracing.
repeated MsgEthereumTx predecessors = 4;
// block number of requested transaction
// block_number of requested transaction
int64 block_number = 5;
// block hex hash of requested transaction
// block_hash of requested transaction
string block_hash = 6;
// block time of requested transaction
// block_time of requested transaction
google.protobuf.Timestamp block_time = 7 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// the proposer of the requested block
// proposer_address is the proposer of the requested block
bytes proposer_address = 8 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
// chain_id is the the eip155 chain id parsed from the requested block header
int64 chain_id = 9;
}
// QueryTraceTxResponse defines TraceTx response
message QueryTraceTxResponse {
// response serialized in bytes
// data is the response serialized in bytes
bytes data = 1;
}
// QueryTraceBlockRequest defines TraceTx request
message QueryTraceBlockRequest {
// txs messages in the block
// txs is an array of messages in the block
repeated MsgEthereumTx txs = 1;
// TraceConfig holds extra parameters to trace functions.
// trace_config holds extra parameters to trace functions.
TraceConfig trace_config = 3;
// block number
// block_number of the traced block
int64 block_number = 5;
// block hex hash
// block_hash (hex) of the traced block
string block_hash = 6;
// block time
// block_time of the traced block
google.protobuf.Timestamp block_time = 7 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// the proposer of the requested block
// proposer_address is the address of the requested block
bytes proposer_address = 8 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
// chain_id is the eip155 chain id parsed from the requested block header
int64 chain_id = 9;
}
// QueryTraceBlockResponse defines TraceBlock response
message QueryTraceBlockResponse {
// data is the response serialized in bytes
bytes data = 1;
}
@ -284,7 +291,8 @@ message QueryTraceBlockResponse {
// fee.
message QueryBaseFeeRequest {}
// BaseFeeResponse returns the EIP1559 base fee.
// QueryBaseFeeResponse returns the EIP1559 base fee.
message QueryBaseFeeResponse {
// base_fee is the EIP1559 base fee
string base_fee = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
}

View File

@ -1,11 +1,11 @@
syntax = "proto3";
package ethermint.evm.v1;
import "cosmos_proto/cosmos.proto";
import "ethermint/evm/v1/evm.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";
import "ethermint/evm/v1/evm.proto";
option go_package = "github.com/evmos/ethermint/x/evm/types";
@ -21,15 +21,14 @@ service Msg {
message MsgEthereumTx {
option (gogoproto.goproto_getters) = false;
// inner transaction data
// data is inner transaction data of the Ethereum transaction
google.protobuf.Any data = 1;
// caches
// DEPRECATED: encoded storage size of the transaction
// size is the encoded storage size of the transaction (DEPRECATED)
double size = 2 [(gogoproto.jsontag) = "-"];
// transaction hash in hex format
// hash of the transaction in hex format
string hash = 3 [(gogoproto.moretags) = "rlp:\"-\""];
// ethereum signer address in hex format. This address value is checked
// from is the ethereum signer address in hex format. This address value is checked
// against the address derived from the signature (V, R, S) using the
// secp256k1 elliptic curve
string from = 4;
@ -39,21 +38,21 @@ message MsgEthereumTx {
// NOTE: All non-protected transactions (i.e non EIP155 signed) will fail if the
// AllowUnprotectedTxs parameter is disabled.
message LegacyTx {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_getters) = false;
option (cosmos_proto.implements_interface) = "TxData";
// nonce corresponds to the account nonce (transaction sequence).
uint64 nonce = 1;
// gas price defines the value for each gas unit
// gas_price defines the value for each gas unit
string gas_price = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas defines the gas limit defined for the transaction.
uint64 gas = 3 [(gogoproto.customname) = "GasLimit"];
// hex formatted address of the recipient
// to is the hex formatted address of the recipient
string to = 4;
// value defines the unsigned integer value of the transaction amount.
string value = 5
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.customname) = "Amount"];
// input defines the data payload bytes of the transaction.
// data is the data payload bytes of the transaction.
bytes data = 6;
// v defines the signature value
bytes v = 7;
@ -65,28 +64,29 @@ message LegacyTx {
// AccessListTx is the data of EIP-2930 access list transactions.
message AccessListTx {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_getters) = false;
option (cosmos_proto.implements_interface) = "TxData";
// destination EVM chain ID
// chain_id of the destination EVM chain
string chain_id = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.customname) = "ChainID",
(gogoproto.jsontag) = "chainID"
(gogoproto.jsontag) = "chainID"
];
// nonce corresponds to the account nonce (transaction sequence).
uint64 nonce = 2;
// gas price defines the value for each gas unit
// gas_price defines the value for each gas unit
string gas_price = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas defines the gas limit defined for the transaction.
uint64 gas = 4 [(gogoproto.customname) = "GasLimit"];
// hex formatted address of the recipient
// to is the recipient address in hex format
string to = 5;
// value defines the unsigned integer value of the transaction amount.
string value = 6
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.customname) = "Amount"];
// input defines the data payload bytes of the transaction.
bytes data = 7;
// data is the data payload bytes of the transaction.
bytes data = 7;
// accesses is an array of access tuples
repeated AccessTuple accesses = 8
[(gogoproto.castrepeated) = "AccessList", (gogoproto.jsontag) = "accessList", (gogoproto.nullable) = false];
// v defines the signature value
@ -99,30 +99,31 @@ message AccessListTx {
// DynamicFeeTx is the data of EIP-1559 dinamic fee transactions.
message DynamicFeeTx {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_getters) = false;
option (cosmos_proto.implements_interface) = "TxData";
// destination EVM chain ID
// chain_id of the destination EVM chain
string chain_id = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.customname) = "ChainID",
(gogoproto.jsontag) = "chainID"
(gogoproto.jsontag) = "chainID"
];
// nonce corresponds to the account nonce (transaction sequence).
uint64 nonce = 2;
// gas tip cap defines the max value for the gas tip
// gas_tip_cap defines the max value for the gas tip
string gas_tip_cap = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas fee cap defines the max value for the gas fee
// gas_fee_cap defines the max value for the gas fee
string gas_fee_cap = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas defines the gas limit defined for the transaction.
uint64 gas = 5 [(gogoproto.customname) = "GasLimit"];
// hex formatted address of the recipient
// to is the hex formatted address of the recipient
string to = 6;
// value defines the the transaction amount.
string value = 7
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.customname) = "Amount"];
// input defines the data payload bytes of the transaction.
bytes data = 8;
// data is the data payload bytes of the transaction.
bytes data = 8;
// accesses is an array of access tuples
repeated AccessTuple accesses = 9
[(gogoproto.castrepeated) = "AccessList", (gogoproto.jsontag) = "accessList", (gogoproto.nullable) = false];
// v defines the signature value
@ -133,6 +134,7 @@ message DynamicFeeTx {
bytes s = 12;
}
// ExtensionOptionsEthereumTx is an extension option for ethereum transactions
message ExtensionOptionsEthereumTx {
option (gogoproto.goproto_getters) = false;
}
@ -141,18 +143,18 @@ message ExtensionOptionsEthereumTx {
message MsgEthereumTxResponse {
option (gogoproto.goproto_getters) = false;
// ethereum transaction hash in hex format. This hash differs from the
// hash of the ethereum transaction in hex format. This hash differs from the
// Tendermint sha256 hash of the transaction bytes. See
// https://github.com/tendermint/tendermint/issues/6539 for reference
string hash = 1;
// logs contains the transaction hash and the proto-compatible ethereum
// logs.
repeated Log logs = 2;
// returned data from evm function (result or data supplied with revert
// ret is the returned data from evm function (result or data supplied with revert
// opcode)
bytes ret = 3;
// vm error is the error returned by vm execution
// vm_error is the error returned by vm execution
string vm_error = 4;
// gas consumed by the transaction
// gas_used specifies how much gas was consumed by the transaction
uint64 gas_used = 5;
}

View File

@ -7,26 +7,26 @@ option go_package = "github.com/evmos/ethermint/x/feemarket/types";
// Params defines the EVM module parameters
message Params {
// no base fee forces the EIP-1559 base fee to 0 (needed for 0 price calls)
// no_base_fee forces the EIP-1559 base fee to 0 (needed for 0 price calls)
bool no_base_fee = 1;
// base fee change denominator bounds the amount the base fee can change
// base_fee_change_denominator bounds the amount the base fee can change
// between blocks.
uint32 base_fee_change_denominator = 2;
// elasticity multiplier bounds the maximum gas limit an EIP-1559 block may
// elasticity_multiplier bounds the maximum gas limit an EIP-1559 block may
// have.
uint32 elasticity_multiplier = 3;
// DEPRECATED: initial base fee for EIP-1559 blocks.
reserved 4;
reserved "initial_base_fee";
// height at which the base fee calculation is enabled.
// enable_height defines at which block height the base fee calculation is enabled.
int64 enable_height = 5;
// base fee for EIP-1559 blocks.
// base_fee for EIP-1559 blocks.
string base_fee = 6 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
// min_gas_price defines the minimum gas price value for cosmos and eth transactions
string min_gas_price = 7
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
// min gas denominator bounds the minimum gasUsed to be charged
// to senders based on GasLimit
// min_gas_multiplier bounds the minimum gas used to be charged
// to senders based on gas limit
string min_gas_multiplier = 8
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

View File

@ -1,20 +1,20 @@
syntax = "proto3";
package ethermint.feemarket.v1;
import "gogoproto/gogo.proto";
import "ethermint/feemarket/v1/feemarket.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/evmos/ethermint/x/feemarket/types";
// GenesisState defines the feemarket module's genesis state.
message GenesisState {
// params defines all the paramaters of the module.
// params defines all the parameters of the feemarket module.
Params params = 1 [(gogoproto.nullable) = false];
// DEPRECATED: base fee is the exported value from previous software version.
// Zero by default.
reserved 2;
reserved "base_fee";
// block gas is the amount of gas wanted on the last block before the upgrade.
// block_gas is the amount of gas wanted on the last block before the upgrade.
// Zero by default.
uint64 block_gas = 3;
}

View File

@ -3,8 +3,8 @@ package ethermint.feemarket.v1;
import "gogoproto/gogo.proto";
// import "cosmos/base/query/v1beta1/pagination.proto";
import "google/api/annotations.proto";
import "ethermint/feemarket/v1/feemarket.proto";
import "google/api/annotations.proto";
option go_package = "github.com/evmos/ethermint/x/feemarket/types";
@ -39,8 +39,9 @@ message QueryParamsResponse {
// fee.
message QueryBaseFeeRequest {}
// BaseFeeResponse returns the EIP1559 base fee.
// QueryBaseFeeResponse returns the EIP1559 base fee.
message QueryBaseFeeResponse {
// base_fee is the EIP1559 base fee
string base_fee = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
}
@ -50,5 +51,6 @@ message QueryBlockGasRequest {}
// QueryBlockGasResponse returns block gas used for a given height.
message QueryBlockGasResponse {
// gas is the returned block gas
int64 gas = 1;
}

View File

@ -10,13 +10,16 @@ option go_package = "github.com/evmos/ethermint/types";
// EthAccount implements the authtypes.AccountI interface and embeds an
// authtypes.BaseAccount type. It is compatible with the auth AccountKeeper.
message EthAccount {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;
option (gogoproto.equal) = false;
option (gogoproto.equal) = false;
option (cosmos_proto.implements_interface) = "github.com/cosmos/cosmos-sdk/x/auth/types.AccountI";
// base_account is an authtypes.BaseAccount
cosmos.auth.v1beta1.BaseAccount base_account = 1
[(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""];
// code_hash is the hash calculated from the code contents
string code_hash = 2 [(gogoproto.moretags) = "yaml:\"code_hash\""];
}

View File

@ -5,9 +5,9 @@ import "gogoproto/gogo.proto";
option go_package = "github.com/evmos/ethermint/types";
// ExtensionOptionDynamicFeeTx is an extension option that specify the maxPrioPrice for cosmos tx
// ExtensionOptionDynamicFeeTx is an extension option that specifies the maxPrioPrice for cosmos tx
message ExtensionOptionDynamicFeeTx {
// the same as `max_priority_fee_per_gas` in eip-1559 spec
// max_priority_price is the same as `max_priority_fee_per_gas` in eip-1559 spec
string max_priority_price = 1
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
}

View File

@ -9,21 +9,22 @@ option go_package = "github.com/evmos/ethermint/types";
message TxResult {
option (gogoproto.goproto_getters) = false;
// the block height
// height of the blockchain
int64 height = 1;
// cosmos tx index
// tx_index of the cosmos transaction
uint32 tx_index = 2;
// the msg index in a batch tx
// msg_index in a batch transaction
uint32 msg_index = 3;
// eth tx index, the index in the list of valid eth tx in the block,
// eth_tx_index is the index in the list of valid eth tx in the block,
// aka. the transaction list returned by eth_getBlock api.
int32 eth_tx_index = 4;
// if the eth tx is failed
// failed is true if the eth transaction did not go succeed
bool failed = 5;
// gas used by tx, if exceeds block gas limit,
// it's set to gas limit which is what's actually deducted by ante handler.
// gas_used by the transaction. If it exceeds the block gas limit,
// it's set to gas limit, which is what's actually deducted by ante handler.
uint64 gas_used = 6;
// the cumulative gas used within current batch tx
// cumulative_gas_used specifies the cumulated amount of gas used for all
// processed messages within the current batch transaction.
uint64 cumulative_gas_used = 7;
}

View File

@ -5,19 +5,21 @@ import "gogoproto/gogo.proto";
option go_package = "github.com/evmos/ethermint/types";
// ExtensionOptionsWeb3Tx is an extension option that specifies the typed chain id,
// the fee payer as well as its signature data.
message ExtensionOptionsWeb3Tx {
option (gogoproto.goproto_getters) = false;
// typed data chain id used only in EIP712 Domain and should match
// typed_data_chain_id is used only in EIP712 Domain and should match
// Ethereum network ID in a Web3 provider (e.g. Metamask).
uint64 typed_data_chain_id = 1
[(gogoproto.jsontag) = "typedDataChainID,omitempty", (gogoproto.customname) = "TypedDataChainID"];
// fee payer is an account address for the fee payer. It will be validated
// fee_payer is an account address for the fee payer. It will be validated
// during EIP712 signature checking.
string fee_payer = 2 [(gogoproto.jsontag) = "feePayer,omitempty"];
// fee payer sig is a signature data from the fee paying account,
// fee_payer_sig is a signature data from the fee paying account,
// allows to perform fee delegation when using EIP712 Domain.
bytes fee_payer_sig = 3 [(gogoproto.jsontag) = "feePayerSig,omitempty"];
}

View File

@ -75,16 +75,10 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr
return nil, err
}
// check for proof
var proofStr string
if proof != nil {
proofStr = proof.String()
}
storageProofs[i] = rpctypes.StorageResult{
Key: key,
Value: (*hexutil.Big)(new(big.Int).SetBytes(valueBz)),
Proof: []string{proofStr},
Proof: GetHexProofs(proof),
}
}
@ -105,12 +99,6 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr
return nil, err
}
// check for proof
var accProofStr string
if proof != nil {
accProofStr = proof.String()
}
balance, ok := sdkmath.NewIntFromString(res.Balance)
if !ok {
return nil, errors.New("invalid balance")
@ -118,7 +106,7 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr
return &rpctypes.AccountResult{
Address: address,
AccountProof: []string{accProofStr},
AccountProof: GetHexProofs(proof),
Balance: (*hexutil.Big)(balance.BigInt()),
CodeHash: common.HexToHash(res.CodeHash),
Nonce: hexutil.Uint64(res.Nonce),

View File

@ -103,6 +103,18 @@ func (suite *BackendTestSuite) TestGetProof() {
false,
&rpctypes.AccountResult{},
},
{
"fail - Block doesn't exist)",
address1,
[]string{},
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockError(client, bn.Int64())
},
false,
&rpctypes.AccountResult{},
},
{
"pass",
address1,
@ -351,6 +363,27 @@ func (suite *BackendTestSuite) TestGetTransactionCount() {
true,
hexutil.Uint64(0),
},
// TODO: Error mocking the GetAccount call - problem with Any type
//{
// "pass - returns the number of transactions at the given address up to the given block number",
// true,
// rpctypes.NewBlockNumber(big.NewInt(1)),
// func(addr common.Address, bn rpctypes.BlockNumber) {
// client := suite.backend.clientCtx.Client.(*mocks.Client)
// account, err := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, suite.acc)
// suite.Require().NoError(err)
// request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(suite.acc.Bytes()).String()}
// requestMarshal, _ := request.Marshal()
// RegisterABCIQueryAccount(
// client,
// requestMarshal,
// tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
// account,
// )
// },
// true,
// hexutil.Uint64(0),
//},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {

View File

@ -6,7 +6,6 @@ import (
"time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -16,12 +15,10 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/evmos/ethermint/crypto/hd"
rpctypes "github.com/evmos/ethermint/rpc/types"
"github.com/evmos/ethermint/server/config"
ethermint "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
)
@ -162,23 +159,6 @@ func NewBackend(
panic(err)
}
algos, _ := clientCtx.Keyring.SupportedAlgorithms()
if !algos.Contains(hd.EthSecp256k1) {
kr, err := keyring.New(
sdk.KeyringServiceName(),
viper.GetString(flags.FlagKeyringBackend),
clientCtx.KeyringDir,
clientCtx.Input,
clientCtx.Codec,
hd.EthSecp256k1Option(),
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithKeyring(kr)
}
return &Backend{
ctx: context.Background(),
clientCtx: clientCtx,

View File

@ -2,12 +2,13 @@ package backend
import (
"bufio"
"fmt"
"math/big"
"os"
"path/filepath"
"testing"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/client"
@ -33,19 +34,22 @@ type BackendTestSuite struct {
suite.Suite
backend *Backend
acc sdk.AccAddress
signer keyring.Signer
}
func TestBackendTestSuite(t *testing.T) {
suite.Run(t, new(BackendTestSuite))
}
const ChainID = "ethermint_9000-1"
// SetupTest is executed before every BackendTestSuite test
func (suite *BackendTestSuite) SetupTest() {
ctx := server.NewDefaultContext()
ctx.Viper.Set("telemetry.global-labels", []interface{}{})
baseDir := suite.T().TempDir()
nodeDirName := fmt.Sprintf("node")
nodeDirName := "node"
clientDir := filepath.Join(baseDir, nodeDirName, "evmoscli")
keyRing, err := suite.generateTestKeyring(clientDir)
if err != nil {
@ -61,8 +65,12 @@ func (suite *BackendTestSuite) SetupTest() {
Seq: uint64(1),
}
priv, err := ethsecp256k1.GenerateKey()
suite.signer = tests.NewSigner(priv)
suite.Require().NoError(err)
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
clientCtx := client.Context{}.WithChainID("ethermint_9000-1").
clientCtx := client.Context{}.WithChainID(ChainID).
WithHeight(1).
WithTxConfig(encodingConfig.TxConfig).
WithKeyringDir(clientDir).
@ -70,19 +78,24 @@ func (suite *BackendTestSuite) SetupTest() {
WithAccountRetriever(client.TestAccountRetriever{Accounts: accounts})
allowUnprotectedTxs := false
idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx)
suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer)
suite.backend.queryClient.QueryClient = mocks.NewEVMQueryClient(suite.T())
suite.backend.clientCtx.Client = mocks.NewClient(suite.T())
suite.backend.queryClient.FeeMarket = mocks.NewFeeMarketQueryClient(suite.T())
suite.backend.ctx = rpctypes.ContextWithHeight(1)
// Add codec
encCfg := encoding.MakeConfig(app.ModuleBasics)
suite.backend.clientCtx.Codec = encCfg.Codec
}
// buildEthereumTx returns an example legacy Ethereum transaction
func (suite *BackendTestSuite) buildEthereumTx() (*evmtypes.MsgEthereumTx, []byte) {
msgEthereumTx := evmtypes.NewTx(
big.NewInt(1),
suite.backend.chainID,
uint64(0),
&common.Address{},
big.NewInt(0),
@ -132,6 +145,7 @@ func (suite *BackendTestSuite) buildFormattedBlock(
uint64(header.Height),
uint64(0),
baseFee,
suite.backend.chainID,
)
suite.Require().NoError(err)
ethRPCTxs = []interface{}{rpcTx}
@ -157,3 +171,25 @@ func (suite *BackendTestSuite) generateTestKeyring(clientDir string) (keyring.Ke
encCfg := encoding.MakeConfig(app.ModuleBasics)
return keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, encCfg.Codec, []keyring.Option{hd.EthSecp256k1Option()}...)
}
func (suite *BackendTestSuite) signAndEncodeEthTx(msgEthereumTx *evmtypes.MsgEthereumTx) []byte {
from, priv := tests.NewAddrKey()
signer := tests.NewSigner(priv)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsWithoutHeader(queryClient, 1)
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
msgEthereumTx.From = from.String()
err := msgEthereumTx.Sign(ethSigner, signer)
suite.Require().NoError(err)
tx, err := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
suite.Require().NoError(err)
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
txBz, err := txEncoder(tx)
suite.Require().NoError(err)
return txBz
}

View File

@ -376,6 +376,7 @@ func (b *Backend) RPCBlockFromTendermintBlock(
uint64(block.Height),
uint64(txIndex),
baseFee,
b.chainID,
)
if err != nil {
b.logger.Debug("NewTransactionFromData for receipt failed", "hash", tx.Hash().Hex(), "error", err.Error())

View File

@ -30,8 +30,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
{
"fail - invalid block header height",
func() {
height := int64(1)
var header metadata.MD
height := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsInvalidHeight(queryClient, &header, int64(height))
},
@ -41,8 +41,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
{
"fail - invalid block header",
func() {
height := int64(1)
var header metadata.MD
height := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsInvalidHeader(queryClient, &header, int64(height))
},
@ -52,8 +52,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
{
"pass - app state header height 1",
func() {
height := int64(1)
var header metadata.MD
height := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, int64(height))
},
@ -552,8 +552,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
"fail - blockNum < 0 with app state height error",
ethrpc.BlockNumber(-1),
func(_ ethrpc.BlockNumber) {
appHeight := int64(1)
var header metadata.MD
appHeight := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsError(queryClient, &header, appHeight)
},
@ -564,8 +564,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
"pass - blockNum < 0 with app state height >= 1",
ethrpc.BlockNumber(-1),
func(blockNum ethrpc.BlockNumber) {
appHeight := int64(1)
var header metadata.MD
appHeight := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, appHeight)
@ -1088,6 +1088,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
uint64(header.Height),
uint64(0),
tc.baseFee,
suite.backend.chainID,
)
suite.Require().NoError(err)
ethRPCTxs = []interface{}{rpcTx}

View File

@ -7,9 +7,9 @@ import (
"fmt"
"math/big"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
@ -151,7 +151,7 @@ func (b *Backend) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
syncCtx := b.clientCtx.WithBroadcastMode(flags.BroadcastSync)
rsp, err := syncCtx.BroadcastTx(txBytes)
if rsp != nil && rsp.Code != 0 {
err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
err = errorsmod.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
}
if err != nil {
b.logger.Error("failed to broadcast tx", "error", err.Error())
@ -269,6 +269,8 @@ func (b *Backend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Transac
Value: args.Value,
Data: input,
AccessList: args.AccessList,
ChainID: args.ChainID,
Nonce: args.Nonce,
}
blockNr := rpctypes.NewBlockNumber(big.NewInt(0))
@ -309,6 +311,7 @@ func (b *Backend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rp
Args: bz,
GasCap: b.RPCGasCap(),
ProposerAddress: sdk.ConsAddress(header.Block.ProposerAddress),
ChainId: b.chainID.Int64(),
}
// From ContextWithHeight: if the provided height is 0,
@ -335,10 +338,12 @@ func (b *Backend) DoCall(
// the error message imitates geth behavior
return nil, errors.New("header not found")
}
req := evmtypes.EthCallRequest{
Args: bz,
GasCap: b.RPCGasCap(),
ProposerAddress: sdk.ConsAddress(header.Block.ProposerAddress),
ChainId: b.chainID.Int64(),
}
// From ContextWithHeight: if the provided height is 0,

493
rpc/backend/call_tx_test.go Normal file
View File

@ -0,0 +1,493 @@
package backend
import (
"encoding/json"
"fmt"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
"github.com/evmos/ethermint/rpc/backend/mocks"
rpctypes "github.com/evmos/ethermint/rpc/types"
"github.com/evmos/ethermint/tests"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"google.golang.org/grpc/metadata"
)
func (suite *BackendTestSuite) TestResend() {
txNonce := (hexutil.Uint64)(1)
baseFee := sdk.NewInt(1)
gasPrice := new(hexutil.Big)
toAddr := tests.GenerateAddress()
chainID := (*hexutil.Big)(suite.backend.chainID)
callArgs := evmtypes.TransactionArgs{
From: nil,
To: &toAddr,
Gas: nil,
GasPrice: nil,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Nonce: &txNonce,
Input: nil,
Data: nil,
AccessList: nil,
ChainID: chainID,
}
testCases := []struct {
name string
registerMock func()
args evmtypes.TransactionArgs
gasPrice *hexutil.Big
gasLimit *hexutil.Uint64
expHash common.Hash
expPass bool
}{
{
"fail - Missing transaction nonce ",
func() {},
evmtypes.TransactionArgs{
Nonce: nil,
},
nil,
nil,
common.Hash{},
false,
},
{
"pass - Can't set Tx defaults BaseFee disabled",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFeeDisabled(queryClient)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
ChainID: callArgs.ChainID,
},
nil,
nil,
common.Hash{},
true,
},
{
"pass - Can't set Tx defaults ",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterFeeMarketParams(feeMarketClient, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
},
nil,
nil,
common.Hash{},
true,
},
{
"pass - MaxFeePerGas is nil",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFeeDisabled(queryClient)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
MaxPriorityFeePerGas: nil,
GasPrice: nil,
MaxFeePerGas: nil,
},
nil,
nil,
common.Hash{},
true,
},
{
"fail - GasPrice and (MaxFeePerGas or MaxPriorityPerGas specified",
func() {},
evmtypes.TransactionArgs{
Nonce: &txNonce,
MaxPriorityFeePerGas: nil,
GasPrice: gasPrice,
MaxFeePerGas: gasPrice,
},
nil,
nil,
common.Hash{},
false,
},
{
"fail - Block error",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlockError(client, 1)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
},
nil,
nil,
common.Hash{},
false,
},
{
"pass - MaxFeePerGas is nil",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
GasPrice: nil,
MaxPriorityFeePerGas: gasPrice,
MaxFeePerGas: gasPrice,
ChainID: callArgs.ChainID,
},
nil,
nil,
common.Hash{},
true,
},
{
"pass - Chain Id is nil",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
MaxPriorityFeePerGas: gasPrice,
ChainID: nil,
},
nil,
nil,
common.Hash{},
true,
},
{
"fail - Pending transactions error",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
RegisterEstimateGas(queryClient, callArgs)
RegisterParams(queryClient, &header, 1)
RegisterParamsWithoutHeader(queryClient, 1)
RegisterUnconfirmedTxsError(client, nil)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
To: &toAddr,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Gas: nil,
ChainID: callArgs.ChainID,
},
gasPrice,
nil,
common.Hash{},
false,
},
{
"fail - Not Ethereum txs",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
RegisterEstimateGas(queryClient, callArgs)
RegisterParams(queryClient, &header, 1)
RegisterParamsWithoutHeader(queryClient, 1)
RegisterUnconfirmedTxsEmpty(client, nil)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
To: &toAddr,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Gas: nil,
ChainID: callArgs.ChainID,
},
gasPrice,
nil,
common.Hash{},
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
hash, err := suite.backend.Resend(tc.args, tc.gasPrice, tc.gasLimit)
if tc.expPass {
suite.Require().Equal(tc.expHash, hash)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestSendRawTransaction() {
ethTx, bz := suite.buildEthereumTx()
rlpEncodedBz, _ := rlp.EncodeToBytes(ethTx.AsTransaction())
cosmosTx, _ := ethTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
txBytes, _ := suite.backend.clientCtx.TxConfig.TxEncoder()(cosmosTx)
testCases := []struct {
name string
registerMock func()
rawTx []byte
expHash common.Hash
expPass bool
}{
{
"fail - empty bytes",
func() {},
[]byte{},
common.Hash{},
false,
},
{
"fail - no RLP encoded bytes",
func() {},
bz,
common.Hash{},
false,
},
{
"fail - unprotected transactions",
func() {
suite.backend.allowUnprotectedTxs = false
},
rlpEncodedBz,
common.Hash{},
false,
},
{
"fail - failed to get evm params",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.allowUnprotectedTxs = true
RegisterParamsWithoutHeaderError(queryClient, 1)
},
rlpEncodedBz,
common.Hash{},
false,
},
{
"fail - failed to broadcast transaction",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.allowUnprotectedTxs = true
RegisterParamsWithoutHeader(queryClient, 1)
RegisterBroadcastTxError(client, txBytes)
},
rlpEncodedBz,
common.HexToHash(ethTx.Hash),
false,
},
{
"pass - Gets the correct transaction hash of the eth transaction",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.allowUnprotectedTxs = true
RegisterParamsWithoutHeader(queryClient, 1)
RegisterBroadcastTx(client, txBytes)
},
rlpEncodedBz,
common.HexToHash(ethTx.Hash),
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
hash, err := suite.backend.SendRawTransaction(tc.rawTx)
if tc.expPass {
suite.Require().Equal(tc.expHash, hash)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestDoCall() {
_, bz := suite.buildEthereumTx()
gasPrice := (*hexutil.Big)(big.NewInt(1))
toAddr := tests.GenerateAddress()
chainID := (*hexutil.Big)(suite.backend.chainID)
callArgs := evmtypes.TransactionArgs{
From: nil,
To: &toAddr,
Gas: nil,
GasPrice: nil,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Input: nil,
Data: nil,
AccessList: nil,
ChainID: chainID,
}
argsBz, err := json.Marshal(callArgs)
suite.Require().NoError(err)
testCases := []struct {
name string
registerMock func()
blockNum rpctypes.BlockNumber
callArgs evmtypes.TransactionArgs
expEthTx *evmtypes.MsgEthereumTxResponse
expPass bool
}{
{
"fail - Invalid request",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, bz)
RegisterEthCallError(queryClient, &evmtypes.EthCallRequest{Args: argsBz, ChainId: suite.backend.chainID.Int64()})
},
rpctypes.BlockNumber(1),
callArgs,
&evmtypes.MsgEthereumTxResponse{},
false,
},
{
"pass - Returned transaction response",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, bz)
RegisterEthCall(queryClient, &evmtypes.EthCallRequest{Args: argsBz, ChainId: suite.backend.chainID.Int64()})
},
rpctypes.BlockNumber(1),
callArgs,
&evmtypes.MsgEthereumTxResponse{},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
msgEthTx, err := suite.backend.DoCall(tc.callArgs, tc.blockNum)
if tc.expPass {
suite.Require().Equal(tc.expEthTx, msgEthTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGasPrice() {
defaultGasPrice := (*hexutil.Big)(big.NewInt(1))
testCases := []struct {
name string
registerMock func()
expGas *hexutil.Big
expPass bool
}{
{
"pass - get the default gas price",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterFeeMarketParams(feeMarketClient, 1)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
defaultGasPrice,
true,
},
{
"fail - can't get gasFee, FeeMarketParams error",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterFeeMarketParamsError(feeMarketClient, 1)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
defaultGasPrice,
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
gasPrice, err := suite.backend.GasPrice()
if tc.expPass {
suite.Require().Equal(tc.expGas, gasPrice)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -153,11 +153,13 @@ func (b *Backend) FeeHistory(
}
blockEnd = int64(blockNumber)
}
userBlockCountInt := int64(userBlockCount)
maxBlockCount := int64(b.cfg.JSONRPC.FeeHistoryCap)
if userBlockCountInt > maxBlockCount {
return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", userBlockCountInt, maxBlockCount)
}
blockStart := blockEnd - userBlockCountInt
if blockStart < 0 {
blockStart = 0
@ -173,6 +175,7 @@ func (b *Backend) FeeHistory(
for i := 0; i < int(blockCount); i++ {
reward[i] = make([]*hexutil.Big, rewardCount)
}
thisBaseFee := make([]*hexutil.Big, blockCount)
thisGasUsedRatio := make([]float64, blockCount)

View File

@ -4,6 +4,12 @@ import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
ethrpc "github.com/ethereum/go-ethereum/rpc"
rpc "github.com/evmos/ethermint/rpc/types"
"github.com/evmos/ethermint/tests"
"google.golang.org/grpc/metadata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/abci/types"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
@ -144,3 +150,297 @@ func (suite *BackendTestSuite) TestBaseFee() {
})
}
}
func (suite *BackendTestSuite) TestChainId() {
expChainId := (*hexutil.Big)(big.NewInt(9000))
testCases := []struct {
name string
registerMock func()
expChainId *hexutil.Big
expPass bool
}{
{
"pass - block is at or past the EIP-155 replay-protection fork block, return chainID from config ",
func() {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsInvalidHeight(queryClient, &header, int64(1))
},
expChainId,
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
chainId, err := suite.backend.ChainID()
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expChainId, chainId)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetCoinbase() {
validatorAcc := sdk.AccAddress(tests.GenerateAddress().Bytes())
testCases := []struct {
name string
registerMock func()
accAddr sdk.AccAddress
expPass bool
}{
{
"fail - Can't retrieve status from node",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterStatusError(client)
},
validatorAcc,
false,
},
{
"fail - Can't query validator account",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterStatus(client)
RegisterValidatorAccountError(queryClient)
},
validatorAcc,
false,
},
{
"pass - Gets coinbase account",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterStatus(client)
RegisterValidatorAccount(queryClient, validatorAcc)
},
validatorAcc,
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
accAddr, err := suite.backend.GetCoinbase()
if tc.expPass {
suite.Require().Equal(tc.accAddr, accAddr)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestSuggestGasTipCap() {
testCases := []struct {
name string
registerMock func()
baseFee *big.Int
expGasTipCap *big.Int
expPass bool
}{
{
"pass - London hardfork not enabled or feemarket not enabled ",
func() {},
nil,
big.NewInt(0),
true,
},
{
"pass - Gets the suggest gas tip cap ",
func() {},
nil,
big.NewInt(0),
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
maxDelta, err := suite.backend.SuggestGasTipCap(tc.baseFee)
if tc.expPass {
suite.Require().Equal(tc.expGasTipCap, maxDelta)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGlobalMinGasPrice() {
testCases := []struct {
name string
registerMock func()
expMinGasPrice sdk.Dec
expPass bool
}{
{
"fail - Can't get FeeMarket params",
func() {
feeMarketCleint := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterFeeMarketParamsError(feeMarketCleint, int64(1))
},
sdk.ZeroDec(),
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
globalMinGasPrice, err := suite.backend.GlobalMinGasPrice()
if tc.expPass {
suite.Require().Equal(tc.expMinGasPrice, globalMinGasPrice)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestFeeHistory() {
testCases := []struct {
name string
registerMock func(validator sdk.AccAddress)
userBlockCount ethrpc.DecimalOrHex
latestBlock ethrpc.BlockNumber
expFeeHistory *rpc.FeeHistoryResult
validator sdk.AccAddress
expPass bool
}{
{
"fail - can't get params ",
func(validator sdk.AccAddress) {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.cfg.JSONRPC.FeeHistoryCap = 0
RegisterParamsError(queryClient, &header, ethrpc.BlockNumber(1).Int64())
},
1,
0,
nil,
nil,
false,
},
{
"fail - user block count higher than max block count ",
func(validator sdk.AccAddress) {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.cfg.JSONRPC.FeeHistoryCap = 0
RegisterParams(queryClient, &header, ethrpc.BlockNumber(1).Int64())
},
1,
0,
nil,
nil,
false,
},
{
"fail - Tendermint block fetching error ",
func(validator sdk.AccAddress) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
RegisterBlockError(client, ethrpc.BlockNumber(1).Int64())
},
1,
1,
nil,
nil,
false,
},
{
"fail - Eth block fetching error",
func(validator sdk.AccAddress) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil)
RegisterBlockResultsError(client, 1)
},
1,
1,
nil,
nil,
true,
},
{
"fail - Invalid base fee",
func(validator sdk.AccAddress) {
//baseFee := sdk.NewInt(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil)
RegisterBlockResults(client, 1)
RegisterBaseFeeError(queryClient)
RegisterValidatorAccount(queryClient, validator)
RegisterConsensusParams(client, 1)
},
1,
1,
nil,
sdk.AccAddress(tests.GenerateAddress().Bytes()),
false,
},
{
"pass - Valid FeeHistoryResults object",
func(validator sdk.AccAddress) {
baseFee := sdk.NewInt(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
RegisterConsensusParams(client, 1)
},
1,
1,
&rpc.FeeHistoryResult{
OldestBlock: (*hexutil.Big)(big.NewInt(0)),
BaseFee: []*hexutil.Big{(*hexutil.Big)(big.NewInt(1))},
GasUsedRatio: []float64{0},
Reward: [][]*hexutil.Big{{(*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0))}},
},
sdk.AccAddress(tests.GenerateAddress().Bytes()),
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock(tc.validator)
feeHistory, err := suite.backend.FeeHistory(tc.userBlockCount, tc.latestBlock, []float64{25, 50, 75, 100})
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(feeHistory, tc.expFeeHistory)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -2,12 +2,15 @@ package backend
import (
"context"
"testing"
"github.com/cosmos/cosmos-sdk/client"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/common"
"github.com/evmos/ethermint/rpc/backend/mocks"
rpc "github.com/evmos/ethermint/rpc/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
mock "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
@ -15,6 +18,7 @@ import (
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
"testing"
)
// Client defines a mocked object that implements the Tendermint JSON-RPC Client
@ -24,7 +28,75 @@ import (
// To use a mock method it has to be registered in a given test.
var _ tmrpcclient.Client = &mocks.Client{}
// Tx Search
func RegisterTxSearch(client *mocks.Client, query string, txBz []byte) {
resulTxs := []*tmrpctypes.ResultTx{{Tx: txBz}}
client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), "").
Return(&tmrpctypes.ResultTxSearch{Txs: resulTxs, TotalCount: 1}, nil)
}
func RegisterTxSearchEmpty(client *mocks.Client, query string) {
client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), "").
Return(&tmrpctypes.ResultTxSearch{}, nil)
}
func RegisterTxSearchError(client *mocks.Client, query string) {
client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), "").
Return(nil, errortypes.ErrInvalidRequest)
}
// Broadcast Tx
func RegisterBroadcastTx(client *mocks.Client, tx types.Tx) {
client.On("BroadcastTxSync", context.Background(), tx).
Return(&tmrpctypes.ResultBroadcastTx{}, nil)
}
func RegisterBroadcastTxError(client *mocks.Client, tx types.Tx) {
client.On("BroadcastTxSync", context.Background(), tx).
Return(nil, errortypes.ErrInvalidRequest)
}
// Unconfirmed Transactions
func RegisterUnconfirmedTxs(client *mocks.Client, limit *int, txs []types.Tx) {
client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit).
Return(&tmrpctypes.ResultUnconfirmedTxs{Txs: txs}, nil)
}
func RegisterUnconfirmedTxsEmpty(client *mocks.Client, limit *int) {
client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit).
Return(&tmrpctypes.ResultUnconfirmedTxs{
Txs: make([]types.Tx, 2),
}, nil)
}
func RegisterUnconfirmedTxsError(client *mocks.Client, limit *int) {
client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit).
Return(nil, errortypes.ErrInvalidRequest)
}
// Status
func RegisterStatus(client *mocks.Client) {
client.On("Status", rpc.ContextWithHeight(1)).
Return(&tmrpctypes.ResultStatus{}, nil)
}
func RegisterStatusError(client *mocks.Client) {
client.On("Status", rpc.ContextWithHeight(1)).
Return(nil, errortypes.ErrInvalidRequest)
}
// Block
func RegisterBlockMultipleTxs(
client *mocks.Client,
height int64,
txs []types.Tx,
) (*tmrpctypes.ResultBlock, error) {
block := types.MakeBlock(height, txs, nil, nil)
block.ChainID = ChainID
resBlock := &tmrpctypes.ResultBlock{Block: block}
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
return resBlock, nil
}
func RegisterBlock(
client *mocks.Client,
height int64,
@ -33,24 +105,24 @@ func RegisterBlock(
// without tx
if tx == nil {
emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil)
emptyBlock.ChainID = ChainID
resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock}
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
Return(resBlock, nil)
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
return resBlock, nil
}
// with tx
block := types.MakeBlock(height, []types.Tx{tx}, nil, nil)
block.ChainID = ChainID
resBlock := &tmrpctypes.ResultBlock{Block: block}
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
Return(resBlock, nil)
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
return resBlock, nil
}
// Block returns error
func RegisterBlockError(client *mocks.Client, height int64) {
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}
// Block not found
@ -72,6 +144,7 @@ func TestRegisterBlock(t *testing.T) {
res, err := client.Block(rpc.ContextWithHeight(height), &height)
emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil)
emptyBlock.ChainID = ChainID
resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock}
require.Equal(t, resBlock, res)
require.NoError(t, err)
@ -86,7 +159,7 @@ func RegisterConsensusParams(client *mocks.Client, height int64) {
func RegisterConsensusParamsError(client *mocks.Client, height int64) {
client.On("ConsensusParams", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}
func TestRegisterConsensusParams(t *testing.T) {
@ -101,6 +174,26 @@ func TestRegisterConsensusParams(t *testing.T) {
}
// BlockResults
func RegisterBlockResultsWithEventLog(client *mocks.Client, height int64) (*tmrpctypes.ResultBlockResults, error) {
res := &tmrpctypes.ResultBlockResults{
Height: height,
TxsResults: []*abci.ResponseDeliverTx{
{Code: 0, GasUsed: 0, Events: []abci.Event{{
Type: evmtypes.EventTypeTxLog,
Attributes: []abci.EventAttribute{{
Key: []byte(evmtypes.AttributeKeyTxLog),
Value: []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}, // Represents {"test": "hello"}
Index: true,
}},
}}},
},
}
client.On("BlockResults", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
Return(res, nil)
return res, nil
}
func RegisterBlockResults(
client *mocks.Client,
height int64,
@ -117,7 +210,7 @@ func RegisterBlockResults(
func RegisterBlockResultsError(client *mocks.Client, height int64) {
client.On("BlockResults", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}
func TestRegisterBlockResults(t *testing.T) {
@ -150,7 +243,7 @@ func RegisterBlockByHash(
func RegisterBlockByHashError(client *mocks.Client, hash common.Hash, tx []byte) {
client.On("BlockByHash", rpc.ContextWithHeight(1), []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}
func RegisterBlockByHashNotFound(client *mocks.Client, hash common.Hash, tx []byte) {
@ -167,3 +260,22 @@ func RegisterABCIQueryWithOptions(client *mocks.Client, height int64, path strin
},
}, nil)
}
func RegisterABCIQueryWithOptionsError(clients *mocks.Client, path string, data bytes.HexBytes, opts tmrpcclient.ABCIQueryOptions) {
clients.On("ABCIQueryWithOptions", context.Background(), path, data, opts).
Return(nil, errortypes.ErrInvalidRequest)
}
func RegisterABCIQueryAccount(clients *mocks.Client, data bytes.HexBytes, opts tmrpcclient.ABCIQueryOptions, acc client.Account) {
baseAccount := authtypes.NewBaseAccount(acc.GetAddress(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence())
accAny, _ := codectypes.NewAnyWithValue(baseAccount)
accResponse := authtypes.QueryAccountResponse{Account: accAny}
respBz, _ := accResponse.Marshal()
clients.On("ABCIQueryWithOptions", context.Background(), "/cosmos.auth.v1beta1.Query/Account", data, opts).
Return(&tmrpctypes.ResultABCIQuery{
Response: abci.ResponseQuery{
Value: respBz,
Height: 1,
},
}, nil)
}

View File

@ -1,12 +1,11 @@
package backend
import (
"context"
"encoding/json"
"fmt"
"strconv"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/ethereum/go-ethereum/common"
"github.com/evmos/ethermint/rpc/backend/mocks"
@ -19,6 +18,8 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"strconv"
"testing"
)
// QueryClient defines a mocked object that implements the ethermint GRPC
@ -28,6 +29,38 @@ import (
// To use a mock method it has to be registered in a given test.
var _ evmtypes.QueryClient = &mocks.EVMQueryClient{}
// TraceTransaction
func RegisterTraceTransactionWithPredecessors(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx, predecessors []*evmtypes.MsgEthereumTx) {
data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}
queryClient.On("TraceTx", rpc.ContextWithHeight(1),
&evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1, Predecessors: predecessors, ChainId: 9000}).
Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil)
}
func RegisterTraceTransaction(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx) {
data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}
queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1, ChainId: 9000}).
Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil)
}
func RegisterTraceTransactionError(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx) {
queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1, ChainId: 9000}).
Return(nil, errortypes.ErrInvalidRequest)
}
// TraceBlock
func RegisterTraceBlock(queryClient *mocks.EVMQueryClient, txs []*evmtypes.MsgEthereumTx) {
data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}
queryClient.On("TraceBlock", rpc.ContextWithHeight(1),
&evmtypes.QueryTraceBlockRequest{Txs: txs, BlockNumber: 1, TraceConfig: &evmtypes.TraceConfig{}, ChainId: 9000}).
Return(&evmtypes.QueryTraceBlockResponse{Data: data}, nil)
}
func RegisterTraceBlockError(queryClient *mocks.EVMQueryClient) {
queryClient.On("TraceBlock", rpc.ContextWithHeight(1), &evmtypes.QueryTraceBlockRequest{}).
Return(nil, errortypes.ErrInvalidRequest)
}
// Params
func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
@ -41,6 +74,11 @@ func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, heig
})
}
func RegisterParamsWithoutHeader(queryClient *mocks.EVMQueryClient, height int64) {
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}).
Return(&evmtypes.QueryParamsResponse{Params: evmtypes.DefaultParams()}, nil)
}
func RegisterParamsInvalidHeader(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
Return(&evmtypes.QueryParamsResponse{}, nil).
@ -64,15 +102,21 @@ func RegisterParamsInvalidHeight(queryClient *mocks.EVMQueryClient, header *meta
})
}
func RegisterParamsWithoutHeaderError(queryClient *mocks.EVMQueryClient, height int64) {
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}).
Return(nil, errortypes.ErrInvalidRequest)
}
// Params returns error
func RegisterParamsError(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}
func TestRegisterParams(t *testing.T) {
queryClient := mocks.NewEVMQueryClient(t)
var header metadata.MD
queryClient := mocks.NewEVMQueryClient(t)
height := int64(1)
RegisterParams(queryClient, &header, height)
@ -91,6 +135,26 @@ func TestRegisterParamsError(t *testing.T) {
require.Error(t, err)
}
// ETH Call
func RegisterEthCall(queryClient *mocks.EVMQueryClient, request *evmtypes.EthCallRequest) {
ctx, _ := context.WithCancel(rpc.ContextWithHeight(1))
queryClient.On("EthCall", ctx, request).
Return(&evmtypes.MsgEthereumTxResponse{}, nil)
}
func RegisterEthCallError(queryClient *mocks.EVMQueryClient, request *evmtypes.EthCallRequest) {
ctx, _ := context.WithCancel(rpc.ContextWithHeight(1))
queryClient.On("EthCall", ctx, request).
Return(nil, errortypes.ErrInvalidRequest)
}
// Estimate Gas
func RegisterEstimateGas(queryClient *mocks.EVMQueryClient, args evmtypes.TransactionArgs) {
bz, _ := json.Marshal(args)
queryClient.On("EstimateGas", rpc.ContextWithHeight(1), &evmtypes.EthCallRequest{Args: bz, ChainId: args.ChainID.ToInt().Int64()}).
Return(&evmtypes.EstimateGasResponse{}, nil)
}
// BaseFee
func RegisterBaseFee(queryClient *mocks.EVMQueryClient, baseFee sdk.Int) {
queryClient.On("BaseFee", rpc.ContextWithHeight(1), &evmtypes.QueryBaseFeeRequest{}).
@ -137,12 +201,7 @@ func TestRegisterBaseFeeDisabled(t *testing.T) {
// ValidatorAccount
func RegisterValidatorAccount(queryClient *mocks.EVMQueryClient, validator sdk.AccAddress) {
queryClient.On("ValidatorAccount", rpc.ContextWithHeight(1), &evmtypes.QueryValidatorAccountRequest{}).
Return(
&evmtypes.QueryValidatorAccountResponse{
AccountAddress: validator.String(),
},
nil,
)
Return(&evmtypes.QueryValidatorAccountResponse{AccountAddress: validator.String()}, nil)
}
func RegisterValidatorAccountError(queryClient *mocks.EVMQueryClient) {
@ -168,7 +227,7 @@ func RegisterCode(queryClient *mocks.EVMQueryClient, addr common.Address, code [
func RegisterCodeError(queryClient *mocks.EVMQueryClient, addr common.Address) {
queryClient.On("Code", rpc.ContextWithHeight(1), &evmtypes.QueryCodeRequest{Address: addr.String()}).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}
// Storage
@ -179,7 +238,7 @@ func RegisterStorageAt(queryClient *mocks.EVMQueryClient, addr common.Address, k
func RegisterStorageAtError(queryClient *mocks.EVMQueryClient, addr common.Address, key string) {
queryClient.On("Storage", rpc.ContextWithHeight(1), &evmtypes.QueryStorageRequest{Address: addr.String(), Key: key}).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}
func RegisterAccount(queryClient *mocks.EVMQueryClient, addr common.Address, height int64) {
@ -211,5 +270,5 @@ func RegisterBalanceNegative(queryClient *mocks.EVMQueryClient, addr common.Addr
func RegisterBalanceError(queryClient *mocks.EVMQueryClient, addr common.Address, height int64) {
queryClient.On("Balance", rpc.ContextWithHeight(height), &evmtypes.QueryBalanceRequest{Address: addr.String()}).
Return(nil, sdkerrors.ErrInvalidRequest)
Return(nil, errortypes.ErrInvalidRequest)
}

View File

@ -0,0 +1,21 @@
package backend
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/evmos/ethermint/rpc/backend/mocks"
rpc "github.com/evmos/ethermint/rpc/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
)
var _ feemarkettypes.QueryClient = &mocks.FeeMarketQueryClient{}
// Params
func RegisterFeeMarketParams(feeMarketClient *mocks.FeeMarketQueryClient, height int64) {
feeMarketClient.On("Params", rpc.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{}).
Return(&feemarkettypes.QueryParamsResponse{Params: feemarkettypes.DefaultParams()}, nil)
}
func RegisterFeeMarketParamsError(feeMarketClient *mocks.FeeMarketQueryClient, height int64) {
feeMarketClient.On("Params", rpc.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{}).
Return(nil, sdkerrors.ErrInvalidRequest)
}

View File

@ -15,7 +15,6 @@ func (b *Backend) GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) {
if resBlock == nil {
return nil, errors.Errorf("block not found for hash %s", hash)
}
return b.GetLogsByHeight(&resBlock.Block.Header.Height)
}

117
rpc/backend/filters_test.go Normal file
View File

@ -0,0 +1,117 @@
package backend
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/evmos/ethermint/rpc/backend/mocks"
ethrpc "github.com/evmos/ethermint/rpc/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
tmtypes "github.com/tendermint/tendermint/types"
)
func (suite *BackendTestSuite) TestGetLogs() {
_, bz := suite.buildEthereumTx()
block := tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil)
logs := make([]*evmtypes.Log, 0, 1)
var log evmtypes.Log
json.Unmarshal([]byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}, &log)
logs = append(logs, &log)
testCases := []struct {
name string
registerMock func(hash common.Hash)
blockHash common.Hash
expLogs [][]*ethtypes.Log
expPass bool
}{
{
"fail - no block with that hash",
func(hash common.Hash) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockByHashNotFound(client, hash, bz)
},
common.Hash{},
nil,
false,
},
{
"fail - error fetching block by hash",
func(hash common.Hash) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockByHashError(client, hash, bz)
},
common.Hash{},
nil,
false,
},
{
"fail - error getting block results",
func(hash common.Hash) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockByHash(client, hash, bz)
RegisterBlockResultsError(client, 1)
},
common.Hash{},
nil,
false,
},
{
"success - getting logs with block hash",
func(hash common.Hash) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockByHash(client, hash, bz)
RegisterBlockResultsWithEventLog(client, ethrpc.BlockNumber(1).Int64())
},
common.BytesToHash(block.Hash()),
[][]*ethtypes.Log{evmtypes.LogsToEthereum(logs)},
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest()
tc.registerMock(tc.blockHash)
logs, err := suite.backend.GetLogs(tc.blockHash)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expLogs, logs)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestBloomStatus() {
testCases := []struct {
name string
registerMock func()
expResult uint64
expPass bool
}{
{
"pass - returns the BloomBitsBlocks and the number of processed sections maintained",
func() {},
4096,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest()
tc.registerMock()
bloom, _ := suite.backend.BloomStatus()
if tc.expPass {
suite.Require().Equal(tc.expResult, bloom)
}
})
}
}

View File

@ -0,0 +1,123 @@
// Code generated by mockery v2.14.1. DO NOT EDIT.
package mocks
import (
context "context"
grpc "google.golang.org/grpc"
mock "github.com/stretchr/testify/mock"
types "github.com/evmos/ethermint/x/feemarket/types"
)
// FeeMarketQueryClient is an autogenerated mock type for the QueryClient type
type FeeMarketQueryClient struct {
mock.Mock
}
// BaseFee provides a mock function with given fields: ctx, in, opts
func (_m *FeeMarketQueryClient) BaseFee(ctx context.Context, in *types.QueryBaseFeeRequest, opts ...grpc.CallOption) (*types.QueryBaseFeeResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *types.QueryBaseFeeResponse
if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBaseFeeRequest, ...grpc.CallOption) *types.QueryBaseFeeResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.QueryBaseFeeResponse)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *types.QueryBaseFeeRequest, ...grpc.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// BlockGas provides a mock function with given fields: ctx, in, opts
func (_m *FeeMarketQueryClient) BlockGas(ctx context.Context, in *types.QueryBlockGasRequest, opts ...grpc.CallOption) (*types.QueryBlockGasResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *types.QueryBlockGasResponse
if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBlockGasRequest, ...grpc.CallOption) *types.QueryBlockGasResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.QueryBlockGasResponse)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *types.QueryBlockGasRequest, ...grpc.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Params provides a mock function with given fields: ctx, in, opts
func (_m *FeeMarketQueryClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *types.QueryParamsResponse
if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.QueryParamsResponse)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
type mockConstructorTestingTNewQueryClient interface {
mock.TestingT
Cleanup(func())
}
// NewQueryClient creates a new instance of QueryClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewFeeMarketQueryClient(t mockConstructorTestingTNewQueryClient) *FeeMarketQueryClient {
mock := &FeeMarketQueryClient{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -5,6 +5,7 @@ import (
"math/big"
"time"
errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
@ -12,7 +13,6 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdkconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/ethereum/go-ethereum/common"
@ -165,7 +165,7 @@ func (b *Backend) SetEtherbase(etherbase common.Address) bool {
syncCtx := b.clientCtx.WithBroadcastMode(flags.BroadcastSync)
rsp, err := syncCtx.BroadcastTx(txBytes)
if rsp != nil && rsp.Code != 0 {
err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
err = errorsmod.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
}
if err != nil {
b.logger.Debug("failed to broadcast tx", "error", err.Error())

View File

@ -0,0 +1,355 @@
package backend
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/evmos/ethermint/rpc/backend/mocks"
ethermint "github.com/evmos/ethermint/types"
"github.com/spf13/viper"
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
"math/big"
)
func (suite *BackendTestSuite) TestRPCMinGasPrice() {
testCases := []struct {
name string
registerMock func()
expMinGasPrice int64
expPass bool
}{
{
"pass - default gas price",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsWithoutHeaderError(queryClient, 1)
},
ethermint.DefaultGasPrice,
true,
},
{
"pass - min gas price is 0",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsWithoutHeader(queryClient, 1)
},
ethermint.DefaultGasPrice,
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
minPrice := suite.backend.RPCMinGasPrice()
if tc.expPass {
suite.Require().Equal(tc.expMinGasPrice, minPrice)
} else {
suite.Require().NotEqual(tc.expMinGasPrice, minPrice)
}
})
}
}
func (suite *BackendTestSuite) TestSetGasPrice() {
defaultGasPrice := (*hexutil.Big)(big.NewInt(1))
testCases := []struct {
name string
registerMock func()
gasPrice hexutil.Big
expOutput bool
}{
{
"pass - cannot get server config",
func() {
suite.backend.clientCtx.Viper = viper.New()
},
*defaultGasPrice,
false,
},
{
"pass - cannot find coin denom",
func() {
suite.backend.clientCtx.Viper = viper.New()
suite.backend.clientCtx.Viper.Set("telemetry.global-labels", []interface{}{})
},
*defaultGasPrice,
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
output := suite.backend.SetGasPrice(tc.gasPrice)
suite.Require().Equal(tc.expOutput, output)
})
}
}
// TODO: Combine these 2 into one test since the code is identical
func (suite *BackendTestSuite) TestListAccounts() {
testCases := []struct {
name string
registerMock func()
expAddr []common.Address
expPass bool
}{
{
"pass - returns empty address",
func() {},
[]common.Address{},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
output, err := suite.backend.ListAccounts()
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expAddr, output)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestAccounts() {
testCases := []struct {
name string
registerMock func()
expAddr []common.Address
expPass bool
}{
{
"pass - returns empty address",
func() {},
[]common.Address{},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
output, err := suite.backend.Accounts()
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expAddr, output)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestSyncing() {
testCases := []struct {
name string
registerMock func()
expResponse interface{}
expPass bool
}{
{
"fail - Can't get status",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterStatusError(client)
},
false,
false,
},
{
"pass - Node not catching up",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterStatus(client)
},
false,
true,
},
{
"pass - Node is catching up",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterStatus(client)
status, _ := client.Status(suite.backend.ctx)
status.SyncInfo.CatchingUp = true
},
map[string]interface{}{
"startingBlock": hexutil.Uint64(0),
"currentBlock": hexutil.Uint64(0),
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
output, err := suite.backend.Syncing()
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expResponse, output)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestSetEtherbase() {
testCases := []struct {
name string
registerMock func()
etherbase common.Address
expResult bool
}{
{
"pass - Failed to get coinbase address",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterStatusError(client)
},
common.Address{},
false,
},
{
"pass - the minimum fee is not set",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterStatus(client)
RegisterValidatorAccount(queryClient, suite.acc)
},
common.Address{},
false,
},
{
"fail - error querying for account ",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterStatus(client)
RegisterValidatorAccount(queryClient, suite.acc)
c := sdk.NewDecCoin("aphoton", sdk.NewIntFromBigInt(big.NewInt(1)))
suite.backend.cfg.SetMinGasPrices(sdk.DecCoins{c})
delAddr, _ := suite.backend.GetCoinbase()
//account, _ := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, delAddr)
delCommonAddr := common.BytesToAddress(delAddr.Bytes())
request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(delCommonAddr.Bytes()).String()}
requestMarshal, _ := request.Marshal()
RegisterABCIQueryWithOptionsError(
client,
"/cosmos.auth.v1beta1.Query/Account",
requestMarshal,
tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
)
},
common.Address{},
false,
},
// TODO: Finish this test case once ABCIQuery GetAccount is fixed
//{
// "pass - set the etherbase for the miner",
// func() {
// client := suite.backend.clientCtx.Client.(*mocks.Client)
// queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
// RegisterStatus(client)
// RegisterValidatorAccount(queryClient, suite.acc)
// c := sdk.NewDecCoin("aphoton", sdk.NewIntFromBigInt(big.NewInt(1)))
// suite.backend.cfg.SetMinGasPrices(sdk.DecCoins{c})
// delAddr, _ := suite.backend.GetCoinbase()
// account, _ := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, delAddr)
// delCommonAddr := common.BytesToAddress(delAddr.Bytes())
// request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(delCommonAddr.Bytes()).String()}
// requestMarshal, _ := request.Marshal()
// RegisterABCIQueryAccount(
// client,
// requestMarshal,
// tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
// account,
// )
// },
// common.Address{},
// false,
//},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
output := suite.backend.SetEtherbase(tc.etherbase)
suite.Require().Equal(tc.expResult, output)
})
}
}
func (suite *BackendTestSuite) TestImportRawKey() {
priv, _ := ethsecp256k1.GenerateKey()
privHex := common.Bytes2Hex(priv.Bytes())
pubAddr := common.BytesToAddress(priv.PubKey().Address().Bytes())
testCases := []struct {
name string
registerMock func()
privKey string
password string
expAddr common.Address
expPass bool
}{
{
"fail - not a valid private key",
func() {},
"",
"",
common.Address{},
false,
},
{
"pass - returning correct address",
func() {},
privHex,
"",
pubAddr,
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
output, err := suite.backend.ImportRawKey(tc.privKey, tc.password)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expAddr, output)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -1,21 +1,21 @@
package backend
import (
"errors"
"fmt"
"math/big"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/evmos/ethermint/ethereum/eip712"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/pkg/errors"
)
// SendTransaction sends transaction based on received args using Node's key to sign it
@ -27,6 +27,10 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e
return common.Hash{}, fmt.Errorf("%s; %s", keystore.ErrNoMatch, err.Error())
}
if args.ChainID != nil && (b.chainID).Cmp((*big.Int)(args.ChainID)) != 0 {
return common.Hash{}, fmt.Errorf("chainId does not match node's (have=%v, want=%v)", args.ChainID, (*hexutil.Big)(b.chainID))
}
args, err = b.SetTxDefaults(args)
if err != nil {
return common.Hash{}, err
@ -89,7 +93,7 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e
syncCtx := b.clientCtx.WithBroadcastMode(flags.BroadcastSync)
rsp, err := syncCtx.BroadcastTx(txBytes)
if rsp != nil && rsp.Code != 0 {
err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
err = errorsmod.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
}
if err != nil {
b.logger.Error("failed to broadcast tx", "error", err.Error())
@ -131,7 +135,7 @@ func (b *Backend) SignTypedData(address common.Address, typedData apitypes.Typed
return nil, fmt.Errorf("%s; %s", keystore.ErrNoMatch, err.Error())
}
sigHash, err := eip712.ComputeTypedDataHash(typedData)
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
if err != nil {
return nil, err
}

260
rpc/backend/sign_tx_test.go Normal file
View File

@ -0,0 +1,260 @@
package backend
import (
"fmt"
"github.com/cosmos/cosmos-sdk/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
goethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/evmos/ethermint/rpc/backend/mocks"
"github.com/evmos/ethermint/tests"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"google.golang.org/grpc/metadata"
)
func (suite *BackendTestSuite) TestSendTransaction() {
gasPrice := new(hexutil.Big)
gas := hexutil.Uint64(1)
zeroGas := hexutil.Uint64(0)
toAddr := tests.GenerateAddress()
priv, _ := ethsecp256k1.GenerateKey()
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
nonce := hexutil.Uint64(1)
baseFee := sdk.NewInt(1)
callArgsDefault := evmtypes.TransactionArgs{
From: &from,
To: &toAddr,
GasPrice: gasPrice,
Gas: &gas,
Nonce: &nonce,
}
hash := common.Hash{}
testCases := []struct {
name string
registerMock func()
args evmtypes.TransactionArgs
expHash common.Hash
expPass bool
}{
{
"fail - Can't find account in Keyring",
func() {},
evmtypes.TransactionArgs{},
hash,
false,
},
{
"fail - Block error can't set Tx defaults",
func() {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
RegisterParams(queryClient, &header, 1)
RegisterBlockError(client, 1)
},
callArgsDefault,
hash,
false,
},
{
"fail - Cannot validate transaction gas set to 0",
func() {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
},
evmtypes.TransactionArgs{
From: &from,
To: &toAddr,
GasPrice: gasPrice,
Gas: &zeroGas,
Nonce: &nonce,
},
hash,
false,
},
{
"fail - Cannot broadcast transaction",
func() {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
RegisterParamsWithoutHeader(queryClient, 1)
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
msg := callArgsDefault.ToTransaction()
msg.Sign(ethSigner, suite.backend.clientCtx.Keyring)
tx, _ := msg.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
txBytes, _ := txEncoder(tx)
RegisterBroadcastTxError(client, txBytes)
},
callArgsDefault,
common.Hash{},
false,
},
{
"pass - Return the transaction hash",
func() {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
RegisterParamsWithoutHeader(queryClient, 1)
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
msg := callArgsDefault.ToTransaction()
msg.Sign(ethSigner, suite.backend.clientCtx.Keyring)
tx, _ := msg.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
txBytes, _ := txEncoder(tx)
RegisterBroadcastTx(client, txBytes)
},
callArgsDefault,
hash,
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
if tc.expPass {
// Sign the transaction and get the hash
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsWithoutHeader(queryClient, 1)
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
msg := callArgsDefault.ToTransaction()
msg.Sign(ethSigner, suite.backend.clientCtx.Keyring)
tc.expHash = msg.AsTransaction().Hash()
}
responseHash, err := suite.backend.SendTransaction(tc.args)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expHash, responseHash)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestSign() {
from, priv := tests.NewAddrKey()
testCases := []struct {
name string
registerMock func()
fromAddr common.Address
inputBz hexutil.Bytes
expPass bool
}{
{
"fail - can't find key in Keyring",
func() {},
from,
nil,
false,
},
{
"pass - sign nil data",
func() {
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
},
from,
nil,
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
responseBz, err := suite.backend.Sign(tc.fromAddr, tc.inputBz)
if tc.expPass {
signature, _, err := suite.backend.clientCtx.Keyring.SignByAddress((sdk.AccAddress)(from.Bytes()), tc.inputBz)
signature[goethcrypto.RecoveryIDOffset] += 27
suite.Require().NoError(err)
suite.Require().Equal((hexutil.Bytes)(signature), responseBz)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestSignTypedData() {
from, priv := tests.NewAddrKey()
testCases := []struct {
name string
registerMock func()
fromAddr common.Address
inputTypedData apitypes.TypedData
expPass bool
}{
{
"fail - can't find key in Keyring",
func() {},
from,
apitypes.TypedData{},
false,
},
{
"fail - empty TypeData",
func() {
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
},
from,
apitypes.TypedData{},
false,
},
// TODO: Generate a TypedData msg
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
responseBz, err := suite.backend.SignTypedData(tc.fromAddr, tc.inputTypedData)
if tc.expPass {
sigHash, _, err := apitypes.TypedDataAndHash(tc.inputTypedData)
signature, _, err := suite.backend.clientCtx.Keyring.SignByAddress((sdk.AccAddress)(from.Bytes()), sigHash)
signature[goethcrypto.RecoveryIDOffset] += 27
suite.Require().NoError(err)
suite.Require().Equal((hexutil.Bytes)(signature), responseBz)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -84,6 +84,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi
BlockTime: blk.Block.Time,
BlockHash: common.Bytes2Hex(blk.BlockID.Hash),
ProposerAddress: sdk.ConsAddress(blk.Block.ProposerAddress),
ChainId: b.chainID.Int64(),
}
if config != nil {
@ -112,7 +113,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi
return decodedResult, nil
}
// traceBlock configures a new tracer according to the provided configuration, and
// TraceBlock configures a new tracer according to the provided configuration, and
// executes all the transactions contained within. The return value will be one item
// per transaction, dependent on the requested tracer.
func (b *Backend) TraceBlock(height rpctypes.BlockNumber,
@ -162,6 +163,7 @@ func (b *Backend) TraceBlock(height rpctypes.BlockNumber,
BlockTime: block.Block.Time,
BlockHash: common.Bytes2Hex(block.BlockID.Hash),
ProposerAddress: sdk.ConsAddress(block.Block.ProposerAddress),
ChainId: b.chainID.Int64(),
}
res, err := b.queryClient.TraceBlock(ctxWithHeight, traceBlockRequest)

250
rpc/backend/tracing_test.go Normal file
View File

@ -0,0 +1,250 @@
package backend
import (
"fmt"
"github.com/cosmos/cosmos-sdk/crypto"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/evmos/ethermint/indexer"
"github.com/evmos/ethermint/rpc/backend/mocks"
evmtypes "github.com/evmos/ethermint/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types"
tmlog "github.com/tendermint/tendermint/libs/log"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db"
)
func (suite *BackendTestSuite) TestTraceTransaction() {
msgEthereumTx, _ := suite.buildEthereumTx()
msgEthereumTx2, _ := suite.buildEthereumTx()
txHash := msgEthereumTx.AsTransaction().Hash()
txHash2 := msgEthereumTx2.AsTransaction().Hash()
priv, _ := ethsecp256k1.GenerateKey()
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsWithoutHeader(queryClient, 1)
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
msgEthereumTx.From = from.String()
msgEthereumTx.Sign(ethSigner, suite.signer)
tx, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
txBz, _ := txEncoder(tx)
msgEthereumTx2.From = from.String()
msgEthereumTx2.Sign(ethSigner, suite.signer)
tx2, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
txBz2, _ := txEncoder(tx2)
testCases := []struct {
name string
registerMock func()
block *types.Block
responseBlock []*abci.ResponseDeliverTx
expResult interface{}
expPass bool
}{
{
"fail - tx not found",
func() {},
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{}}},
[]*abci.ResponseDeliverTx{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
{Key: []byte("txIndex"), Value: []byte("0")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
}},
},
},
},
nil,
false,
},
{
"fail - block not found",
func() {
//var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockError(client, 1)
},
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
[]*abci.ResponseDeliverTx{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
{Key: []byte("txIndex"), Value: []byte("0")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
}},
},
},
},
map[string]interface{}{"test": "hello"},
false,
},
{
"pass - transaction found in a block with multiple transactions",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockMultipleTxs(client, 1, []types.Tx{txBz, txBz2})
RegisterTraceTransactionWithPredecessors(queryClient, msgEthereumTx, []*evmtypes.MsgEthereumTx{msgEthereumTx})
},
&types.Block{Header: types.Header{Height: 1, ChainID: ChainID}, Data: types.Data{Txs: []types.Tx{txBz, txBz2}}},
[]*abci.ResponseDeliverTx{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
{Key: []byte("txIndex"), Value: []byte("0")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
}},
},
},
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(txHash2.Hex())},
{Key: []byte("txIndex"), Value: []byte("1")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
}},
},
},
},
map[string]interface{}{"test": "hello"},
true,
},
{
"pass - transaction found",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, 1, txBz)
RegisterTraceTransaction(queryClient, msgEthereumTx)
},
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
[]*abci.ResponseDeliverTx{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
{Key: []byte("txIndex"), Value: []byte("0")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
}},
},
},
},
map[string]interface{}{"test": "hello"},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
db := dbm.NewMemDB()
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
err := suite.backend.indexer.IndexBlock(tc.block, tc.responseBlock)
suite.Require().NoError(err)
txResult, err := suite.backend.TraceTransaction(txHash, nil)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expResult, txResult)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestTraceBlock() {
msgEthTx, bz := suite.buildEthereumTx()
emptyBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{}, nil, nil)
emptyBlock.ChainID = ChainID
filledBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil)
filledBlock.ChainID = ChainID
resBlockEmpty := tmrpctypes.ResultBlock{Block: emptyBlock, BlockID: emptyBlock.LastBlockID}
resBlockFilled := tmrpctypes.ResultBlock{Block: filledBlock, BlockID: filledBlock.LastBlockID}
testCases := []struct {
name string
registerMock func()
expTraceResults []*evmtypes.TxTraceResult
resBlock *tmrpctypes.ResultBlock
config *evmtypes.TraceConfig
expPass bool
}{
{
"pass - no transaction returning empty array",
func() {},
[]*evmtypes.TxTraceResult{},
&resBlockEmpty,
&evmtypes.TraceConfig{},
true,
},
{
"fail - cannot unmarshal data",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterTraceBlock(queryClient, []*evmtypes.MsgEthereumTx{msgEthTx})
},
[]*evmtypes.TxTraceResult{},
&resBlockFilled,
&evmtypes.TraceConfig{},
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
traceResults, err := suite.backend.TraceBlock(1, tc.config, tc.resBlock)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expTraceResults, traceResults)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -3,8 +3,8 @@ package backend
import (
"fmt"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
@ -74,6 +74,7 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac
uint64(res.Height),
uint64(res.EthTxIndex),
baseFee,
b.chainID,
)
}
@ -102,6 +103,7 @@ func (b *Backend) getTransactionByHashPending(txHash common.Hash) (*rpctypes.RPC
uint64(0),
uint64(0),
nil,
b.chainID,
)
if err != nil {
return nil, err
@ -214,6 +216,7 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{
// sender and receiver (contract or EOA) addreses
"from": from,
"to": txData.GetTo(),
"type": hexutil.Uint(ethMsg.AsTransaction().Type()),
}
if logs == nil {
@ -288,7 +291,7 @@ func (b *Backend) GetTxByEthHash(hash common.Hash) (*ethermint.TxResult, error)
return txs.GetTxByHash(hash)
})
if err != nil {
return nil, sdkerrors.Wrapf(err, "GetTxByEthHash %s", hash.Hex())
return nil, errorsmod.Wrapf(err, "GetTxByEthHash %s", hash.Hex())
}
return txResult, nil
}
@ -308,7 +311,7 @@ func (b *Backend) GetTxByTxIndex(height int64, index uint) (*ethermint.TxResult,
return txs.GetTxByTxIndex(int(index))
})
if err != nil {
return nil, sdkerrors.Wrapf(err, "GetTxByTxIndex %d %d", height, index)
return nil, errorsmod.Wrapf(err, "GetTxByTxIndex %d %d", height, index)
}
return txResult, nil
}
@ -339,7 +342,7 @@ func (b *Backend) queryTendermintTxIndexer(query string, txGetter func(*rpctypes
return rpctypes.ParseTxIndexerResult(txResult, tx, txGetter)
}
// getTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`.
// GetTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`.
func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height)
if err != nil {
@ -386,5 +389,6 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, i
uint64(block.Block.Height),
uint64(idx),
baseFee,
b.chainID,
)
}

600
rpc/backend/tx_info_test.go Normal file
View File

@ -0,0 +1,600 @@
package backend
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/evmos/ethermint/indexer"
"github.com/evmos/ethermint/rpc/backend/mocks"
rpctypes "github.com/evmos/ethermint/rpc/types"
ethermint "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types"
tmlog "github.com/tendermint/tendermint/libs/log"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db"
"google.golang.org/grpc/metadata"
"math/big"
)
func (suite *BackendTestSuite) TestGetTransactionByHash() {
msgEthereumTx, _ := suite.buildEthereumTx()
txHash := msgEthereumTx.AsTransaction().Hash()
txBz := suite.signAndEncodeEthTx(msgEthereumTx)
block := &types.Block{Header: types.Header{Height: 1, ChainID: "test"}, Data: types.Data{Txs: []types.Tx{txBz}}}
responseDeliver := []*abci.ResponseDeliverTx{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
{Key: []byte("txIndex"), Value: []byte("0")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("")},
}},
},
},
}
rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID)
testCases := []struct {
name string
registerMock func()
tx *evmtypes.MsgEthereumTx
expRPCTx *rpctypes.RPCTransaction
expPass bool
}{
{
"fail - Block error",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockError(client, 1)
},
msgEthereumTx,
rpcTransaction,
false,
},
{
"fail - Block Result error",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, 1, txBz)
RegisterBlockResultsError(client, 1)
},
msgEthereumTx,
nil,
true,
},
{
"pass - Base fee error",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, txBz)
RegisterBlockResults(client, 1)
RegisterBaseFeeError(queryClient)
},
msgEthereumTx,
rpcTransaction,
true,
},
{
"pass - Transaction found and returned",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, txBz)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
msgEthereumTx,
rpcTransaction,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
db := dbm.NewMemDB()
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
err := suite.backend.indexer.IndexBlock(block, responseDeliver)
suite.Require().NoError(err)
rpcTx, err := suite.backend.GetTransactionByHash(common.HexToHash(tc.tx.Hash))
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(rpcTx, tc.expRPCTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTransactionsByHashPending() {
msgEthereumTx, bz := suite.buildEthereumTx()
rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID)
testCases := []struct {
name string
registerMock func()
tx *evmtypes.MsgEthereumTx
expRPCTx *rpctypes.RPCTransaction
expPass bool
}{
{
"fail - Pending transactions returns error",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterUnconfirmedTxsError(client, nil)
},
msgEthereumTx,
nil,
true,
},
{
"fail - Tx not found return nil",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterUnconfirmedTxs(client, nil, nil)
},
msgEthereumTx,
nil,
true,
},
{
"pass - Tx found and returned",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterUnconfirmedTxs(client, nil, types.Txs{bz})
},
msgEthereumTx,
rpcTransaction,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
rpcTx, err := suite.backend.getTransactionByHashPending(common.HexToHash(tc.tx.Hash))
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(rpcTx, tc.expRPCTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTxByEthHash() {
msgEthereumTx, bz := suite.buildEthereumTx()
rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID)
testCases := []struct {
name string
registerMock func()
tx *evmtypes.MsgEthereumTx
expRPCTx *rpctypes.RPCTransaction
expPass bool
}{
{
"fail - Indexer disabled can't find transaction",
func() {
suite.backend.indexer = nil
client := suite.backend.clientCtx.Client.(*mocks.Client)
query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, common.HexToHash(msgEthereumTx.Hash).Hex())
RegisterTxSearch(client, query, bz)
},
msgEthereumTx,
rpcTransaction,
false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
rpcTx, err := suite.backend.GetTxByEthHash(common.HexToHash(tc.tx.Hash))
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(rpcTx, tc.expRPCTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTransactionByBlockHashAndIndex() {
_, bz := suite.buildEthereumTx()
testCases := []struct {
name string
registerMock func()
blockHash common.Hash
expRPCTx *rpctypes.RPCTransaction
expPass bool
}{
{
"pass - block not found",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockByHashError(client, common.Hash{}, bz)
},
common.Hash{},
nil,
true,
},
{
"pass - Block results error",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockByHash(client, common.Hash{}, bz)
RegisterBlockResultsError(client, 1)
},
common.Hash{},
nil,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
rpcTx, err := suite.backend.GetTransactionByBlockHashAndIndex(tc.blockHash, 1)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(rpcTx, tc.expRPCTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTransactionByBlockAndIndex() {
msgEthTx, bz := suite.buildEthereumTx()
defaultBlock := types.MakeBlock(1, []types.Tx{bz}, nil, nil)
defaultResponseDeliverTx := []*abci.ResponseDeliverTx{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(common.HexToHash(msgEthTx.Hash).Hex())},
{Key: []byte("txIndex"), Value: []byte("0")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("")},
}},
},
},
}
txFromMsg, _ := rpctypes.NewTransactionFromMsg(
msgEthTx,
common.BytesToHash(defaultBlock.Hash().Bytes()),
1,
0,
big.NewInt(1),
suite.backend.chainID,
)
testCases := []struct {
name string
registerMock func()
block *tmrpctypes.ResultBlock
idx hexutil.Uint
expRPCTx *rpctypes.RPCTransaction
expPass bool
}{
{
"pass - block txs index out of bound ",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockResults(client, 1)
},
&tmrpctypes.ResultBlock{Block: types.MakeBlock(1, []types.Tx{bz}, nil, nil)},
1,
nil,
true,
},
{
"pass - Can't fetch base fee",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockResults(client, 1)
RegisterBaseFeeError(queryClient)
},
&tmrpctypes.ResultBlock{Block: defaultBlock},
0,
txFromMsg,
true,
},
{
"pass - Gets Tx by transaction index",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
db := dbm.NewMemDB()
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
txBz := suite.signAndEncodeEthTx(msgEthTx)
block := &types.Block{Header: types.Header{Height: 1, ChainID: "test"}, Data: types.Data{Txs: []types.Tx{txBz}}}
err := suite.backend.indexer.IndexBlock(block, defaultResponseDeliverTx)
suite.Require().NoError(err)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
&tmrpctypes.ResultBlock{Block: defaultBlock},
0,
txFromMsg,
true,
},
{
"pass - returns the Ethereum format transaction by the Ethereum hash",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
&tmrpctypes.ResultBlock{Block: defaultBlock},
0,
txFromMsg,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
rpcTx, err := suite.backend.GetTransactionByBlockAndIndex(tc.block, tc.idx)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(rpcTx, tc.expRPCTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTransactionByBlockNumberAndIndex() {
msgEthTx, bz := suite.buildEthereumTx()
defaultBlock := types.MakeBlock(1, []types.Tx{bz}, nil, nil)
txFromMsg, _ := rpctypes.NewTransactionFromMsg(
msgEthTx,
common.BytesToHash(defaultBlock.Hash().Bytes()),
1,
0,
big.NewInt(1),
suite.backend.chainID,
)
testCases := []struct {
name string
registerMock func()
blockNum rpctypes.BlockNumber
idx hexutil.Uint
expRPCTx *rpctypes.RPCTransaction
expPass bool
}{
{
"fail - block not found return nil",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockError(client, 1)
},
0,
0,
nil,
true,
},
{
"pass - returns the transaction identified by block number and index",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, bz)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
0,
0,
txFromMsg,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
rpcTx, err := suite.backend.GetTransactionByBlockNumberAndIndex(tc.blockNum, tc.idx)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(rpcTx, tc.expRPCTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTransactionByTxIndex() {
_, bz := suite.buildEthereumTx()
testCases := []struct {
name string
registerMock func()
height int64
index uint
expTxResult *ethermint.TxResult
expPass bool
}{
{
"fail - Ethereum tx with query not found",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
suite.backend.indexer = nil
RegisterTxSearch(client, "tx.height=0 AND ethereum_tx.txIndex=0", bz)
},
0,
0,
&ethermint.TxResult{},
false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
txResults, err := suite.backend.GetTxByTxIndex(tc.height, tc.index)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(txResults, tc.expTxResult)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestQueryTendermintTxIndexer() {
testCases := []struct {
name string
registerMock func()
txGetter func(*rpctypes.ParsedTxs) *rpctypes.ParsedTx
query string
expTxResult *ethermint.TxResult
expPass bool
}{
{
"fail - Ethereum tx with query not found",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterTxSearchEmpty(client, "")
},
func(txs *rpctypes.ParsedTxs) *rpctypes.ParsedTx {
return &rpctypes.ParsedTx{}
},
"",
&ethermint.TxResult{},
false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
txResults, err := suite.backend.queryTendermintTxIndexer(tc.query, tc.txGetter)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(txResults, tc.expTxResult)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTransactionReceipt() {
msgEthereumTx, _ := suite.buildEthereumTx()
txHash := msgEthereumTx.AsTransaction().Hash()
txBz := suite.signAndEncodeEthTx(msgEthereumTx)
testCases := []struct {
name string
registerMock func()
tx *evmtypes.MsgEthereumTx
block *types.Block
blockResult []*abci.ResponseDeliverTx
expTxReceipt map[string]interface{}
expPass bool
}{
{
"fail - Receipts do not match ",
func() {
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterParams(queryClient, &header, 1)
RegisterParamsWithoutHeader(queryClient, 1)
RegisterBlock(client, 1, txBz)
RegisterBlockResults(client, 1)
},
msgEthereumTx,
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
[]*abci.ResponseDeliverTx{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
{Key: []byte("txIndex"), Value: []byte("0")},
{Key: []byte("amount"), Value: []byte("1000")},
{Key: []byte("txGasUsed"), Value: []byte("21000")},
{Key: []byte("txHash"), Value: []byte("")},
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
}},
},
},
},
map[string]interface{}(nil),
false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.registerMock()
db := dbm.NewMemDB()
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
err := suite.backend.indexer.IndexBlock(tc.block, tc.blockResult)
suite.Require().NoError(err)
txReceipt, err := suite.backend.GetTransactionReceipt(common.HexToHash(tc.tx.Hash))
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(txReceipt, tc.expTxReceipt)
} else {
suite.Require().NotEqual(txReceipt, tc.expTxReceipt)
}
})
}
}

View File

@ -10,6 +10,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@ -21,6 +23,7 @@ import (
"github.com/evmos/ethermint/rpc/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/tendermint/tendermint/proto/tendermint/crypto"
)
type txGasAndReward struct {
@ -45,8 +48,15 @@ func (s sortGasAndReward) Less(i, j int) bool {
// Todo: include the ability to specify a blockNumber
func (b *Backend) getAccountNonce(accAddr common.Address, pending bool, height int64, logger log.Logger) (uint64, error) {
queryClient := authtypes.NewQueryClient(b.clientCtx)
res, err := queryClient.Account(types.ContextWithHeight(height), &authtypes.QueryAccountRequest{Address: sdk.AccAddress(accAddr.Bytes()).String()})
adr := sdk.AccAddress(accAddr.Bytes()).String()
ctx := types.ContextWithHeight(height)
res, err := queryClient.Account(ctx, &authtypes.QueryAccountRequest{Address: adr})
if err != nil {
st, ok := status.FromError(err)
// treat as account doesn't exist yet
if ok && st.Code() == codes.NotFound {
return 0, nil
}
return 0, err
}
var acc authtypes.AccountI
@ -260,6 +270,22 @@ func GetLogsFromBlockResults(blockRes *tmrpctypes.ResultBlockResults) ([][]*etht
blockLogs = append(blockLogs, logs...)
}
return blockLogs, nil
}
// GetHexProofs returns list of hex data of proof op
func GetHexProofs(proof *crypto.ProofOps) []string {
if proof == nil {
return []string{""}
}
proofs := []string{}
// check for proof
for _, p := range proof.Ops {
proof := ""
if len(p.Data) > 0 {
proof = hexutil.Encode(p.Data)
}
proofs = append(proofs, proof)
}
return proofs
}

52
rpc/backend/utils_test.go Normal file
View File

@ -0,0 +1,52 @@
package backend
import (
"fmt"
"github.com/tendermint/tendermint/proto/tendermint/crypto"
)
func mookProofs(num int, withData bool) *crypto.ProofOps {
var proofOps *crypto.ProofOps
if num > 0 {
proofOps = new(crypto.ProofOps)
for i := 0; i < num; i++ {
proof := crypto.ProofOp{}
if withData {
proof.Data = []byte("\n\031\n\003KEY\022\005VALUE\032\013\010\001\030\001 \001*\003\000\002\002")
}
proofOps.Ops = append(proofOps.Ops, proof)
}
}
return proofOps
}
func (suite *BackendTestSuite) TestGetHexProofs() {
defaultRes := []string{""}
testCases := []struct {
name string
proof *crypto.ProofOps
exp []string
}{
{
"no proof provided",
mookProofs(0, false),
defaultRes,
},
{
"no proof data provided",
mookProofs(1, false),
defaultRes,
},
{
"valid proof provided",
mookProofs(1, true),
[]string{"0x0a190a034b4559120556414c55451a0b0801180120012a03000202"},
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.Require().Equal(tc.exp, GetHexProofs(tc.proof))
})
}
}

View File

@ -499,6 +499,7 @@ func (e *PublicAPI) GetPendingTransactions() ([]*rpctypes.RPCTransaction, error)
uint64(0),
uint64(0),
nil,
e.backend.ChainConfig().ChainID,
)
if err != nil {
return nil, err

View File

@ -292,12 +292,9 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID {
continue
}
baseFee := types.BaseFeeFromEvents(data.ResultBeginBlock.Events)
header := types.EthHeaderFromTendermint(data.Header, ethtypes.Bloom{}, baseFee)
api.filtersMu.Lock()
if f, found := api.filters[headerSub.ID()]; found {
f.hashes = append(f.hashes, header.Hash())
f.hashes = append(f.hashes, common.BytesToHash(data.Header.Hash()))
}
api.filtersMu.Unlock()
case <-errCh:

View File

@ -33,6 +33,7 @@ const (
BlockParamEarliest = "earliest"
BlockParamLatest = "latest"
BlockParamFinalized = "finalized"
BlockParamSafe = "safe"
BlockParamPending = "pending"
)
@ -73,7 +74,7 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
case BlockParamEarliest:
*bn = EthEarliestBlockNumber
return nil
case BlockParamLatest, BlockParamFinalized:
case BlockParamLatest, BlockParamFinalized, BlockParamSafe:
*bn = EthLatestBlockNumber
return nil
case BlockParamPending:
@ -159,7 +160,7 @@ func (bnh *BlockNumberOrHash) decodeFromString(input string) error {
case BlockParamEarliest:
bn := EthEarliestBlockNumber
bnh.BlockNumber = &bn
case BlockParamLatest:
case BlockParamLatest, BlockParamFinalized:
bn := EthLatestBlockNumber
bnh.BlockNumber = &bn
case BlockParamPending:

View File

@ -88,7 +88,7 @@ func TestUnmarshalBlockNumberOrHash(t *testing.T) {
}
for _, tc := range testCases {
fmt.Sprintf("Case %s", tc.msg)
fmt.Printf("Case %s", tc.msg)
// reset input
bnh = new(BlockNumberOrHash)
err := bnh.UnmarshalJSON(tc.input)

View File

@ -10,8 +10,9 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
errorsmod "cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/client"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
evmtypes "github.com/evmos/ethermint/x/evm/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
@ -31,7 +32,7 @@ const ExceedBlockGasLimitError = "out of gas in location: block gas meter; gasWa
func RawTxToEthTx(clientCtx client.Context, txBz tmtypes.Tx) ([]*evmtypes.MsgEthereumTx, error) {
tx, err := clientCtx.TxConfig.TxDecoder()(txBz)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
return nil, errorsmod.Wrap(errortypes.ErrJSONUnmarshal, err.Error())
}
ethTxs := make([]*evmtypes.MsgEthereumTx, len(tx.GetMsgs()))
@ -144,15 +145,17 @@ func NewTransactionFromMsg(
blockHash common.Hash,
blockNumber, index uint64,
baseFee *big.Int,
chainID *big.Int,
) (*RPCTransaction, error) {
tx := msg.AsTransaction()
return NewRPCTransaction(tx, blockHash, blockNumber, index, baseFee)
return NewRPCTransaction(tx, blockHash, blockNumber, index, baseFee, chainID)
}
// NewTransactionFromData returns a transaction that will serialize to the RPC
// representation, with the given location metadata set (if available).
func NewRPCTransaction(
tx *ethtypes.Transaction, blockHash common.Hash, blockNumber, index uint64, baseFee *big.Int,
chainID *big.Int,
) (*RPCTransaction, error) {
// Determine the signer. For replay-protected transactions, use the most permissive
// signer, because we assume that signers are backwards-compatible with old
@ -179,6 +182,7 @@ func NewRPCTransaction(
V: (*hexutil.Big)(v),
R: (*hexutil.Big)(r),
S: (*hexutil.Big)(s),
ChainID: (*hexutil.Big)(chainID),
}
if blockHash != (common.Hash{}) {
result.BlockHash = &blockHash

View File

@ -65,12 +65,15 @@ fi
echo "compiling ethermint"
make build
# PID array declaration
arr=()
init_func() {
"$PWD"/build/ethermintd keys add $KEY"$i" --keyring-backend test --home "$DATA_DIR$i" --no-backup --algo "eth_secp256k1"
"$PWD"/build/ethermintd init $MONIKER --chain-id $CHAINID --home "$DATA_DIR$i"
# Set gas limit in genesis
cat $DATA_DIR$i/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="10000000"' > $DATA_DIR$i/config/tmp_genesis.json && mv $DATA_DIR$i/config/tmp_genesis.json $DATA_DIR$i/config/genesis.json
"$PWD"/build/ethermintd add-genesis-account \
"$("$PWD"/build/ethermintd keys show "$KEY$i" --keyring-backend test -a --home "$DATA_DIR$i")" 1000000000000000000aphoton,1000000000000000000stake \
--keyring-backend test --home "$DATA_DIR$i"
@ -141,17 +144,6 @@ echo "done sleeping"
set +e
if [[ -z $TEST || $TEST == "integration" ]] ; then
time_out=300s
for i in $(seq 1 "$TEST_QTD"); do
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
echo "going to test ethermint node $HOST_RPC ..."
MODE=$MODE HOST=$HOST_RPC go test ./tests/e2e/... -timeout=$time_out -v -short
TEST_FAIL=$?
done
fi
if [[ -z $TEST || $TEST == "rpc" || $TEST == "pending" ]]; then
time_out=300s
if [[ $TEST == "pending" ]]; then
@ -186,7 +178,7 @@ for i in "${arr[@]}"; do
stop_func "$i"
done
if [[ (-z $TEST || $TEST == "rpc" || $TEST == "integration" ) && $TEST_FAIL -ne 0 ]]; then
if [[ (-z $TEST || $TEST == "rpc") && $TEST_FAIL -ne 0 ]]; then
exit $TEST_FAIL
else
exit 0

Some files were not shown because too many files have changed in this diff Show More