From 6bc80c5357b0ab845df69c0c0cc4378d81044883 Mon Sep 17 00:00:00 2001 From: Justin Thompson <37157877+J-Thompson12@users.noreply.github.com> Date: Wed, 15 Jul 2020 04:36:55 -0600 Subject: [PATCH] x/evm: state_transition test (#389) * draft state_transition * working test * keeper test * Update x/evm/types/state_transition_test.go * update state_transition_test.go * failed Finalize test case Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze --- x/evm/keeper/keeper_test.go | 30 ++--- x/evm/keeper/querier_test.go | 14 ++- x/evm/types/state_transition_test.go | 163 +++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 18 deletions(-) create mode 100644 x/evm/types/state_transition_test.go diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 7a1b3722..16a98317 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -19,10 +19,10 @@ import ( ) const addrHex = "0x756F45E3FA69347A9A973A725E3C98bC4db0b4c1" +const hex = "0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68" var ( - address = ethcmn.HexToAddress(addrHex) - hash = ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68") + hash = ethcmn.FromHex(hex) ) type KeeperTestSuite struct { @@ -31,6 +31,7 @@ type KeeperTestSuite struct { ctx sdk.Context querier sdk.Querier app *app.EthermintApp + address ethcmn.Address } func (suite *KeeperTestSuite) SetupTest() { @@ -39,6 +40,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.app = app.Setup(checkTx) suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()}) suite.querier = keeper.NewQuerier(suite.app.EvmKeeper) + suite.address = ethcmn.HexToAddress(addrHex) } func TestKeeperTestSuite(t *testing.T) { @@ -48,12 +50,12 @@ func TestKeeperTestSuite(t *testing.T) { func (suite *KeeperTestSuite) TestTransactionLogs() { ethHash := ethcmn.BytesToHash(hash) log := ðtypes.Log{ - Address: address, + Address: suite.address, Data: []byte("log"), BlockNumber: 10, } log2 := ðtypes.Log{ - Address: address, + Address: suite.address, Data: []byte("log2"), BlockNumber: 11, } @@ -75,7 +77,7 @@ func (suite *KeeperTestSuite) TestTransactionLogs() { // add another log under the zero hash log3 := ðtypes.Log{ - Address: address, + Address: suite.address, Data: []byte("log3"), BlockNumber: 10, } @@ -93,11 +95,11 @@ func (suite *KeeperTestSuite) TestTransactionLogs() { func (suite *KeeperTestSuite) TestDBStorage() { // Perform state transitions - suite.app.EvmKeeper.CreateAccount(suite.ctx, address) - suite.app.EvmKeeper.SetBalance(suite.ctx, address, big.NewInt(5)) - suite.app.EvmKeeper.SetNonce(suite.ctx, address, 4) - suite.app.EvmKeeper.SetState(suite.ctx, address, ethcmn.HexToHash("0x2"), ethcmn.HexToHash("0x3")) - suite.app.EvmKeeper.SetCode(suite.ctx, address, []byte{0x1}) + suite.app.EvmKeeper.CreateAccount(suite.ctx, suite.address) + suite.app.EvmKeeper.SetBalance(suite.ctx, suite.address, big.NewInt(5)) + suite.app.EvmKeeper.SetNonce(suite.ctx, suite.address, 4) + suite.app.EvmKeeper.SetState(suite.ctx, suite.address, ethcmn.HexToHash("0x2"), ethcmn.HexToHash("0x3")) + suite.app.EvmKeeper.SetCode(suite.ctx, suite.address, []byte{0x1}) // Test block hash mapping functionality suite.app.EvmKeeper.SetBlockHash(suite.ctx, hash, 7) @@ -112,10 +114,10 @@ func (suite *KeeperTestSuite) TestDBStorage() { suite.app.EvmKeeper.SetBlockBloom(suite.ctx, 4, testBloom) // Get those state transitions - suite.Require().Equal(suite.app.EvmKeeper.GetBalance(suite.ctx, address).Cmp(big.NewInt(5)), 0) - suite.Require().Equal(suite.app.EvmKeeper.GetNonce(suite.ctx, address), uint64(4)) - suite.Require().Equal(suite.app.EvmKeeper.GetState(suite.ctx, address, ethcmn.HexToHash("0x2")), ethcmn.HexToHash("0x3")) - suite.Require().Equal(suite.app.EvmKeeper.GetCode(suite.ctx, address), []byte{0x1}) + suite.Require().Equal(suite.app.EvmKeeper.GetBalance(suite.ctx, suite.address).Cmp(big.NewInt(5)), 0) + suite.Require().Equal(suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address), uint64(4)) + suite.Require().Equal(suite.app.EvmKeeper.GetState(suite.ctx, suite.address, ethcmn.HexToHash("0x2")), ethcmn.HexToHash("0x3")) + suite.Require().Equal(suite.app.EvmKeeper.GetCode(suite.ctx, suite.address), []byte{0x1}) height, found = suite.app.EvmKeeper.GetBlockHash(suite.ctx, hash) suite.Require().True(found) diff --git a/x/evm/keeper/querier_test.go b/x/evm/keeper/querier_test.go index 048e461d..c5a70ae8 100644 --- a/x/evm/keeper/querier_test.go +++ b/x/evm/keeper/querier_test.go @@ -4,6 +4,7 @@ import ( "math/big" "github.com/cosmos/ethermint/x/evm/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -18,15 +19,20 @@ func (suite *KeeperTestSuite) TestQuerier() { }{ {"protocol version", []string{types.QueryProtocolVersion}, func() {}, true}, {"balance", []string{types.QueryBalance, addrHex}, func() { - suite.app.EvmKeeper.SetBalance(suite.ctx, address, big.NewInt(5)) + suite.app.EvmKeeper.SetBalance(suite.ctx, suite.address, big.NewInt(5)) }, true}, - // {"balance", []string{types.QueryBalance, "0x01232"}, func() {}, false}, + // {"balance fail", []string{types.QueryBalance, "0x01232"}, func() {}, false}, {"block number", []string{types.QueryBlockNumber, "0x0"}, func() {}, true}, {"storage", []string{types.QueryStorage, "0x0", "0x0"}, func() {}, true}, {"code", []string{types.QueryCode, "0x0"}, func() {}, true}, - // {"hash to height", []string{types.QueryHashToHeight, "0x0"}, func() {}, true}, + {"hash to height", []string{types.QueryHashToHeight, hex}, func() { + suite.app.EvmKeeper.SetBlockHash(suite.ctx, hash, 8) + }, true}, {"tx logs", []string{types.QueryTransactionLogs, "0x0"}, func() {}, true}, - // {"logs bloom", []string{types.QueryLogsBloom, "0x0"}, func() {}, true}, + {"bloom", []string{types.QueryBloom, "4"}, func() { + testBloom := ethtypes.BytesToBloom([]byte{0x1, 0x3}) + suite.app.EvmKeeper.SetBlockBloom(suite.ctx, 4, testBloom) + }, true}, {"logs", []string{types.QueryLogs, "0x0"}, func() {}, true}, {"account", []string{types.QueryAccount, "0x0"}, func() {}, true}, {"exportAccount", []string{types.QueryExportAccount, "0x0"}, func() {}, true}, diff --git a/x/evm/types/state_transition_test.go b/x/evm/types/state_transition_test.go new file mode 100644 index 00000000..ba8f40a4 --- /dev/null +++ b/x/evm/types/state_transition_test.go @@ -0,0 +1,163 @@ +package types_test + +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ethermint/crypto" + ethermint "github.com/cosmos/ethermint/types" + "github.com/cosmos/ethermint/x/evm/types" + + ethcmn "github.com/ethereum/go-ethereum/common" + ethcrypto "github.com/ethereum/go-ethereum/crypto" +) + +func (suite *StateDBTestSuite) TestTransitionDb() { + suite.stateDB.SetNonce(suite.address, 123) + + addr := sdk.AccAddress(suite.address.Bytes()) + balance := sdk.NewCoin(ethermint.DenomDefault, sdk.NewInt(5000)) + suite.app.BankKeeper.SetBalance(suite.ctx, addr, balance) + + priv, err := crypto.GenerateKey() + suite.Require().NoError(err) + recipient := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) + + testCase := []struct { + name string + malleate func() + state types.StateTransition + expPass bool + }{ + { + "passing state transition", + func() {}, + types.StateTransition{ + AccountNonce: 123, + Price: big.NewInt(10), + GasLimit: 11, + Recipient: &recipient, + Amount: big.NewInt(50), + Payload: []byte("data"), + ChainID: big.NewInt(1), + Csdb: suite.stateDB, + TxHash: ðcmn.Hash{}, + Sender: suite.address, + Simulate: suite.ctx.IsCheckTx(), + }, + true, + }, + { + "contract creation", + func() {}, + types.StateTransition{ + AccountNonce: 123, + Price: big.NewInt(10), + GasLimit: 11, + Recipient: nil, + Amount: big.NewInt(10), + Payload: []byte("data"), + ChainID: big.NewInt(1), + Csdb: suite.stateDB, + TxHash: ðcmn.Hash{}, + Sender: suite.address, + Simulate: true, + }, + true, + }, + { + "state transition simulation", + func() {}, + types.StateTransition{ + AccountNonce: 123, + Price: big.NewInt(10), + GasLimit: 11, + Recipient: &recipient, + Amount: big.NewInt(10), + Payload: []byte("data"), + ChainID: big.NewInt(1), + Csdb: suite.stateDB, + TxHash: ðcmn.Hash{}, + Sender: suite.address, + Simulate: true, + }, + true, + }, + { + "fail by sending more than balance", + func() {}, + types.StateTransition{ + AccountNonce: 123, + Price: big.NewInt(10), + GasLimit: 11, + Recipient: &recipient, + Amount: big.NewInt(4951), + Payload: []byte("data"), + ChainID: big.NewInt(1), + Csdb: suite.stateDB, + TxHash: ðcmn.Hash{}, + Sender: suite.address, + Simulate: suite.ctx.IsCheckTx(), + }, + false, + }, + { + "failed to Finalize", + func() {}, + types.StateTransition{ + AccountNonce: 123, + Price: big.NewInt(10), + GasLimit: 11, + Recipient: &recipient, + Amount: big.NewInt(-5000), + Payload: []byte("data"), + ChainID: big.NewInt(1), + Csdb: suite.stateDB, + TxHash: ðcmn.Hash{}, + Sender: suite.address, + Simulate: false, + }, + false, + }, + { + "nil gas price", + func() { + invalidGas := sdk.DecCoins{ + {Denom: ethermint.DenomDefault}, + } + suite.ctx = suite.ctx.WithMinGasPrices(invalidGas) + }, + types.StateTransition{ + AccountNonce: 123, + Price: big.NewInt(10), + GasLimit: 11, + Recipient: &recipient, + Amount: big.NewInt(10), + Payload: []byte("data"), + ChainID: big.NewInt(1), + Csdb: suite.stateDB, + TxHash: ðcmn.Hash{}, + Sender: suite.address, + Simulate: suite.ctx.IsCheckTx(), + }, + false, + }, + } + + for _, tc := range testCase { + tc.malleate() + + _, err = tc.state.TransitionDb(suite.ctx) + + if tc.expPass { + suite.Require().NoError(err, tc.name) + fromBalance := suite.app.EvmKeeper.GetBalance(suite.ctx, suite.address) + toBalance := suite.app.EvmKeeper.GetBalance(suite.ctx, recipient) + suite.Require().Equal(fromBalance, big.NewInt(4950), tc.name) + suite.Require().Equal(toBalance, big.NewInt(50), tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +}