From a924b20091caddb1ea68582669156e5b52f17254 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Thu, 24 Sep 2020 19:50:47 +0200 Subject: [PATCH] update chain-id format (#542) * chain_id.go * rpc changes * update scripts * additional test * changelog * fix tests * update script * rpc updates * validate testnet command chain-id * validate rest server chain-id * fix lint * rpc updates * changelog * comment simulations --- .github/workflows/sims.yml | 211 +++++++++++++++---------------- CHANGELOG.md | 5 + app/ante/ante_test.go | 4 +- app/ante/eth.go | 10 +- app/ante/utils_test.go | 12 +- client/config.go | 14 +- client/testnet.go | 14 +- cmd/ethermintcli/main.go | 4 +- docs/quickstart/testnet.md | 2 +- init.sh | 2 +- rpc/eth_api.go | 69 +++++----- rpc/net_api.go | 8 +- scripts/contract-test.sh | 2 +- scripts/integration-test-all.sh | 174 ++++++++++++------------- scripts/run-solidity-tests.sh | 24 ++-- scripts/start.sh | 2 +- tests-solidity/README.md | 4 +- tests-solidity/init-test-node.sh | 2 +- types/chain_id.go | 48 +++++++ types/chain_id_test.go | 75 +++++++++++ x/evm/handler.go | 22 ++-- x/evm/handler_test.go | 20 ++- 22 files changed, 427 insertions(+), 301 deletions(-) create mode 100644 types/chain_id.go create mode 100644 types/chain_id_test.go diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml index aaa475c5..a3899d3b 100644 --- a/.github/workflows/sims.yml +++ b/.github/workflows/sims.yml @@ -16,111 +16,106 @@ jobs: - uses: rokroskar/workflow-run-cleanup-action@master env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - install-runsim: - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, 'skip-sims')" - steps: - - uses: actions/setup-go@v2.1.2 - - name: install runsim - run: | - export GO111MODULE="on" && go get github.com/cosmos/tools/cmd/runsim@v1.0.0 - - uses: actions/cache@v2.1.1 - with: - path: ~/go/bin - key: ${{ runner.os }}-go-runsim-binary - - test-sim-nondeterminism: - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, 'skip-sims')" - needs: install-runsim - steps: - - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v3.2 - with: - SUFFIX_FILTER: | - .go - .mod - .sum - SET_ENV_NAME_INSERTIONS: 1 - SET_ENV_NAME_LINES: 1 - - uses: actions/cache@v2.1.1 - with: - path: ~/go/bin - key: ${{ runner.os }}-go-runsim-binary - if: "env.GIT_DIFF != ''" - - name: test-sim-nondeterminism - run: | - make test-sim-nondeterminism - if: "env.GIT_DIFF != ''" - - test-sim-import-export: - runs-on: ubuntu-latest - needs: install-runsim - steps: - - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v3.2 - with: - SUFFIX_FILTER: | - .go - .mod - .sum - SET_ENV_NAME_INSERTIONS: 1 - SET_ENV_NAME_LINES: 1 - - uses: actions/cache@v2.1.1 - with: - path: ~/go/bin - key: ${{ runner.os }}-go-runsim-binary - if: "env.GIT_DIFF != ''" - - name: test-sim-import-export - run: | - make test-sim-import-export - if: "env.GIT_DIFF != ''" - - test-sim-after-import: - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, 'skip-sims')" - needs: install-runsim - steps: - - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v3.2 - with: - SUFFIX_FILTER: | - .go - .mod - .sum - SET_ENV_NAME_INSERTIONS: 1 - SET_ENV_NAME_LINES: 1 - - uses: actions/cache@v2.1.1 - with: - path: ~/go/bin - key: ${{ runner.os }}-go-runsim-binary - if: "env.GIT_DIFF != ''" - - name: test-sim-after-import - run: | - make test-sim-after-import - if: "env.GIT_DIFF != ''" - - test-sim-multi-seed-short: - runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, 'skip-sims')" - needs: install-runsim - steps: - - uses: actions/checkout@v2 - - uses: technote-space/get-diff-action@v3.2 - with: - SUFFIX_FILTER: | - .go - .mod - .sum - SET_ENV_NAME_INSERTIONS: 1 - SET_ENV_NAME_LINES: 1 - - uses: actions/cache@v2.1.1 - with: - path: ~/go/bin - key: ${{ runner.os }}-go-runsim-binary - if: "env.GIT_DIFF != ''" - - name: test-sim-multi-seed-short - run: | - make test-sim-multi-seed-short - if: "env.GIT_DIFF != ''" + # install-runsim: + # runs-on: ubuntu-latest + # if: "!contains(github.event.head_commit.message, 'skip-sims')" + # steps: + # - uses: actions/setup-go@v2.1.2 + # - name: install runsim + # run: | + # export GO111MODULE="on" && go get github.com/cosmos/tools/cmd/runsim@v1.0.0 + # - uses: actions/cache@v2.1.1 + # with: + # path: ~/go/bin + # key: ${{ runner.os }}-go-runsim-binary + # test-sim-nondeterminism: + # runs-on: ubuntu-latest + # if: "!contains(github.event.head_commit.message, 'skip-sims')" + # needs: install-runsim + # steps: + # - uses: actions/checkout@v2 + # - uses: technote-space/get-diff-action@v3.2 + # with: + # SUFFIX_FILTER: | + # .go + # .mod + # .sum + # SET_ENV_NAME_INSERTIONS: 1 + # SET_ENV_NAME_LINES: 1 + # - uses: actions/cache@v2.1.1 + # with: + # path: ~/go/bin + # key: ${{ runner.os }}-go-runsim-binary + # if: "env.GIT_DIFF != ''" + # - name: test-sim-nondeterminism + # run: | + # make test-sim-nondeterminism + # if: "env.GIT_DIFF != ''" + # test-sim-import-export: + # runs-on: ubuntu-latest + # needs: install-runsim + # steps: + # - uses: actions/checkout@v2 + # - uses: technote-space/get-diff-action@v3.2 + # with: + # SUFFIX_FILTER: | + # .go + # .mod + # .sum + # SET_ENV_NAME_INSERTIONS: 1 + # SET_ENV_NAME_LINES: 1 + # - uses: actions/cache@v2.1.1 + # with: + # path: ~/go/bin + # key: ${{ runner.os }}-go-runsim-binary + # if: "env.GIT_DIFF != ''" + # - name: test-sim-import-export + # run: | + # make test-sim-import-export + # if: "env.GIT_DIFF != ''" + # test-sim-after-import: + # runs-on: ubuntu-latest + # if: "!contains(github.event.head_commit.message, 'skip-sims')" + # needs: install-runsim + # steps: + # - uses: actions/checkout@v2 + # - uses: technote-space/get-diff-action@v3.2 + # with: + # SUFFIX_FILTER: | + # .go + # .mod + # .sum + # SET_ENV_NAME_INSERTIONS: 1 + # SET_ENV_NAME_LINES: 1 + # - uses: actions/cache@v2.1.1 + # with: + # path: ~/go/bin + # key: ${{ runner.os }}-go-runsim-binary + # if: "env.GIT_DIFF != ''" + # - name: test-sim-after-import + # run: | + # make test-sim-after-import + # if: "env.GIT_DIFF != ''" + # test-sim-multi-seed-short: + # runs-on: ubuntu-latest + # if: "!contains(github.event.head_commit.message, 'skip-sims')" + # needs: install-runsim + # steps: + # - uses: actions/checkout@v2 + # - uses: technote-space/get-diff-action@v3.2 + # with: + # SUFFIX_FILTER: | + # .go + # .mod + # .sum + # SET_ENV_NAME_INSERTIONS: 1 + # SET_ENV_NAME_LINES: 1 + # - uses: actions/cache@v2.1.1 + # with: + # path: ~/go/bin + # key: ${{ runner.os }}-go-runsim-binary + # if: "env.GIT_DIFF != ''" + # - name: test-sim-multi-seed-short + # run: | + # make test-sim-multi-seed-short + # if: "env.GIT_DIFF != ''" diff --git a/CHANGELOG.md b/CHANGELOG.md index 6749cfde..c17b4ac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### State Machine Breaking + +* (app) [\#540](https://github.com/ChainSafe/ethermint/issues/540) Chain identifier's format has been changed to match the Cosmos `chainID` [standard](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-5.md), which is required for IBC. The epoch number of the ID is used as the EVM `chainID`. + ### API Breaking * (types) [\#503](https://github.com/ChainSafe/ethermint/pull/503) The `types.DenomDefault` constant for `"aphoton"` has been renamed to `types.AttoPhoton`. @@ -57,6 +61,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (ante) [\#525](https://github.com/ChainSafe/ethermint/pull/525) Add message validation decorator to `AnteHandler` for `MsgEthereumTx`. * (types) [\#507](https://github.com/ChainSafe/ethermint/pull/507) Fix hardcoded `aphoton` on `EthAccount` balance getter and setter. +* (types) [\#501](https://github.com/ChainSafe/ethermint/pull/501) Fix bech32 encoding error by using the compressed ethereum secp256k1 public key. * (`x/evm`) [\#496](https://github.com/ChainSafe/ethermint/pull/496) Fix bugs on `journal.revert` and `CommitStateDB.Copy`. * (types) [\#480](https://github.com/ChainSafe/ethermint/pull/480) Update [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) coin type to `60` to satisfy [EIP84](https://github.com/ethereum/EIPs/issues/84). * (types) [\#513](https://github.com/ChainSafe/ethermint/pull/513) Fix simulated transaction bug that was causing a consensus error by unintentionally affecting the state. diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 0bb85d05..44d74d68 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -180,7 +180,7 @@ func (suite *AnteTestSuite) TestEthInvalidSig() { tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) suite.Require().NoError(err) - ctx := suite.ctx.WithChainID("4") + ctx := suite.ctx.WithChainID("ethermint-4") requireInvalidTx(suite.T(), suite.anteHandler, ctx, tx, false) } @@ -253,7 +253,7 @@ func (suite *AnteTestSuite) TestEthInvalidIntrinsicGas() { func (suite *AnteTestSuite) TestEthInvalidMempoolFees() { // setup app with checkTx = true suite.app = app.Setup(true) - suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) + suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()}) suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams()) suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) diff --git a/app/ante/eth.go b/app/ante/eth.go index bb16afbc..38ad814c 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -10,7 +10,7 @@ import ( authante "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/types" - emint "github.com/cosmos/ethermint/types" + ethermint "github.com/cosmos/ethermint/types" evmtypes "github.com/cosmos/ethermint/x/evm/types" "github.com/ethereum/go-ethereum/common" @@ -141,13 +141,13 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s } // parse the chainID from a string to a base-10 integer - chainID, ok := new(big.Int).SetString(ctx.ChainID(), 10) - if !ok { - return ctx, sdkerrors.Wrap(emint.ErrInvalidChainID, ctx.ChainID()) + chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID()) + if err != nil { + return ctx, err } // validate sender/signature and cache the address - _, err = msgEthTx.VerifySig(chainID) + _, err = msgEthTx.VerifySig(chainIDEpoch) if err != nil { return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "signature verification failed: %s", err.Error()) } diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index d81c55e9..87043750 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -2,7 +2,6 @@ package ante_test import ( "fmt" - "math/big" "testing" "time" @@ -37,7 +36,7 @@ func (suite *AnteTestSuite) SetupTest() { suite.app = app.Setup(checkTx) suite.app.Codec().RegisterConcrete(&sdk.TestMsg{}, "test/TestMsg", nil) - suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) + suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()}) suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams()) suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper) @@ -91,9 +90,9 @@ func newTestSDKTx( } func newTestEthTx(ctx sdk.Context, msg evmtypes.MsgEthereumTx, priv tmcrypto.PrivKey) (sdk.Tx, error) { - chainID, ok := new(big.Int).SetString(ctx.ChainID(), 10) - if !ok { - return nil, fmt.Errorf("invalid chainID: %s", ctx.ChainID()) + chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID()) + if err != nil { + return nil, err } privkey, ok := priv.(crypto.PrivKeySecp256k1) @@ -101,8 +100,7 @@ func newTestEthTx(ctx sdk.Context, msg evmtypes.MsgEthereumTx, priv tmcrypto.Pri return nil, fmt.Errorf("invalid private key type: %T", priv) } - err := msg.Sign(chainID, privkey.ToECDSA()) - if err != nil { + if err := msg.Sign(chainIDEpoch, privkey.ToECDSA()); err != nil { return nil, err } diff --git a/client/config.go b/client/config.go index 05914624..1069e5c0 100644 --- a/client/config.go +++ b/client/config.go @@ -2,15 +2,17 @@ package client import ( "fmt" - "math/big" "os" "path" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client/flags" "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/client/flags" + + ethermint "github.com/cosmos/ethermint/types" ) // InitConfig adds the chain-id, encoding and output flags to the persistent flag set. @@ -47,12 +49,10 @@ func ValidateChainID(baseCmd *cobra.Command) *cobra.Command { // Function to replace command's RunE function validateFn := func(cmd *cobra.Command, args []string) error { - chainIDFlag := viper.GetString(flags.FlagChainID) + chainID := viper.GetString(flags.FlagChainID) - // Verify that the chain-id entered is a base 10 integer - _, ok := new(big.Int).SetString(chainIDFlag, 10) - if !ok { - return fmt.Errorf("invalid chainID: %s, must be base-10 integer format", chainIDFlag) + if !ethermint.IsValidChainID(chainID) { + return fmt.Errorf("invalid chain-id format: %s", chainID) } return baseRunE(cmd, args) diff --git a/client/testnet.go b/client/testnet.go index 9202772b..11b8af51 100644 --- a/client/testnet.go +++ b/client/testnet.go @@ -37,7 +37,7 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/ethermint/crypto" - "github.com/cosmos/ethermint/types" + ethermint "github.com/cosmos/ethermint/types" evmtypes "github.com/cosmos/ethermint/x/evm/types" ) @@ -96,8 +96,8 @@ Note, strict routability for addresses is turned off in the config file.`, cmd.Flags().String(flagNodeCLIHome, "ethermintcli", "Home directory of the node's cli configuration") cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)") cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") - cmd.Flags().String(flagCoinDenom, types.AttoPhoton, "Coin denomination used for staking, governance, mint, crisis and evm parameters") - cmd.Flags().String(server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", types.AttoPhoton), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01aphoton,0.001stake)") + cmd.Flags().String(flagCoinDenom, ethermint.AttoPhoton, "Coin denomination used for staking, governance, mint, crisis and evm parameters") + cmd.Flags().String(server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", ethermint.AttoPhoton), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01aphoton,0.001stake)") cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") cmd.Flags().String(flagKeyAlgo, string(crypto.EthSecp256k1), "Key signing algorithm to generate keys for") return cmd @@ -124,7 +124,11 @@ func InitTestnet( ) error { if chainID == "" { - chainID = fmt.Sprintf("%d", tmrand.Int63()) + chainID = fmt.Sprintf("ethermint-%d", tmrand.Int63n(9999999999999)+1) + } + + if !ethermint.IsValidChainID(chainID) { + return fmt.Errorf("invalid chain-id: %s", chainID) } if err := sdk.ValidateDenom(coinDenom); err != nil { @@ -219,7 +223,7 @@ func InitTestnet( sdk.NewCoin(coinDenom, accStakingTokens), ) - genAccounts = append(genAccounts, types.EthAccount{ + genAccounts = append(genAccounts, ethermint.EthAccount{ BaseAccount: authtypes.NewBaseAccount(addr, coins, nil, 0, 0), CodeHash: ethcrypto.Keccak256(nil), }) diff --git a/cmd/ethermintcli/main.go b/cmd/ethermintcli/main.go index aa1b60b9..6fe3505b 100644 --- a/cmd/ethermintcli/main.go +++ b/cmd/ethermintcli/main.go @@ -66,7 +66,9 @@ func main() { sdkclient.ConfigCmd(app.DefaultCLIHome), queryCmd(cdc), txCmd(cdc), - rpc.EmintServeCmd(cdc), + client.ValidateChainID( + rpc.EmintServeCmd(cdc), + ), flags.LineBreak, client.KeyCommands(), flags.LineBreak, diff --git a/docs/quickstart/testnet.md b/docs/quickstart/testnet.md index b47d225d..6303c05c 100644 --- a/docs/quickstart/testnet.md +++ b/docs/quickstart/testnet.md @@ -22,7 +22,7 @@ This guide helps you create a single validator node that runs a network locally ```bash $MONIKER=testing $KEY=mykey -$CHAINID=8 +$CHAINID="ethermint-1" ethermintd init $MONIKER --chain-id=$CHAINID ``` diff --git a/init.sh b/init.sh index bbb82325..17223d4f 100755 --- a/init.sh +++ b/init.sh @@ -1,7 +1,7 @@ #!/bin/bash KEY="mykey" -CHAINID=8 +CHAINID="ethermint-1" MONIKER="localtestnet" # remove existing daemon and client diff --git a/rpc/eth_api.go b/rpc/eth_api.go index 8e0d918d..a360fcfb 100644 --- a/rpc/eth_api.go +++ b/rpc/eth_api.go @@ -6,14 +6,13 @@ import ( "fmt" "math/big" "os" - "strconv" "sync" "github.com/spf13/viper" "github.com/cosmos/ethermint/crypto" params "github.com/cosmos/ethermint/rpc/args" - emint "github.com/cosmos/ethermint/types" + ethermint "github.com/cosmos/ethermint/types" "github.com/cosmos/ethermint/utils" "github.com/cosmos/ethermint/version" evmtypes "github.com/cosmos/ethermint/x/evm/types" @@ -43,27 +42,34 @@ import ( // PublicEthAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec. type PublicEthAPI struct { - cliCtx context.CLIContext - logger log.Logger - backend Backend - keys []crypto.PrivKeySecp256k1 - nonceLock *AddrLocker - keybaseLock sync.Mutex + cliCtx context.CLIContext + chainIDEpoch *big.Int + logger log.Logger + backend Backend + keys []crypto.PrivKeySecp256k1 + nonceLock *AddrLocker + keybaseLock sync.Mutex } // NewPublicEthAPI creates an instance of the public ETH Web3 API. func NewPublicEthAPI(cliCtx context.CLIContext, backend Backend, nonceLock *AddrLocker, key []crypto.PrivKeySecp256k1) *PublicEthAPI { - api := &PublicEthAPI{ - cliCtx: cliCtx, - logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "json-rpc"), - backend: backend, - keys: key, - nonceLock: nonceLock, - } - err := api.getKeybaseInfo() + epoch, err := ethermint.ParseChainID(cliCtx.ChainID) if err != nil { + panic(err) + } + + api := &PublicEthAPI{ + cliCtx: cliCtx, + chainIDEpoch: epoch, + logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "json-rpc"), + backend: backend, + keys: key, + nonceLock: nonceLock, + } + + if err := api.getKeybaseInfo(); err != nil { api.logger.Error("failed to get keybase info", "error", err) } @@ -101,14 +107,7 @@ func (e *PublicEthAPI) ProtocolVersion() hexutil.Uint { // ChainId returns the chain's identifier in hex format func (e *PublicEthAPI) ChainId() (hexutil.Uint, error) { // nolint e.logger.Debug("eth_chainId") - - // parse the chainID from a integer string - intChainID, err := strconv.ParseUint(e.cliCtx.ChainID, 0, 64) - if err != nil { - return 0, fmt.Errorf("invalid chainID: %s, must be integer format", e.cliCtx.ChainID) - } - - return hexutil.Uint(intChainID), nil + return hexutil.Uint(uint(e.chainIDEpoch.Uint64())), nil } // Syncing returns whether or not the current node is syncing with other peers. Returns false if not, or a struct @@ -404,13 +403,13 @@ func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, err // ChainID must be set as flag to send transaction chainID := viper.GetString(flags.FlagChainID) // parse the chainID from a string to a base-10 integer - intChainID, ok := new(big.Int).SetString(chainID, 10) - if !ok { - return common.Hash{}, fmt.Errorf("invalid chainID: %s, must be integer format", chainID) + chainIDEpoch, err := ethermint.ParseChainID(chainID) + if err != nil { + return common.Hash{}, err } // Sign transaction - if err := tx.Sign(intChainID, key.ToECDSA()); err != nil { + if err := tx.Sign(chainIDEpoch, key.ToECDSA()); err != nil { e.logger.Debug("failed to sign tx", "error", err) return common.Hash{}, err } @@ -475,7 +474,7 @@ type CallArgs struct { // Call performs a raw contract call. func (e *PublicEthAPI) Call(args CallArgs, blockNr BlockNumber, _ *map[common.Address]account) (hexutil.Bytes, error) { e.logger.Debug("eth_call", "args", args, "block number", blockNr) - simRes, err := e.doCall(args, blockNr, big.NewInt(emint.DefaultRPCGasLimit)) + simRes, err := e.doCall(args, blockNr, big.NewInt(ethermint.DefaultRPCGasLimit)) if err != nil { return []byte{}, err } @@ -528,7 +527,7 @@ func (e *PublicEthAPI) doCall( // Set default gas & gas price if none were set // Change this to uint64(math.MaxUint64 / 2) if gas cap can be configured - gas := uint64(emint.DefaultRPCGasLimit) + gas := uint64(ethermint.DefaultRPCGasLimit) if args.Gas != nil { gas = uint64(*args.Gas) } @@ -538,7 +537,7 @@ func (e *PublicEthAPI) doCall( } // Set gas price using default or parameter if passed in - gasPrice := new(big.Int).SetUint64(emint.DefaultGasPrice) + gasPrice := new(big.Int).SetUint64(ethermint.DefaultGasPrice) if args.GasPrice != nil { gasPrice = args.GasPrice.ToInt() } @@ -565,6 +564,10 @@ func (e *PublicEthAPI) doCall( msg := evmtypes.NewMsgEthermint(0, &toAddr, sdk.NewIntFromBigInt(value), gas, sdk.NewIntFromBigInt(gasPrice), data, sdk.AccAddress(addr.Bytes())) + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + // Generate tx to be used to simulate (signature isn't needed) var stdSig authtypes.StdSignature tx := authtypes.NewStdTx([]sdk.Msg{msg}, authtypes.StdFee{}, []authtypes.StdSignature{stdSig}, "") @@ -594,7 +597,7 @@ func (e *PublicEthAPI) doCall( // param from the SDK. func (e *PublicEthAPI) EstimateGas(args CallArgs) (hexutil.Uint64, error) { e.logger.Debug("eth_estimateGas", "args", args) - simResponse, err := e.doCall(args, 0, big.NewInt(emint.DefaultRPCGasLimit)) + simResponse, err := e.doCall(args, 0, big.NewInt(ethermint.DefaultRPCGasLimit)) if err != nil { return 0, err } @@ -1000,7 +1003,7 @@ func (e *PublicEthAPI) generateFromArgs(args params.SendTxArgs) (*evmtypes.MsgEt // Set default gas price // TODO: Change to min gas price from context once available through server/daemon - gasPrice = big.NewInt(emint.DefaultGasPrice) + gasPrice = big.NewInt(ethermint.DefaultGasPrice) } if args.Nonce == nil { diff --git a/rpc/net_api.go b/rpc/net_api.go index 013117be..2d065930 100644 --- a/rpc/net_api.go +++ b/rpc/net_api.go @@ -2,12 +2,12 @@ package rpc import ( "fmt" - "strconv" "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/flags" + ethermint "github.com/cosmos/ethermint/types" ) // PublicNetAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec. @@ -19,13 +19,13 @@ type PublicNetAPI struct { func NewPublicNetAPI(_ context.CLIContext) *PublicNetAPI { chainID := viper.GetString(flags.FlagChainID) // parse the chainID from a integer string - intChainID, err := strconv.ParseUint(chainID, 0, 64) + chainIDEpoch, err := ethermint.ParseChainID(chainID) if err != nil { - panic(fmt.Sprintf("invalid chainID: %s, must be integer format", chainID)) + panic(err) } return &PublicNetAPI{ - networkVersion: intChainID, + networkVersion: chainIDEpoch.Uint64(), } } diff --git a/scripts/contract-test.sh b/scripts/contract-test.sh index 213bbd23..087676fa 100644 --- a/scripts/contract-test.sh +++ b/scripts/contract-test.sh @@ -2,7 +2,7 @@ KEY="mykey" TESTKEY="test" -CHAINID=123321 +CHAINID="ethermint-100" MONIKER="localtestnet" # stop and remove existing daemon and client data and process(es) diff --git a/scripts/integration-test-all.sh b/scripts/integration-test-all.sh index 1beb4536..0001f4aa 100755 --- a/scripts/integration-test-all.sh +++ b/scripts/integration-test-all.sh @@ -15,7 +15,7 @@ IP_ADDR="0.0.0.0" MODE="rpc" KEY="mykey" -CHAINID=8 +CHAINID="ethermint-2" MONIKER="mymoniker" ## default port prefixes for ethermintd @@ -24,25 +24,25 @@ NODE_PORT="2663" NODE_RPC_PORT="2666" usage() { - echo "Usage: $SCRIPT" - echo "Optional command line arguments" - echo "-t -- Test to run. eg: rpc" - echo "-q -- Quantity of nodes to run. eg: 3" - echo "-z -- Quantity of nodes to run tests against eg: 3" - echo "-s -- Sleep between operations in secs. eg: 5" - exit 1 + echo "Usage: $SCRIPT" + echo "Optional command line arguments" + echo "-t -- Test to run. eg: rpc" + echo "-q -- Quantity of nodes to run. eg: 3" + echo "-z -- Quantity of nodes to run tests against eg: 3" + echo "-s -- Sleep between operations in secs. eg: 5" + exit 1 } while getopts "h?t:q:z:s:" args; do -case $args in - h|\?) - usage; - exit;; - t ) TEST=${OPTARG};; - q ) QTD=${OPTARG};; - z ) TEST_QTD=${OPTARG};; - s ) SLEEP_TIMEOUT=${OPTARG};; - esac + case $args in + h|\?) + usage; + exit;; + t ) TEST=${OPTARG};; + q ) QTD=${OPTARG};; + z ) TEST_QTD=${OPTARG};; + s ) SLEEP_TIMEOUT=${OPTARG};; + esac done set -euxo pipefail @@ -50,15 +50,15 @@ set -euxo pipefail DATA_DIR=$(mktemp -d -t ethermint-datadir.XXXXX) if [[ ! "$DATA_DIR" ]]; then - echo "Could not create $DATA_DIR" - exit 1 + echo "Could not create $DATA_DIR" + exit 1 fi DATA_CLI_DIR=$(mktemp -d -t ethermint-cli-datadir.XXXXX) if [[ ! "$DATA_CLI_DIR" ]]; then - echo "Could not create $DATA_CLI_DIR" - exit 1 + echo "Could not create $DATA_CLI_DIR" + exit 1 fi # Compile ethermint @@ -72,64 +72,64 @@ arr=() arrcli=() init_func() { - echo "create and add new keys" - "$PWD"/build/ethermintcli config keyring-backend test --home "$DATA_CLI_DIR$i" - "$PWD"/build/ethermintcli keys add $KEY"$i" --home "$DATA_CLI_DIR$i" --no-backup --chain-id $CHAINID - echo "init Ethermint with moniker=$MONIKER and chain-id=$CHAINID" - "$PWD"/build/ethermintd init $MONIKER --chain-id $CHAINID --home "$DATA_DIR$i" - echo "init ethermintcli with chain-id=$CHAINID and config it trust-node true" - "$PWD"/build/ethermintcli config chain-id $CHAINID --home "$DATA_CLI_DIR$i" - "$PWD"/build/ethermintcli config output json --home "$DATA_CLI_DIR$i" - "$PWD"/build/ethermintcli config indent true --home "$DATA_CLI_DIR$i" - "$PWD"/build/ethermintcli config trust-node true --home "$DATA_CLI_DIR$i" - echo "prepare genesis: Allocate genesis accounts" - "$PWD"/build/ethermintd add-genesis-account \ - "$("$PWD"/build/ethermintcli keys show "$KEY$i" -a --home "$DATA_CLI_DIR$i" )" 1000000000000000000aphoton,1000000000000000000stake \ - --home "$DATA_DIR$i" --home-client "$DATA_CLI_DIR$i" - echo "prepare genesis: Sign genesis transaction" - "$PWD"/build/ethermintd gentx --name $KEY"$i" --keyring-backend test --home "$DATA_DIR$i" --home-client "$DATA_CLI_DIR$i" - echo "prepare genesis: Collect genesis tx" - "$PWD"/build/ethermintd collect-gentxs --home "$DATA_DIR$i" - echo "prepare genesis: Run validate-genesis to ensure everything worked and that the genesis file is setup correctly" - "$PWD"/build/ethermintd validate-genesis --home "$DATA_DIR$i" + echo "create and add new keys" + "$PWD"/build/ethermintcli config keyring-backend test --home "$DATA_CLI_DIR$i" + "$PWD"/build/ethermintcli keys add $KEY"$i" --home "$DATA_CLI_DIR$i" --no-backup --chain-id $CHAINID + echo "init Ethermint with moniker=$MONIKER and chain-id=$CHAINID" + "$PWD"/build/ethermintd init $MONIKER --chain-id $CHAINID --home "$DATA_DIR$i" + echo "init ethermintcli with chain-id=$CHAINID and config it trust-node true" + "$PWD"/build/ethermintcli config chain-id $CHAINID --home "$DATA_CLI_DIR$i" + "$PWD"/build/ethermintcli config output json --home "$DATA_CLI_DIR$i" + "$PWD"/build/ethermintcli config indent true --home "$DATA_CLI_DIR$i" + "$PWD"/build/ethermintcli config trust-node true --home "$DATA_CLI_DIR$i" + echo "prepare genesis: Allocate genesis accounts" + "$PWD"/build/ethermintd add-genesis-account \ + "$("$PWD"/build/ethermintcli keys show "$KEY$i" -a --home "$DATA_CLI_DIR$i" )" 1000000000000000000aphoton,1000000000000000000stake \ + --home "$DATA_DIR$i" --home-client "$DATA_CLI_DIR$i" + echo "prepare genesis: Sign genesis transaction" + "$PWD"/build/ethermintd gentx --name $KEY"$i" --keyring-backend test --home "$DATA_DIR$i" --home-client "$DATA_CLI_DIR$i" + echo "prepare genesis: Collect genesis tx" + "$PWD"/build/ethermintd collect-gentxs --home "$DATA_DIR$i" + echo "prepare genesis: Run validate-genesis to ensure everything worked and that the genesis file is setup correctly" + "$PWD"/build/ethermintd validate-genesis --home "$DATA_DIR$i" } start_func() { - echo "starting ethermint node $i in background ..." - "$PWD"/build/ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" \ - --p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" --address tcp://$IP_ADDR:$NODE_PORT"$i" --rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ - --home "$DATA_DIR$i" \ - >"$DATA_DIR"/node"$i".log 2>&1 & disown - - ETHERMINT_PID=$! - echo "started ethermint node, pid=$ETHERMINT_PID" - # add PID to array - arr+=("$ETHERMINT_PID") + echo "starting ethermint node $i in background ..." + "$PWD"/build/ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" \ + --p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" --address tcp://$IP_ADDR:$NODE_PORT"$i" --rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ + --home "$DATA_DIR$i" \ + >"$DATA_DIR"/node"$i".log 2>&1 & disown + + ETHERMINT_PID=$! + echo "started ethermint node, pid=$ETHERMINT_PID" + # add PID to array + arr+=("$ETHERMINT_PID") } start_cli_func() { - echo "starting ethermint node $i in background ..." - "$PWD"/build/ethermintcli rest-server --unlock-key $KEY"$i" --chain-id $CHAINID --trace \ - --laddr "tcp://localhost:$RPC_PORT$i" --node tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ - --home "$DATA_CLI_DIR$i" --read-timeout 30 --write-timeout 30 \ - >"$DATA_CLI_DIR"/cli"$i".log 2>&1 & disown - - ETHERMINT_CLI_PID=$! - echo "started ethermintcli node, pid=$ETHERMINT_CLI_PID" - # add PID to array - arrcli+=("$ETHERMINT_CLI_PID") + echo "starting ethermint node $i in background ..." + "$PWD"/build/ethermintcli rest-server --unlock-key $KEY"$i" --chain-id $CHAINID --trace \ + --laddr "tcp://localhost:$RPC_PORT$i" --node tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ + --home "$DATA_CLI_DIR$i" --read-timeout 30 --write-timeout 30 \ + >"$DATA_CLI_DIR"/cli"$i".log 2>&1 & disown + + ETHERMINT_CLI_PID=$! + echo "started ethermintcli node, pid=$ETHERMINT_CLI_PID" + # add PID to array + arrcli+=("$ETHERMINT_CLI_PID") } # Run node with static blockchain database # For loop N times for i in $(seq 1 "$QTD"); do - init_func "$i" - start_func "$i" - sleep 1 - start_cli_func "$i" - echo "sleeping $SLEEP_TIMEOUT seconds for startup" - sleep "$SLEEP_TIMEOUT" - echo "done sleeping" + init_func "$i" + start_func "$i" + sleep 1 + start_cli_func "$i" + echo "sleeping $SLEEP_TIMEOUT seconds for startup" + sleep "$SLEEP_TIMEOUT" + echo "done sleeping" done echo "sleeping $SLEEP_TIMEOUT seconds before running tests ... " @@ -139,37 +139,37 @@ echo "done sleeping" set +e if [[ -z $TEST || $TEST == "rpc" ]]; then - - 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/... -timeout=300s -v -short - - RPC_FAIL=$? - done - + + 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/... -timeout=300s -v -short + + RPC_FAIL=$? + done + fi stop_func() { - ETHERMINT_PID=$i - echo "shutting down node, pid=$ETHERMINT_PID ..." - - # Shutdown ethermint node - kill -9 "$ETHERMINT_PID" - wait "$ETHERMINT_PID" + ETHERMINT_PID=$i + echo "shutting down node, pid=$ETHERMINT_PID ..." + + # Shutdown ethermint node + kill -9 "$ETHERMINT_PID" + wait "$ETHERMINT_PID" } for i in "${arrcli[@]}"; do - stop_func "$i" + stop_func "$i" done for i in "${arr[@]}"; do - stop_func "$i" + stop_func "$i" done if [[ (-z $TEST || $TEST == "rpc") && $RPC_FAIL -ne 0 ]]; then - exit $RPC_FAIL + exit $RPC_FAIL else - exit 0 + exit 0 fi diff --git a/scripts/run-solidity-tests.sh b/scripts/run-solidity-tests.sh index 891e5ca5..c56afd1b 100755 --- a/scripts/run-solidity-tests.sh +++ b/scripts/run-solidity-tests.sh @@ -2,27 +2,29 @@ export GOPATH=~/go export PATH=$PATH:$GOPATH/bin -go build -o ./build/ethermintd ./cmd/ethermintd +go build -o ./build/ethermintd ./cmd/ethermintd go build -o ./build/ethermintcli ./cmd/ethermintcli mkdir $GOPATH/bin cp ./build/ethermintd $GOPATH/bin cp ./build/ethermintcli $GOPATH/bin +CHAINID="ethermint-1337" + cd tests-solidity if command -v yarn &> /dev/null; then - yarn install -else - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list - sudo apt update && sudo apt install yarn - yarn install + yarn install +else + curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - + echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list + sudo apt update && sudo apt install yarn + yarn install fi chmod +x ./init-test-node.sh ./init-test-node.sh > ethermintd.log & sleep 5 -ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key localkey,user1,user2 --chain-id 1337 --trace --wsport 8546 > ethermintcli.log & +ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key localkey,user1,user2 --chain-id $CHAINID --trace --wsport 8546 > ethermintcli.log & cd suites/initializable yarn test-ethermint @@ -30,7 +32,7 @@ yarn test-ethermint ok=$? if (( $? != 0 )); then - echo "initializable test failed: exit code $?" + echo "initializable test failed: exit code $?" fi killall ethermintcli @@ -43,7 +45,7 @@ exit $ok ./../../init-test-node.sh > ethermintd.log & sleep 5 -ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key localkey,user1,user2 --chain-id 1337 --trace --wsport 8546 > ethermintcli.log & +ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key localkey,user1,user2 --chain-id $CHAINID --trace --wsport 8546 > ethermintcli.log & cd ../initializable-buidler yarn test-ethermint @@ -51,7 +53,7 @@ yarn test-ethermint ok=$(($? + $ok)) if (( $? != 0 )); then - echo "initializable-buidler test failed: exit code $?" + echo "initializable-buidler test failed: exit code $?" fi killall ethermintcli diff --git a/scripts/start.sh b/scripts/start.sh index 2c5719eb..da1320ed 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -1,5 +1,5 @@ #!/bin/sh ethermintd --home /ethermint/node$ID/ethermintd/ start > ethermintd.log & sleep 5 -ethermintcli rest-server --laddr "tcp://localhost:8545" --chain-id 7305661614933169792 --trace > ethermintcli.log & +ethermintcli rest-server --laddr "tcp://localhost:8545" --chain-id "ethermint-7305661614933169792" --trace > ethermintcli.log & tail -f /dev/null \ No newline at end of file diff --git a/tests-solidity/README.md b/tests-solidity/README.md index 08c58766..e39ef4c6 100644 --- a/tests-solidity/README.md +++ b/tests-solidity/README.md @@ -25,7 +25,7 @@ In the first, run `ethermintd`: In the second, run `ethermintcli` as mentioned in the script's output: ```sh -ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key localkey,user1,user2 --chain-id 1337 --trace --wsport 8546 +ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key localkey,user1,user2 --chain-id "ethermint-1337" --trace --wsport 8546 ``` You will now have three ethereum accounts unlocked in the test node: @@ -83,7 +83,7 @@ Running `ethermintcli list keys` should output: And running: -``` +```sh curl localhost:8545 -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' ``` diff --git a/tests-solidity/init-test-node.sh b/tests-solidity/init-test-node.sh index 86735a00..867081ae 100755 --- a/tests-solidity/init-test-node.sh +++ b/tests-solidity/init-test-node.sh @@ -1,6 +1,6 @@ #!/bin/bash -CHAINID=1337 +CHAINID="ethermint-1337" MONIKER="localtestnet" VAL_KEY="localkey" diff --git a/types/chain_id.go b/types/chain_id.go new file mode 100644 index 00000000..7bc316b1 --- /dev/null +++ b/types/chain_id.go @@ -0,0 +1,48 @@ +package types + +import ( + "fmt" + "math/big" + "regexp" + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var ( + regexChainID = `[a-z]*` + regexSeparator = `-{1}` + regexEpoch = `[1-9][0-9]*` + ethermintChainID = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, regexChainID, regexSeparator, regexEpoch)) +) + +// IsValidChainID returns false if the given chain identifier is incorrectly formatted. +func IsValidChainID(chainID string) bool { + if len(chainID) > 48 { + return false + } + + return ethermintChainID.MatchString(chainID) +} + +// ParseChainID parses a string chain identifier's epoch to an Ethereum-compatible +// chain-id in *big.Int format. The function returns an error if the chain-id has an invalid format +func ParseChainID(chainID string) (*big.Int, error) { + chainID = strings.TrimSpace(chainID) + if len(chainID) > 48 { + return nil, sdkerrors.Wrapf(ErrInvalidChainID, "chain-id '%s' cannot exceed 48 chars", chainID) + } + + matches := ethermintChainID.FindStringSubmatch(chainID) + if matches == nil || len(matches) != 3 || matches[1] == "" { + return nil, sdkerrors.Wrap(ErrInvalidChainID, chainID) + } + + // verify that the chain-id entered is a base 10 integer + chainIDInt, ok := new(big.Int).SetString(matches[2], 10) + if !ok { + return nil, sdkerrors.Wrapf(ErrInvalidChainID, "epoch %s must be base-10 integer format", matches[2]) + } + + return chainIDInt, nil +} diff --git a/types/chain_id_test.go b/types/chain_id_test.go new file mode 100644 index 00000000..63a6b902 --- /dev/null +++ b/types/chain_id_test.go @@ -0,0 +1,75 @@ +package types + +import ( + "math/big" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseChainID(t *testing.T) { + testCases := []struct { + name string + chainID string + expError bool + expInt *big.Int + }{ + { + "valid chain-id, single digit", "ethermint-1", false, big.NewInt(1), + }, + { + "valid chain-id, multiple digits", "aragonchain-256", false, big.NewInt(256), + }, + { + "invalid chain-id, double dash", "aragon-chain-1", true, nil, + }, + { + "invalid chain-id, dash only", "-", true, nil, + }, + { + "invalid chain-id, undefined", "-1", true, nil, + }, + { + "invalid chain-id, uppercases", "ETHERMINT-1", true, nil, + }, + { + "invalid chain-id, mixed cases", "Ethermint-1", true, nil, + }, + { + "invalid chain-id, special chars", "$&*#!-1", true, nil, + }, + { + "invalid epoch, cannot start with 0", "ethermint-001", true, nil, + }, + { + "invalid epoch, cannot invalid base", "ethermint-0x212", true, nil, + }, + { + "invalid epoch, non-integer", "ethermint-ethermint", true, nil, + }, + { + "invalid epoch, undefined", "ethermint-", true, nil, + }, + { + "blank chain ID", " ", true, nil, + }, + { + "empty chain ID", "", true, nil, + }, + { + "long chain-id", "ethermint-" + strings.Repeat("1", 40), true, nil, + }, + } + + for _, tc := range testCases { + chainIDEpoch, err := ParseChainID(tc.chainID) + if tc.expError { + require.Error(t, err, tc.name) + require.Nil(t, chainIDEpoch) + } else { + require.NoError(t, err, tc.name) + require.Equal(t, tc.expInt, chainIDEpoch, tc.name) + } + } +} diff --git a/x/evm/handler.go b/x/evm/handler.go index b29b1d61..f1615f67 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -1,11 +1,9 @@ package evm import ( - "math/big" - "github.com/ethereum/go-ethereum/common" - emint "github.com/cosmos/ethermint/types" + ethermint "github.com/cosmos/ethermint/types" "github.com/cosmos/ethermint/x/evm/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -32,13 +30,13 @@ func NewHandler(k Keeper) sdk.Handler { // handleMsgEthereumTx handles an Ethereum specific tx func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) { // parse the chainID from a string to a base-10 integer - intChainID, ok := new(big.Int).SetString(ctx.ChainID(), 10) - if !ok { - return nil, sdkerrors.Wrap(emint.ErrInvalidChainID, ctx.ChainID()) + chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID()) + if err != nil { + return nil, err } // Verify signature and retrieve sender address - sender, err := msg.VerifySig(intChainID) + sender, err := msg.VerifySig(chainIDEpoch) if err != nil { return nil, err } @@ -54,7 +52,7 @@ func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s Amount: msg.Data.Amount, Payload: msg.Data.Payload, Csdb: k.CommitStateDB.WithContext(ctx), - ChainID: intChainID, + ChainID: chainIDEpoch, TxHash: ðHash, Sender: sender, Simulate: ctx.IsCheckTx(), @@ -123,9 +121,9 @@ func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s // handleMsgEthermint handles an sdk.StdTx for an Ethereum state transition func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk.Result, error) { // parse the chainID from a string to a base-10 integer - intChainID, ok := new(big.Int).SetString(ctx.ChainID(), 10) - if !ok { - return nil, sdkerrors.Wrap(emint.ErrInvalidChainID, ctx.ChainID()) + chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID()) + if err != nil { + return nil, err } txHash := tmtypes.Tx(ctx.TxBytes()).Hash() @@ -138,7 +136,7 @@ func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk Amount: msg.Amount.BigInt(), Payload: msg.Payload, Csdb: k.CommitStateDB.WithContext(ctx), - ChainID: intChainID, + ChainID: chainIDEpoch, TxHash: ðHash, Sender: common.BytesToAddress(msg.From.Bytes()), Simulate: ctx.IsCheckTx(), diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index 79e781ce..70244f25 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -21,6 +21,7 @@ import ( "github.com/cosmos/ethermint/app" "github.com/cosmos/ethermint/crypto" + ethermint "github.com/cosmos/ethermint/types" "github.com/cosmos/ethermint/x/evm" "github.com/cosmos/ethermint/x/evm/keeper" "github.com/cosmos/ethermint/x/evm/types" @@ -43,7 +44,7 @@ func (suite *EvmTestSuite) SetupTest() { checkTx := false suite.app = app.Setup(checkTx) - suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) + suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()}) suite.handler = evm.NewHandler(suite.app.EvmKeeper) suite.querier = keeper.NewQuerier(suite.app.EvmKeeper) suite.codec = codec.New() @@ -58,10 +59,7 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() { suite.Require().NoError(err) sender := ethcmn.HexToAddress(privkey.PubKey().Address().String()) - var ( - tx types.MsgEthereumTx - chainID *big.Int - ) + var tx types.MsgEthereumTx testCases := []struct { msg string @@ -75,9 +73,8 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() { tx = types.NewMsgEthereumTx(0, &sender, big.NewInt(100), 0, big.NewInt(10000), nil) // parse context chain ID to big.Int - var ok bool - chainID, ok = new(big.Int).SetString(suite.ctx.ChainID(), 10) - suite.Require().True(ok) + chainID, err := ethermint.ParseChainID(suite.ctx.ChainID()) + suite.Require().NoError(err) // sign transaction err = tx.Sign(chainID, privkey.ToECDSA()) @@ -91,9 +88,8 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() { tx = types.NewMsgEthereumTxContract(0, big.NewInt(100), 0, big.NewInt(10000), nil) // parse context chain ID to big.Int - var ok bool - chainID, ok = new(big.Int).SetString(suite.ctx.ChainID(), 10) - suite.Require().True(ok) + chainID, err := ethermint.ParseChainID(suite.ctx.ChainID()) + suite.Require().NoError(err) // sign transaction err = tx.Sign(chainID, privkey.ToECDSA()) @@ -125,7 +121,7 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() { } for _, tc := range testCases { - suite.Run("", func() { + suite.Run(tc.msg, func() { suite.SetupTest() // reset //nolint tc.malleate()