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
This commit is contained in:
Federico Kunze 2020-09-24 19:50:47 +02:00 committed by GitHub
parent b9a10b3f3e
commit a924b20091
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 427 additions and 301 deletions

View File

@ -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 != ''"

View File

@ -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.

View File

@ -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)

View File

@ -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())
}

View File

@ -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
}

View File

@ -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)

View File

@ -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),
})

View File

@ -66,7 +66,9 @@ func main() {
sdkclient.ConfigCmd(app.DefaultCLIHome),
queryCmd(cdc),
txCmd(cdc),
client.ValidateChainID(
rpc.EmintServeCmd(cdc),
),
flags.LineBreak,
client.KeyCommands(),
flags.LineBreak,

View File

@ -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
```

View File

@ -1,7 +1,7 @@
#!/bin/bash
KEY="mykey"
CHAINID=8
CHAINID="ethermint-1"
MONIKER="localtestnet"
# remove existing daemon and client

View File

@ -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"
@ -44,6 +43,7 @@ import (
// PublicEthAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PublicEthAPI struct {
cliCtx context.CLIContext
chainIDEpoch *big.Int
logger log.Logger
backend Backend
keys []crypto.PrivKeySecp256k1
@ -55,15 +55,21 @@ type PublicEthAPI struct {
func NewPublicEthAPI(cliCtx context.CLIContext, backend Backend, nonceLock *AddrLocker,
key []crypto.PrivKeySecp256k1) *PublicEthAPI {
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,
}
err := api.getKeybaseInfo()
if err != nil {
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 {

View File

@ -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(),
}
}

View File

@ -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)

View File

@ -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

View File

@ -8,6 +8,8 @@ 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
@ -22,7 +24,7 @@ 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
@ -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

View File

@ -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

View File

@ -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}'
```

View File

@ -1,6 +1,6 @@
#!/bin/bash
CHAINID=1337
CHAINID="ethermint-1337"
MONIKER="localtestnet"
VAL_KEY="localkey"

48
types/chain_id.go Normal file
View File

@ -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
}

75
types/chain_id_test.go Normal file
View File

@ -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)
}
}
}

View File

@ -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: &ethHash,
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: &ethHash,
Sender: common.BytesToAddress(msg.From.Bytes()),
Simulate: ctx.IsCheckTx(),

View File

@ -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()