forked from cerc-io/laconicd-deprecated
		
	evm: remove CommitStateDB, journal and stateObject (#84)
				
					
				
			* evm: remove CommitStateDB and stateObject * imported build fixes * lint * rm set nonce * update account response * changelog
This commit is contained in:
		
							parent
							
								
									6eadc8fdf8
								
							
						
					
					
						commit
						0c6e44d3d3
					
				| @ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ | ||||
| 
 | ||||
| ### State Machine Breaking | ||||
| 
 | ||||
| * (evm) [tharsis#84](https://github.com/tharsis/ethermint/pull/84) Remove `journal`, `CommitStateDB` and `stateObjects`. | ||||
| * (rpc, evm) [tharsis#81](https://github.com/tharsis/ethermint/pull/81) Remove tx `Receipt` from store and replace it with fields obtained from the Tendermint RPC client. | ||||
| * (evm) [tharsis#72](https://github.com/tharsis/ethermint/issues/72) Update `AccessList` to use `TransientStore` instead of map. | ||||
| * (evm) [tharsis#68](https://github.com/tharsis/ethermint/issues/68) Replace block hash storage map to use staking `HistoricalInfo`. | ||||
|  | ||||
| @ -385,7 +385,7 @@ func NewEthermintApp( | ||||
| 		params.NewAppModule(app.ParamsKeeper), | ||||
| 		transferModule, | ||||
| 		// Ethermint app modules
 | ||||
| 		evm.NewAppModule(app.EvmKeeper, app.AccountKeeper, app.BankKeeper), | ||||
| 		evm.NewAppModule(app.EvmKeeper, app.AccountKeeper), | ||||
| 	) | ||||
| 
 | ||||
| 	// During begin block slashing happens after distr.BeginBlocker so that
 | ||||
|  | ||||
| @ -427,7 +427,7 @@ QueryAccountResponse is the response type for the Query/Account RPC method. | ||||
| | Field | Type | Label | Description | | ||||
| | ----- | ---- | ----- | ----------- | | ||||
| | `balance` | [string](#string) |  | balance is the balance of the EVM denomination. | | ||||
| | `code_hash` | [bytes](#bytes) |  | code_hash is the code bytes from the EOA. | | ||||
| | `code_hash` | [string](#string) |  | code hash is the hex-formatted code bytes from the EOA. | | ||||
| | `nonce` | [uint64](#uint64) |  | nonce is the account's sequence number. | | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -45,7 +45,7 @@ require ( | ||||
| 	github.com/tyler-smith/go-bip39 v1.1.0 | ||||
| 	github.com/xlab/closer v0.0.0-20190328110542-03326addb7c2 | ||||
| 	github.com/xlab/suplog v1.3.0 | ||||
| 	golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a | ||||
| 	golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect | ||||
| 	google.golang.org/genproto v0.0.0-20210607140030-00d4fb20b1ae | ||||
| 	google.golang.org/grpc v1.38.0 | ||||
| 	gopkg.in/yaml.v2 v2.4.0 | ||||
|  | ||||
| @ -75,8 +75,8 @@ message QueryAccountRequest { | ||||
| message QueryAccountResponse { | ||||
|   // balance is the balance of the EVM denomination. | ||||
|   string balance = 1; | ||||
|   // code_hash is the code bytes from the EOA. | ||||
|   bytes code_hash = 2; | ||||
|   // 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; | ||||
| } | ||||
|  | ||||
| @ -107,7 +107,7 @@ func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak authkeeper. | ||||
| 	genBlock := ethcore.DefaultGenesisBlock() | ||||
| 	ms := cms.CacheMultiStore() | ||||
| 	ctx := sdk.NewContext(ms, tmproto.Header{}, false, logger) | ||||
| 	evmKeeper.CommitStateDB.WithContext(ctx) | ||||
| 	evmKeeper.WithContext(ctx) | ||||
| 
 | ||||
| 	// Set the default Ethermint parameters to the parameter keeper store
 | ||||
| 	evmKeeper.SetParams(ctx, evmtypes.DefaultParams()) | ||||
| @ -126,25 +126,19 @@ func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak authkeeper. | ||||
| 		addr := ethcmn.HexToAddress(addrStr) | ||||
| 		acc := genBlock.Alloc[addr] | ||||
| 
 | ||||
| 		evmKeeper.CommitStateDB.AddBalance(addr, acc.Balance) | ||||
| 		evmKeeper.CommitStateDB.SetCode(addr, acc.Code) | ||||
| 		evmKeeper.CommitStateDB.SetNonce(addr, acc.Nonce) | ||||
| 		evmKeeper.AddBalance(addr, acc.Balance) | ||||
| 		evmKeeper.SetCode(addr, acc.Code) | ||||
| 		evmKeeper.SetNonce(addr, acc.Nonce) | ||||
| 
 | ||||
| 		for key, value := range acc.Storage { | ||||
| 			evmKeeper.CommitStateDB.SetState(addr, key, value) | ||||
| 			evmKeeper.SetState(addr, key, value) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// get balance of one of the genesis account having 400 ETH
 | ||||
| 	b := evmKeeper.CommitStateDB.GetBalance(genInvestor) | ||||
| 	b := evmKeeper.GetBalance(genInvestor) | ||||
| 	require.Equal(t, "200000000000000000000", b.String()) | ||||
| 
 | ||||
| 	// commit the stateDB with 'false' to delete empty objects
 | ||||
| 	//
 | ||||
| 	// NOTE: Commit does not yet return the intra merkle root (version)
 | ||||
| 	_, err := evmKeeper.CommitStateDB.Commit(false) | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	// persist multi-store cache state
 | ||||
| 	ms.Write() | ||||
| 
 | ||||
| @ -267,15 +261,13 @@ func TestImportBlocks(t *testing.T) { | ||||
| 		ms := cms.CacheMultiStore() | ||||
| 		ctx := sdk.NewContext(ms, tmproto.Header{}, false, logger) | ||||
| 		ctx = ctx.WithBlockHeight(int64(block.NumberU64())) | ||||
| 		evmKeeper.CommitStateDB.WithContext(ctx) | ||||
| 		evmKeeper.WithContext(ctx) | ||||
| 
 | ||||
| 		if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 { | ||||
| 			applyDAOHardFork(evmKeeper) | ||||
| 		} | ||||
| 
 | ||||
| 		for i, tx := range block.Transactions() { | ||||
| 			evmKeeper.CommitStateDB.Prepare(tx.Hash(), block.Hash(), i) | ||||
| 			// evmKeeper.CommitStateDB.Set(block.Hash())
 | ||||
| 		for _, tx := range block.Transactions() { | ||||
| 
 | ||||
| 			receipt, gas, err := applyTransaction( | ||||
| 				chainConfig, chainContext, nil, gp, evmKeeper, header, tx, usedGas, vmConfig, | ||||
| @ -287,10 +279,6 @@ func TestImportBlocks(t *testing.T) { | ||||
| 		// apply mining rewards
 | ||||
| 		accumulateRewards(chainConfig, evmKeeper, header, block.Uncles()) | ||||
| 
 | ||||
| 		// commit stateDB
 | ||||
| 		_, err := evmKeeper.CommitStateDB.Commit(chainConfig.IsEIP158(block.Number())) | ||||
| 		require.NoError(t, err, "failed to commit StateDB") | ||||
| 
 | ||||
| 		// simulate BaseApp EndBlocker commitment
 | ||||
| 		ms.Write() | ||||
| 		cms.Commit() | ||||
| @ -325,12 +313,12 @@ func accumulateRewards( | ||||
| 		r.Sub(r, header.Number) | ||||
| 		r.Mul(r, blockReward) | ||||
| 		r.Div(r, rewardBig8) | ||||
| 		evmKeeper.CommitStateDB.AddBalance(uncle.Coinbase, r) | ||||
| 		evmKeeper.AddBalance(uncle.Coinbase, r) | ||||
| 		r.Div(blockReward, rewardBig32) | ||||
| 		reward.Add(reward, r) | ||||
| 	} | ||||
| 
 | ||||
| 	evmKeeper.CommitStateDB.AddBalance(header.Coinbase, reward) | ||||
| 	evmKeeper.AddBalance(header.Coinbase, reward) | ||||
| } | ||||
| 
 | ||||
| // ApplyDAOHardFork modifies the state database according to the DAO hard-fork
 | ||||
| @ -341,14 +329,13 @@ func accumulateRewards( | ||||
| // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/consensus/misc/dao.go#L74
 | ||||
| func applyDAOHardFork(evmKeeper *evmkeeper.Keeper) { | ||||
| 	// Retrieve the contract to refund balances into
 | ||||
| 	if !evmKeeper.CommitStateDB.Exist(ethparams.DAORefundContract) { | ||||
| 		evmKeeper.CommitStateDB.CreateAccount(ethparams.DAORefundContract) | ||||
| 	if !evmKeeper.Exist(ethparams.DAORefundContract) { | ||||
| 		evmKeeper.CreateAccount(ethparams.DAORefundContract) | ||||
| 	} | ||||
| 
 | ||||
| 	// Move every DAO account and extra-balance account funds into the refund contract
 | ||||
| 	for _, addr := range ethparams.DAODrainList() { | ||||
| 		evmKeeper.CommitStateDB.AddBalance(ethparams.DAORefundContract, evmKeeper.CommitStateDB.GetBalance(addr)) | ||||
| 		evmKeeper.CommitStateDB.SetBalance(addr, new(big.Int)) | ||||
| 		evmKeeper.AddBalance(ethparams.DAORefundContract, evmKeeper.GetBalance(addr)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -374,7 +361,7 @@ func applyTransaction( | ||||
| 
 | ||||
| 	// Create a new environment which holds all relevant information
 | ||||
| 	// about the transaction and calling mechanisms.
 | ||||
| 	vmenv := ethvm.NewEVM(blockCtx, txCtx, evmKeeper.CommitStateDB, config, cfg) | ||||
| 	vmenv := ethvm.NewEVM(blockCtx, txCtx, evmKeeper, config, cfg) | ||||
| 
 | ||||
| 	// Apply the transaction to the current state (included in the env)
 | ||||
| 	execResult, err := ethcore.ApplyMessage(vmenv, msg, gp) | ||||
| @ -383,19 +370,11 @@ func applyTransaction( | ||||
| 		return ðtypes.Receipt{}, 0, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Update the state with pending changes
 | ||||
| 	var intRoot ethcmn.Hash | ||||
| 	if config.IsByzantium(header.Number) { | ||||
| 		err = evmKeeper.CommitStateDB.Finalise(true) | ||||
| 	} else { | ||||
| 		intRoot, err = evmKeeper.CommitStateDB.IntermediateRoot(config.IsEIP158(header.Number)) | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, execResult.UsedGas, err | ||||
| 	} | ||||
| 
 | ||||
| 	root := intRoot.Bytes() | ||||
| 	root := ethcmn.Hash{}.Bytes() | ||||
| 	*usedGas += execResult.UsedGas | ||||
| 
 | ||||
| 	// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
 | ||||
| @ -410,11 +389,11 @@ func applyTransaction( | ||||
| 	} | ||||
| 
 | ||||
| 	// Set the receipt logs and create a bloom for filtering
 | ||||
| 	receipt.Logs, err = evmKeeper.CommitStateDB.GetLogs(tx.Hash()) | ||||
| 	receipt.Logs = evmKeeper.GetTxLogs(tx.Hash()) | ||||
| 	receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt}) | ||||
| 	receipt.BlockHash = evmKeeper.CommitStateDB.BlockHash() | ||||
| 	receipt.BlockHash = header.Hash() | ||||
| 	receipt.BlockNumber = header.Number | ||||
| 	receipt.TransactionIndex = uint(evmKeeper.CommitStateDB.TxIndex()) | ||||
| 	receipt.TransactionIndex = uint(evmKeeper.GetTxIndexTransient()) | ||||
| 
 | ||||
| 	return receipt, execResult.UsedGas, err | ||||
| } | ||||
|  | ||||
| @ -18,16 +18,12 @@ func InitGenesis( | ||||
| 	ctx sdk.Context, | ||||
| 	k *keeper.Keeper, | ||||
| 	accountKeeper types.AccountKeeper, // nolint: interfacer
 | ||||
| 	bankKeeper types.BankKeeper, | ||||
| 	data types.GenesisState, | ||||
| ) []abci.ValidatorUpdate { | ||||
| 	k.WithContext(ctx) | ||||
| 	k.WithChainID(ctx) | ||||
| 
 | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 
 | ||||
| 	k.SetParams(ctx, data.Params) | ||||
| 	evmDenom := data.Params.EvmDenom | ||||
| 
 | ||||
| 	for _, account := range data.Accounts { | ||||
| 		address := ethcmn.HexToAddress(account.Address) | ||||
| @ -47,46 +43,25 @@ func InitGenesis( | ||||
| 			) | ||||
| 		} | ||||
| 
 | ||||
| 		evmBalance := bankKeeper.GetBalance(ctx, accAddress, evmDenom) | ||||
| 		k.CommitStateDB.SetBalance(address, evmBalance.Amount.BigInt()) | ||||
| 		k.CommitStateDB.SetNonce(address, acc.GetSequence()) | ||||
| 		k.CommitStateDB.SetCode(address, ethcmn.Hex2Bytes(account.Code)) | ||||
| 		k.SetCode(address, ethcmn.Hex2Bytes(account.Code)) | ||||
| 
 | ||||
| 		for _, storage := range account.Storage { | ||||
| 			k.SetState(address, ethcmn.HexToHash(storage.Key), ethcmn.HexToHash(storage.Value)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	for _, txLog := range data.TxsLogs { | ||||
| 		err = k.CommitStateDB.SetLogs(ethcmn.HexToHash(txLog.Hash), txLog.EthLogs()) | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 		k.SetLogs(ethcmn.HexToHash(txLog.Hash), txLog.EthLogs()) | ||||
| 	} | ||||
| 
 | ||||
| 	k.SetChainConfig(ctx, data.ChainConfig) | ||||
| 
 | ||||
| 	// set state objects and code to store
 | ||||
| 	_, err = k.CommitStateDB.Commit(false) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// set storage to store
 | ||||
| 	// NOTE: don't delete empty object to prevent import-export simulation failure
 | ||||
| 	err = k.CommitStateDB.Finalise(false) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	return []abci.ValidatorUpdate{} | ||||
| } | ||||
| 
 | ||||
| // ExportGenesis exports genesis state of the EVM module
 | ||||
| func ExportGenesis(ctx sdk.Context, k *keeper.Keeper, ak types.AccountKeeper) *types.GenesisState { | ||||
| 	k.WithContext(ctx) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 
 | ||||
| 	// nolint: prealloc
 | ||||
| 	var ethGenAccounts []types.GenesisAccount | ||||
| @ -106,7 +81,7 @@ func ExportGenesis(ctx sdk.Context, k *keeper.Keeper, ak types.AccountKeeper) *t | ||||
| 
 | ||||
| 		genAccount := types.GenesisAccount{ | ||||
| 			Address: addr.String(), | ||||
| 			Code:    ethcmn.Bytes2Hex(k.CommitStateDB.GetCode(addr)), | ||||
| 			Code:    ethcmn.Bytes2Hex(k.GetCode(addr)), | ||||
| 			Storage: storage, | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
| @ -91,13 +91,13 @@ func (suite *EvmTestSuite) TestInitGenesis() { | ||||
| 			if tc.expPanic { | ||||
| 				suite.Require().Panics( | ||||
| 					func() { | ||||
| 						_ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper, suite.app.BankKeeper, *tc.genState) | ||||
| 						_ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper, *tc.genState) | ||||
| 					}, | ||||
| 				) | ||||
| 			} else { | ||||
| 				suite.Require().NotPanics( | ||||
| 					func() { | ||||
| 						_ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper, suite.app.BankKeeper, *tc.genState) | ||||
| 						_ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper, *tc.genState) | ||||
| 					}, | ||||
| 				) | ||||
| 			} | ||||
|  | ||||
| @ -8,12 +8,11 @@ import ( | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||||
| 
 | ||||
| 	"github.com/cosmos/ethermint/x/evm/keeper" | ||||
| 	"github.com/cosmos/ethermint/x/evm/types" | ||||
| ) | ||||
| 
 | ||||
| // NewHandler returns a handler for Ethermint type messages.
 | ||||
| func NewHandler(k *keeper.Keeper) sdk.Handler { | ||||
| func NewHandler(server types.MsgServer) sdk.Handler { | ||||
| 	return func(ctx sdk.Context, msg sdk.Msg) (result *sdk.Result, err error) { | ||||
| 		defer Recover(&err) | ||||
| 
 | ||||
| @ -22,7 +21,7 @@ func NewHandler(k *keeper.Keeper) sdk.Handler { | ||||
| 		switch msg := msg.(type) { | ||||
| 		case *types.MsgEthereumTx: | ||||
| 			// execute state transition
 | ||||
| 			res, err := k.EthereumTx(sdk.WrapSDKContext(ctx), msg) | ||||
| 			res, err := server.EthereumTx(sdk.WrapSDKContext(ctx), msg) | ||||
| 			return sdk.WrapServiceResult(ctx, res, err) | ||||
| 
 | ||||
| 		default: | ||||
|  | ||||
| @ -49,7 +49,7 @@ func (suite *EvmTestSuite) SetupTest() { | ||||
| 
 | ||||
| 	suite.app = app.Setup(checkTx) | ||||
| 	suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "ethermint-1", Time: time.Now().UTC()}) | ||||
| 	suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx) | ||||
| 	suite.app.EvmKeeper.WithContext(suite.ctx) | ||||
| 	suite.handler = evm.NewHandler(suite.app.EvmKeeper) | ||||
| 	suite.codec = suite.app.AppCodec() | ||||
| 	suite.chainID = suite.app.EvmKeeper.ChainID() | ||||
| @ -84,7 +84,6 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() { | ||||
| 		{ | ||||
| 			"passed", | ||||
| 			func() { | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetBalance(suite.from, big.NewInt(100)) | ||||
| 				to := ethcmn.BytesToAddress(suite.to) | ||||
| 				tx = types.NewMsgEthereumTx(suite.chainID, 0, &to, big.NewInt(100), 0, big.NewInt(10000), nil, nil) | ||||
| 				tx.From = suite.from.String() | ||||
| @ -189,11 +188,10 @@ func (suite *EvmTestSuite) TestHandlerLogs() { | ||||
| 	suite.Require().Equal(len(txResponse.Logs[0].Topics), 2) | ||||
| 
 | ||||
| 	hash := []byte{1} | ||||
| 	err = suite.app.EvmKeeper.CommitStateDB.SetLogs(ethcmn.BytesToHash(hash), types.LogsToEthereum(txResponse.Logs)) | ||||
| 	suite.app.EvmKeeper.SetLogs(ethcmn.BytesToHash(hash), types.LogsToEthereum(txResponse.Logs)) | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	logs, err := suite.app.EvmKeeper.CommitStateDB.GetLogs(ethcmn.BytesToHash(hash)) | ||||
| 	suite.Require().NoError(err, "failed to get logs") | ||||
| 	logs := suite.app.EvmKeeper.GetTxLogs(ethcmn.BytesToHash(hash)) | ||||
| 
 | ||||
| 	suite.Require().Equal(logs, txResponse.Logs) | ||||
| } | ||||
| @ -310,8 +308,6 @@ func (suite *EvmTestSuite) TestSendTransaction() { | ||||
| 	gasLimit := uint64(21000) | ||||
| 	gasPrice := big.NewInt(0x55ae82600) | ||||
| 
 | ||||
| 	suite.app.EvmKeeper.CommitStateDB.SetBalance(suite.from, big.NewInt(100)) | ||||
| 
 | ||||
| 	// send simple value transfer with gasLimit=21000
 | ||||
| 	tx := types.NewMsgEthereumTx(suite.chainID, 1, ðcmn.Address{0x1}, big.NewInt(1), gasLimit, gasPrice, nil, nil) | ||||
| 	tx.From = suite.from.String() | ||||
| @ -390,12 +386,12 @@ func (suite *EvmTestSuite) TestOutOfGasWhenDeployContract() { | ||||
| 	err := tx.Sign(suite.ethSigner, suite.signer) | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) | ||||
| 	snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper) | ||||
| 	suite.Require().Nil(err) | ||||
| 
 | ||||
| 	defer func() { | ||||
| 		if r := recover(); r != nil { | ||||
| 			currentCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) | ||||
| 			currentCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper) | ||||
| 			suite.Require().Nil(err) | ||||
| 			suite.Require().Equal(snapshotCommitStateDBJson, currentCommitStateDBJson) | ||||
| 		} else { | ||||
| @ -419,13 +415,13 @@ func (suite *EvmTestSuite) TestErrorWhenDeployContract() { | ||||
| 	err := tx.Sign(suite.ethSigner, suite.signer) | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) | ||||
| 	snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper) | ||||
| 	suite.Require().Nil(err) | ||||
| 
 | ||||
| 	_, sdkErr := suite.handler(suite.ctx, tx) | ||||
| 	suite.Require().NotNil(sdkErr) | ||||
| 
 | ||||
| 	currentCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) | ||||
| 	currentCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper) | ||||
| 	suite.Require().Nil(err) | ||||
| 	suite.Require().Equal(snapshotCommitStateDBJson, currentCommitStateDBJson) | ||||
| } | ||||
|  | ||||
| @ -27,29 +27,13 @@ func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { | ||||
| // deleting the empty ones. It also sets the bloom filers for the request block to
 | ||||
| // the store. The EVM end block logic doesn't update the validator set, thus it returns
 | ||||
| // an empty slice.
 | ||||
| func (k Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { | ||||
| func (k *Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { | ||||
| 	defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker) | ||||
| 
 | ||||
| 	// Gas costs are handled within msg handler so costs should be ignored
 | ||||
| 	ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	// Update account balances before committing other parts of state
 | ||||
| 	k.CommitStateDB.UpdateAccounts() | ||||
| 
 | ||||
| 	root, err := k.CommitStateDB.Commit(true) | ||||
| 	// Commit state objects to KV store
 | ||||
| 	if err != nil { | ||||
| 		k.Logger(ctx).Error("failed to commit state objects", "error", err, "height", ctx.BlockHeight()) | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// reset all cache after account data has been committed, that make sure node state consistent
 | ||||
| 	if err = k.CommitStateDB.Reset(root); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// get the block bloom bytes from the transient store and set it to the persistent storage
 | ||||
| 	bloomBig, found := k.GetBlockBloomTransient() | ||||
| 	if !found { | ||||
| @ -57,7 +41,8 @@ func (k Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.Valid | ||||
| 	} | ||||
| 
 | ||||
| 	bloom := ethtypes.BytesToBloom(bloomBig.Bytes()) | ||||
| 	k.SetBlockBloom(ctx, req.Height, bloom) | ||||
| 	k.SetBlockBloom(infCtx, req.Height, bloom) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	return []abci.ValidatorUpdate{} | ||||
| } | ||||
|  | ||||
| @ -2,13 +2,10 @@ package keeper | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"google.golang.org/grpc/codes" | ||||
| 	"google.golang.org/grpc/status" | ||||
| 
 | ||||
| 	tmtypes "github.com/tendermint/tendermint/types" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/store/prefix" | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	"github.com/cosmos/cosmos-sdk/types/query" | ||||
| @ -33,19 +30,15 @@ func (k Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*typ | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	addr := ethcmn.HexToAddress(req.Address) | ||||
| 
 | ||||
| 	so := k.CommitStateDB.GetOrNewStateObject(ethcmn.HexToAddress(req.Address)) | ||||
| 	balance, err := ethermint.MarshalBigInt(so.Balance()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	return &types.QueryAccountResponse{ | ||||
| 		Balance:  balance, | ||||
| 		CodeHash: so.CodeHash(), | ||||
| 		Nonce:    so.Nonce(), | ||||
| 		Balance:  k.GetBalance(addr).String(), | ||||
| 		CodeHash: k.GetCodeHash(addr).Hex(), | ||||
| 		Nonce:    k.GetNonce(addr), | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| @ -61,7 +54,7 @@ func (k Keeper) CosmosAccount(c context.Context, req *types.QueryCosmosAccountRe | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	ethAddr := ethcmn.HexToAddress(req.Address) | ||||
| 	cosmosAddr := sdk.AccAddress(ethAddr.Bytes()) | ||||
| @ -93,9 +86,9 @@ func (k Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*typ | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	balanceInt := k.CommitStateDB.GetBalance(ethcmn.HexToAddress(req.Address)) | ||||
| 	balanceInt := k.GetBalance(ethcmn.HexToAddress(req.Address)) | ||||
| 	balance, err := ethermint.MarshalBigInt(balanceInt) | ||||
| 	if err != nil { | ||||
| 		return nil, status.Error( | ||||
| @ -130,12 +123,12 @@ func (k Keeper) Storage(c context.Context, req *types.QueryStorageRequest) (*typ | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	address := ethcmn.HexToAddress(req.Address) | ||||
| 	key := ethcmn.HexToHash(req.Key) | ||||
| 
 | ||||
| 	state := k.CommitStateDB.GetState(address, key) | ||||
| 	state := k.GetState(address, key) | ||||
| 	stateHex := state.Hex() | ||||
| 
 | ||||
| 	if ethermint.IsEmptyHash(stateHex) { | ||||
| @ -163,10 +156,10 @@ func (k Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.Que | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	address := ethcmn.HexToAddress(req.Address) | ||||
| 	code := k.CommitStateDB.GetCode(address) | ||||
| 	code := k.GetCode(address) | ||||
| 
 | ||||
| 	return &types.QueryCodeResponse{ | ||||
| 		Code: code, | ||||
| @ -187,19 +180,13 @@ func (k Keeper) TxLogs(c context.Context, req *types.QueryTxLogsRequest) (*types | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	hash := ethcmn.HexToHash(req.Hash) | ||||
| 	logs, err := k.CommitStateDB.GetLogs(hash) | ||||
| 	if err != nil { | ||||
| 		return nil, status.Error( | ||||
| 			codes.Internal, | ||||
| 			err.Error(), | ||||
| 		) | ||||
| 	} | ||||
| 	logs := k.GetTxLogs(hash) | ||||
| 
 | ||||
| 	return &types.QueryTxLogsResponse{ | ||||
| 		Logs: types.NewTransactionLogsFromEth(hash, logs).Logs, | ||||
| 		Logs: types.NewLogsFromEth(logs), | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| @ -277,59 +264,61 @@ func (k Keeper) StaticCall(c context.Context, req *types.QueryStaticCallRequest) | ||||
| 		return nil, status.Error(codes.InvalidArgument, "empty request") | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(c) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 	// ctx := sdk.UnwrapSDKContext(c)
 | ||||
| 	// k.WithContext(ctx)
 | ||||
| 
 | ||||
| 	// parse the chainID from a string to a base-10 integer
 | ||||
| 	chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID()) | ||||
| 	if err != nil { | ||||
| 		return nil, status.Error(codes.Internal, err.Error()) | ||||
| 	} | ||||
| 	// // parse the chainID from a string to a base-10 integer
 | ||||
| 	// chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
 | ||||
| 	// if err != nil {
 | ||||
| 	// 	return nil, status.Error(codes.Internal, err.Error())
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	txHash := tmtypes.Tx(ctx.TxBytes()).Hash() | ||||
| 	ethHash := ethcmn.BytesToHash(txHash) | ||||
| 	// txHash := tmtypes.Tx(ctx.TxBytes()).Hash()
 | ||||
| 	// ethHash := ethcmn.BytesToHash(txHash)
 | ||||
| 
 | ||||
| 	var recipient *ethcmn.Address | ||||
| 	if len(req.Address) > 0 { | ||||
| 		addr := ethcmn.HexToAddress(req.Address) | ||||
| 		recipient = &addr | ||||
| 	} | ||||
| 	// var recipient *ethcmn.Address
 | ||||
| 	// if len(req.Address) > 0 {
 | ||||
| 	// 	addr := ethcmn.HexToAddress(req.Address)
 | ||||
| 	// 	recipient = &addr
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	so := k.CommitStateDB.GetOrNewStateObject(*recipient) | ||||
| 	sender := ethcmn.HexToAddress("0xaDd00275E3d9d213654Ce5223f0FADE8b106b707") | ||||
| 	// so := k.GetOrNewStateObject(*recipient)
 | ||||
| 	// sender := ethcmn.HexToAddress("0xaDd00275E3d9d213654Ce5223f0FADE8b106b707")
 | ||||
| 
 | ||||
| 	msg := types.NewMsgEthereumTx( | ||||
| 		chainIDEpoch, so.Nonce(), recipient, big.NewInt(0), 100000000, big.NewInt(0), req.Input, nil, | ||||
| 	) | ||||
| 	msg.From = sender.Hex() | ||||
| 	// msg := types.NewMsgEthereumTx(
 | ||||
| 	// 	chainIDEpoch, so.Nonce(), recipient, big.NewInt(0), 100000000, big.NewInt(0), req.Input, nil,
 | ||||
| 	// )
 | ||||
| 	// msg.From = sender.Hex()
 | ||||
| 
 | ||||
| 	if err := msg.ValidateBasic(); err != nil { | ||||
| 		return nil, status.Error(codes.Internal, err.Error()) | ||||
| 	} | ||||
| 	// if err := msg.ValidateBasic(); err != nil {
 | ||||
| 	// 	return nil, status.Error(codes.Internal, err.Error())
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	ethMsg, err := msg.AsMessage() | ||||
| 	if err != nil { | ||||
| 		return nil, status.Error(codes.Internal, err.Error()) | ||||
| 	} | ||||
| 	// ethMsg, err := msg.AsMessage()
 | ||||
| 	// if err != nil {
 | ||||
| 	// 	return nil, status.Error(codes.Internal, err.Error())
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	st := &types.StateTransition{ | ||||
| 		Message:  ethMsg, | ||||
| 		Csdb:     k.CommitStateDB.WithContext(ctx), | ||||
| 		ChainID:  chainIDEpoch, | ||||
| 		TxHash:   ðHash, | ||||
| 		Simulate: ctx.IsCheckTx(), | ||||
| 		Debug:    false, | ||||
| 	} | ||||
| 	// st := &types.StateTransition{
 | ||||
| 	// 	Message:  ethMsg,
 | ||||
| 	// 	Csdb:     k.WithContext(ctx),
 | ||||
| 	// 	ChainID:  chainIDEpoch,
 | ||||
| 	// 	TxHash:   ðHash,
 | ||||
| 	// 	Simulate: ctx.IsCheckTx(),
 | ||||
| 	// 	Debug:    false,
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	config, found := k.GetChainConfig(ctx) | ||||
| 	if !found { | ||||
| 		return nil, status.Error(codes.Internal, types.ErrChainConfigNotFound.Error()) | ||||
| 	} | ||||
| 	// config, found := k.GetChainConfig(ctx)
 | ||||
| 	// if !found {
 | ||||
| 	// 	return nil, status.Error(codes.Internal, types.ErrChainConfigNotFound.Error())
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	ret, err := st.StaticCall(ctx, config) | ||||
| 	if err != nil { | ||||
| 		return nil, status.Error(codes.Internal, err.Error()) | ||||
| 	} | ||||
| 	// ret, err := st.StaticCall(ctx, config)
 | ||||
| 	// if err != nil {
 | ||||
| 	// 	return nil, status.Error(codes.Internal, err.Error())
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	return &types.QueryStaticCallResponse{Data: ret}, nil | ||||
| 	// return &types.QueryStaticCallResponse{Data: ret}, nil
 | ||||
| 
 | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| @ -5,6 +5,7 @@ import ( | ||||
| 
 | ||||
| 	"google.golang.org/grpc/metadata" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	ethcrypto "github.com/ethereum/go-ethereum/crypto" | ||||
| @ -33,7 +34,7 @@ func (suite *KeeperTestSuite) TestQueryAccount() { | ||||
| 				suite.app.BankKeeper.SetBalance(suite.ctx, suite.address.Bytes(), ethermint.NewPhotonCoinInt64(0)) | ||||
| 				expAccount = &types.QueryAccountResponse{ | ||||
| 					Balance:  "0", | ||||
| 					CodeHash: ethcrypto.Keccak256(nil), | ||||
| 					CodeHash: common.BytesToHash(ethcrypto.Keccak256(nil)).Hex(), | ||||
| 					Nonce:    0, | ||||
| 				} | ||||
| 				req = &types.QueryAccountRequest{ | ||||
| @ -48,7 +49,7 @@ func (suite *KeeperTestSuite) TestQueryAccount() { | ||||
| 				suite.app.BankKeeper.SetBalance(suite.ctx, suite.address.Bytes(), ethermint.NewPhotonCoinInt64(100)) | ||||
| 				expAccount = &types.QueryAccountResponse{ | ||||
| 					Balance:  "100", | ||||
| 					CodeHash: ethcrypto.Keccak256(nil), | ||||
| 					CodeHash: common.BytesToHash(ethcrypto.Keccak256(nil)).Hex(), | ||||
| 					Nonce:    0, | ||||
| 				} | ||||
| 				req = &types.QueryAccountRequest{ | ||||
| @ -245,7 +246,7 @@ func (suite *KeeperTestSuite) TestQueryStorage() { | ||||
| 				key := ethcmn.BytesToHash([]byte("key")) | ||||
| 				value := ethcmn.BytesToHash([]byte("value")) | ||||
| 				expValue = value.String() | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetState(suite.address, key, value) | ||||
| 				suite.app.EvmKeeper.SetState(suite.address, key, value) | ||||
| 				req = &types.QueryStorageRequest{ | ||||
| 					Address: suite.address.String(), | ||||
| 					Key:     key.String(), | ||||
| @ -300,7 +301,7 @@ func (suite *KeeperTestSuite) TestQueryCode() { | ||||
| 			"success", | ||||
| 			func() { | ||||
| 				expCode = []byte("code") | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetCode(suite.address, expCode) | ||||
| 				suite.app.EvmKeeper.SetCode(suite.address, expCode) | ||||
| 
 | ||||
| 				req = &types.QueryCodeRequest{ | ||||
| 					Address: suite.address.String(), | ||||
| @ -377,7 +378,7 @@ func (suite *KeeperTestSuite) TestQueryTxLogs() { | ||||
| 					}, | ||||
| 				} | ||||
| 
 | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetLogs(hash, types.LogsToEthereum(expLogs)) | ||||
| 				suite.app.EvmKeeper.SetLogs(hash, types.LogsToEthereum(expLogs)) | ||||
| 
 | ||||
| 				req = &types.QueryTxLogsRequest{ | ||||
| 					Hash: hash.String(), | ||||
| @ -486,8 +487,8 @@ func (suite *KeeperTestSuite) TestQueryBlockLogs() { | ||||
| 					}, | ||||
| 				} | ||||
| 
 | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetLogs(ethcmn.BytesToHash([]byte("tx_hash_0")), types.LogsToEthereum(expLogs[0].Logs)) | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetLogs(ethcmn.BytesToHash([]byte("tx_hash_1")), types.LogsToEthereum(expLogs[1].Logs)) | ||||
| 				suite.app.EvmKeeper.SetLogs(ethcmn.BytesToHash([]byte("tx_hash_0")), types.LogsToEthereum(expLogs[0].Logs)) | ||||
| 				suite.app.EvmKeeper.SetLogs(ethcmn.BytesToHash([]byte("tx_hash_1")), types.LogsToEthereum(expLogs[1].Logs)) | ||||
| 
 | ||||
| 				req = &types.QueryBlockLogsRequest{ | ||||
| 					Hash: hash.String(), | ||||
|  | ||||
| @ -1,105 +0,0 @@ | ||||
| package keeper | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||||
| 
 | ||||
| 	ethermint "github.com/cosmos/ethermint/types" | ||||
| 	"github.com/cosmos/ethermint/x/evm/types" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	balanceInvariant = "balance" | ||||
| 	nonceInvariant   = "nonce" | ||||
| ) | ||||
| 
 | ||||
| // RegisterInvariants registers the evm module invariants
 | ||||
| func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { | ||||
| 	ir.RegisterRoute(types.ModuleName, balanceInvariant, k.BalanceInvariant()) | ||||
| 	ir.RegisterRoute(types.ModuleName, nonceInvariant, k.NonceInvariant()) | ||||
| } | ||||
| 
 | ||||
| // BalanceInvariant checks that all auth module's EthAccounts in the application have the same balance
 | ||||
| // as the EVM one.
 | ||||
| func (k Keeper) BalanceInvariant() sdk.Invariant { | ||||
| 	return func(ctx sdk.Context) (string, bool) { | ||||
| 		var ( | ||||
| 			msg   string | ||||
| 			count int | ||||
| 		) | ||||
| 
 | ||||
| 		k.CommitStateDB.WithContext(ctx) | ||||
| 
 | ||||
| 		k.accountKeeper.IterateAccounts(ctx, func(account authtypes.AccountI) bool { | ||||
| 			ethAccount, ok := account.(*ethermint.EthAccount) | ||||
| 			if !ok { | ||||
| 				// ignore non EthAccounts
 | ||||
| 				return false | ||||
| 			} | ||||
| 
 | ||||
| 			evmDenom := k.GetParams(ctx).EvmDenom | ||||
| 
 | ||||
| 			accountBalance := k.bankKeeper.GetBalance(ctx, ethAccount.GetAddress(), evmDenom) | ||||
| 			evmBalance := k.CommitStateDB.GetBalance(ethAccount.EthAddress()) | ||||
| 
 | ||||
| 			if evmBalance.Cmp(accountBalance.Amount.BigInt()) != 0 { | ||||
| 				count++ | ||||
| 				msg += fmt.Sprintf( | ||||
| 					"\tbalance mismatch for address %s: account balance %s, evm balance %s\n", | ||||
| 					account.GetAddress(), accountBalance.String(), evmBalance.String(), | ||||
| 				) | ||||
| 			} | ||||
| 
 | ||||
| 			return false | ||||
| 		}) | ||||
| 
 | ||||
| 		broken := count != 0 | ||||
| 
 | ||||
| 		return sdk.FormatInvariant( | ||||
| 			types.ModuleName, balanceInvariant, | ||||
| 			fmt.Sprintf("account balances mismatches found %d\n%s", count, msg), | ||||
| 		), broken | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NonceInvariant checks that all auth module's EthAccounts in the application have the same nonce
 | ||||
| // sequence as the EVM.
 | ||||
| func (k Keeper) NonceInvariant() sdk.Invariant { | ||||
| 	return func(ctx sdk.Context) (string, bool) { | ||||
| 		var ( | ||||
| 			msg   string | ||||
| 			count int | ||||
| 		) | ||||
| 
 | ||||
| 		k.CommitStateDB.WithContext(ctx) | ||||
| 
 | ||||
| 		k.accountKeeper.IterateAccounts(ctx, func(account authtypes.AccountI) bool { | ||||
| 			ethAccount, ok := account.(*ethermint.EthAccount) | ||||
| 			if !ok { | ||||
| 				// ignore non EthAccounts
 | ||||
| 				return false | ||||
| 			} | ||||
| 
 | ||||
| 			evmNonce := k.CommitStateDB.GetNonce(ethAccount.EthAddress()) | ||||
| 
 | ||||
| 			if evmNonce != ethAccount.Sequence { | ||||
| 				count++ | ||||
| 				msg += fmt.Sprintf( | ||||
| 					"\nonce mismatch for address %s: account nonce %d, evm nonce %d\n", | ||||
| 					account.GetAddress(), ethAccount.Sequence, evmNonce, | ||||
| 				) | ||||
| 			} | ||||
| 
 | ||||
| 			return false | ||||
| 		}) | ||||
| 
 | ||||
| 		broken := count != 0 | ||||
| 
 | ||||
| 		return sdk.FormatInvariant( | ||||
| 			types.ModuleName, nonceInvariant, | ||||
| 			fmt.Sprintf("account nonces mismatches found %d\n%s", count, msg), | ||||
| 		), broken | ||||
| 	} | ||||
| } | ||||
| @ -1,138 +0,0 @@ | ||||
| package keeper_test | ||||
| 
 | ||||
| import ( | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||||
| 	"github.com/cosmos/ethermint/crypto/ethsecp256k1" | ||||
| 	ethermint "github.com/cosmos/ethermint/types" | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| func (suite *KeeperTestSuite) TestBalanceInvariant() { | ||||
| 	privkey, err := ethsecp256k1.GenerateKey() | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	address := ethcmn.HexToAddress(privkey.PubKey().Address().String()) | ||||
| 
 | ||||
| 	testCases := []struct { | ||||
| 		name      string | ||||
| 		malleate  func() | ||||
| 		expBroken bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"balance mismatch", | ||||
| 			func() { | ||||
| 				acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes()) | ||||
| 				suite.Require().NotNil(acc) | ||||
| 				suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewPhotonCoinInt64(1)) | ||||
| 				suite.Require().NoError(err) | ||||
| 				suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 
 | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetBalance(address, big.NewInt(1000)) | ||||
| 			}, | ||||
| 			true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"balance ok", | ||||
| 			func() { | ||||
| 				acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes()) | ||||
| 				suite.Require().NotNil(acc) | ||||
| 				suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewPhotonCoinInt64(1)) | ||||
| 				suite.Require().NoError(err) | ||||
| 				suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 
 | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetBalance(address, big.NewInt(1)) | ||||
| 			}, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"invalid account type", | ||||
| 			func() { | ||||
| 				acc := authtypes.NewBaseAccountWithAddress(address.Bytes()) | ||||
| 				suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 			}, | ||||
| 			false, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCases { | ||||
| 		suite.Run(tc.name, func() { | ||||
| 			suite.SetupTest() // reset values
 | ||||
| 
 | ||||
| 			suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx) | ||||
| 			tc.malleate() | ||||
| 
 | ||||
| 			_, broken := suite.app.EvmKeeper.BalanceInvariant()(suite.ctx) | ||||
| 			if tc.expBroken { | ||||
| 				suite.Require().True(broken) | ||||
| 			} else { | ||||
| 				suite.Require().False(broken) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *KeeperTestSuite) TestNonceInvariant() { | ||||
| 	privkey, err := ethsecp256k1.GenerateKey() | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	address := ethcmn.HexToAddress(privkey.PubKey().Address().String()) | ||||
| 
 | ||||
| 	testCases := []struct { | ||||
| 		name      string | ||||
| 		malleate  func() | ||||
| 		expBroken bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"nonce mismatch", | ||||
| 			func() { | ||||
| 				acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes()) | ||||
| 				suite.Require().NotNil(acc) | ||||
| 				err := acc.SetSequence(1) | ||||
| 				suite.Require().NoError(err) | ||||
| 				suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 
 | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetNonce(address, 100) | ||||
| 			}, | ||||
| 			true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"nonce ok", | ||||
| 			func() { | ||||
| 				acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes()) | ||||
| 				suite.Require().NotNil(acc) | ||||
| 				err := acc.SetSequence(1) | ||||
| 				suite.Require().NoError(err) | ||||
| 				suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 
 | ||||
| 				suite.app.EvmKeeper.CommitStateDB.SetNonce(address, 1) | ||||
| 			}, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"invalid account type", | ||||
| 			func() { | ||||
| 				acc := authtypes.NewBaseAccountWithAddress(address.Bytes()) | ||||
| 				suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 			}, | ||||
| 			false, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCases { | ||||
| 		suite.Run(tc.name, func() { | ||||
| 			suite.SetupTest() // reset values
 | ||||
| 
 | ||||
| 			suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx) | ||||
| 			tc.malleate() | ||||
| 
 | ||||
| 			_, broken := suite.app.EvmKeeper.NonceInvariant()(suite.ctx) | ||||
| 			if tc.expBroken { | ||||
| 				suite.Require().True(broken) | ||||
| 			} else { | ||||
| 				suite.Require().False(broken) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| @ -42,10 +42,6 @@ type Keeper struct { | ||||
| 	eip155ChainID *big.Int | ||||
| 	debug         bool | ||||
| 
 | ||||
| 	// TODO: deprecate
 | ||||
| 	// Ethermint concrete implementation on the EVM StateDB interface
 | ||||
| 	CommitStateDB *types.CommitStateDB | ||||
| 
 | ||||
| 	// hash header for the current height. Reset during abci.RequestBeginBlock
 | ||||
| 	headerHash common.Hash | ||||
| } | ||||
| @ -69,7 +65,6 @@ func NewKeeper( | ||||
| 		stakingKeeper: sk, | ||||
| 		storeKey:      storeKey, | ||||
| 		transientKey:  transientKey, | ||||
| 		CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, transientKey, paramSpace, ak, bankKeeper), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2,20 +2,15 @@ package keeper | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"math/big" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/armon/go-metrics" | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/core/vm" | ||||
| 
 | ||||
| 	tmbytes "github.com/tendermint/tendermint/libs/bytes" | ||||
| 	tmtypes "github.com/tendermint/tendermint/types" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/telemetry" | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||||
| 
 | ||||
| 	"github.com/cosmos/ethermint/x/evm/types" | ||||
| ) | ||||
| @ -26,17 +21,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t | ||||
| 	defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), types.TypeMsgEthereumTx) | ||||
| 
 | ||||
| 	ctx := sdk.UnwrapSDKContext(goCtx) | ||||
| 	k.CommitStateDB.WithContext(ctx) | ||||
| 
 | ||||
| 	ethMsg, err := msg.AsMessage() | ||||
| 	if err != nil { | ||||
| 		return nil, sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	config, found := k.GetChainConfig(ctx) | ||||
| 	if !found { | ||||
| 		return nil, types.ErrChainConfigNotFound | ||||
| 	} | ||||
| 	k.WithContext(ctx) | ||||
| 
 | ||||
| 	var labels []metrics.Label | ||||
| 	if msg.To() == nil { | ||||
| @ -46,62 +31,22 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t | ||||
| 	} else { | ||||
| 		labels = []metrics.Label{ | ||||
| 			telemetry.NewLabel("execution", "call"), | ||||
| 			// add label to the called recipient address (contract or account)
 | ||||
| 			telemetry.NewLabel("to", msg.Data.To), | ||||
| 			telemetry.NewLabel("to", msg.Data.To), // recipient address (contract or account)
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	sender := ethMsg.From() | ||||
| 	sender := msg.From | ||||
| 	tx := msg.AsTransaction() | ||||
| 
 | ||||
| 	txHash := tmtypes.Tx(ctx.TxBytes()).Hash() | ||||
| 	ethHash := ethcmn.BytesToHash(txHash) | ||||
| 
 | ||||
| 	// Ethereum formatted tx hash
 | ||||
| 	etherumTxHash := msg.AsTransaction().Hash() | ||||
| 
 | ||||
| 	st := &types.StateTransition{ | ||||
| 		Message:  ethMsg, | ||||
| 		Csdb:     k.CommitStateDB.WithContext(ctx), | ||||
| 		ChainID:  msg.ChainID(), | ||||
| 		TxHash:   ðHash, | ||||
| 		Simulate: ctx.IsCheckTx(), | ||||
| 	} | ||||
| 
 | ||||
| 	// since the txCount is used by the stateDB, and a simulated tx is run only on the node it's submitted to,
 | ||||
| 	// then this will cause the txCount/stateDB of the node that ran the simulated tx to be different than the
 | ||||
| 	// other nodes, causing a consensus error
 | ||||
| 	if !st.Simulate { | ||||
| 		// Prepare db for logs
 | ||||
| 		k.CommitStateDB.Prepare(ethHash, k.headerHash, int(k.GetTxIndexTransient())) | ||||
| 		k.IncreaseTxIndexTransient() | ||||
| 	} | ||||
| 
 | ||||
| 	executionResult, err := st.TransitionDb(ctx, config) | ||||
| 	response, err := k.ApplyTransaction(tx) | ||||
| 	if err != nil { | ||||
| 		if errors.Is(err, vm.ErrExecutionReverted) && executionResult != nil { | ||||
| 			// keep the execution result for revert reason
 | ||||
| 			executionResult.Response.Reverted = true | ||||
| 			return executionResult.Response, nil | ||||
| 		} | ||||
| 
 | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if !st.Simulate { | ||||
| 		bloom, found := k.GetBlockBloomTransient() | ||||
| 		if !found { | ||||
| 			bloom = big.NewInt(0) | ||||
| 		} | ||||
| 		// update block bloom filter
 | ||||
| 		logsBloom := ethtypes.LogsBloom(executionResult.Logs) | ||||
| 		bloom = bloom.Or(bloom, new(big.Int).SetBytes(logsBloom)) | ||||
| 		k.SetBlockBloomTransient(bloom) | ||||
| 	} | ||||
| 
 | ||||
| 	defer func() { | ||||
| 		if st.Message.Value().IsInt64() { | ||||
| 		if tx.Value().IsInt64() { | ||||
| 			telemetry.SetGauge( | ||||
| 				float32(st.Message.Value().Int64()), | ||||
| 				float32(tx.Value().Int64()), | ||||
| 				"tx", "msg", "ethereum_tx", | ||||
| 			) | ||||
| 		} | ||||
| @ -114,9 +59,15 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t | ||||
| 	}() | ||||
| 
 | ||||
| 	attrs := []sdk.Attribute{ | ||||
| 		sdk.NewAttribute(sdk.AttributeKeyAmount, st.Message.Value().String()), | ||||
| 		sdk.NewAttribute(types.AttributeKeyTxHash, ethcmn.BytesToHash(txHash).Hex()), | ||||
| 		sdk.NewAttribute(types.AttributeKeyEthereumTxHash, etherumTxHash.Hex()), | ||||
| 		sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()), | ||||
| 		// add event for ethereum transaction hash format
 | ||||
| 		sdk.NewAttribute(types.AttributeKeyEthereumTxHash, response.Hash), | ||||
| 	} | ||||
| 
 | ||||
| 	if len(ctx.TxBytes()) > 0 { | ||||
| 		// add event for tendermint transaction hash format
 | ||||
| 		hash := tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()) | ||||
| 		attrs = append(attrs, sdk.NewAttribute(types.AttributeKeyTxHash, hash.String())) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(msg.Data.To) > 0 { | ||||
| @ -132,10 +83,9 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t | ||||
| 		sdk.NewEvent( | ||||
| 			sdk.EventTypeMessage, | ||||
| 			sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), | ||||
| 			sdk.NewAttribute(sdk.AttributeKeySender, sender.String()), | ||||
| 			sdk.NewAttribute(sdk.AttributeKeySender, sender), | ||||
| 		), | ||||
| 	}) | ||||
| 
 | ||||
| 	executionResult.Response.Hash = etherumTxHash.Hex() | ||||
| 	return executionResult.Response, nil | ||||
| 	return response, nil | ||||
| } | ||||
|  | ||||
| @ -18,6 +18,7 @@ import ( | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/core/vm" | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| ) | ||||
| @ -91,7 +92,7 @@ func (k Keeper) GetHashFn() vm.GetHashFunc { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // TransitionDb runs and attempts to perform a state transition with the given transaction (i.e Message), that will
 | ||||
| // ApplyTransaction runs and attempts to perform a state transition with the given transaction (i.e Message), that will
 | ||||
| // only be persisted to the underlying KVStore if the transaction does not error.
 | ||||
| //
 | ||||
| // Gas tracking
 | ||||
| @ -108,23 +109,39 @@ func (k Keeper) GetHashFn() vm.GetHashFunc { | ||||
| // returning.
 | ||||
| //
 | ||||
| // For relevant discussion see: https://github.com/cosmos/cosmos-sdk/discussions/9072
 | ||||
| func (k *Keeper) TransitionDb(msg core.Message) (*types.ExecutionResult, error) { | ||||
| func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumTxResponse, error) { | ||||
| 	defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), types.MetricKeyTransitionDB) | ||||
| 
 | ||||
| 	cfg, found := k.GetChainConfig(k.ctx) | ||||
| 	gasMeter := k.ctx.GasMeter() // tx gas meter
 | ||||
| 	infCtx := k.ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) | ||||
| 
 | ||||
| 	cfg, found := k.GetChainConfig(infCtx) | ||||
| 	if !found { | ||||
| 		return nil, types.ErrChainConfigNotFound | ||||
| 	} | ||||
| 	ethCfg := cfg.EthereumConfig(k.eip155ChainID) | ||||
| 
 | ||||
| 	evm := k.NewEVM(msg, cfg.EthereumConfig(k.eip155ChainID)) | ||||
| 
 | ||||
| 	// create an ethereum StateTransition instance and run TransitionDb
 | ||||
| 	result, err := k.ApplyMessage(evm, msg) | ||||
| 	msg, err := tx.AsMessage(ethtypes.MakeSigner(ethCfg, big.NewInt(k.ctx.BlockHeight()))) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return result, nil | ||||
| 	evm := k.NewEVM(msg, ethCfg) | ||||
| 
 | ||||
| 	k.IncreaseTxIndexTransient() | ||||
| 
 | ||||
| 	k.WithContext(k.ctx.WithGasMeter(gasMeter)) | ||||
| 	// create an ethereum StateTransition instance and run TransitionDb
 | ||||
| 	res, err := k.ApplyMessage(evm, msg, ethCfg) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	txHash := tx.Hash() | ||||
| 	res.Hash = txHash.Hex() | ||||
| 	res.Logs = types.NewLogsFromEth(k.GetTxLogs(txHash)) | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // Gas consumption notes (write doc from this)
 | ||||
| @ -143,10 +160,10 @@ func (k *Keeper) TransitionDb(msg core.Message) (*types.ExecutionResult, error) | ||||
| // TODO: (@fedekunze) currently we consume the entire gas limit in the ante handler, so if a transaction fails
 | ||||
| // the amount spent will be grater than the gas spent in an Ethereum tx (i.e here the leftover gas won't be refunded).
 | ||||
| 
 | ||||
| func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message) (*types.ExecutionResult, error) { | ||||
| func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainConfig) (*types.MsgEthereumTxResponse, error) { | ||||
| 	var ( | ||||
| 		ret        []byte // return bytes from evm execution
 | ||||
| 		vmErr, err error  // vm errors do not effect consensus and are therefore not assigned to err
 | ||||
| 		ret   []byte // return bytes from evm execution
 | ||||
| 		vmErr error  // vm errors do not effect consensus and are therefore not assigned to err
 | ||||
| 	) | ||||
| 
 | ||||
| 	sender := vm.AccountRef(msg.From()) | ||||
| @ -166,7 +183,7 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message) (*types.ExecutionRe | ||||
| 
 | ||||
| 	// ensure gas is consistent during CheckTx
 | ||||
| 	if k.ctx.IsCheckTx() { | ||||
| 		if err := k.checkGasConsumption(msg, gasConsumed, contractCreation); err != nil { | ||||
| 		if err := k.CheckGasConsumption(msg, cfg, gasConsumed, contractCreation); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| @ -178,8 +195,7 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message) (*types.ExecutionRe | ||||
| 	} | ||||
| 
 | ||||
| 	// refund gas prior to handling the vm error in order to set the updated gas meter
 | ||||
| 	gasConsumed, leftoverGas, err = k.refundGas(msg, leftoverGas) | ||||
| 	if err != nil { | ||||
| 	if err := k.RefundGas(msg, leftoverGas); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| @ -193,26 +209,17 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message) (*types.ExecutionRe | ||||
| 		return nil, sdkerrors.Wrap(types.ErrVMExecution, vmErr.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	return &types.ExecutionResult{ | ||||
| 		Response: &types.MsgEthereumTxResponse{ | ||||
| 			Ret: ret, | ||||
| 		}, | ||||
| 		GasInfo: types.GasInfo{ | ||||
| 			GasLimit:    k.ctx.GasMeter().Limit(), | ||||
| 			GasConsumed: gasConsumed, | ||||
| 			GasRefunded: leftoverGas, | ||||
| 		}, | ||||
| 	return &types.MsgEthereumTxResponse{ | ||||
| 		Ret:      ret, | ||||
| 		Reverted: false, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // checkGasConsumption verifies that the amount of gas consumed so far matches the intrinsic gas value.
 | ||||
| func (k *Keeper) checkGasConsumption(msg core.Message, gasConsumed uint64, isContractCreation bool) error { | ||||
| 	cfg, _ := k.GetChainConfig(k.ctx) | ||||
| 	ethCfg := cfg.EthereumConfig(k.eip155ChainID) | ||||
| 
 | ||||
| // CheckGasConsumption verifies that the amount of gas consumed so far matches the intrinsic gas value.
 | ||||
| func (k *Keeper) CheckGasConsumption(msg core.Message, cfg *params.ChainConfig, gasConsumed uint64, isContractCreation bool) error { | ||||
| 	height := big.NewInt(k.ctx.BlockHeight()) | ||||
| 	homestead := ethCfg.IsHomestead(height) | ||||
| 	istanbul := ethCfg.IsIstanbul(height) | ||||
| 	homestead := cfg.IsHomestead(height) | ||||
| 	istanbul := cfg.IsIstanbul(height) | ||||
| 
 | ||||
| 	intrinsicGas, err := core.IntrinsicGas(msg.Data(), msg.AccessList(), isContractCreation, homestead, istanbul) | ||||
| 	if err != nil { | ||||
| @ -227,11 +234,11 @@ func (k *Keeper) checkGasConsumption(msg core.Message, gasConsumed uint64, isCon | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // refundGas transfers the leftover gas to the sender of the message, caped to half of the total gas
 | ||||
| // RefundGas transfers the leftover gas to the sender of the message, caped to half of the total gas
 | ||||
| // consumed in the transaction. Additionally, the function sets the total gas consumed to the value
 | ||||
| // returned by the EVM execution, thus ignoring the previous intrinsic gas inconsumed during in the
 | ||||
| // AnteHandler.
 | ||||
| func (k *Keeper) refundGas(msg core.Message, leftoverGas uint64) (consumed, leftover uint64, err error) { | ||||
| func (k *Keeper) RefundGas(msg core.Message, leftoverGas uint64) error { | ||||
| 	gasConsumed := msg.Gas() - leftoverGas | ||||
| 
 | ||||
| 	// Apply refund counter, capped to half of the used gas.
 | ||||
| @ -246,18 +253,21 @@ func (k *Keeper) refundGas(msg core.Message, leftoverGas uint64) (consumed, left | ||||
| 	// Return EVM tokens for remaining gas, exchanged at the original rate.
 | ||||
| 	remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice()) | ||||
| 
 | ||||
| 	// ignore gas consumption
 | ||||
| 	infCtx := k.ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) | ||||
| 
 | ||||
| 	switch remaining.Sign() { | ||||
| 	case -1: | ||||
| 		// negative refund errors
 | ||||
| 		return 0, 0, fmt.Errorf("refunded amount value cannot be negative %d", remaining.Int64()) | ||||
| 		return fmt.Errorf("refunded amount value cannot be negative %d", remaining.Int64()) | ||||
| 	case 1: | ||||
| 		// positive amount refund
 | ||||
| 		params := k.GetParams(k.ctx) | ||||
| 		params := k.GetParams(infCtx) | ||||
| 		refundedCoins := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(remaining))} | ||||
| 
 | ||||
| 		// refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees
 | ||||
| 		if err := k.bankKeeper.SendCoinsFromModuleToAccount(k.ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins); err != nil { | ||||
| 			return 0, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error()) | ||||
| 		if err := k.bankKeeper.SendCoinsFromModuleToAccount(infCtx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins); err != nil { | ||||
| 			return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error()) | ||||
| 		} | ||||
| 	default: | ||||
| 		// no refund, consume gas and update the tx gas meter
 | ||||
| @ -270,5 +280,5 @@ func (k *Keeper) refundGas(msg core.Message, leftoverGas uint64) (consumed, left | ||||
| 	gasMeter.ConsumeGas(gasConsumed, "update gas consumption after refund") | ||||
| 	k.WithContext(k.ctx.WithGasMeter(gasMeter)) | ||||
| 
 | ||||
| 	return gasConsumed, leftoverGas, nil | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -88,16 +88,14 @@ type AppModule struct { | ||||
| 	AppModuleBasic | ||||
| 	keeper *keeper.Keeper | ||||
| 	ak     types.AccountKeeper | ||||
| 	bk     types.BankKeeper | ||||
| } | ||||
| 
 | ||||
| // NewAppModule creates a new AppModule object
 | ||||
| func NewAppModule(k *keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper) AppModule { | ||||
| func NewAppModule(k *keeper.Keeper, ak types.AccountKeeper) AppModule { | ||||
| 	return AppModule{ | ||||
| 		AppModuleBasic: AppModuleBasic{}, | ||||
| 		keeper:         k, | ||||
| 		ak:             ak, | ||||
| 		bk:             bk, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -151,7 +149,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j | ||||
| 	var genesisState types.GenesisState | ||||
| 
 | ||||
| 	cdc.MustUnmarshalJSON(data, &genesisState) | ||||
| 	InitGenesis(ctx, am.keeper, am.ak, am.bk, genesisState) | ||||
| 	InitGenesis(ctx, am.keeper, am.ak, genesisState) | ||||
| 	return []abci.ValidatorUpdate{} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,348 +0,0 @@ | ||||
| package types | ||||
| 
 | ||||
| import ( | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 
 | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| var ripemd = ethcmn.HexToAddress("0000000000000000000000000000000000000003") | ||||
| 
 | ||||
| // journalEntry is a modification entry in the state change journal that can be
 | ||||
| // reverted on demand.
 | ||||
| type journalEntry interface { | ||||
| 	// revert undoes the changes introduced by this journal entry.
 | ||||
| 	revert(*CommitStateDB) | ||||
| 
 | ||||
| 	// dirtied returns the Ethereum address modified by this journal entry.
 | ||||
| 	dirtied() *ethcmn.Address | ||||
| } | ||||
| 
 | ||||
| type revision struct { | ||||
| 	id           int | ||||
| 	journalIndex int | ||||
| } | ||||
| 
 | ||||
| // journal contains the list of state modifications applied since the last state
 | ||||
| // commit. These are tracked to be able to be reverted in case of an execution
 | ||||
| // exception or revertal request.
 | ||||
| type journal struct { | ||||
| 	entries               []journalEntry         // Current changes tracked by the journal
 | ||||
| 	dirties               []dirty                // Dirty accounts and the number of changes
 | ||||
| 	addressToJournalIndex map[ethcmn.Address]int // map from address to the index of the dirties slice
 | ||||
| } | ||||
| 
 | ||||
| // dirty represents a single key value pair of the journal dirties, where the
 | ||||
| // key correspons to the account address and the value to the number of
 | ||||
| // changes for that account.
 | ||||
| type dirty struct { | ||||
| 	address ethcmn.Address | ||||
| 	changes int | ||||
| } | ||||
| 
 | ||||
| // newJournal create a new initialized journal.
 | ||||
| func newJournal() *journal { | ||||
| 	return &journal{ | ||||
| 		dirties:               []dirty{}, | ||||
| 		addressToJournalIndex: make(map[ethcmn.Address]int), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // append inserts a new modification entry to the end of the change journal.
 | ||||
| func (j *journal) append(entry journalEntry) { | ||||
| 	j.entries = append(j.entries, entry) | ||||
| 	if addr := entry.dirtied(); addr != nil { | ||||
| 		j.addDirty(*addr) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // revert undoes a batch of journalled modifications along with any reverted
 | ||||
| // dirty handling too.
 | ||||
| func (j *journal) revert(statedb *CommitStateDB, snapshot int) { | ||||
| 	for i := len(j.entries) - 1; i >= snapshot; i-- { | ||||
| 		// Undo the changes made by the operation
 | ||||
| 		j.entries[i].revert(statedb) | ||||
| 
 | ||||
| 		// Drop any dirty tracking induced by the change
 | ||||
| 		if addr := j.entries[i].dirtied(); addr != nil { | ||||
| 			j.substractDirty(*addr) | ||||
| 			if j.getDirty(*addr) == 0 { | ||||
| 				j.deleteDirty(*addr) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	j.entries = j.entries[:snapshot] | ||||
| } | ||||
| 
 | ||||
| // dirty explicitly sets an address to dirty, even if the change entries would
 | ||||
| // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
 | ||||
| // precompile consensus exception.
 | ||||
| func (j *journal) dirty(addr ethcmn.Address) { | ||||
| 	j.addDirty(addr) | ||||
| } | ||||
| 
 | ||||
| // length returns the current number of entries in the journal.
 | ||||
| func (j *journal) length() int { | ||||
| 	return len(j.entries) | ||||
| } | ||||
| 
 | ||||
| // getDirty returns the dirty count for a given address. If the address is not
 | ||||
| // found it returns 0.
 | ||||
| func (j *journal) getDirty(addr ethcmn.Address) int { | ||||
| 	idx, found := j.addressToJournalIndex[addr] | ||||
| 	if !found { | ||||
| 		return 0 | ||||
| 	} | ||||
| 
 | ||||
| 	return j.dirties[idx].changes | ||||
| } | ||||
| 
 | ||||
| // addDirty adds 1 to the dirty count of an address. If the dirty entry is not
 | ||||
| // found it creates it.
 | ||||
| func (j *journal) addDirty(addr ethcmn.Address) { | ||||
| 	idx, found := j.addressToJournalIndex[addr] | ||||
| 	if !found { | ||||
| 		j.dirties = append(j.dirties, dirty{address: addr, changes: 0}) | ||||
| 		idx = len(j.dirties) - 1 | ||||
| 		j.addressToJournalIndex[addr] = idx | ||||
| 	} | ||||
| 
 | ||||
| 	j.dirties[idx].changes++ | ||||
| } | ||||
| 
 | ||||
| // substractDirty subtracts 1 to the dirty count of an address. It performs a
 | ||||
| // no-op if the address is not found.
 | ||||
| func (j *journal) substractDirty(addr ethcmn.Address) { | ||||
| 	idx, found := j.addressToJournalIndex[addr] | ||||
| 	if !found { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if j.dirties[idx].changes == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	j.dirties[idx].changes-- | ||||
| } | ||||
| 
 | ||||
| // deleteDirty deletes a dirty entry from the jounal's dirties slice. If the
 | ||||
| // entry is not found it performs a no-op.
 | ||||
| func (j *journal) deleteDirty(addr ethcmn.Address) { | ||||
| 	idx, found := j.addressToJournalIndex[addr] | ||||
| 	if !found { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	j.dirties = append(j.dirties[:idx], j.dirties[idx+1:]...) | ||||
| 	delete(j.addressToJournalIndex, addr) | ||||
| } | ||||
| 
 | ||||
| type ( | ||||
| 	// Changes to the account trie.
 | ||||
| 	createObjectChange struct { | ||||
| 		account *ethcmn.Address | ||||
| 	} | ||||
| 
 | ||||
| 	resetObjectChange struct { | ||||
| 		prev *stateObject | ||||
| 	} | ||||
| 
 | ||||
| 	suicideChange struct { | ||||
| 		account     *ethcmn.Address | ||||
| 		prev        bool // whether account had already suicided
 | ||||
| 		prevBalance sdk.Int | ||||
| 	} | ||||
| 
 | ||||
| 	// Changes to individual accounts.
 | ||||
| 	balanceChange struct { | ||||
| 		account *ethcmn.Address | ||||
| 		prev    sdk.Int | ||||
| 	} | ||||
| 
 | ||||
| 	nonceChange struct { | ||||
| 		account *ethcmn.Address | ||||
| 		prev    uint64 | ||||
| 	} | ||||
| 
 | ||||
| 	storageChange struct { | ||||
| 		account        *ethcmn.Address | ||||
| 		key, prevValue ethcmn.Hash | ||||
| 	} | ||||
| 
 | ||||
| 	codeChange struct { | ||||
| 		account            *ethcmn.Address | ||||
| 		prevCode, prevHash []byte | ||||
| 	} | ||||
| 
 | ||||
| 	// Changes to other state values.
 | ||||
| 	refundChange struct { | ||||
| 		prev uint64 | ||||
| 	} | ||||
| 
 | ||||
| 	addLogChange struct { | ||||
| 		txhash ethcmn.Hash | ||||
| 	} | ||||
| 
 | ||||
| 	addPreimageChange struct { | ||||
| 		hash ethcmn.Hash | ||||
| 	} | ||||
| 
 | ||||
| 	touchChange struct { | ||||
| 		account *ethcmn.Address | ||||
| 		// prev      bool
 | ||||
| 		// prevDirty bool
 | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| func (ch createObjectChange) revert(s *CommitStateDB) { | ||||
| 	delete(s.stateObjectsDirty, *ch.account) | ||||
| 
 | ||||
| 	idx, exists := s.addressToObjectIndex[*ch.account] | ||||
| 	if !exists { | ||||
| 		// perform no-op
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// remove from the slice
 | ||||
| 	delete(s.addressToObjectIndex, *ch.account) | ||||
| 
 | ||||
| 	// if the slice contains one element, delete it
 | ||||
| 	if len(s.stateObjects) == 1 { | ||||
| 		s.stateObjects = []stateEntry{} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// move the elements one position left on the array
 | ||||
| 	for i := idx + 1; i < len(s.stateObjects); i++ { | ||||
| 		s.stateObjects[i-1] = s.stateObjects[i] | ||||
| 		// the new index is i - 1
 | ||||
| 		s.addressToObjectIndex[s.stateObjects[i].address] = i - 1 | ||||
| 	} | ||||
| 
 | ||||
| 	//  finally, delete the last element of the slice to account for the removed object
 | ||||
| 	s.stateObjects = s.stateObjects[:len(s.stateObjects)-1] | ||||
| } | ||||
| 
 | ||||
| func (ch createObjectChange) dirtied() *ethcmn.Address { | ||||
| 	return ch.account | ||||
| } | ||||
| 
 | ||||
| func (ch resetObjectChange) revert(s *CommitStateDB) { | ||||
| 	s.setStateObject(ch.prev) | ||||
| } | ||||
| 
 | ||||
| func (ch resetObjectChange) dirtied() *ethcmn.Address { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (ch suicideChange) revert(s *CommitStateDB) { | ||||
| 	so := s.getStateObject(*ch.account) | ||||
| 	if so != nil { | ||||
| 		so.suicided = ch.prev | ||||
| 		so.setBalance(ch.prevBalance) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ch suicideChange) dirtied() *ethcmn.Address { | ||||
| 	return ch.account | ||||
| } | ||||
| 
 | ||||
| func (ch touchChange) revert(s *CommitStateDB) { | ||||
| } | ||||
| 
 | ||||
| func (ch touchChange) dirtied() *ethcmn.Address { | ||||
| 	return ch.account | ||||
| } | ||||
| 
 | ||||
| func (ch balanceChange) revert(s *CommitStateDB) { | ||||
| 	s.getStateObject(*ch.account).setBalance(ch.prev) | ||||
| } | ||||
| 
 | ||||
| func (ch balanceChange) dirtied() *ethcmn.Address { | ||||
| 	return ch.account | ||||
| } | ||||
| 
 | ||||
| func (ch nonceChange) revert(s *CommitStateDB) { | ||||
| 	s.getStateObject(*ch.account).setNonce(ch.prev) | ||||
| } | ||||
| 
 | ||||
| func (ch nonceChange) dirtied() *ethcmn.Address { | ||||
| 	return ch.account | ||||
| } | ||||
| 
 | ||||
| func (ch codeChange) revert(s *CommitStateDB) { | ||||
| 	s.getStateObject(*ch.account).setCode(ethcmn.BytesToHash(ch.prevHash), ch.prevCode) | ||||
| } | ||||
| 
 | ||||
| func (ch codeChange) dirtied() *ethcmn.Address { | ||||
| 	return ch.account | ||||
| } | ||||
| 
 | ||||
| func (ch storageChange) revert(s *CommitStateDB) { | ||||
| 	s.getStateObject(*ch.account).setState(ch.key, ch.prevValue) | ||||
| } | ||||
| 
 | ||||
| func (ch storageChange) dirtied() *ethcmn.Address { | ||||
| 	return ch.account | ||||
| } | ||||
| 
 | ||||
| func (ch refundChange) revert(s *CommitStateDB) { | ||||
| 	s.refund = ch.prev | ||||
| } | ||||
| 
 | ||||
| func (ch refundChange) dirtied() *ethcmn.Address { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (ch addLogChange) revert(s *CommitStateDB) { | ||||
| 	logs, err := s.GetLogs(ch.txhash) | ||||
| 	if err != nil { | ||||
| 		// panic on unmarshal error
 | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// delete logs if entry is empty or has only one item
 | ||||
| 	if len(logs) <= 1 { | ||||
| 		s.DeleteLogs(ch.txhash) | ||||
| 	} else if err := s.SetLogs(ch.txhash, logs[:len(logs)-1]); err != nil { | ||||
| 		// panic on marshal error
 | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	s.logSize-- | ||||
| } | ||||
| 
 | ||||
| func (ch addLogChange) dirtied() *ethcmn.Address { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (ch addPreimageChange) revert(s *CommitStateDB) { | ||||
| 	idx, exists := s.hashToPreimageIndex[ch.hash] | ||||
| 	if !exists { | ||||
| 		// perform no-op
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// remove from the slice
 | ||||
| 	delete(s.hashToPreimageIndex, ch.hash) | ||||
| 
 | ||||
| 	// if the slice contains one element, delete it
 | ||||
| 	if len(s.preimages) == 1 { | ||||
| 		s.preimages = []preimageEntry{} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// move the elements one position left on the array
 | ||||
| 	for i := idx + 1; i < len(s.preimages); i++ { | ||||
| 		s.preimages[i-1] = s.preimages[i] | ||||
| 		// the new index is i - 1
 | ||||
| 		s.hashToPreimageIndex[s.preimages[i].hash] = i - 1 | ||||
| 	} | ||||
| 
 | ||||
| 	//  finally, delete the last element
 | ||||
| 
 | ||||
| 	s.preimages = s.preimages[:len(s.preimages)-1] | ||||
| } | ||||
| 
 | ||||
| func (ch addPreimageChange) dirtied() *ethcmn.Address { | ||||
| 	return nil | ||||
| } | ||||
| @ -1,354 +0,0 @@ | ||||
| package types | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/cosmos/ethermint/crypto/ethsecp256k1" | ||||
| 	enccodec "github.com/cosmos/ethermint/encoding/codec" | ||||
| 	ethermint "github.com/cosmos/ethermint/types" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/suite" | ||||
| 
 | ||||
| 	tmlog "github.com/tendermint/tendermint/libs/log" | ||||
| 	tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||||
| 	tmdb "github.com/tendermint/tm-db" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/store" | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" | ||||
| 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||||
| 	bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" | ||||
| 	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||||
| 	paramkeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" | ||||
| 	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" | ||||
| 
 | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	ethcrypto "github.com/ethereum/go-ethereum/crypto" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/codec" | ||||
| 	codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||||
| ) | ||||
| 
 | ||||
| func newTestCodec() (codec.BinaryMarshaler, *codec.LegacyAmino) { | ||||
| 	interfaceRegistry := codectypes.NewInterfaceRegistry() | ||||
| 	cdc := codec.NewProtoCodec(interfaceRegistry) | ||||
| 	amino := codec.NewLegacyAmino() | ||||
| 
 | ||||
| 	sdk.RegisterLegacyAminoCodec(amino) | ||||
| 
 | ||||
| 	enccodec.RegisterInterfaces(interfaceRegistry) | ||||
| 
 | ||||
| 	return cdc, amino | ||||
| } | ||||
| 
 | ||||
| type JournalTestSuite struct { | ||||
| 	suite.Suite | ||||
| 
 | ||||
| 	address ethcmn.Address | ||||
| 	journal *journal | ||||
| 	ctx     sdk.Context | ||||
| 	stateDB *CommitStateDB | ||||
| } | ||||
| 
 | ||||
| func (suite *JournalTestSuite) SetupTest() { | ||||
| 	suite.setup() | ||||
| 
 | ||||
| 	privkey, err := ethsecp256k1.GenerateKey() | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	suite.address = ethcmn.BytesToAddress(privkey.PubKey().Address().Bytes()) | ||||
| 	suite.journal = newJournal() | ||||
| 
 | ||||
| 	balance := ethermint.NewPhotonCoin(sdk.NewInt(100)) | ||||
| 	acc := ðermint.EthAccount{ | ||||
| 		BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0), | ||||
| 		CodeHash:    ethcrypto.Keccak256(nil), | ||||
| 	} | ||||
| 
 | ||||
| 	suite.stateDB.accountKeeper.SetAccount(suite.ctx, acc) | ||||
| 	suite.stateDB.bankKeeper.SetBalance(suite.ctx, sdk.AccAddress(suite.address.Bytes()), balance) | ||||
| 	suite.stateDB.SetLogs(ethcmn.BytesToHash([]byte("txhash")), []*ethtypes.Log{ | ||||
| 		{ | ||||
| 			Address:     suite.address, | ||||
| 			Topics:      []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic_0"))}, | ||||
| 			Data:        []byte("data_0"), | ||||
| 			BlockNumber: 1, | ||||
| 			TxHash:      ethcmn.BytesToHash([]byte("tx_hash")), | ||||
| 			TxIndex:     1, | ||||
| 			BlockHash:   ethcmn.BytesToHash([]byte("block_hash")), | ||||
| 			Index:       1, | ||||
| 			Removed:     false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Address:     suite.address, | ||||
| 			Topics:      []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic_1"))}, | ||||
| 			Data:        []byte("data_1"), | ||||
| 			BlockNumber: 10, | ||||
| 			TxHash:      ethcmn.BytesToHash([]byte("tx_hash")), | ||||
| 			TxIndex:     0, | ||||
| 			BlockHash:   ethcmn.BytesToHash([]byte("block_hash")), | ||||
| 			Index:       0, | ||||
| 			Removed:     false, | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // setup performs a manual setup of the GoLevelDB and mounts the required IAVL stores. We use the manual
 | ||||
| // setup here instead of the Ethermint app test setup because the journal methods are private and using
 | ||||
| // the latter would result in a cycle dependency. We also want to avoid declaring the journal methods public
 | ||||
| // to maintain consistency with the Geth implementation.
 | ||||
| func (suite *JournalTestSuite) setup() { | ||||
| 	authKey := sdk.NewKVStoreKey(authtypes.StoreKey) | ||||
| 	paramsKey := sdk.NewKVStoreKey(paramtypes.StoreKey) | ||||
| 	paramsTKey := sdk.NewTransientStoreKey(paramtypes.TStoreKey) | ||||
| 	tKey := sdk.NewTransientStoreKey(TransientKey) | ||||
| 	bankKey := sdk.NewKVStoreKey(banktypes.StoreKey) | ||||
| 	storeKey := sdk.NewKVStoreKey(StoreKey) | ||||
| 
 | ||||
| 	db, err := tmdb.NewDB("state", tmdb.GoLevelDBBackend, "temp") | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	defer func() { | ||||
| 		os.RemoveAll("temp") | ||||
| 	}() | ||||
| 
 | ||||
| 	cms := store.NewCommitMultiStore(db) | ||||
| 	cms.MountStoreWithDB(authKey, sdk.StoreTypeIAVL, db) | ||||
| 	cms.MountStoreWithDB(bankKey, sdk.StoreTypeIAVL, db) | ||||
| 	cms.MountStoreWithDB(paramsKey, sdk.StoreTypeIAVL, db) | ||||
| 	cms.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) | ||||
| 	cms.MountStoreWithDB(paramsTKey, sdk.StoreTypeTransient, db) | ||||
| 	cms.MountStoreWithDB(tKey, sdk.StoreTypeTransient, db) | ||||
| 
 | ||||
| 	err = cms.LoadLatestVersion() | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	cdc, amino := newTestCodec() | ||||
| 
 | ||||
| 	paramsKeeper := paramkeeper.NewKeeper(cdc, amino, paramsKey, paramsTKey) | ||||
| 
 | ||||
| 	authSubspace := paramsKeeper.Subspace(authtypes.ModuleName) | ||||
| 	bankSubspace := paramsKeeper.Subspace(banktypes.ModuleName) | ||||
| 	evmSubspace := paramsKeeper.Subspace(ModuleName).WithKeyTable(ParamKeyTable()) | ||||
| 
 | ||||
| 	ak := authkeeper.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount, nil) | ||||
| 	bk := bankkeeper.NewBaseKeeper(cdc, bankKey, ak, bankSubspace, nil) | ||||
| 	suite.ctx = sdk.NewContext(cms, tmproto.Header{ChainID: "ethermint-8"}, false, tmlog.NewNopLogger()) | ||||
| 	suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, tKey, evmSubspace, ak, bk).WithContext(suite.ctx) | ||||
| 	suite.stateDB.SetParams(DefaultParams()) | ||||
| } | ||||
| 
 | ||||
| func TestJournalTestSuite(t *testing.T) { | ||||
| 	suite.Run(t, new(JournalTestSuite)) | ||||
| } | ||||
| 
 | ||||
| func (suite *JournalTestSuite) TestJournal_append_revert() { | ||||
| 	testCases := []struct { | ||||
| 		name  string | ||||
| 		entry journalEntry | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"createObjectChange", | ||||
| 			createObjectChange{ | ||||
| 				account: &suite.address, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"resetObjectChange", | ||||
| 			resetObjectChange{ | ||||
| 				prev: &stateObject{ | ||||
| 					address: suite.address, | ||||
| 					balance: sdk.OneInt(), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"suicideChange", | ||||
| 			suicideChange{ | ||||
| 				account:     &suite.address, | ||||
| 				prev:        false, | ||||
| 				prevBalance: sdk.OneInt(), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"balanceChange", | ||||
| 			balanceChange{ | ||||
| 				account: &suite.address, | ||||
| 				prev:    sdk.OneInt(), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"nonceChange", | ||||
| 			nonceChange{ | ||||
| 				account: &suite.address, | ||||
| 				prev:    1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"storageChange", | ||||
| 			storageChange{ | ||||
| 				account:   &suite.address, | ||||
| 				key:       ethcmn.BytesToHash([]byte("key")), | ||||
| 				prevValue: ethcmn.BytesToHash([]byte("value")), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"codeChange", | ||||
| 			codeChange{ | ||||
| 				account:  &suite.address, | ||||
| 				prevCode: []byte("code"), | ||||
| 				prevHash: []byte("hash"), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"touchChange", | ||||
| 			touchChange{ | ||||
| 				account: &suite.address, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"refundChange", | ||||
| 			refundChange{ | ||||
| 				prev: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"addPreimageChange", | ||||
| 			addPreimageChange{ | ||||
| 				hash: ethcmn.BytesToHash([]byte("hash")), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"addLogChange", | ||||
| 			addLogChange{ | ||||
| 				txhash: ethcmn.BytesToHash([]byte("hash")), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"addLogChange - 2 logs", | ||||
| 			addLogChange{ | ||||
| 				txhash: ethcmn.BytesToHash([]byte("txhash")), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"accessListAddAccountChange", | ||||
| 			accessListAddAccountChange{ | ||||
| 				address: &suite.address, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	var dirtyCount int | ||||
| 	for i, tc := range testCases { | ||||
| 		suite.journal.append(tc.entry) | ||||
| 		suite.Require().Equal(suite.journal.length(), i+1, tc.name) | ||||
| 		if tc.entry.dirtied() != nil { | ||||
| 			dirtyCount++ | ||||
| 
 | ||||
| 			suite.Require().Equal(dirtyCount, suite.journal.getDirty(suite.address), tc.name) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// revert to the initial journal state
 | ||||
| 	suite.journal.revert(suite.stateDB, 0) | ||||
| 
 | ||||
| 	// verify the dirty entry has been deleted
 | ||||
| 	idx, ok := suite.journal.addressToJournalIndex[suite.address] | ||||
| 	suite.Require().False(ok) | ||||
| 	suite.Require().Zero(idx) | ||||
| } | ||||
| 
 | ||||
| func (suite *JournalTestSuite) TestJournal_preimage_revert() { | ||||
| 	suite.stateDB.preimages = []preimageEntry{ | ||||
| 		{ | ||||
| 			hash:     ethcmn.BytesToHash([]byte("hash")), | ||||
| 			preimage: []byte("preimage0"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			hash:     ethcmn.BytesToHash([]byte("hash1")), | ||||
| 			preimage: []byte("preimage1"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			hash:     ethcmn.BytesToHash([]byte("hash2")), | ||||
| 			preimage: []byte("preimage2"), | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for i, preimage := range suite.stateDB.preimages { | ||||
| 		suite.stateDB.hashToPreimageIndex[preimage.hash] = i | ||||
| 	} | ||||
| 
 | ||||
| 	change := addPreimageChange{ | ||||
| 		hash: ethcmn.BytesToHash([]byte("hash")), | ||||
| 	} | ||||
| 
 | ||||
| 	// delete first entry
 | ||||
| 	change.revert(suite.stateDB) | ||||
| 	suite.Require().Len(suite.stateDB.preimages, 2) | ||||
| 	suite.Require().Equal(len(suite.stateDB.preimages), len(suite.stateDB.hashToPreimageIndex)) | ||||
| 
 | ||||
| 	for i, entry := range suite.stateDB.preimages { | ||||
| 		suite.Require().Equal(fmt.Sprintf("preimage%d", i+1), string(entry.preimage), entry.hash.String()) | ||||
| 		idx, found := suite.stateDB.hashToPreimageIndex[entry.hash] | ||||
| 		suite.Require().True(found) | ||||
| 		suite.Require().Equal(i, idx) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *JournalTestSuite) TestJournal_createObjectChange_revert() { | ||||
| 	addr := ethcmn.BytesToAddress([]byte("addr")) | ||||
| 
 | ||||
| 	suite.stateDB.stateObjects = []stateEntry{ | ||||
| 		{ | ||||
| 			address: addr, | ||||
| 			stateObject: &stateObject{ | ||||
| 				address: addr, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			address: ethcmn.BytesToAddress([]byte("addr1")), | ||||
| 			stateObject: &stateObject{ | ||||
| 				address: ethcmn.BytesToAddress([]byte("addr1")), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			address: ethcmn.BytesToAddress([]byte("addr2")), | ||||
| 			stateObject: &stateObject{ | ||||
| 				address: ethcmn.BytesToAddress([]byte("addr2")), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for i, so := range suite.stateDB.stateObjects { | ||||
| 		suite.stateDB.addressToObjectIndex[so.address] = i | ||||
| 	} | ||||
| 
 | ||||
| 	change := createObjectChange{ | ||||
| 		account: &addr, | ||||
| 	} | ||||
| 
 | ||||
| 	// delete first entry
 | ||||
| 	change.revert(suite.stateDB) | ||||
| 	suite.Require().Len(suite.stateDB.stateObjects, 2) | ||||
| 	suite.Require().Equal(len(suite.stateDB.stateObjects), len(suite.stateDB.addressToObjectIndex)) | ||||
| 
 | ||||
| 	for i, entry := range suite.stateDB.stateObjects { | ||||
| 		suite.Require().Equal(ethcmn.BytesToAddress([]byte(fmt.Sprintf("addr%d", i+1))).String(), entry.address.String()) | ||||
| 		idx, found := suite.stateDB.addressToObjectIndex[entry.address] | ||||
| 		suite.Require().True(found) | ||||
| 		suite.Require().Equal(i, idx) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *JournalTestSuite) TestJournal_dirty() { | ||||
| 	// dirty entry hasn't been set
 | ||||
| 	idx, ok := suite.journal.addressToJournalIndex[suite.address] | ||||
| 	suite.Require().False(ok) | ||||
| 	suite.Require().Zero(idx) | ||||
| 
 | ||||
| 	// update dirty count
 | ||||
| 	suite.journal.dirty(suite.address) | ||||
| 	suite.Require().Equal(1, suite.journal.getDirty(suite.address)) | ||||
| } | ||||
| @ -89,7 +89,7 @@ func (log *Log) ToEthereum() *ethtypes.Log { | ||||
| } | ||||
| 
 | ||||
| func NewLogsFromEth(ethlogs []*ethtypes.Log) []*Log { | ||||
| 	var logs []*Log | ||||
| 	var logs []*Log // nolint: prealloc
 | ||||
| 	for _, ethlog := range ethlogs { | ||||
| 		logs = append(logs, NewLogFromEth(ethlog)) | ||||
| 	} | ||||
|  | ||||
| @ -2,7 +2,6 @@ package types | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/crypto/keyring" | ||||
| @ -14,7 +13,6 @@ import ( | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| @ -191,48 +189,6 @@ func (msg MsgEthereumTx) GetSignBytes() []byte { | ||||
| 	panic("must use 'RLPSignBytes' with a chain ID to get the valid bytes to sign") | ||||
| } | ||||
| 
 | ||||
| // RLPSignBytes returns the RLP hash of an Ethereum transaction message with a
 | ||||
| // given chainID used for signing.
 | ||||
| func (msg MsgEthereumTx) RLPSignBytes(chainID *big.Int) ethcmn.Hash { | ||||
| 	if msg.Data.ChainID != nil { | ||||
| 		chainID = new(big.Int).SetBytes(msg.Data.ChainID) | ||||
| 	} | ||||
| 
 | ||||
| 	var accessList *ethtypes.AccessList | ||||
| 	if msg.Data.Accesses != nil { | ||||
| 		accessList = msg.Data.Accesses.ToEthAccessList() | ||||
| 	} | ||||
| 
 | ||||
| 	return rlpHash([]interface{}{ | ||||
| 		chainID, | ||||
| 		msg.Data.Nonce, | ||||
| 		new(big.Int).SetBytes(msg.Data.GasPrice), | ||||
| 		msg.Data.GasLimit, | ||||
| 		msg.To(), | ||||
| 		new(big.Int).SetBytes(msg.Data.Amount), | ||||
| 		new(big.Int).SetBytes(msg.Data.Input), | ||||
| 		accessList, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // EncodeRLP implements the rlp.Encoder interface.
 | ||||
| func (msg *MsgEthereumTx) EncodeRLP(w io.Writer) error { | ||||
| 	tx := msg.AsTransaction() | ||||
| 	return tx.EncodeRLP(w) | ||||
| } | ||||
| 
 | ||||
| // DecodeRLP implements the rlp.Decoder interface.
 | ||||
| func (msg *MsgEthereumTx) DecodeRLP(stream *rlp.Stream) error { | ||||
| 	tx := ðtypes.Transaction{} | ||||
| 	if err := tx.DecodeRLP(stream); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	msg.FromEthereumTx(tx) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Sign calculates a secp256k1 ECDSA signature and signs the transaction. It
 | ||||
| // takes a keyring signer and the chainID to sign an Ethereum transaction according to
 | ||||
| // EIP155 standard.
 | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| package types | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"math/big" | ||||
| 	"testing" | ||||
| 
 | ||||
| @ -15,7 +14,6 @@ import ( | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| ) | ||||
| 
 | ||||
| type MsgsTestSuite struct { | ||||
| @ -91,23 +89,6 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *MsgsTestSuite) TestMsgEthereumTx_EncodeRLP() { | ||||
| 	expMsg := NewMsgEthereumTx(suite.chainID, 0, &suite.to, nil, 100000, nil, []byte("test"), nil) | ||||
| 
 | ||||
| 	raw, err := rlp.EncodeToBytes(&expMsg) | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	msg := &MsgEthereumTx{} | ||||
| 	err = rlp.Decode(bytes.NewReader(raw), &msg) | ||||
| 	suite.Require().NoError(err) | ||||
| 	suite.Require().Equal(expMsg.Data, msg.Data) | ||||
| } | ||||
| 
 | ||||
| func (suite *MsgsTestSuite) TestMsgEthereumTx_RLPSignBytes() { | ||||
| 	msg := NewMsgEthereumTx(suite.chainID, 0, &suite.to, nil, 100000, nil, []byte("test"), nil) | ||||
| 	suite.NotPanics(func() { _ = msg.RLPSignBytes(suite.chainID) }) | ||||
| } | ||||
| 
 | ||||
| func (suite *MsgsTestSuite) TestMsgEthereumTx_Sign() { | ||||
| 	msg := NewMsgEthereumTx(suite.chainID, 0, &suite.to, nil, 100000, nil, []byte("test"), nil) | ||||
| 
 | ||||
|  | ||||
| @ -73,8 +73,8 @@ var xxx_messageInfo_QueryAccountRequest proto.InternalMessageInfo | ||||
| type QueryAccountResponse struct { | ||||
| 	// balance is the balance of the EVM denomination.
 | ||||
| 	Balance string `protobuf:"bytes,1,opt,name=balance,proto3" json:"balance,omitempty"` | ||||
| 	// code_hash is the code bytes from the EOA.
 | ||||
| 	CodeHash []byte `protobuf:"bytes,2,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` | ||||
| 	// code hash is the hex-formatted code bytes from the EOA.
 | ||||
| 	CodeHash string `protobuf:"bytes,2,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` | ||||
| 	// nonce is the account's sequence number.
 | ||||
| 	Nonce uint64 `protobuf:"varint,3,opt,name=nonce,proto3" json:"nonce,omitempty"` | ||||
| } | ||||
| @ -119,11 +119,11 @@ func (m *QueryAccountResponse) GetBalance() string { | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func (m *QueryAccountResponse) GetCodeHash() []byte { | ||||
| func (m *QueryAccountResponse) GetCodeHash() string { | ||||
| 	if m != nil { | ||||
| 		return m.CodeHash | ||||
| 	} | ||||
| 	return nil | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func (m *QueryAccountResponse) GetNonce() uint64 { | ||||
| @ -972,72 +972,72 @@ func init() { | ||||
| } | ||||
| 
 | ||||
| var fileDescriptor_8bbc79ec2b6c5cb2 = []byte{ | ||||
| 	// 1028 bytes of a gzipped FileDescriptorProto
 | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x96, 0xcf, 0x6f, 0x1b, 0x45, | ||||
| 	0x14, 0xc7, 0xbd, 0x8d, 0x63, 0x27, 0x2f, 0x09, 0x2a, 0x83, 0x29, 0x61, 0x8b, 0x1c, 0x6b, 0x51, | ||||
| 	0x63, 0xe7, 0x47, 0x77, 0x6b, 0x23, 0xf1, 0x4b, 0x48, 0x28, 0xa9, 0x14, 0x2a, 0x51, 0xa1, 0xe2, | ||||
| 	0xf4, 0xc4, 0xc5, 0x1a, 0xaf, 0x47, 0x6b, 0x2b, 0xeb, 0x1d, 0xd7, 0xb3, 0xb6, 0x12, 0x45, 0xb9, | ||||
| 	0x70, 0x40, 0x20, 0x71, 0x00, 0x71, 0xa0, 0x42, 0x42, 0xea, 0x95, 0x1b, 0x7f, 0x46, 0x8f, 0x95, | ||||
| 	0xb8, 0x70, 0x42, 0x28, 0xe1, 0xc0, 0x9f, 0x81, 0x66, 0xe6, 0xad, 0xbd, 0x9b, 0x78, 0xb3, 0x0e, | ||||
| 	0xb7, 0x9d, 0xf1, 0xfb, 0xf1, 0x79, 0xef, 0xcd, 0x7c, 0xc7, 0x60, 0xb1, 0xb0, 0xcb, 0x86, 0xfd, | ||||
| 	0x5e, 0x10, 0x3a, 0x6c, 0xdc, 0x77, 0xc6, 0x75, 0xea, 0x0f, 0xba, 0xb4, 0xee, 0x3c, 0x1b, 0xb1, | ||||
| 	0xe1, 0x89, 0x3d, 0x18, 0xf2, 0x90, 0x93, 0x3b, 0x13, 0x1b, 0x9b, 0x8d, 0xfb, 0x76, 0x64, 0x63, | ||||
| 	0x96, 0x3c, 0xee, 0x71, 0x65, 0xe2, 0xc8, 0x2f, 0x6d, 0x6d, 0x6e, 0xbb, 0x5c, 0xf4, 0xb9, 0x70, | ||||
| 	0xda, 0x54, 0x30, 0x1d, 0xc6, 0x19, 0xd7, 0xdb, 0x2c, 0xa4, 0x75, 0x67, 0x40, 0xbd, 0x5e, 0x40, | ||||
| 	0xc3, 0x1e, 0x0f, 0xd0, 0xf6, 0x1d, 0x8f, 0x73, 0xcf, 0x67, 0x0e, 0x1d, 0xf4, 0x1c, 0x1a, 0x04, | ||||
| 	0x3c, 0x54, 0x3f, 0x0a, 0xfc, 0xb5, 0x92, 0xc2, 0x26, 0x21, 0x94, 0x85, 0xf5, 0x11, 0xbc, 0xf1, | ||||
| 	0xa5, 0xcc, 0xb0, 0xe7, 0xba, 0x7c, 0x14, 0x84, 0x4d, 0xf6, 0x6c, 0xc4, 0x44, 0x48, 0xd6, 0xa1, | ||||
| 	0x48, 0x3b, 0x9d, 0x21, 0x13, 0x62, 0xdd, 0xa8, 0x18, 0xb5, 0xe5, 0x66, 0xb4, 0xfc, 0x78, 0xe9, | ||||
| 	0xdb, 0x17, 0x1b, 0xb9, 0x7f, 0x5f, 0x6c, 0xe4, 0x2c, 0x17, 0x4a, 0x49, 0x57, 0x31, 0xe0, 0x81, | ||||
| 	0x60, 0xd2, 0xb7, 0x4d, 0x7d, 0x1a, 0xb8, 0x2c, 0xf2, 0xc5, 0x25, 0xb9, 0x0b, 0xcb, 0x2e, 0xef, | ||||
| 	0xb0, 0x56, 0x97, 0x8a, 0xee, 0xfa, 0xad, 0x8a, 0x51, 0x5b, 0x6d, 0x2e, 0xc9, 0x8d, 0x47, 0x54, | ||||
| 	0x74, 0x49, 0x09, 0x16, 0x03, 0x2e, 0x9d, 0x16, 0x2a, 0x46, 0x2d, 0xdf, 0xd4, 0x0b, 0xeb, 0x53, | ||||
| 	0x78, 0x5b, 0x25, 0x79, 0xa8, 0x5a, 0xf2, 0x3f, 0x28, 0xbf, 0x31, 0xc0, 0x9c, 0x15, 0x01, 0x61, | ||||
| 	0xef, 0xc1, 0x6b, 0xba, 0xdb, 0xad, 0x64, 0xa4, 0x35, 0xbd, 0xbb, 0xa7, 0x37, 0x89, 0x09, 0x4b, | ||||
| 	0x42, 0x26, 0x95, 0x7c, 0xb7, 0x14, 0xdf, 0x64, 0x2d, 0x43, 0x50, 0x1d, 0xb5, 0x15, 0x8c, 0xfa, | ||||
| 	0x6d, 0x36, 0xc4, 0x0a, 0xd6, 0x70, 0xf7, 0x0b, 0xb5, 0x39, 0xe9, 0xf4, 0xbe, 0x6e, 0xc6, 0x4d, | ||||
| 	0x6a, 0x78, 0x80, 0x9d, 0x9e, 0xb8, 0x66, 0x75, 0xda, 0xfa, 0x1c, 0x93, 0x1d, 0x86, 0x7c, 0x48, | ||||
| 	0xbd, 0xec, 0x64, 0xe4, 0x36, 0x2c, 0x1c, 0xb1, 0x13, 0x55, 0xdb, 0x72, 0x53, 0x7e, 0xc6, 0xd2, | ||||
| 	0xef, 0x62, 0xfa, 0x49, 0x30, 0x4c, 0x5f, 0x82, 0xc5, 0x31, 0xf5, 0x47, 0x51, 0x72, 0xbd, 0xb0, | ||||
| 	0xde, 0x87, 0xdb, 0xd8, 0xef, 0xce, 0x8d, 0x8a, 0xac, 0xc2, 0xeb, 0x31, 0x3f, 0x4c, 0x41, 0x20, | ||||
| 	0x2f, 0x0f, 0x88, 0xf2, 0x5a, 0x6d, 0xaa, 0x6f, 0xab, 0x01, 0x44, 0x19, 0x3e, 0x3d, 0x7e, 0xcc, | ||||
| 	0x3d, 0x11, 0xa5, 0x20, 0x90, 0x57, 0xc7, 0x4a, 0xc7, 0x57, 0xdf, 0xb1, 0xe0, 0x07, 0xd8, 0x8f, | ||||
| 	0xc8, 0x07, 0xc3, 0x3b, 0x90, 0xf7, 0xb9, 0x27, 0xa1, 0x16, 0x6a, 0x2b, 0x8d, 0xbb, 0xf6, 0xec, | ||||
| 	0x6b, 0x6a, 0x3f, 0xe6, 0x5e, 0x53, 0x19, 0x5a, 0x67, 0xf0, 0xa6, 0x9e, 0x84, 0xcf, 0xdd, 0xa3, | ||||
| 	0x8c, 0xf4, 0xe4, 0x00, 0x60, 0x7a, 0x5f, 0x55, 0x6b, 0x57, 0x1a, 0x9b, 0xb6, 0x3e, 0x58, 0xb6, | ||||
| 	0xbc, 0xdc, 0xb6, 0xd6, 0x08, 0xbc, 0xdc, 0xf6, 0x93, 0xe9, 0xa4, 0x9a, 0x31, 0xcf, 0x58, 0x19, | ||||
| 	0xbf, 0x19, 0x70, 0xe7, 0x72, 0x7e, 0x2c, 0xe5, 0x00, 0x8a, 0xe1, 0x71, 0x2b, 0x56, 0x4d, 0x35, | ||||
| 	0xad, 0x9a, 0xa7, 0x43, 0x1a, 0x08, 0xea, 0xca, 0xd0, 0x32, 0xc2, 0x7e, 0xfe, 0xe5, 0x5f, 0x1b, | ||||
| 	0xb9, 0x66, 0x21, 0x54, 0xad, 0x21, 0x9f, 0xcd, 0x80, 0xae, 0x66, 0x42, 0x6b, 0x88, 0x38, 0xb5, | ||||
| 	0xb5, 0x1e, 0x47, 0xdd, 0xf7, 0x39, 0xef, 0x63, 0x6d, 0x96, 0x03, 0x6f, 0x5d, 0xf9, 0x65, 0x7a, | ||||
| 	0xa4, 0xda, 0x72, 0x03, 0x07, 0xae, 0x17, 0x56, 0x09, 0x27, 0xfe, 0x84, 0x0e, 0x69, 0x3f, 0x6a, | ||||
| 	0xb9, 0x75, 0x88, 0x33, 0x8d, 0x76, 0x31, 0xc4, 0x27, 0x50, 0x18, 0xa8, 0x1d, 0x15, 0x63, 0xa5, | ||||
| 	0x51, 0x4e, 0xeb, 0x83, 0xf6, 0x8b, 0xca, 0xd7, 0x3e, 0xd6, 0x23, 0xa4, 0x3e, 0x94, 0x42, 0xea, | ||||
| 	0x3e, 0xa4, 0xbe, 0x9f, 0x7d, 0x77, 0x4a, 0xb0, 0xd8, 0x0b, 0x06, 0xa3, 0x10, 0x25, 0x4d, 0x2f, | ||||
| 	0xac, 0xfb, 0x58, 0x65, 0x3c, 0xd2, 0xf4, 0x54, 0x77, 0x68, 0x48, 0xa3, 0x53, 0x2d, 0xbf, 0x1b, | ||||
| 	0xcf, 0x57, 0x61, 0x51, 0xd9, 0x93, 0x9f, 0x0d, 0x28, 0xa2, 0x4c, 0x91, 0x9d, 0x34, 0xf8, 0x19, | ||||
| 	0xa2, 0x6d, 0xee, 0xce, 0x67, 0xac, 0x21, 0xac, 0xfa, 0xd7, 0x7f, 0xfc, 0xf3, 0xd3, 0xad, 0x1d, | ||||
| 	0xb2, 0xe5, 0xa4, 0x3c, 0x12, 0x28, 0x5f, 0xce, 0x29, 0xd6, 0x79, 0x46, 0x7e, 0x37, 0x60, 0x2d, | ||||
| 	0x21, 0xa3, 0xa4, 0x7e, 0x6d, 0xca, 0x59, 0xa2, 0x6d, 0x36, 0x6e, 0xe2, 0x82, 0xac, 0x1f, 0x2a, | ||||
| 	0xd6, 0x06, 0x79, 0x90, 0xc6, 0x1a, 0x69, 0xf8, 0x15, 0xe4, 0xe7, 0x06, 0x14, 0x51, 0x36, 0x33, | ||||
| 	0x9a, 0x99, 0xd4, 0xe5, 0x8c, 0x66, 0x5e, 0x52, 0x62, 0xab, 0xa1, 0x00, 0x77, 0xc9, 0x76, 0x1a, | ||||
| 	0x20, 0x0a, 0xb3, 0x88, 0xa1, 0xfd, 0x6a, 0x40, 0x11, 0x25, 0x35, 0x03, 0x2d, 0xa9, 0xe2, 0x19, | ||||
| 	0x68, 0x97, 0x54, 0xda, 0xfa, 0x40, 0xa1, 0xd5, 0x89, 0x93, 0x86, 0x26, 0xb4, 0xc3, 0x94, 0xcc, | ||||
| 	0x39, 0x3d, 0x62, 0x27, 0x67, 0xe4, 0x7b, 0x03, 0xf2, 0x52, 0x8c, 0x49, 0x2d, 0x63, 0x62, 0x13, | ||||
| 	0x9d, 0x37, 0xb7, 0xe6, 0xb0, 0x44, 0x2c, 0x47, 0x61, 0x6d, 0x91, 0x6a, 0xfa, 0x48, 0x3b, 0x89, | ||||
| 	0x76, 0xfd, 0x68, 0x40, 0x41, 0xcb, 0x37, 0xd9, 0xbe, 0x36, 0x4d, 0xe2, 0x5d, 0x30, 0x77, 0xe6, | ||||
| 	0xb2, 0x45, 0x28, 0x5b, 0x41, 0xd5, 0xc8, 0x66, 0x1a, 0x14, 0x4a, 0xac, 0x73, 0x2a, 0x05, 0x5e, | ||||
| 	0x8d, 0x70, 0x79, 0x22, 0xc5, 0xe4, 0xfe, 0xf5, 0x47, 0xe6, 0xd2, 0x93, 0x61, 0xda, 0xf3, 0x9a, | ||||
| 	0xcf, 0x7b, 0x61, 0xdb, 0xd2, 0x25, 0xc1, 0xf7, 0x8b, 0x01, 0x30, 0x55, 0x59, 0x32, 0x47, 0xc6, | ||||
| 	0xb8, 0x50, 0x9b, 0xce, 0xdc, 0xf6, 0x88, 0xb8, 0xa3, 0x10, 0xef, 0x91, 0x77, 0xaf, 0x47, 0x54, | ||||
| 	0xaa, 0x4e, 0xbe, 0x33, 0xa0, 0xa0, 0x35, 0x38, 0x63, 0xa0, 0x09, 0xd9, 0xcf, 0x18, 0x68, 0xf2, | ||||
| 	0x31, 0xb0, 0x36, 0x15, 0x50, 0x85, 0x94, 0xd3, 0x80, 0xb4, 0xec, 0xab, 0x46, 0x4d, 0x85, 0x3a, | ||||
| 	0xa3, 0x51, 0x57, 0xde, 0x86, 0x8c, 0x46, 0x5d, 0x7d, 0x01, 0xb2, 0x1b, 0x25, 0x94, 0x4f, 0xcb, | ||||
| 	0xa5, 0xbe, 0xbf, 0xbf, 0xf7, 0xf2, 0xbc, 0x6c, 0xbc, 0x3a, 0x2f, 0x1b, 0x7f, 0x9f, 0x97, 0x8d, | ||||
| 	0x1f, 0x2e, 0xca, 0xb9, 0x57, 0x17, 0xe5, 0xdc, 0x9f, 0x17, 0xe5, 0xdc, 0x57, 0x55, 0xaf, 0x17, | ||||
| 	0x76, 0x47, 0x6d, 0xdb, 0xe5, 0x7d, 0x94, 0xc0, 0x58, 0xbc, 0x63, 0x15, 0x31, 0x3c, 0x19, 0x30, | ||||
| 	0xd1, 0x2e, 0xa8, 0x7f, 0xfb, 0xef, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0xc1, 0xa4, 0x09, 0x94, | ||||
| 	0xad, 0x0c, 0x00, 0x00, | ||||
| 	// 1026 bytes of a gzipped FileDescriptorProto
 | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x96, 0xcf, 0x6f, 0xe3, 0x44, | ||||
| 	0x14, 0xc7, 0xe3, 0x36, 0x4d, 0xda, 0xd7, 0x16, 0x2d, 0x43, 0x58, 0x8a, 0x17, 0xa5, 0x95, 0xd1, | ||||
| 	0x36, 0xe9, 0x8f, 0xb5, 0x37, 0x41, 0xe2, 0x97, 0x90, 0x50, 0xbb, 0x52, 0x59, 0x89, 0x15, 0x5a, | ||||
| 	0xd2, 0x3d, 0x71, 0x89, 0x26, 0xce, 0xc8, 0x89, 0xea, 0x78, 0xb2, 0x19, 0x27, 0x6a, 0x55, 0xf5, | ||||
| 	0xc2, 0x01, 0x81, 0xc4, 0x01, 0xc4, 0x81, 0x15, 0x12, 0xd2, 0x5e, 0xb9, 0xf1, 0x67, 0xec, 0xb1, | ||||
| 	0x12, 0x17, 0x4e, 0x08, 0xb5, 0x1c, 0xf8, 0x33, 0xd0, 0xcc, 0x3c, 0x27, 0x76, 0x1b, 0xd7, 0x29, | ||||
| 	0x37, 0xcf, 0xe4, 0xfd, 0xf8, 0xbc, 0xf7, 0x66, 0xbe, 0x13, 0xb0, 0x58, 0xd8, 0x61, 0x83, 0x5e, | ||||
| 	0x37, 0x08, 0x1d, 0x36, 0xea, 0x39, 0xa3, 0x1a, 0xf5, 0xfb, 0x1d, 0x5a, 0x73, 0x9e, 0x0f, 0xd9, | ||||
| 	0xe0, 0xc4, 0xee, 0x0f, 0x78, 0xc8, 0xc9, 0xdd, 0xb1, 0x8d, 0xcd, 0x46, 0x3d, 0x3b, 0xb2, 0x31, | ||||
| 	0x4b, 0x1e, 0xf7, 0xb8, 0x32, 0x71, 0xe4, 0x97, 0xb6, 0x36, 0xb7, 0x5d, 0x2e, 0x7a, 0x5c, 0x38, | ||||
| 	0x2d, 0x2a, 0x98, 0x0e, 0xe3, 0x8c, 0x6a, 0x2d, 0x16, 0xd2, 0x9a, 0xd3, 0xa7, 0x5e, 0x37, 0xa0, | ||||
| 	0x61, 0x97, 0x07, 0x68, 0xfb, 0x8e, 0xc7, 0xb9, 0xe7, 0x33, 0x87, 0xf6, 0xbb, 0x0e, 0x0d, 0x02, | ||||
| 	0x1e, 0xaa, 0x1f, 0x05, 0xfe, 0xba, 0x91, 0xc2, 0x26, 0x21, 0x94, 0x85, 0xf5, 0x11, 0xbc, 0xf1, | ||||
| 	0xa5, 0xcc, 0xb0, 0xe7, 0xba, 0x7c, 0x18, 0x84, 0x0d, 0xf6, 0x7c, 0xc8, 0x44, 0x48, 0xd6, 0xa0, | ||||
| 	0x48, 0xdb, 0xed, 0x01, 0x13, 0x62, 0xcd, 0xd8, 0x30, 0xaa, 0x4b, 0x8d, 0x68, 0xf9, 0xf1, 0xe2, | ||||
| 	0xb7, 0x2f, 0xd7, 0x73, 0xff, 0xbe, 0x5c, 0xcf, 0x59, 0x2e, 0x94, 0x92, 0xae, 0xa2, 0xcf, 0x03, | ||||
| 	0xc1, 0xa4, 0x6f, 0x8b, 0xfa, 0x34, 0x70, 0x59, 0xe4, 0x8b, 0x4b, 0x72, 0x0f, 0x96, 0x5c, 0xde, | ||||
| 	0x66, 0xcd, 0x0e, 0x15, 0x9d, 0xb5, 0x39, 0xf5, 0xdb, 0xa2, 0xdc, 0x78, 0x4c, 0x45, 0x87, 0x94, | ||||
| 	0x60, 0x21, 0xe0, 0xd2, 0x69, 0x7e, 0xc3, 0xa8, 0xe6, 0x1b, 0x7a, 0x61, 0x7d, 0x0a, 0x6f, 0xab, | ||||
| 	0x24, 0x8f, 0x54, 0x4b, 0xfe, 0x07, 0xe5, 0x37, 0x06, 0x98, 0xd3, 0x22, 0x20, 0xec, 0x7d, 0x78, | ||||
| 	0x4d, 0x77, 0xbb, 0x99, 0x8c, 0xb4, 0xaa, 0x77, 0xf7, 0xf4, 0x26, 0x31, 0x61, 0x51, 0xc8, 0xa4, | ||||
| 	0x92, 0x6f, 0x4e, 0xf1, 0x8d, 0xd7, 0x32, 0x04, 0xd5, 0x51, 0x9b, 0xc1, 0xb0, 0xd7, 0x62, 0x03, | ||||
| 	0xac, 0x60, 0x15, 0x77, 0xbf, 0x50, 0x9b, 0xe3, 0x4e, 0xef, 0xeb, 0x66, 0xdc, 0xa6, 0x86, 0x87, | ||||
| 	0xd8, 0xe9, 0xb1, 0x6b, 0x56, 0xa7, 0xad, 0xcf, 0x31, 0xd9, 0x61, 0xc8, 0x07, 0xd4, 0xcb, 0x4e, | ||||
| 	0x46, 0xee, 0xc0, 0xfc, 0x11, 0x3b, 0xc1, 0xa1, 0xc8, 0xcf, 0x58, 0xfa, 0x5d, 0x4c, 0x3f, 0x0e, | ||||
| 	0x86, 0xe9, 0x4b, 0xb0, 0x30, 0xa2, 0xfe, 0x30, 0x4a, 0xae, 0x17, 0xd6, 0xfb, 0x70, 0x07, 0xfb, | ||||
| 	0xdd, 0xbe, 0x55, 0x91, 0x15, 0x78, 0x3d, 0xe6, 0x87, 0x29, 0x08, 0xe4, 0xe5, 0x01, 0x51, 0x5e, | ||||
| 	0x2b, 0x0d, 0xf5, 0x6d, 0xd5, 0x81, 0x28, 0xc3, 0x67, 0xc7, 0x4f, 0xb8, 0x27, 0xa2, 0x14, 0x04, | ||||
| 	0xf2, 0xea, 0x58, 0xe9, 0xf8, 0xea, 0x3b, 0x16, 0xfc, 0x00, 0xfb, 0x11, 0xf9, 0x60, 0x78, 0x07, | ||||
| 	0xf2, 0x3e, 0xf7, 0x24, 0xd4, 0x7c, 0x75, 0xb9, 0x7e, 0xcf, 0x9e, 0x7e, 0x4d, 0xed, 0x27, 0xdc, | ||||
| 	0x6b, 0x28, 0x43, 0xeb, 0x0c, 0xde, 0xd4, 0x93, 0xf0, 0xb9, 0x7b, 0x94, 0x91, 0x9e, 0x1c, 0x00, | ||||
| 	0x4c, 0xee, 0xab, 0x6a, 0xed, 0x72, 0x7d, 0xd3, 0xd6, 0x07, 0xcb, 0x96, 0x97, 0xdb, 0xd6, 0x1a, | ||||
| 	0x81, 0x97, 0xdb, 0x7e, 0x3a, 0x99, 0x54, 0x23, 0xe6, 0x19, 0x2b, 0xe3, 0x37, 0x03, 0xee, 0x5e, | ||||
| 	0xcd, 0x8f, 0xa5, 0x1c, 0x40, 0x31, 0x3c, 0x6e, 0xc6, 0xaa, 0xa9, 0xa4, 0x55, 0xf3, 0x6c, 0x40, | ||||
| 	0x03, 0x41, 0x5d, 0x19, 0x5a, 0x46, 0xd8, 0xcf, 0xbf, 0xfa, 0x6b, 0x3d, 0xd7, 0x28, 0x84, 0xaa, | ||||
| 	0x35, 0xe4, 0xb3, 0x29, 0xd0, 0x95, 0x4c, 0x68, 0x0d, 0x11, 0xa7, 0xb6, 0xd6, 0xe2, 0xa8, 0xfb, | ||||
| 	0x3e, 0xe7, 0x3d, 0xac, 0xcd, 0x72, 0xe0, 0xad, 0x6b, 0xbf, 0x4c, 0x8e, 0x54, 0x4b, 0x6e, 0xe0, | ||||
| 	0xc0, 0xf5, 0xc2, 0x2a, 0xe1, 0xc4, 0x9f, 0xd2, 0x01, 0xed, 0x45, 0x2d, 0xb7, 0x0e, 0x71, 0xa6, | ||||
| 	0xd1, 0x2e, 0x86, 0xf8, 0x04, 0x0a, 0x7d, 0xb5, 0xa3, 0x62, 0x2c, 0xd7, 0xcb, 0x69, 0x7d, 0xd0, | ||||
| 	0x7e, 0x51, 0xf9, 0xda, 0xc7, 0x7a, 0x8c, 0xd4, 0x87, 0x52, 0x48, 0xdd, 0x47, 0xd4, 0xf7, 0xb3, | ||||
| 	0xef, 0x4e, 0x09, 0x16, 0xba, 0x41, 0x7f, 0x18, 0xaa, 0x6e, 0xad, 0x34, 0xf4, 0xc2, 0x7a, 0x80, | ||||
| 	0x55, 0xc6, 0x23, 0x4d, 0x4e, 0x75, 0x9b, 0x86, 0x34, 0x3a, 0xd5, 0xf2, 0xbb, 0xfe, 0x62, 0x05, | ||||
| 	0x16, 0x94, 0x3d, 0xf9, 0xd9, 0x80, 0x22, 0xca, 0x14, 0xd9, 0x49, 0x83, 0x9f, 0x22, 0xda, 0xe6, | ||||
| 	0xee, 0x6c, 0xc6, 0x1a, 0xc2, 0xaa, 0x7d, 0xfd, 0xc7, 0x3f, 0x3f, 0xcd, 0xed, 0x90, 0x2d, 0x27, | ||||
| 	0xe5, 0x91, 0x40, 0xf9, 0x72, 0x4e, 0xb1, 0xce, 0x33, 0xf2, 0xbb, 0x01, 0xab, 0x09, 0x19, 0x25, | ||||
| 	0xb5, 0x1b, 0x53, 0x4e, 0x13, 0x6d, 0xb3, 0x7e, 0x1b, 0x17, 0x64, 0xfd, 0x50, 0xb1, 0xd6, 0xc9, | ||||
| 	0xc3, 0x34, 0xd6, 0x48, 0xc3, 0xaf, 0x21, 0xbf, 0x30, 0xa0, 0x88, 0xb2, 0x99, 0xd1, 0xcc, 0xa4, | ||||
| 	0x2e, 0x67, 0x34, 0xf3, 0x8a, 0x12, 0x5b, 0x75, 0x05, 0xb8, 0x4b, 0xb6, 0xd3, 0x00, 0x51, 0x98, | ||||
| 	0x45, 0x0c, 0xed, 0x57, 0x03, 0x8a, 0x28, 0xa9, 0x19, 0x68, 0x49, 0x15, 0xcf, 0x40, 0xbb, 0xa2, | ||||
| 	0xd2, 0xd6, 0x07, 0x0a, 0xad, 0x46, 0x9c, 0x34, 0x34, 0xa1, 0x1d, 0x26, 0x64, 0xce, 0xe9, 0x11, | ||||
| 	0x3b, 0x39, 0x23, 0xdf, 0x1b, 0x90, 0x97, 0x62, 0x4c, 0xaa, 0x19, 0x13, 0x1b, 0xeb, 0xbc, 0xb9, | ||||
| 	0x35, 0x83, 0x25, 0x62, 0x39, 0x0a, 0x6b, 0x8b, 0x54, 0xd2, 0x47, 0xda, 0x4e, 0xb4, 0xeb, 0x47, | ||||
| 	0x03, 0x0a, 0x5a, 0xbe, 0xc9, 0xf6, 0x8d, 0x69, 0x12, 0xef, 0x82, 0xb9, 0x33, 0x93, 0x2d, 0x42, | ||||
| 	0xd9, 0x0a, 0xaa, 0x4a, 0x36, 0xd3, 0xa0, 0x50, 0x62, 0x9d, 0x53, 0x29, 0xf0, 0x6a, 0x84, 0x4b, | ||||
| 	0x63, 0x29, 0x26, 0x0f, 0x6e, 0x3e, 0x32, 0x57, 0x9e, 0x0c, 0xd3, 0x9e, 0xd5, 0x7c, 0xd6, 0x0b, | ||||
| 	0xdb, 0x92, 0x2e, 0x09, 0xbe, 0x5f, 0x0c, 0x80, 0x89, 0xca, 0x92, 0x19, 0x32, 0xc6, 0x85, 0xda, | ||||
| 	0x74, 0x66, 0xb6, 0x47, 0xc4, 0x1d, 0x85, 0x78, 0x9f, 0xbc, 0x7b, 0x33, 0xa2, 0x52, 0x75, 0xf2, | ||||
| 	0x9d, 0x01, 0x05, 0xad, 0xc1, 0x19, 0x03, 0x4d, 0xc8, 0x7e, 0xc6, 0x40, 0x93, 0x8f, 0x81, 0xb5, | ||||
| 	0xa9, 0x80, 0x36, 0x48, 0x39, 0x0d, 0x48, 0xcb, 0xbe, 0x6a, 0xd4, 0x44, 0xa8, 0x33, 0x1a, 0x75, | ||||
| 	0xed, 0x6d, 0xc8, 0x68, 0xd4, 0xf5, 0x17, 0x20, 0xbb, 0x51, 0x42, 0xf9, 0x34, 0x5d, 0xea, 0xfb, | ||||
| 	0xfb, 0x7b, 0xaf, 0x2e, 0xca, 0xc6, 0xf9, 0x45, 0xd9, 0xf8, 0xfb, 0xa2, 0x6c, 0xfc, 0x70, 0x59, | ||||
| 	0xce, 0x9d, 0x5f, 0x96, 0x73, 0x7f, 0x5e, 0x96, 0x73, 0x5f, 0x55, 0xbc, 0x6e, 0xd8, 0x19, 0xb6, | ||||
| 	0x6c, 0x97, 0xf7, 0x50, 0x02, 0x63, 0xf1, 0x8e, 0x55, 0xc4, 0xf0, 0xa4, 0xcf, 0x44, 0xab, 0xa0, | ||||
| 	0xfe, 0xed, 0xbf, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4b, 0xf0, 0x51, 0x91, 0xad, 0x0c, | ||||
| 	0x00, 0x00, | ||||
| } | ||||
| 
 | ||||
| // Reference imports to suppress errors if they are not otherwise used.
 | ||||
| @ -2579,7 +2579,7 @@ func (m *QueryAccountResponse) Unmarshal(dAtA []byte) error { | ||||
| 			if wireType != 2 { | ||||
| 				return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType) | ||||
| 			} | ||||
| 			var byteLen int | ||||
| 			var stringLen uint64 | ||||
| 			for shift := uint(0); ; shift += 7 { | ||||
| 				if shift >= 64 { | ||||
| 					return ErrIntOverflowQuery | ||||
| @ -2589,25 +2589,23 @@ func (m *QueryAccountResponse) Unmarshal(dAtA []byte) error { | ||||
| 				} | ||||
| 				b := dAtA[iNdEx] | ||||
| 				iNdEx++ | ||||
| 				byteLen |= int(b&0x7F) << shift | ||||
| 				stringLen |= uint64(b&0x7F) << shift | ||||
| 				if b < 0x80 { | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			if byteLen < 0 { | ||||
| 			intStringLen := int(stringLen) | ||||
| 			if intStringLen < 0 { | ||||
| 				return ErrInvalidLengthQuery | ||||
| 			} | ||||
| 			postIndex := iNdEx + byteLen | ||||
| 			postIndex := iNdEx + intStringLen | ||||
| 			if postIndex < 0 { | ||||
| 				return ErrInvalidLengthQuery | ||||
| 			} | ||||
| 			if postIndex > l { | ||||
| 				return io.ErrUnexpectedEOF | ||||
| 			} | ||||
| 			m.CodeHash = append(m.CodeHash[:0], dAtA[iNdEx:postIndex]...) | ||||
| 			if m.CodeHash == nil { | ||||
| 				m.CodeHash = []byte{} | ||||
| 			} | ||||
| 			m.CodeHash = string(dAtA[iNdEx:postIndex]) | ||||
| 			iNdEx = postIndex | ||||
| 		case 3: | ||||
| 			if wireType != 0 { | ||||
|  | ||||
| @ -1,457 +0,0 @@ | ||||
| package types | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/store/prefix" | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||||
| 
 | ||||
| 	ethermint "github.com/cosmos/ethermint/types" | ||||
| 
 | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethstate "github.com/ethereum/go-ethereum/core/state" | ||||
| 	ethcrypto "github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	_ StateObject = (*stateObject)(nil) | ||||
| 
 | ||||
| 	EmptyCodeHash = ethcrypto.Keccak256(nil) | ||||
| ) | ||||
| 
 | ||||
| // StateObject interface for interacting with state object
 | ||||
| type StateObject interface { | ||||
| 	GetCommittedState(db ethstate.Database, key ethcmn.Hash) ethcmn.Hash | ||||
| 	GetState(db ethstate.Database, key ethcmn.Hash) ethcmn.Hash | ||||
| 	SetState(db ethstate.Database, key, value ethcmn.Hash) | ||||
| 
 | ||||
| 	Code(db ethstate.Database) []byte | ||||
| 	SetCode(codeHash ethcmn.Hash, code []byte) | ||||
| 	CodeHash() []byte | ||||
| 
 | ||||
| 	AddBalance(amount *big.Int) | ||||
| 	SubBalance(amount *big.Int) | ||||
| 	SetBalance(amount *big.Int) | ||||
| 
 | ||||
| 	Balance() *big.Int | ||||
| 	ReturnGas(gas *big.Int) | ||||
| 	Address() ethcmn.Address | ||||
| 
 | ||||
| 	SetNonce(nonce uint64) | ||||
| 	Nonce() uint64 | ||||
| } | ||||
| 
 | ||||
| // stateObject represents an Ethereum account which is being modified.
 | ||||
| //
 | ||||
| // The usage pattern is as follows:
 | ||||
| // First you need to obtain a state object.
 | ||||
| // Account values can be accessed and modified through the object.
 | ||||
| // Finally, call CommitTrie to write the modified storage trie into a database.
 | ||||
| type stateObject struct { | ||||
| 	code ethermint.Code // contract bytecode, which gets set when code is loaded
 | ||||
| 	// State objects are used by the consensus core and VM which are
 | ||||
| 	// unable to deal with database-level errors. Any error that occurs
 | ||||
| 	// during a database read is memoized here and will eventually be returned
 | ||||
| 	// by StateDB.Commit.
 | ||||
| 	originStorage Storage // Storage cache of original entries to dedup rewrites
 | ||||
| 	dirtyStorage  Storage // Storage entries that need to be flushed to disk
 | ||||
| 
 | ||||
| 	// DB error
 | ||||
| 	dbErr   error | ||||
| 	stateDB *CommitStateDB | ||||
| 	account *ethermint.EthAccount | ||||
| 	// balance represents the amount of the EVM denom token that an account holds
 | ||||
| 	balance sdk.Int | ||||
| 
 | ||||
| 	keyToOriginStorageIndex map[ethcmn.Hash]int | ||||
| 	keyToDirtyStorageIndex  map[ethcmn.Hash]int | ||||
| 
 | ||||
| 	address ethcmn.Address | ||||
| 
 | ||||
| 	// cache flags
 | ||||
| 	//
 | ||||
| 	// When an object is marked suicided it will be delete from the trie during
 | ||||
| 	// the "update" phase of the state transition.
 | ||||
| 	dirtyCode bool // true if the code was updated
 | ||||
| 	suicided  bool | ||||
| 	deleted   bool | ||||
| } | ||||
| 
 | ||||
| func newStateObject(db *CommitStateDB, accProto authtypes.AccountI, balance sdk.Int) *stateObject { | ||||
| 	ethAccount, ok := accProto.(*ethermint.EthAccount) | ||||
| 	if !ok { | ||||
| 		panic(fmt.Sprintf("invalid account type for state object: %T", accProto)) | ||||
| 	} | ||||
| 
 | ||||
| 	// set empty code hash
 | ||||
| 	if ethAccount.CodeHash == nil { | ||||
| 		ethAccount.CodeHash = EmptyCodeHash | ||||
| 	} | ||||
| 
 | ||||
| 	return &stateObject{ | ||||
| 		stateDB:                 db, | ||||
| 		account:                 ethAccount, | ||||
| 		balance:                 balance, | ||||
| 		address:                 ethAccount.EthAddress(), | ||||
| 		originStorage:           Storage{}, | ||||
| 		dirtyStorage:            Storage{}, | ||||
| 		keyToOriginStorageIndex: make(map[ethcmn.Hash]int), | ||||
| 		keyToDirtyStorageIndex:  make(map[ethcmn.Hash]int), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Setters
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // SetState updates a value in account storage. Note, the key will be prefixed
 | ||||
| // with the address of the state object.
 | ||||
| func (so *stateObject) SetState(db ethstate.Database, key, value ethcmn.Hash) { | ||||
| 	// if the new value is the same as old, don't set
 | ||||
| 	prev := so.GetState(db, key) | ||||
| 	if prev == value { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	prefixKey := so.GetStorageByAddressKey(key.Bytes()) | ||||
| 
 | ||||
| 	// since the new value is different, update and journal the change
 | ||||
| 	so.stateDB.journal.append(storageChange{ | ||||
| 		account:   &so.address, | ||||
| 		key:       prefixKey, | ||||
| 		prevValue: prev, | ||||
| 	}) | ||||
| 
 | ||||
| 	so.setState(prefixKey, value) | ||||
| } | ||||
| 
 | ||||
| // setState sets a state with a prefixed key and value to the dirty storage.
 | ||||
| func (so *stateObject) setState(key, value ethcmn.Hash) { | ||||
| 	idx, ok := so.keyToDirtyStorageIndex[key] | ||||
| 	if ok { | ||||
| 		so.dirtyStorage[idx].Value = value.String() | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// create new entry
 | ||||
| 	so.dirtyStorage = append(so.dirtyStorage, NewState(key, value)) | ||||
| 	idx = len(so.dirtyStorage) - 1 | ||||
| 	so.keyToDirtyStorageIndex[key] = idx | ||||
| } | ||||
| 
 | ||||
| // SetCode sets the state object's code.
 | ||||
| func (so *stateObject) SetCode(codeHash ethcmn.Hash, code []byte) { | ||||
| 	prevCode := so.Code(nil) | ||||
| 
 | ||||
| 	so.stateDB.journal.append(codeChange{ | ||||
| 		account:  &so.address, | ||||
| 		prevHash: so.CodeHash(), | ||||
| 		prevCode: prevCode, | ||||
| 	}) | ||||
| 
 | ||||
| 	so.setCode(codeHash, code) | ||||
| } | ||||
| 
 | ||||
| func (so *stateObject) setCode(codeHash ethcmn.Hash, code []byte) { | ||||
| 	so.code = code | ||||
| 	so.account.CodeHash = codeHash.Bytes() | ||||
| 	so.dirtyCode = true | ||||
| } | ||||
| 
 | ||||
| // AddBalance adds an amount to a state object's balance. It is used to add
 | ||||
| // funds to the destination account of a transfer.
 | ||||
| func (so *stateObject) AddBalance(amount *big.Int) { | ||||
| 	amt := sdk.NewIntFromBigInt(amount) | ||||
| 	// EIP158: We must check emptiness for the objects such that the account
 | ||||
| 	// clearing (0,0,0 objects) can take effect.
 | ||||
| 
 | ||||
| 	// NOTE: this will panic if amount is nil
 | ||||
| 	if amt.IsZero() { | ||||
| 		if so.empty() { | ||||
| 			so.touch() | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	newBalance := so.balance.Add(amt) | ||||
| 	so.SetBalance(newBalance.BigInt()) | ||||
| } | ||||
| 
 | ||||
| // SubBalance removes an amount from the stateObject's balance. It is used to
 | ||||
| // remove funds from the origin account of a transfer.
 | ||||
| func (so *stateObject) SubBalance(amount *big.Int) { | ||||
| 	amt := sdk.NewIntFromBigInt(amount) | ||||
| 	if amt.IsZero() { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	newBalance := so.balance.Sub(amt) | ||||
| 	so.SetBalance(newBalance.BigInt()) | ||||
| } | ||||
| 
 | ||||
| // SetBalance sets the state object's balance. It doesn't perform any validation
 | ||||
| // on the amount value.
 | ||||
| func (so *stateObject) SetBalance(amount *big.Int) { | ||||
| 	amt := sdk.NewIntFromBigInt(amount) | ||||
| 
 | ||||
| 	so.stateDB.journal.append(balanceChange{ | ||||
| 		account: &so.address, | ||||
| 		prev:    so.balance, | ||||
| 	}) | ||||
| 
 | ||||
| 	so.setBalance(amt) | ||||
| } | ||||
| 
 | ||||
| func (so *stateObject) setBalance(amount sdk.Int) { | ||||
| 	so.balance = amount | ||||
| } | ||||
| 
 | ||||
| // SetNonce sets the state object's nonce (i.e sequence number of the account).
 | ||||
| func (so *stateObject) SetNonce(nonce uint64) { | ||||
| 	so.stateDB.journal.append(nonceChange{ | ||||
| 		account: &so.address, | ||||
| 		prev:    so.account.Sequence, | ||||
| 	}) | ||||
| 
 | ||||
| 	so.setNonce(nonce) | ||||
| } | ||||
| 
 | ||||
| func (so *stateObject) setNonce(nonce uint64) { | ||||
| 	if so.account == nil { | ||||
| 		panic("state object account is empty") | ||||
| 	} | ||||
| 	so.account.Sequence = nonce | ||||
| } | ||||
| 
 | ||||
| // setError remembers the first non-nil error it is called with.
 | ||||
| func (so *stateObject) setError(err error) { | ||||
| 	if so.dbErr == nil { | ||||
| 		so.dbErr = err | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (so *stateObject) markSuicided() { | ||||
| 	so.suicided = true | ||||
| } | ||||
| 
 | ||||
| // commitState commits all dirty storage to a KVStore and resets
 | ||||
| // the dirty storage slice to the empty state.
 | ||||
| func (so *stateObject) commitState() { | ||||
| 	ctx := so.stateDB.ctx | ||||
| 	store := prefix.NewStore(ctx.KVStore(so.stateDB.storeKey), AddressStoragePrefix(so.Address())) | ||||
| 
 | ||||
| 	for _, state := range so.dirtyStorage { | ||||
| 		// NOTE: key is already prefixed from GetStorageByAddressKey
 | ||||
| 
 | ||||
| 		key := ethcmn.HexToHash(state.Key) | ||||
| 		value := ethcmn.HexToHash(state.Value) | ||||
| 		// delete empty values from the store
 | ||||
| 		if ethermint.IsEmptyHash(state.Value) { | ||||
| 			store.Delete(key.Bytes()) | ||||
| 		} | ||||
| 
 | ||||
| 		delete(so.keyToDirtyStorageIndex, key) | ||||
| 
 | ||||
| 		// skip no-op changes, persist actual changes
 | ||||
| 		idx, ok := so.keyToOriginStorageIndex[key] | ||||
| 		if !ok { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if ethermint.IsEmptyHash(state.Value) { | ||||
| 			delete(so.keyToOriginStorageIndex, key) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if state.Value == so.originStorage[idx].Value { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		so.originStorage[idx].Value = state.Value | ||||
| 		store.Set(key.Bytes(), value.Bytes()) | ||||
| 	} | ||||
| 	// clean storage as all entries are dirty
 | ||||
| 	so.dirtyStorage = Storage{} | ||||
| } | ||||
| 
 | ||||
| // commitCode persists the state object's code to the KVStore.
 | ||||
| func (so *stateObject) commitCode() { | ||||
| 	ctx := so.stateDB.ctx | ||||
| 	store := prefix.NewStore(ctx.KVStore(so.stateDB.storeKey), KeyPrefixCode) | ||||
| 	store.Set(so.CodeHash(), so.code) | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Getters
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // Address returns the address of the state object.
 | ||||
| func (so stateObject) Address() ethcmn.Address { | ||||
| 	return so.address | ||||
| } | ||||
| 
 | ||||
| // Balance returns the state object's current balance.
 | ||||
| func (so *stateObject) Balance() *big.Int { | ||||
| 	balance := so.balance.BigInt() | ||||
| 	if balance == nil { | ||||
| 		return zeroBalance | ||||
| 	} | ||||
| 	return balance | ||||
| } | ||||
| 
 | ||||
| // CodeHash returns the state object's code hash.
 | ||||
| func (so *stateObject) CodeHash() []byte { | ||||
| 	if so.account == nil || len(so.account.CodeHash) == 0 { | ||||
| 		return EmptyCodeHash | ||||
| 	} | ||||
| 	return so.account.CodeHash | ||||
| } | ||||
| 
 | ||||
| // Nonce returns the state object's current nonce (sequence number).
 | ||||
| func (so *stateObject) Nonce() uint64 { | ||||
| 	if so.account == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return so.account.Sequence | ||||
| } | ||||
| 
 | ||||
| // Code returns the contract code associated with this object, if any.
 | ||||
| func (so *stateObject) Code(_ ethstate.Database) []byte { | ||||
| 	if len(so.code) > 0 { | ||||
| 		return so.code | ||||
| 	} | ||||
| 
 | ||||
| 	if bytes.Equal(so.CodeHash(), EmptyCodeHash) { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := so.stateDB.ctx | ||||
| 	store := prefix.NewStore(ctx.KVStore(so.stateDB.storeKey), KeyPrefixCode) | ||||
| 	code := store.Get(so.CodeHash()) | ||||
| 
 | ||||
| 	if len(code) == 0 { | ||||
| 		so.setError(fmt.Errorf("failed to get code hash %x for address %s", so.CodeHash(), so.Address().String())) | ||||
| 	} | ||||
| 
 | ||||
| 	return code | ||||
| } | ||||
| 
 | ||||
| // GetState retrieves a value from the account storage trie. Note, the key will
 | ||||
| // be prefixed with the address of the state object.
 | ||||
| func (so *stateObject) GetState(db ethstate.Database, key ethcmn.Hash) ethcmn.Hash { | ||||
| 	prefixKey := so.GetStorageByAddressKey(key.Bytes()) | ||||
| 
 | ||||
| 	// if we have a dirty value for this state entry, return it
 | ||||
| 	idx, dirty := so.keyToDirtyStorageIndex[prefixKey] | ||||
| 	if dirty { | ||||
| 		value := ethcmn.HexToHash(so.dirtyStorage[idx].Value) | ||||
| 		return value | ||||
| 	} | ||||
| 
 | ||||
| 	// otherwise return the entry's original value
 | ||||
| 	value := so.GetCommittedState(db, key) | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| // GetCommittedState retrieves a value from the committed account storage trie.
 | ||||
| //
 | ||||
| // NOTE: the key will be prefixed with the address of the state object.
 | ||||
| func (so *stateObject) GetCommittedState(_ ethstate.Database, key ethcmn.Hash) ethcmn.Hash { | ||||
| 	prefixKey := so.GetStorageByAddressKey(key.Bytes()) | ||||
| 
 | ||||
| 	// if we have the original value cached, return that
 | ||||
| 	idx, cached := so.keyToOriginStorageIndex[prefixKey] | ||||
| 	if cached { | ||||
| 		value := ethcmn.HexToHash(so.originStorage[idx].Value) | ||||
| 		return value | ||||
| 	} | ||||
| 
 | ||||
| 	// otherwise load the value from the KVStore
 | ||||
| 	state := NewState(prefixKey, ethcmn.Hash{}) | ||||
| 	value := ethcmn.Hash{} | ||||
| 
 | ||||
| 	ctx := so.stateDB.ctx | ||||
| 	store := prefix.NewStore(ctx.KVStore(so.stateDB.storeKey), AddressStoragePrefix(so.Address())) | ||||
| 	rawValue := store.Get(prefixKey.Bytes()) | ||||
| 
 | ||||
| 	if len(rawValue) > 0 { | ||||
| 		value.SetBytes(rawValue) | ||||
| 		state.Value = value.String() | ||||
| 	} | ||||
| 
 | ||||
| 	so.originStorage = append(so.originStorage, state) | ||||
| 	so.keyToOriginStorageIndex[prefixKey] = len(so.originStorage) - 1 | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Auxiliary
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // ReturnGas returns the gas back to the origin. Used by the Virtual machine or
 | ||||
| // Closures. It performs a no-op.
 | ||||
| func (so *stateObject) ReturnGas(gas *big.Int) {} | ||||
| 
 | ||||
| func (so *stateObject) deepCopy(db *CommitStateDB) *stateObject { | ||||
| 	newStateObj := newStateObject(db, so.account, so.balance) | ||||
| 
 | ||||
| 	newStateObj.code = so.code | ||||
| 	newStateObj.dirtyStorage = so.dirtyStorage.Copy() | ||||
| 	newStateObj.originStorage = so.originStorage.Copy() | ||||
| 	newStateObj.suicided = so.suicided | ||||
| 	newStateObj.dirtyCode = so.dirtyCode | ||||
| 	newStateObj.deleted = so.deleted | ||||
| 
 | ||||
| 	return newStateObj | ||||
| } | ||||
| 
 | ||||
| // empty returns whether the account is considered empty.
 | ||||
| func (so *stateObject) empty() bool { | ||||
| 	return so.account == nil || | ||||
| 		(so.account != nil && | ||||
| 			so.account.Sequence == 0 && | ||||
| 			(so.balance.BigInt() == nil || so.balance.IsZero()) && | ||||
| 			bytes.Equal(so.account.CodeHash, EmptyCodeHash)) | ||||
| } | ||||
| 
 | ||||
| // EncodeRLP implements rlp.Encoder.
 | ||||
| func (so *stateObject) EncodeRLP(w io.Writer) error { | ||||
| 	return rlp.Encode(w, so.account) | ||||
| } | ||||
| 
 | ||||
| func (so *stateObject) touch() { | ||||
| 	so.stateDB.journal.append(touchChange{ | ||||
| 		account: &so.address, | ||||
| 	}) | ||||
| 
 | ||||
| 	if so.address == ripemd { | ||||
| 		// Explicitly put it in the dirty-cache, which is otherwise generated from
 | ||||
| 		// flattened journals.
 | ||||
| 		so.stateDB.journal.dirty(so.address) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetStorageByAddressKey returns a hash of the composite key for a state
 | ||||
| // object's storage prefixed with it's address.
 | ||||
| func (so stateObject) GetStorageByAddressKey(key []byte) ethcmn.Hash { | ||||
| 	prefix := so.Address().Bytes() | ||||
| 	compositeKey := make([]byte, len(prefix)+len(key)) | ||||
| 
 | ||||
| 	copy(compositeKey, prefix) | ||||
| 	copy(compositeKey[len(prefix):], key) | ||||
| 
 | ||||
| 	return ethcrypto.Keccak256Hash(compositeKey) | ||||
| } | ||||
| 
 | ||||
| // stateEntry represents a single key value pair from the StateDB's stateObject mappindg.
 | ||||
| // This is to prevent non determinism at genesis initialization or export.
 | ||||
| type stateEntry struct { | ||||
| 	// address key of the state object
 | ||||
| 	address     ethcmn.Address | ||||
| 	stateObject *stateObject | ||||
| } | ||||
| @ -1,135 +0,0 @@ | ||||
| package types_test | ||||
| 
 | ||||
| import ( | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateObject_State() { | ||||
| 	testCase := []struct { | ||||
| 		name     string | ||||
| 		key      ethcmn.Hash | ||||
| 		expValue ethcmn.Hash | ||||
| 		malleate func() | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"no set value, load from KVStore", | ||||
| 			ethcmn.BytesToHash([]byte("key")), | ||||
| 			ethcmn.Hash{}, | ||||
| 			func() {}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"no-op SetState", | ||||
| 			ethcmn.BytesToHash([]byte("key")), | ||||
| 			ethcmn.Hash{}, | ||||
| 			func() { | ||||
| 				suite.stateObject.SetState(nil, ethcmn.BytesToHash([]byte("key")), ethcmn.Hash{}) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"cached value", | ||||
| 			ethcmn.BytesToHash([]byte("key1")), | ||||
| 			ethcmn.BytesToHash([]byte("value1")), | ||||
| 			func() { | ||||
| 				suite.stateObject.SetState(nil, ethcmn.BytesToHash([]byte("key1")), ethcmn.BytesToHash([]byte("value1"))) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"update value", | ||||
| 			ethcmn.BytesToHash([]byte("key1")), | ||||
| 			ethcmn.BytesToHash([]byte("value2")), | ||||
| 			func() { | ||||
| 				suite.stateObject.SetState(nil, ethcmn.BytesToHash([]byte("key1")), ethcmn.BytesToHash([]byte("value2"))) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"update various keys", | ||||
| 			ethcmn.BytesToHash([]byte("key1")), | ||||
| 			ethcmn.BytesToHash([]byte("value1")), | ||||
| 			func() { | ||||
| 				suite.stateObject.SetState(nil, ethcmn.BytesToHash([]byte("key1")), ethcmn.BytesToHash([]byte("value1"))) | ||||
| 				suite.stateObject.SetState(nil, ethcmn.BytesToHash([]byte("key2")), ethcmn.BytesToHash([]byte("value2"))) | ||||
| 				suite.stateObject.SetState(nil, ethcmn.BytesToHash([]byte("key3")), ethcmn.BytesToHash([]byte("value3"))) | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 
 | ||||
| 		value := suite.stateObject.GetState(nil, tc.key) | ||||
| 		suite.Require().Equal(tc.expValue, value, tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateObject_AddBalance() { | ||||
| 	testCase := []struct { | ||||
| 		name       string | ||||
| 		amount     *big.Int | ||||
| 		expBalance *big.Int | ||||
| 	}{ | ||||
| 		{"zero amount", big.NewInt(0), big.NewInt(0)}, | ||||
| 		{"positive amount", big.NewInt(10), big.NewInt(10)}, | ||||
| 		{"negative amount", big.NewInt(-1), big.NewInt(9)}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		suite.stateObject.AddBalance(tc.amount) | ||||
| 		suite.Require().Equal(tc.expBalance, suite.stateObject.Balance(), tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateObject_SubBalance() { | ||||
| 	testCase := []struct { | ||||
| 		name       string | ||||
| 		amount     *big.Int | ||||
| 		expBalance *big.Int | ||||
| 	}{ | ||||
| 		{"zero amount", big.NewInt(0), big.NewInt(0)}, | ||||
| 		{"negative amount", big.NewInt(-10), big.NewInt(10)}, | ||||
| 		{"positive amount", big.NewInt(1), big.NewInt(9)}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		suite.stateObject.SubBalance(tc.amount) | ||||
| 		suite.Require().Equal(tc.expBalance, suite.stateObject.Balance(), tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateObject_Code() { | ||||
| 	testCase := []struct { | ||||
| 		name     string | ||||
| 		expCode  []byte | ||||
| 		malleate func() | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"cached code", | ||||
| 			[]byte("code"), | ||||
| 			func() { | ||||
| 				suite.stateObject.SetCode(ethcmn.BytesToHash([]byte("code_hash")), []byte("code")) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"empty code hash", | ||||
| 			nil, | ||||
| 			func() { | ||||
| 				suite.stateObject.SetCode(ethcmn.Hash{}, nil) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"empty code", | ||||
| 			nil, | ||||
| 			func() { | ||||
| 				suite.stateObject.SetCode(ethcmn.BytesToHash([]byte("code_hash")), nil) | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 
 | ||||
| 		code := suite.stateObject.Code(nil) | ||||
| 		suite.Require().Equal(tc.expCode, code, tc.name) | ||||
| 	} | ||||
| } | ||||
| @ -1,340 +0,0 @@ | ||||
| package types | ||||
| 
 | ||||
| import ( | ||||
| 	"math/big" | ||||
| 	"os" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/pkg/errors" | ||||
| 	log "github.com/xlab/suplog" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/core/vm" | ||||
| 	tmtypes "github.com/tendermint/tendermint/types" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/telemetry" | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||||
| ) | ||||
| 
 | ||||
| // StateTransition defines data to transitionDB in evm
 | ||||
| type StateTransition struct { | ||||
| 	// TxData fields
 | ||||
| 	Message core.Message | ||||
| 
 | ||||
| 	ChainID  *big.Int | ||||
| 	Csdb     *CommitStateDB | ||||
| 	TxHash   *common.Hash | ||||
| 	Simulate bool // i.e CheckTx execution
 | ||||
| 	Debug    bool // enable EVM debugging
 | ||||
| } | ||||
| 
 | ||||
| // GasInfo returns the gas limit, gas consumed and gas refunded from the EVM transition
 | ||||
| // execution
 | ||||
| type GasInfo struct { | ||||
| 	GasLimit    uint64 | ||||
| 	GasConsumed uint64 | ||||
| 	GasRefunded uint64 | ||||
| } | ||||
| 
 | ||||
| // ExecutionResult represents what's returned from a transition
 | ||||
| type ExecutionResult struct { | ||||
| 	Logs     []*ethtypes.Log | ||||
| 	Bloom    *big.Int | ||||
| 	Response *MsgEthereumTxResponse | ||||
| 	GasInfo  GasInfo | ||||
| } | ||||
| 
 | ||||
| // GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases:
 | ||||
| //  1. The requested height matches the current height from context (and thus same epoch number)
 | ||||
| //  2. The requested height is from an previous height from the same chain epoch
 | ||||
| //  3. The requested height is from a height greater than the latest one
 | ||||
| func GetHashFn(ctx sdk.Context, csdb *CommitStateDB) vm.GetHashFunc { | ||||
| 	return func(height uint64) common.Hash { | ||||
| 		switch { | ||||
| 		case ctx.BlockHeight() == int64(height): | ||||
| 			// Case 1: The requested height matches the one from the context so we can retrieve the header
 | ||||
| 			// hash directly from the context.
 | ||||
| 			return csdb.bhash | ||||
| 
 | ||||
| 		case ctx.BlockHeight() > int64(height): | ||||
| 			// Case 2: if the chain is not the current height we need to retrieve the hash from the store for the
 | ||||
| 			// current chain epoch. This only applies if the current height is greater than the requested height.
 | ||||
| 			return csdb.WithContext(ctx).GetHeightHash(height) | ||||
| 
 | ||||
| 		default: | ||||
| 			// Case 3: heights greater than the current one returns an empty hash.
 | ||||
| 			return common.Hash{} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (st *StateTransition) newEVM( | ||||
| 	ctx sdk.Context, | ||||
| 	csdb *CommitStateDB, | ||||
| 	gasLimit uint64, | ||||
| 	config ChainConfig, | ||||
| 	extraEIPs []int64, | ||||
| ) *vm.EVM { | ||||
| 	// Create context for evm
 | ||||
| 	blockCtx := vm.BlockContext{ | ||||
| 		CanTransfer: core.CanTransfer, | ||||
| 		Transfer:    core.Transfer, | ||||
| 		GetHash:     GetHashFn(ctx, csdb), | ||||
| 		Coinbase:    common.Address{}, // there's no beneficiary since we're not mining
 | ||||
| 		BlockNumber: big.NewInt(ctx.BlockHeight()), | ||||
| 		Time:        big.NewInt(ctx.BlockHeader().Time.Unix()), | ||||
| 		Difficulty:  big.NewInt(0), // unused. Only required in PoW context
 | ||||
| 		GasLimit:    gasLimit, | ||||
| 	} | ||||
| 
 | ||||
| 	txCtx := core.NewEVMTxContext(st.Message) | ||||
| 
 | ||||
| 	eips := make([]int, len(extraEIPs)) | ||||
| 	for i, eip := range extraEIPs { | ||||
| 		eips[i] = int(eip) | ||||
| 	} | ||||
| 
 | ||||
| 	vmConfig := vm.Config{ | ||||
| 		EnablePreimageRecording: false, // no need for StateDB.AddPreimage
 | ||||
| 		ExtraEips:               eips, | ||||
| 	} | ||||
| 
 | ||||
| 	if st.Debug { | ||||
| 		vmConfig.Tracer = vm.NewJSONLogger(&vm.LogConfig{ | ||||
| 			Debug: true, | ||||
| 		}, os.Stderr) | ||||
| 
 | ||||
| 		vmConfig.Debug = true | ||||
| 	} | ||||
| 
 | ||||
| 	return vm.NewEVM(blockCtx, txCtx, csdb, config.EthereumConfig(st.ChainID), vmConfig) | ||||
| } | ||||
| 
 | ||||
| // TransitionDb will transition the state by applying the current transaction and
 | ||||
| // returning the evm execution result.
 | ||||
| // NOTE: State transition checks are run during AnteHandler execution.
 | ||||
| func (st *StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (resp *ExecutionResult, err error) { | ||||
| 	defer telemetry.ModuleMeasureSince(ModuleName, time.Now(), MetricKeyTransitionDB) | ||||
| 
 | ||||
| 	contractCreation := st.Message.To() == nil | ||||
| 
 | ||||
| 	cost, err := core.IntrinsicGas(st.Message.Data(), st.Message.AccessList(), true, false, true) | ||||
| 	if err != nil { | ||||
| 		err = sdkerrors.Wrap(err, "invalid intrinsic gas for transaction") | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// This gas limit the the transaction gas limit with intrinsic gas subtracted
 | ||||
| 	gasLimit := st.Message.Gas() - ctx.GasMeter().GasConsumed() | ||||
| 
 | ||||
| 	csdb := st.Csdb.WithContext(ctx) | ||||
| 	if st.Simulate { | ||||
| 		// gasLimit is set here because stdTxs incur gaskv charges in the ante handler, but for eth_call
 | ||||
| 		// the cost needs to be the same as an Ethereum transaction sent through the web3 API
 | ||||
| 		consumedGas := ctx.GasMeter().GasConsumed() | ||||
| 		gasLimit = st.Message.Gas() - cost | ||||
| 		if consumedGas < cost { | ||||
| 			// If Cosmos standard tx ante handler cost is less than EVM intrinsic cost
 | ||||
| 			// gas must be consumed to match to accurately simulate an Ethereum transaction
 | ||||
| 			ctx.GasMeter().ConsumeGas(cost-consumedGas, "Intrinsic gas match") | ||||
| 		} | ||||
| 
 | ||||
| 		csdb = st.Csdb.Copy() | ||||
| 	} | ||||
| 
 | ||||
| 	// This gas meter is set up to consume gas from gaskv during evm execution and be ignored
 | ||||
| 	currentGasMeter := ctx.GasMeter() | ||||
| 	evmGasMeter := sdk.NewInfiniteGasMeter() | ||||
| 	csdb.WithContext(ctx.WithGasMeter(evmGasMeter)) | ||||
| 
 | ||||
| 	// Clear cache of accounts to handle changes outside of the EVM
 | ||||
| 	csdb.UpdateAccounts() | ||||
| 
 | ||||
| 	params := csdb.GetParams() | ||||
| 
 | ||||
| 	gasPrice := ctx.MinGasPrices().AmountOf(params.EvmDenom) | ||||
| 	//gasPrice := sdk.ZeroDec()
 | ||||
| 	if gasPrice.IsNil() { | ||||
| 		return nil, errors.New("min gas price cannot be nil") | ||||
| 	} | ||||
| 
 | ||||
| 	evm := st.newEVM(ctx, csdb, gasLimit, config, params.ExtraEIPs) | ||||
| 
 | ||||
| 	var ( | ||||
| 		ret             []byte | ||||
| 		leftOverGas     uint64 | ||||
| 		contractAddress common.Address | ||||
| 		senderRef       = vm.AccountRef(st.Message.From()) | ||||
| 	) | ||||
| 
 | ||||
| 	// Get nonce of account outside of the EVM
 | ||||
| 	currentNonce := csdb.GetNonce(st.Message.From()) | ||||
| 	// Set nonce of sender account before evm state transition for usage in generating Create address
 | ||||
| 	csdb.SetNonce(st.Message.From(), st.Message.Nonce()) | ||||
| 
 | ||||
| 	// create contract or execute call
 | ||||
| 	switch contractCreation { | ||||
| 	case true: | ||||
| 		if !params.EnableCreate { | ||||
| 			return nil, ErrCreateDisabled | ||||
| 		} | ||||
| 
 | ||||
| 		ret, contractAddress, leftOverGas, err = evm.Create(senderRef, st.Message.Data(), gasLimit, st.Message.Value()) | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			log.WithField("simulate", st.Simulate). | ||||
| 				WithField("nonce", st.Message.Nonce()). | ||||
| 				WithField("contract", contractAddress.String()). | ||||
| 				WithError(err).Warningln("evm contract creation failed") | ||||
| 		} | ||||
| 
 | ||||
| 		gasConsumed := gasLimit - leftOverGas | ||||
| 		resp = &ExecutionResult{ | ||||
| 			Response: &MsgEthereumTxResponse{ | ||||
| 				Ret: ret, | ||||
| 			}, | ||||
| 			GasInfo: GasInfo{ | ||||
| 				GasConsumed: gasConsumed, | ||||
| 				GasLimit:    gasLimit, | ||||
| 				GasRefunded: leftOverGas, | ||||
| 			}, | ||||
| 		} | ||||
| 	default: | ||||
| 		if !params.EnableCall { | ||||
| 			return nil, ErrCallDisabled | ||||
| 		} | ||||
| 
 | ||||
| 		// Increment the nonce for the next transaction	(just for evm state transition)
 | ||||
| 		csdb.SetNonce(st.Message.From(), csdb.GetNonce(st.Message.From())+1) | ||||
| 
 | ||||
| 		ret, leftOverGas, err = evm.Call(senderRef, *st.Message.To(), st.Message.Data(), gasLimit, st.Message.Value()) | ||||
| 
 | ||||
| 		// fmt.Println("EVM CALL!!!", senderRef.Address().Hex(), (*st.Message.To()).Hex(), gasLimit)
 | ||||
| 		// fmt.Println("EVM CALL RESULT", common.ToHex(ret), leftOverGas, err)
 | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			log.WithField("recipient", st.Message.To().String()). | ||||
| 				WithError(err).Debugln("evm call failed") | ||||
| 		} | ||||
| 
 | ||||
| 		gasConsumed := gasLimit - leftOverGas | ||||
| 		resp = &ExecutionResult{ | ||||
| 			Response: &MsgEthereumTxResponse{ | ||||
| 				Ret: ret, | ||||
| 			}, | ||||
| 			GasInfo: GasInfo{ | ||||
| 				GasConsumed: gasConsumed, | ||||
| 				GasLimit:    gasLimit, | ||||
| 				GasRefunded: leftOverGas, | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		// Consume gas before returning
 | ||||
| 		ctx.GasMeter().ConsumeGas(resp.GasInfo.GasConsumed, "evm execution consumption") | ||||
| 		return resp, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Resets nonce to value pre state transition
 | ||||
| 	csdb.SetNonce(st.Message.From(), currentNonce) | ||||
| 
 | ||||
| 	var ( | ||||
| 		logs []*ethtypes.Log | ||||
| 	) | ||||
| 
 | ||||
| 	if st.TxHash != nil && !st.Simulate { | ||||
| 		logs, err = csdb.GetLogs(*st.TxHash) | ||||
| 		if err != nil { | ||||
| 			err = errors.Wrap(err, "failed to get logs") | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if !st.Simulate { | ||||
| 		// Finalise state if not a simulated transaction
 | ||||
| 		// TODO: change to depend on config
 | ||||
| 		if err := csdb.Finalise(true); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	resp.Logs = logs | ||||
| 	resp.Response = &MsgEthereumTxResponse{ | ||||
| 		Logs: NewLogsFromEth(logs), | ||||
| 		Ret:  ret, | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: Refund unused gas here, if intended in future
 | ||||
| 
 | ||||
| 	// Consume gas from evm execution
 | ||||
| 	// Out of gas check does not need to be done here since it is done within the EVM execution
 | ||||
| 
 | ||||
| 	// TODO: @albert, @maxim, decide if can take this out, since InternalEthereumTx may want to continue execution afterwards
 | ||||
| 	// which will use gas.
 | ||||
| 	_ = currentGasMeter | ||||
| 	//ctx.WithGasMeter(currentGasMeter).GasMeter().ConsumeGas(resp.GasInfo.GasConsumed, "EVM execution consumption")
 | ||||
| 
 | ||||
| 	return resp, nil | ||||
| } | ||||
| 
 | ||||
| // StaticCall executes the contract associated with the addr with the given input
 | ||||
| // as parameters while disallowing any modifications to the state during the call.
 | ||||
| // Opcodes that attempt to perform such modifications will result in exceptions
 | ||||
| // instead of performing the modifications.
 | ||||
| func (st *StateTransition) StaticCall(ctx sdk.Context, config ChainConfig) ([]byte, error) { | ||||
| 	defer telemetry.ModuleMeasureSince(ModuleName, time.Now(), MetricKeyStaticCall) | ||||
| 
 | ||||
| 	// This gas limit the the transaction gas limit with intrinsic gas subtracted
 | ||||
| 	gasLimit := st.Message.Gas() - ctx.GasMeter().GasConsumed() | ||||
| 	csdb := st.Csdb.WithContext(ctx) | ||||
| 
 | ||||
| 	// This gas meter is set up to consume gas from gaskv during evm execution and be ignored
 | ||||
| 	evmGasMeter := sdk.NewInfiniteGasMeter() | ||||
| 	csdb.WithContext(ctx.WithGasMeter(evmGasMeter)) | ||||
| 
 | ||||
| 	// Clear cache of accounts to handle changes outside of the EVM
 | ||||
| 	csdb.UpdateAccounts() | ||||
| 
 | ||||
| 	params := csdb.GetParams() | ||||
| 
 | ||||
| 	gasPrice := ctx.MinGasPrices().AmountOf(params.EvmDenom) | ||||
| 	if gasPrice.IsNil() { | ||||
| 		return []byte{}, errors.New("min gas price cannot be nil") | ||||
| 	} | ||||
| 
 | ||||
| 	evm := st.newEVM(ctx, csdb, gasLimit, config, params.ExtraEIPs) | ||||
| 	senderRef := vm.AccountRef(st.Message.From()) | ||||
| 
 | ||||
| 	ret, _, err := evm.StaticCall(senderRef, *st.Message.To(), st.Message.Data(), gasLimit) | ||||
| 
 | ||||
| 	// fmt.Println("EVM STATIC CALL!!!", senderRef.Address().Hex(), (*st.Message.To()).Hex(), st.Message.Data(), gasLimit)
 | ||||
| 	// fmt.Println("EVM STATIC CALL RESULT", common.ToHex(ret), leftOverGas, err)
 | ||||
| 
 | ||||
| 	return ret, err | ||||
| } | ||||
| 
 | ||||
| // HashFromContext returns the Ethereum Header hash from the context's Tendermint
 | ||||
| // block header.
 | ||||
| func HashFromContext(ctx sdk.Context) common.Hash { | ||||
| 	// cast the ABCI header to tendermint Header type
 | ||||
| 	protoHeader := ctx.BlockHeader() | ||||
| 	tmHeader, err := tmtypes.HeaderFromProto(&protoHeader) | ||||
| 	if err != nil { | ||||
| 		return common.Hash{} | ||||
| 	} | ||||
| 
 | ||||
| 	// get the Tendermint block hash from the current header
 | ||||
| 	tmBlockHash := tmHeader.Hash() | ||||
| 
 | ||||
| 	// NOTE: if the validator set hash is missing the hash will be returned as nil,
 | ||||
| 	// so we need to check for this case to prevent a panic when calling Bytes()
 | ||||
| 	if tmBlockHash == nil { | ||||
| 		return common.Hash{} | ||||
| 	} | ||||
| 
 | ||||
| 	return common.BytesToHash(tmBlockHash.Bytes()) | ||||
| } | ||||
| @ -1,190 +0,0 @@ | ||||
| package types_test | ||||
| 
 | ||||
| import ( | ||||
| 	"math/big" | ||||
| 
 | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 
 | ||||
| 	"github.com/cosmos/ethermint/crypto/ethsecp256k1" | ||||
| 	ethermint "github.com/cosmos/ethermint/types" | ||||
| 	"github.com/cosmos/ethermint/x/evm/types" | ||||
| 
 | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	ethcrypto "github.com/ethereum/go-ethereum/crypto" | ||||
| ) | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestTransitionDb() { | ||||
| 	suite.stateDB.SetNonce(suite.address, 123) | ||||
| 
 | ||||
| 	addr := sdk.AccAddress(suite.address.Bytes()) | ||||
| 	balance := ethermint.NewPhotonCoin(sdk.NewInt(5000)) | ||||
| 	acc := suite.app.AccountKeeper.GetAccount(suite.ctx, addr) | ||||
| 	suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 	suite.app.BankKeeper.SetBalance(suite.ctx, addr, balance) | ||||
| 
 | ||||
| 	priv, err := ethsecp256k1.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{ | ||||
| 				Message: ethtypes.NewMessage( | ||||
| 					suite.address, | ||||
| 					&recipient, | ||||
| 					123, | ||||
| 					big.NewInt(50), | ||||
| 					11, | ||||
| 					big.NewInt(10), | ||||
| 					[]byte("data"), | ||||
| 					nil, | ||||
| 					true, | ||||
| 				), | ||||
| 				ChainID:  big.NewInt(1), | ||||
| 				Csdb:     suite.stateDB, | ||||
| 				TxHash:   ðcmn.Hash{}, | ||||
| 				Simulate: suite.ctx.IsCheckTx(), | ||||
| 			}, | ||||
| 			true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"contract creation", | ||||
| 			func() {}, | ||||
| 			types.StateTransition{ | ||||
| 				Message: ethtypes.NewMessage( | ||||
| 					suite.address, | ||||
| 					nil, | ||||
| 					123, | ||||
| 					big.NewInt(50), | ||||
| 					11, | ||||
| 					big.NewInt(10), | ||||
| 					[]byte("data"), | ||||
| 					nil, | ||||
| 					true, | ||||
| 				), | ||||
| 				ChainID:  big.NewInt(1), | ||||
| 				Csdb:     suite.stateDB, | ||||
| 				TxHash:   ðcmn.Hash{}, | ||||
| 				Simulate: true, | ||||
| 			}, | ||||
| 			true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"state transition simulation", | ||||
| 			func() {}, | ||||
| 			types.StateTransition{ | ||||
| 				Message: ethtypes.NewMessage( | ||||
| 					suite.address, | ||||
| 					&recipient, | ||||
| 					123, | ||||
| 					big.NewInt(50), | ||||
| 					11, | ||||
| 					big.NewInt(10), | ||||
| 					[]byte("data"), | ||||
| 					nil, | ||||
| 					true, | ||||
| 				), | ||||
| 				ChainID:  big.NewInt(1), | ||||
| 				Csdb:     suite.stateDB, | ||||
| 				TxHash:   ðcmn.Hash{}, | ||||
| 				Simulate: true, | ||||
| 			}, | ||||
| 			true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fail by sending more than balance", | ||||
| 			func() {}, | ||||
| 			types.StateTransition{ | ||||
| 				Message: ethtypes.NewMessage( | ||||
| 					suite.address, | ||||
| 					&recipient, | ||||
| 					123, | ||||
| 					big.NewInt(50000000), | ||||
| 					11, | ||||
| 					big.NewInt(10), | ||||
| 					[]byte("data"), | ||||
| 					nil, | ||||
| 					true, | ||||
| 				), | ||||
| 				ChainID:  big.NewInt(1), | ||||
| 				Csdb:     suite.stateDB, | ||||
| 				TxHash:   ðcmn.Hash{}, | ||||
| 				Simulate: suite.ctx.IsCheckTx(), | ||||
| 			}, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"failed to Finalize", | ||||
| 			func() {}, | ||||
| 			types.StateTransition{ | ||||
| 				Message: ethtypes.NewMessage( | ||||
| 					suite.address, | ||||
| 					&recipient, | ||||
| 					123, | ||||
| 					big.NewInt(-5000), | ||||
| 					11, | ||||
| 					big.NewInt(10), | ||||
| 					[]byte("data"), | ||||
| 					nil, | ||||
| 					true, | ||||
| 				), | ||||
| 				ChainID:  big.NewInt(1), | ||||
| 				Csdb:     suite.stateDB, | ||||
| 				TxHash:   ðcmn.Hash{}, | ||||
| 				Simulate: false, | ||||
| 			}, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"nil gas price", | ||||
| 			func() { | ||||
| 				invalidGas := sdk.DecCoins{ | ||||
| 					{Denom: ethermint.AttoPhoton}, | ||||
| 				} | ||||
| 				suite.ctx = suite.ctx.WithMinGasPrices(invalidGas) | ||||
| 			}, | ||||
| 			types.StateTransition{ | ||||
| 				Message: ethtypes.NewMessage( | ||||
| 					suite.address, | ||||
| 					&recipient, | ||||
| 					123, | ||||
| 					big.NewInt(50), | ||||
| 					11, | ||||
| 					nil, | ||||
| 					[]byte("data"), | ||||
| 					nil, | ||||
| 					true, | ||||
| 				), | ||||
| 				ChainID:  big.NewInt(1), | ||||
| 				Csdb:     suite.stateDB, | ||||
| 				TxHash:   ðcmn.Hash{}, | ||||
| 				Simulate: suite.ctx.IsCheckTx(), | ||||
| 			}, | ||||
| 			false, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 
 | ||||
| 		_, err = tc.state.TransitionDb(suite.ctx, types.DefaultChainConfig()) | ||||
| 
 | ||||
| 		if tc.expPass { | ||||
| 			suite.Require().NoError(err, tc.name) | ||||
| 			fromBalance := suite.app.EvmKeeper.CommitStateDB.GetBalance(suite.address) | ||||
| 			toBalance := suite.app.EvmKeeper.CommitStateDB.GetBalance(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) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -1,990 +0,0 @@ | ||||
| package types | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/cosmos/cosmos-sdk/store/prefix" | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" | ||||
| 
 | ||||
| 	ethermint "github.com/cosmos/ethermint/types" | ||||
| 
 | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethstate "github.com/ethereum/go-ethereum/core/state" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	ethvm "github.com/ethereum/go-ethereum/core/vm" | ||||
| 	ethcrypto "github.com/ethereum/go-ethereum/crypto" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	_ ethvm.StateDB = (*CommitStateDB)(nil) | ||||
| 
 | ||||
| 	zeroBalance = sdk.ZeroInt().BigInt() | ||||
| ) | ||||
| 
 | ||||
| // CommitStateDB implements the Geth state.StateDB interface. Instead of using
 | ||||
| // a trie and database for querying and persistence, the Keeper uses KVStores
 | ||||
| // and an AccountKeeper to facilitate state transitions.
 | ||||
| //
 | ||||
| // TODO: This implementation is subject to change in regards to its statefull
 | ||||
| // manner. In otherwords, how this relates to the keeper in this module.
 | ||||
| type CommitStateDB struct { | ||||
| 	// TODO: We need to store the context as part of the structure itself opposed
 | ||||
| 	// to being passed as a parameter (as it should be) in order to implement the
 | ||||
| 	// StateDB interface. Perhaps there is a better way.
 | ||||
| 	ctx sdk.Context | ||||
| 
 | ||||
| 	storeKey      sdk.StoreKey | ||||
| 	transientKey  sdk.StoreKey | ||||
| 	paramSpace    paramtypes.Subspace | ||||
| 	accountKeeper AccountKeeper | ||||
| 	bankKeeper    BankKeeper | ||||
| 
 | ||||
| 	// array that hold 'live' objects, which will get modified while processing a
 | ||||
| 	// state transition
 | ||||
| 	stateObjects         []stateEntry | ||||
| 	addressToObjectIndex map[ethcmn.Address]int // map from address to the index of the state objects slice
 | ||||
| 	stateObjectsDirty    map[ethcmn.Address]struct{} | ||||
| 
 | ||||
| 	// The refund counter, also used by state transitioning.
 | ||||
| 	refund uint64 | ||||
| 
 | ||||
| 	thash, bhash ethcmn.Hash | ||||
| 	txIndex      int | ||||
| 	logSize      uint | ||||
| 
 | ||||
| 	// TODO: Determine if we actually need this as we do not need preimages in
 | ||||
| 	// the SDK, but it seems to be used elsewhere in Geth.
 | ||||
| 	preimages           []preimageEntry | ||||
| 	hashToPreimageIndex map[ethcmn.Hash]int // map from hash to the index of the preimages slice
 | ||||
| 
 | ||||
| 	// DB error.
 | ||||
| 	// State objects are used by the consensus core and VM which are
 | ||||
| 	// unable to deal with database-level errors. Any error that occurs
 | ||||
| 	// during a database read is memo-ized here and will eventually be returned
 | ||||
| 	// by StateDB.Commit.
 | ||||
| 	dbErr error | ||||
| 
 | ||||
| 	// journal of state modifications. This is the backbone of
 | ||||
| 	// Snapshot and RevertToSnapshot.
 | ||||
| 	journal        *journal | ||||
| 	validRevisions []revision | ||||
| 	nextRevisionID int | ||||
| 
 | ||||
| 	// mutex for state deep copying
 | ||||
| 	lock sync.Mutex | ||||
| } | ||||
| 
 | ||||
| // NewCommitStateDB returns a reference to a newly initialized CommitStateDB
 | ||||
| // which implements Geth's state.StateDB interface.
 | ||||
| //
 | ||||
| // CONTRACT: Stores used for state must be cache-wrapped as the ordering of the
 | ||||
| // key/value space matters in determining the merkle root.
 | ||||
| func NewCommitStateDB( | ||||
| 	ctx sdk.Context, storeKey, tKey sdk.StoreKey, paramSpace paramtypes.Subspace, | ||||
| 	ak AccountKeeper, bankKeeper BankKeeper, | ||||
| ) *CommitStateDB { | ||||
| 	return &CommitStateDB{ | ||||
| 		ctx:                  ctx, | ||||
| 		storeKey:             storeKey, | ||||
| 		transientKey:         tKey, | ||||
| 		paramSpace:           paramSpace, | ||||
| 		accountKeeper:        ak, | ||||
| 		bankKeeper:           bankKeeper, | ||||
| 		stateObjects:         []stateEntry{}, | ||||
| 		addressToObjectIndex: make(map[ethcmn.Address]int), | ||||
| 		stateObjectsDirty:    make(map[ethcmn.Address]struct{}), | ||||
| 		preimages:            []preimageEntry{}, | ||||
| 		hashToPreimageIndex:  make(map[ethcmn.Hash]int), | ||||
| 		journal:              newJournal(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithContext returns a Database with an updated SDK context
 | ||||
| func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB { | ||||
| 	csdb.ctx = ctx | ||||
| 	return csdb | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Setters
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // SetHeightHash sets the block header hash associated with a given height.
 | ||||
| func (csdb *CommitStateDB) SetHeightHash(height uint64, hash ethcmn.Hash) { | ||||
| 	store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightToHeaderHash) | ||||
| 	store.Set(sdk.Uint64ToBigEndian(height), hash.Bytes()) | ||||
| } | ||||
| 
 | ||||
| // SetParams sets the evm parameters to the param space.
 | ||||
| func (csdb *CommitStateDB) SetParams(params Params) { | ||||
| 	csdb.paramSpace.SetParamSet(csdb.ctx, ¶ms) | ||||
| } | ||||
| 
 | ||||
| // SetBalance sets the balance of an account.
 | ||||
| func (csdb *CommitStateDB) SetBalance(addr ethcmn.Address, amount *big.Int) { | ||||
| 	so := csdb.GetOrNewStateObject(addr) | ||||
| 	so.SetBalance(amount) | ||||
| } | ||||
| 
 | ||||
| // AddBalance adds amount to the account associated with addr.
 | ||||
| func (csdb *CommitStateDB) AddBalance(addr ethcmn.Address, amount *big.Int) { | ||||
| 	so := csdb.GetOrNewStateObject(addr) | ||||
| 	so.AddBalance(amount) | ||||
| } | ||||
| 
 | ||||
| // SubBalance subtracts amount from the account associated with addr.
 | ||||
| func (csdb *CommitStateDB) SubBalance(addr ethcmn.Address, amount *big.Int) { | ||||
| 	so := csdb.GetOrNewStateObject(addr) | ||||
| 	so.SubBalance(amount) | ||||
| } | ||||
| 
 | ||||
| // SetNonce sets the nonce (sequence number) of an account.
 | ||||
| func (csdb *CommitStateDB) SetNonce(addr ethcmn.Address, nonce uint64) { | ||||
| 	so := csdb.GetOrNewStateObject(addr) | ||||
| 	so.SetNonce(nonce) | ||||
| } | ||||
| 
 | ||||
| // SetState sets the storage state with a key, value pair for an account.
 | ||||
| func (csdb *CommitStateDB) SetState(addr ethcmn.Address, key, value ethcmn.Hash) { | ||||
| 	so := csdb.GetOrNewStateObject(addr) | ||||
| 	so.SetState(nil, key, value) | ||||
| } | ||||
| 
 | ||||
| // SetCode sets the code for a given account.
 | ||||
| func (csdb *CommitStateDB) SetCode(addr ethcmn.Address, code []byte) { | ||||
| 	so := csdb.GetOrNewStateObject(addr) | ||||
| 	so.SetCode(ethcrypto.Keccak256Hash(code), code) | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Transaction logs
 | ||||
| // Required for upgrade logic or ease of querying.
 | ||||
| // NOTE: we use BinaryLengthPrefixed since the tx logs are also included on Result data,
 | ||||
| // which can't use BinaryBare.
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // SetLogs sets the logs for a transaction in the KVStore.
 | ||||
| func (csdb *CommitStateDB) SetLogs(hash ethcmn.Hash, logs []*ethtypes.Log) error { | ||||
| 	store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixLogs) | ||||
| 
 | ||||
| 	txLogs := NewTransactionLogsFromEth(hash, logs) | ||||
| 	bz, err := ModuleCdc.MarshalBinaryBare(&txLogs) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	store.Set(hash.Bytes(), bz) | ||||
| 	csdb.logSize = uint(len(logs)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeleteLogs removes the logs from the KVStore. It is used during journal.Revert.
 | ||||
| func (csdb *CommitStateDB) DeleteLogs(hash ethcmn.Hash) { | ||||
| 	store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixLogs) | ||||
| 	store.Delete(hash.Bytes()) | ||||
| } | ||||
| 
 | ||||
| // AddLog adds a new log to the state and sets the log metadata from the state.
 | ||||
| func (csdb *CommitStateDB) AddLog(log *ethtypes.Log) { | ||||
| 	csdb.journal.append(addLogChange{txhash: csdb.thash}) | ||||
| 
 | ||||
| 	log.TxHash = csdb.thash | ||||
| 	log.BlockHash = csdb.bhash | ||||
| 	log.TxIndex = uint(csdb.txIndex) | ||||
| 	log.Index = csdb.logSize | ||||
| 
 | ||||
| 	logs, err := csdb.GetLogs(csdb.thash) | ||||
| 	if err != nil { | ||||
| 		// panic on unmarshal error
 | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = csdb.SetLogs(csdb.thash, append(logs, log)); err != nil { | ||||
| 		// panic on marshal error
 | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AddPreimage records a SHA3 preimage seen by the VM.
 | ||||
| func (csdb *CommitStateDB) AddPreimage(hash ethcmn.Hash, preimage []byte) { | ||||
| 	if _, ok := csdb.hashToPreimageIndex[hash]; !ok { | ||||
| 		csdb.journal.append(addPreimageChange{hash: hash}) | ||||
| 
 | ||||
| 		pi := make([]byte, len(preimage)) | ||||
| 		copy(pi, preimage) | ||||
| 
 | ||||
| 		csdb.preimages = append(csdb.preimages, preimageEntry{hash: hash, preimage: pi}) | ||||
| 		csdb.hashToPreimageIndex[hash] = len(csdb.preimages) - 1 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AddRefund adds gas to the refund counter.
 | ||||
| func (csdb *CommitStateDB) AddRefund(gas uint64) { | ||||
| 	csdb.journal.append(refundChange{prev: csdb.refund}) | ||||
| 	csdb.refund += gas | ||||
| } | ||||
| 
 | ||||
| // SubRefund removes gas from the refund counter. It will panic if the refund
 | ||||
| // counter goes below zero.
 | ||||
| func (csdb *CommitStateDB) SubRefund(gas uint64) { | ||||
| 	csdb.journal.append(refundChange{prev: csdb.refund}) | ||||
| 	if gas > csdb.refund { | ||||
| 		panic("refund counter below zero") | ||||
| 	} | ||||
| 
 | ||||
| 	csdb.refund -= gas | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Access List // TODO: deprecate
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // PrepareAccessList handles the preparatory steps for executing a state transition with
 | ||||
| // regards to both EIP-2929 and EIP-2930:
 | ||||
| //
 | ||||
| // 	- Add sender to access list (2929)
 | ||||
| // 	- Add destination to access list (2929)
 | ||||
| // 	- Add precompiles to access list (2929)
 | ||||
| // 	- Add the contents of the optional tx access list (2930)
 | ||||
| //
 | ||||
| // This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.
 | ||||
| func (csdb *CommitStateDB) PrepareAccessList(sender ethcmn.Address, dest *ethcmn.Address, precompiles []ethcmn.Address, txAccesses ethtypes.AccessList) { | ||||
| 	csdb.AddAddressToAccessList(sender) | ||||
| 	if dest != nil { | ||||
| 		csdb.AddAddressToAccessList(*dest) | ||||
| 		// If it's a create-tx, the destination will be added inside evm.create
 | ||||
| 	} | ||||
| 	for _, addr := range precompiles { | ||||
| 		csdb.AddAddressToAccessList(addr) | ||||
| 	} | ||||
| 	for _, tuple := range txAccesses { | ||||
| 		csdb.AddAddressToAccessList(tuple.Address) | ||||
| 		for _, key := range tuple.StorageKeys { | ||||
| 			csdb.AddSlotToAccessList(tuple.Address, key) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AddressInAccessList returns true if the address is registered on the access list map.
 | ||||
| func (csdb *CommitStateDB) AddressInAccessList(addr ethcmn.Address) bool { | ||||
| 	ts := prefix.NewStore(csdb.ctx.TransientStore(csdb.transientKey), KeyPrefixTransientAccessListAddress) | ||||
| 	return ts.Has(addr.Bytes()) | ||||
| } | ||||
| 
 | ||||
| func (csdb *CommitStateDB) SlotInAccessList(addr ethcmn.Address, slot ethcmn.Hash) (addressOk bool, slotOk bool) { | ||||
| 	addressOk = csdb.AddressInAccessList(addr) | ||||
| 	slotOk = csdb.addressSlotInAccessList(addr, slot) | ||||
| 	return addressOk, slotOk | ||||
| } | ||||
| 
 | ||||
| func (csdb *CommitStateDB) addressSlotInAccessList(addr ethcmn.Address, slot ethcmn.Hash) bool { | ||||
| 	ts := prefix.NewStore(csdb.ctx.TransientStore(csdb.transientKey), KeyPrefixTransientAccessListSlot) | ||||
| 	key := append(addr.Bytes(), slot.Bytes()...) | ||||
| 	return ts.Has(key) | ||||
| } | ||||
| 
 | ||||
| // AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
 | ||||
| // even if the feature/fork is not active yet
 | ||||
| func (csdb *CommitStateDB) AddAddressToAccessList(addr ethcmn.Address) { | ||||
| 	if csdb.AddressInAccessList(addr) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ts := prefix.NewStore(csdb.ctx.TransientStore(csdb.transientKey), KeyPrefixTransientAccessListAddress) | ||||
| 	ts.Set(addr.Bytes(), []byte{0x1}) | ||||
| } | ||||
| 
 | ||||
| // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
 | ||||
| // even if the feature/fork is not active yet
 | ||||
| func (csdb *CommitStateDB) AddSlotToAccessList(addr ethcmn.Address, slot ethcmn.Hash) { | ||||
| 	csdb.AddAddressToAccessList(addr) | ||||
| 	if csdb.addressSlotInAccessList(addr, slot) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ts := prefix.NewStore(csdb.ctx.TransientStore(csdb.transientKey), KeyPrefixTransientAccessListSlot) | ||||
| 	key := append(addr.Bytes(), slot.Bytes()...) | ||||
| 	ts.Set(key, []byte{0x1}) | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Getters
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // GetHeightHash returns the block header hash associated with a given block height and chain epoch number.
 | ||||
| func (csdb *CommitStateDB) GetHeightHash(height uint64) ethcmn.Hash { | ||||
| 	store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightToHeaderHash) | ||||
| 	key := sdk.Uint64ToBigEndian(height) | ||||
| 	bz := store.Get(key) | ||||
| 	if len(bz) == 0 { | ||||
| 		return ethcmn.Hash{} | ||||
| 	} | ||||
| 
 | ||||
| 	return ethcmn.BytesToHash(bz) | ||||
| } | ||||
| 
 | ||||
| // GetParams returns the total set of evm parameters.
 | ||||
| func (csdb *CommitStateDB) GetParams() (params Params) { | ||||
| 	csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms) | ||||
| 	return params | ||||
| } | ||||
| 
 | ||||
| // GetBalance retrieves the balance from the given address or 0 if object not
 | ||||
| // found.
 | ||||
| func (csdb *CommitStateDB) GetBalance(addr ethcmn.Address) *big.Int { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so != nil { | ||||
| 		return so.Balance() | ||||
| 	} | ||||
| 
 | ||||
| 	return zeroBalance | ||||
| } | ||||
| 
 | ||||
| // GetNonce returns the nonce (sequence number) for a given account.
 | ||||
| func (csdb *CommitStateDB) GetNonce(addr ethcmn.Address) uint64 { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so != nil { | ||||
| 		return so.Nonce() | ||||
| 	} | ||||
| 
 | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // TxIndex returns the current transaction index set by Prepare.
 | ||||
| func (csdb *CommitStateDB) TxIndex() int { | ||||
| 	return csdb.txIndex | ||||
| } | ||||
| 
 | ||||
| // BlockHash returns the current block hash set by Prepare.
 | ||||
| func (csdb *CommitStateDB) BlockHash() ethcmn.Hash { | ||||
| 	return csdb.bhash | ||||
| } | ||||
| 
 | ||||
| // GetCode returns the code for a given account.
 | ||||
| func (csdb *CommitStateDB) GetCode(addr ethcmn.Address) []byte { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so != nil { | ||||
| 		return so.Code(nil) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // GetCodeSize returns the code size for a given account.
 | ||||
| func (csdb *CommitStateDB) GetCodeSize(addr ethcmn.Address) int { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 
 | ||||
| 	if so.code != nil { | ||||
| 		return len(so.code) | ||||
| 	} | ||||
| 
 | ||||
| 	return len(so.Code(nil)) | ||||
| } | ||||
| 
 | ||||
| // GetCodeHash returns the code hash for a given account.
 | ||||
| func (csdb *CommitStateDB) GetCodeHash(addr ethcmn.Address) ethcmn.Hash { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so == nil { | ||||
| 		return ethcmn.Hash{} | ||||
| 	} | ||||
| 
 | ||||
| 	return ethcmn.BytesToHash(so.CodeHash()) | ||||
| } | ||||
| 
 | ||||
| // GetState retrieves a value from the given account's storage store.
 | ||||
| func (csdb *CommitStateDB) GetState(addr ethcmn.Address, hash ethcmn.Hash) ethcmn.Hash { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so != nil { | ||||
| 		return so.GetState(nil, hash) | ||||
| 	} | ||||
| 
 | ||||
| 	return ethcmn.Hash{} | ||||
| } | ||||
| 
 | ||||
| // GetCommittedState retrieves a value from the given account's committed
 | ||||
| // storage.
 | ||||
| func (csdb *CommitStateDB) GetCommittedState(addr ethcmn.Address, hash ethcmn.Hash) ethcmn.Hash { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so != nil { | ||||
| 		return so.GetCommittedState(nil, hash) | ||||
| 	} | ||||
| 
 | ||||
| 	return ethcmn.Hash{} | ||||
| } | ||||
| 
 | ||||
| // GetLogs returns the current logs for a given transaction hash from the KVStore.
 | ||||
| func (csdb *CommitStateDB) GetLogs(hash ethcmn.Hash) ([]*ethtypes.Log, error) { | ||||
| 	store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixLogs) | ||||
| 	bz := store.Get(hash.Bytes()) | ||||
| 	if len(bz) == 0 { | ||||
| 		// return nil error if logs are not found
 | ||||
| 		return []*ethtypes.Log{}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	var txLogs TransactionLogs | ||||
| 	if err := ModuleCdc.UnmarshalBinaryBare(bz, &txLogs); err != nil { | ||||
| 		return []*ethtypes.Log{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	allLogs := []*ethtypes.Log{} | ||||
| 	for _, txLog := range txLogs.Logs { | ||||
| 		allLogs = append(allLogs, txLog.ToEthereum()) | ||||
| 	} | ||||
| 
 | ||||
| 	return allLogs, nil | ||||
| } | ||||
| 
 | ||||
| // AllLogs returns all the current logs in the state.
 | ||||
| func (csdb *CommitStateDB) AllLogs() []*ethtypes.Log { | ||||
| 	store := csdb.ctx.KVStore(csdb.storeKey) | ||||
| 	iterator := sdk.KVStorePrefixIterator(store, KeyPrefixLogs) | ||||
| 	defer iterator.Close() | ||||
| 
 | ||||
| 	allLogs := []*ethtypes.Log{} | ||||
| 	for ; iterator.Valid(); iterator.Next() { | ||||
| 		var txLogs TransactionLogs | ||||
| 		ModuleCdc.MustUnmarshalBinaryBare(iterator.Value(), &txLogs) | ||||
| 
 | ||||
| 		for _, txLog := range txLogs.Logs { | ||||
| 			allLogs = append(allLogs, txLog.ToEthereum()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return allLogs | ||||
| } | ||||
| 
 | ||||
| // GetRefund returns the current value of the refund counter.
 | ||||
| func (csdb *CommitStateDB) GetRefund() uint64 { | ||||
| 	return csdb.refund | ||||
| } | ||||
| 
 | ||||
| // Preimages returns a list of SHA3 preimages that have been submitted.
 | ||||
| func (csdb *CommitStateDB) Preimages() map[ethcmn.Hash][]byte { | ||||
| 	preimages := map[ethcmn.Hash][]byte{} | ||||
| 
 | ||||
| 	for _, pe := range csdb.preimages { | ||||
| 		preimages[pe.hash] = pe.preimage | ||||
| 	} | ||||
| 	return preimages | ||||
| } | ||||
| 
 | ||||
| // HasSuicided returns if the given account for the specified address has been
 | ||||
| // killed.
 | ||||
| func (csdb *CommitStateDB) HasSuicided(addr ethcmn.Address) bool { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so != nil { | ||||
| 		return so.suicided | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // StorageTrie returns nil as the state in Ethermint does not use a direct
 | ||||
| // storage trie.
 | ||||
| func (csdb *CommitStateDB) StorageTrie(addr ethcmn.Address) ethstate.Trie { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Persistence
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // Commit writes the state to the appropriate KVStores. For each state object
 | ||||
| // in the cache, it will either be removed, or have it's code set and/or it's
 | ||||
| // state (storage) updated. In addition, the state object (account) itself will
 | ||||
| // be written. Finally, the root hash (version) will be returned.
 | ||||
| func (csdb *CommitStateDB) Commit(deleteEmptyObjects bool) (ethcmn.Hash, error) { | ||||
| 	defer csdb.clearJournalAndRefund() | ||||
| 
 | ||||
| 	// remove dirty state object entries based on the journal
 | ||||
| 	for _, dirty := range csdb.journal.dirties { | ||||
| 		csdb.stateObjectsDirty[dirty.address] = struct{}{} | ||||
| 	} | ||||
| 
 | ||||
| 	// set the state objects
 | ||||
| 	for _, stateEntry := range csdb.stateObjects { | ||||
| 		_, isDirty := csdb.stateObjectsDirty[stateEntry.address] | ||||
| 
 | ||||
| 		switch { | ||||
| 		case stateEntry.stateObject.suicided || (isDirty && deleteEmptyObjects && stateEntry.stateObject.empty()): | ||||
| 			// If the state object has been removed, don't bother syncing it and just
 | ||||
| 			// remove it from the store.
 | ||||
| 			csdb.deleteStateObject(stateEntry.stateObject) | ||||
| 
 | ||||
| 		case isDirty: | ||||
| 			// write any contract code associated with the state object
 | ||||
| 			if stateEntry.stateObject.code != nil && stateEntry.stateObject.dirtyCode { | ||||
| 				stateEntry.stateObject.commitCode() | ||||
| 				stateEntry.stateObject.dirtyCode = false | ||||
| 			} | ||||
| 
 | ||||
| 			// update the object in the KVStore
 | ||||
| 			if err := csdb.updateStateObject(stateEntry.stateObject); err != nil { | ||||
| 				return ethcmn.Hash{}, err | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		delete(csdb.stateObjectsDirty, stateEntry.address) | ||||
| 	} | ||||
| 
 | ||||
| 	// NOTE: Ethereum returns the trie merkle root here, but as commitment
 | ||||
| 	// actually happens in the BaseApp at EndBlocker, we do not know the root at
 | ||||
| 	// this time.
 | ||||
| 	return ethcmn.Hash{}, nil | ||||
| } | ||||
| 
 | ||||
| // Finalise finalizes the state objects (accounts) state by setting their state,
 | ||||
| // removing the csdb destructed objects and clearing the journal as well as the
 | ||||
| // refunds.
 | ||||
| func (csdb *CommitStateDB) Finalise(deleteEmptyObjects bool) error { | ||||
| 	for _, dirty := range csdb.journal.dirties { | ||||
| 		idx, exist := csdb.addressToObjectIndex[dirty.address] | ||||
| 		if !exist { | ||||
| 			// ripeMD is 'touched' at block 1714175, in tx:
 | ||||
| 			// 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2
 | ||||
| 			//
 | ||||
| 			// That tx goes out of gas, and although the notion of 'touched' does not
 | ||||
| 			// exist there, the touch-event will still be recorded in the journal.
 | ||||
| 			// Since ripeMD is a special snowflake, it will persist in the journal even
 | ||||
| 			// though the journal is reverted. In this special circumstance, it may
 | ||||
| 			// exist in journal.dirties but not in stateObjects. Thus, we can safely
 | ||||
| 			// ignore it here.
 | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		stateEntry := csdb.stateObjects[idx] | ||||
| 		if stateEntry.stateObject.suicided || (deleteEmptyObjects && stateEntry.stateObject.empty()) { | ||||
| 			csdb.deleteStateObject(stateEntry.stateObject) | ||||
| 		} else { | ||||
| 			// Set all the dirty state storage items for the state object in the
 | ||||
| 			// KVStore and finally set the account in the account mapper.
 | ||||
| 			stateEntry.stateObject.commitState() | ||||
| 			if err := csdb.updateStateObject(stateEntry.stateObject); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		csdb.stateObjectsDirty[dirty.address] = struct{}{} | ||||
| 	} | ||||
| 
 | ||||
| 	// invalidate journal because reverting across transactions is not allowed
 | ||||
| 	csdb.clearJournalAndRefund() | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // IntermediateRoot returns the current root hash of the state. It is called in
 | ||||
| // between transactions to get the root hash that goes into transaction
 | ||||
| // receipts.
 | ||||
| //
 | ||||
| // NOTE: The SDK has not concept or method of getting any intermediate merkle
 | ||||
| // root as commitment of the merkle-ized tree doesn't happen until the
 | ||||
| // BaseApps' EndBlocker.
 | ||||
| func (csdb *CommitStateDB) IntermediateRoot(deleteEmptyObjects bool) (ethcmn.Hash, error) { | ||||
| 	if err := csdb.Finalise(deleteEmptyObjects); err != nil { | ||||
| 		return ethcmn.Hash{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	return ethcmn.Hash{}, nil | ||||
| } | ||||
| 
 | ||||
| // updateStateObject writes the given state object to the store.
 | ||||
| func (csdb *CommitStateDB) updateStateObject(so *stateObject) error { | ||||
| 	evmDenom := csdb.GetParams().EvmDenom | ||||
| 	// NOTE: we don't use sdk.NewCoin here to avoid panic on test importer's genesis
 | ||||
| 	newBalance := sdk.Coin{Denom: evmDenom, Amount: sdk.NewIntFromBigInt(so.Balance())} | ||||
| 	if !newBalance.IsValid() { | ||||
| 		return fmt.Errorf("invalid balance %s", newBalance) | ||||
| 	} | ||||
| 
 | ||||
| 	err := csdb.bankKeeper.SetBalance(csdb.ctx, so.account.GetAddress(), newBalance) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	csdb.accountKeeper.SetAccount(csdb.ctx, so.account) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // deleteStateObject removes the given state object from the state store.
 | ||||
| func (csdb *CommitStateDB) deleteStateObject(so *stateObject) { | ||||
| 	so.deleted = true | ||||
| 	csdb.accountKeeper.RemoveAccount(csdb.ctx, so.account) | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Snapshotting
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // Snapshot returns an identifier for the current revision of the state.
 | ||||
| func (csdb *CommitStateDB) Snapshot() int { | ||||
| 	id := csdb.nextRevisionID | ||||
| 	csdb.nextRevisionID++ | ||||
| 
 | ||||
| 	csdb.validRevisions = append( | ||||
| 		csdb.validRevisions, | ||||
| 		revision{ | ||||
| 			id:           id, | ||||
| 			journalIndex: csdb.journal.length(), | ||||
| 		}, | ||||
| 	) | ||||
| 
 | ||||
| 	return id | ||||
| } | ||||
| 
 | ||||
| // RevertToSnapshot reverts all state changes made since the given revision.
 | ||||
| func (csdb *CommitStateDB) RevertToSnapshot(revID int) { | ||||
| 	// find the snapshot in the stack of valid snapshots
 | ||||
| 	idx := sort.Search(len(csdb.validRevisions), func(i int) bool { | ||||
| 		return csdb.validRevisions[i].id >= revID | ||||
| 	}) | ||||
| 
 | ||||
| 	if idx == len(csdb.validRevisions) || csdb.validRevisions[idx].id != revID { | ||||
| 		panic(fmt.Errorf("revision ID %v cannot be reverted", revID)) | ||||
| 	} | ||||
| 
 | ||||
| 	snapshot := csdb.validRevisions[idx].journalIndex | ||||
| 
 | ||||
| 	// replay the journal to undo changes and remove invalidated snapshots
 | ||||
| 	csdb.journal.revert(csdb, snapshot) | ||||
| 	csdb.validRevisions = csdb.validRevisions[:idx] | ||||
| } | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // Auxiliary
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // Database retrieves the low level database supporting the lower level trie
 | ||||
| // ops. It is not used in Ethermint, so it returns nil.
 | ||||
| func (csdb *CommitStateDB) Database() ethstate.Database { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Empty returns whether the state object is either non-existent or empty
 | ||||
| // according to the EIP161 specification (balance = nonce = code = 0).
 | ||||
| func (csdb *CommitStateDB) Empty(addr ethcmn.Address) bool { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	return so == nil || so.empty() | ||||
| } | ||||
| 
 | ||||
| // Exist reports whether the given account address exists in the state. Notably,
 | ||||
| // this also returns true for suicided accounts.
 | ||||
| func (csdb *CommitStateDB) Exist(addr ethcmn.Address) bool { | ||||
| 	return csdb.getStateObject(addr) != nil | ||||
| } | ||||
| 
 | ||||
| // Error returns the first non-nil error the StateDB encountered.
 | ||||
| func (csdb *CommitStateDB) Error() error { | ||||
| 	return csdb.dbErr | ||||
| } | ||||
| 
 | ||||
| // Suicide marks the given account as suicided and clears the account balance.
 | ||||
| //
 | ||||
| // The account's state object is still available until the state is committed,
 | ||||
| // getStateObject will return a non-nil account after Suicide.
 | ||||
| func (csdb *CommitStateDB) Suicide(addr ethcmn.Address) bool { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	csdb.journal.append(suicideChange{ | ||||
| 		account:     &addr, | ||||
| 		prev:        so.suicided, | ||||
| 		prevBalance: sdk.NewIntFromBigInt(so.Balance()), | ||||
| 	}) | ||||
| 
 | ||||
| 	so.markSuicided() | ||||
| 	so.SetBalance(new(big.Int)) | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // Reset clears out all ephemeral state objects from the state db, but keeps
 | ||||
| // the underlying account mapper and store keys to avoid reloading data for the
 | ||||
| // next operations.
 | ||||
| func (csdb *CommitStateDB) Reset(_ ethcmn.Hash) error { | ||||
| 	csdb.stateObjects = []stateEntry{} | ||||
| 	csdb.addressToObjectIndex = make(map[ethcmn.Address]int) | ||||
| 	csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{}) | ||||
| 	csdb.thash = ethcmn.Hash{} | ||||
| 	csdb.bhash = ethcmn.Hash{} | ||||
| 	csdb.txIndex = 0 | ||||
| 	csdb.logSize = 0 | ||||
| 	csdb.preimages = []preimageEntry{} | ||||
| 	csdb.hashToPreimageIndex = make(map[ethcmn.Hash]int) | ||||
| 
 | ||||
| 	csdb.clearJournalAndRefund() | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // UpdateAccounts updates the nonce and coin balances of accounts
 | ||||
| func (csdb *CommitStateDB) UpdateAccounts() { | ||||
| 	for _, stateEntry := range csdb.stateObjects { | ||||
| 		address := sdk.AccAddress(stateEntry.address.Bytes()) | ||||
| 		currAccount := csdb.accountKeeper.GetAccount(csdb.ctx, address) | ||||
| 		ethAcc, ok := currAccount.(*ethermint.EthAccount) | ||||
| 		if !ok { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		evmDenom := csdb.GetParams().EvmDenom | ||||
| 		balance := csdb.bankKeeper.GetBalance(csdb.ctx, address, evmDenom) | ||||
| 
 | ||||
| 		if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() { | ||||
| 			stateEntry.stateObject.balance = balance.Amount | ||||
| 		} | ||||
| 
 | ||||
| 		if stateEntry.stateObject.Nonce() != ethAcc.GetSequence() { | ||||
| 			stateEntry.stateObject.account = ethAcc | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ClearStateObjects clears cache of state objects to handle account changes outside of the EVM
 | ||||
| func (csdb *CommitStateDB) ClearStateObjects() { | ||||
| 	csdb.stateObjects = []stateEntry{} | ||||
| 	csdb.addressToObjectIndex = make(map[ethcmn.Address]int) | ||||
| 	csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{}) | ||||
| } | ||||
| 
 | ||||
| func (csdb *CommitStateDB) clearJournalAndRefund() { | ||||
| 	csdb.journal = newJournal() | ||||
| 	csdb.validRevisions = csdb.validRevisions[:0] | ||||
| 	csdb.refund = 0 | ||||
| } | ||||
| 
 | ||||
| // Prepare sets the current transaction hash and index and block hash which is
 | ||||
| // used when the EVM emits new state logs.
 | ||||
| func (csdb *CommitStateDB) Prepare(thash, bhash ethcmn.Hash, txi int) { | ||||
| 	csdb.thash = thash | ||||
| 	csdb.bhash = bhash | ||||
| 	csdb.txIndex = txi | ||||
| } | ||||
| 
 | ||||
| // CreateAccount explicitly creates a state object. If a state object with the
 | ||||
| // address already exists the balance is carried over to the new account.
 | ||||
| //
 | ||||
| // CreateAccount is called during the EVM CREATE operation. The situation might
 | ||||
| // arise that a contract does the following:
 | ||||
| //
 | ||||
| //   1. sends funds to sha(account ++ (nonce + 1))
 | ||||
| //   2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
 | ||||
| //
 | ||||
| // Carrying over the balance ensures that Ether doesn't disappear.
 | ||||
| func (csdb *CommitStateDB) CreateAccount(addr ethcmn.Address) { | ||||
| 	newobj, prevobj := csdb.createObject(addr) | ||||
| 	if prevobj != nil { | ||||
| 		newobj.setBalance(sdk.NewIntFromBigInt(prevobj.Balance())) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Copy creates a deep, independent copy of the state.
 | ||||
| //
 | ||||
| // NOTE: Snapshots of the copied state cannot be applied to the copy.
 | ||||
| func (csdb *CommitStateDB) Copy() *CommitStateDB { | ||||
| 
 | ||||
| 	// copy all the basic fields, initialize the memory ones
 | ||||
| 	state := &CommitStateDB{} | ||||
| 	CopyCommitStateDB(csdb, state) | ||||
| 
 | ||||
| 	return state | ||||
| } | ||||
| 
 | ||||
| func CopyCommitStateDB(from, to *CommitStateDB) { | ||||
| 	from.lock.Lock() | ||||
| 	defer from.lock.Unlock() | ||||
| 
 | ||||
| 	to.ctx = from.ctx | ||||
| 	to.storeKey = from.storeKey | ||||
| 	to.paramSpace = from.paramSpace | ||||
| 	to.accountKeeper = from.accountKeeper | ||||
| 	to.bankKeeper = from.bankKeeper | ||||
| 	to.stateObjects = []stateEntry{} | ||||
| 	to.addressToObjectIndex = make(map[ethcmn.Address]int) | ||||
| 	to.stateObjectsDirty = make(map[ethcmn.Address]struct{}) | ||||
| 	to.refund = from.refund | ||||
| 	to.logSize = from.logSize | ||||
| 	to.preimages = make([]preimageEntry, len(from.preimages)) | ||||
| 	to.hashToPreimageIndex = make(map[ethcmn.Hash]int, len(from.hashToPreimageIndex)) | ||||
| 	to.journal = newJournal() | ||||
| 	to.thash = from.thash | ||||
| 	to.bhash = from.bhash | ||||
| 	to.txIndex = from.txIndex | ||||
| 	validRevisions := make([]revision, len(from.validRevisions)) | ||||
| 	copy(validRevisions, from.validRevisions) | ||||
| 	to.validRevisions = validRevisions | ||||
| 	to.nextRevisionID = from.nextRevisionID | ||||
| 
 | ||||
| 	// copy the dirty states, logs, and preimages
 | ||||
| 	for _, dirty := range from.journal.dirties { | ||||
| 		// There is a case where an object is in the journal but not in the
 | ||||
| 		// stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we
 | ||||
| 		// need to check for nil.
 | ||||
| 		//
 | ||||
| 		// Ref: https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527
 | ||||
| 		if idx, exist := from.addressToObjectIndex[dirty.address]; exist { | ||||
| 			to.stateObjects = append(to.stateObjects, stateEntry{ | ||||
| 				address:     dirty.address, | ||||
| 				stateObject: from.stateObjects[idx].stateObject.deepCopy(to), | ||||
| 			}) | ||||
| 			to.addressToObjectIndex[dirty.address] = len(to.stateObjects) - 1 | ||||
| 			to.stateObjectsDirty[dirty.address] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Above, we don't copy the actual journal. This means that if the copy is
 | ||||
| 	// copied, the loop above will be a no-op, since the copy's journal is empty.
 | ||||
| 	// Thus, here we iterate over stateObjects, to enable copies of copies.
 | ||||
| 	for addr := range from.stateObjectsDirty { | ||||
| 		if idx, exist := to.addressToObjectIndex[addr]; !exist { | ||||
| 			to.setStateObject(from.stateObjects[idx].stateObject.deepCopy(to)) | ||||
| 			to.stateObjectsDirty[addr] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// copy pre-images
 | ||||
| 	for i, preimageEntry := range from.preimages { | ||||
| 		to.preimages[i] = preimageEntry | ||||
| 		to.hashToPreimageIndex[preimageEntry.hash] = i | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ForEachStorage iterates over each storage items, all invoke the provided
 | ||||
| // callback on each key, value pair.
 | ||||
| func (csdb *CommitStateDB) ForEachStorage(addr ethcmn.Address, cb func(key, value ethcmn.Hash) (stop bool)) error { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	store := csdb.ctx.KVStore(csdb.storeKey) | ||||
| 	prefix := AddressStoragePrefix(so.Address()) | ||||
| 	iterator := sdk.KVStorePrefixIterator(store, prefix) | ||||
| 	defer iterator.Close() | ||||
| 
 | ||||
| 	for ; iterator.Valid(); iterator.Next() { | ||||
| 		key := ethcmn.BytesToHash(iterator.Key()) | ||||
| 		value := ethcmn.BytesToHash(iterator.Value()) | ||||
| 
 | ||||
| 		if idx, dirty := so.keyToDirtyStorageIndex[key]; dirty { | ||||
| 			// check if iteration stops
 | ||||
| 			if cb(key, ethcmn.HexToHash(so.dirtyStorage[idx].Value)) { | ||||
| 				break | ||||
| 			} | ||||
| 
 | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// check if iteration stops
 | ||||
| 		if cb(key, value) { | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // GetOrNewStateObject retrieves a state object or create a new state object if
 | ||||
| // nil.
 | ||||
| func (csdb *CommitStateDB) GetOrNewStateObject(addr ethcmn.Address) StateObject { | ||||
| 	so := csdb.getStateObject(addr) | ||||
| 	if so == nil || so.deleted { | ||||
| 		so, _ = csdb.createObject(addr) | ||||
| 	} | ||||
| 
 | ||||
| 	return so | ||||
| } | ||||
| 
 | ||||
| // createObject creates a new state object. If there is an existing account with
 | ||||
| // the given address, it is overwritten and returned as the second return value.
 | ||||
| func (csdb *CommitStateDB) createObject(addr ethcmn.Address) (newObj, prevObj *stateObject) { | ||||
| 	prevObj = csdb.getStateObject(addr) | ||||
| 
 | ||||
| 	acc := csdb.accountKeeper.NewAccountWithAddress(csdb.ctx, sdk.AccAddress(addr.Bytes())) | ||||
| 
 | ||||
| 	newObj = newStateObject(csdb, acc, sdk.ZeroInt()) | ||||
| 	newObj.setNonce(0) // sets the object to dirty
 | ||||
| 
 | ||||
| 	if prevObj == nil { | ||||
| 		csdb.journal.append(createObjectChange{account: &addr}) | ||||
| 	} else { | ||||
| 		csdb.journal.append(resetObjectChange{prev: prevObj}) | ||||
| 	} | ||||
| 
 | ||||
| 	csdb.setStateObject(newObj) | ||||
| 	return newObj, prevObj | ||||
| } | ||||
| 
 | ||||
| // setError remembers the first non-nil error it is called with.
 | ||||
| func (csdb *CommitStateDB) setError(err error) { | ||||
| 	if csdb.dbErr == nil { | ||||
| 		csdb.dbErr = err | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // getStateObject attempts to retrieve a state object given by the address.
 | ||||
| // Returns nil and sets an error if not found.
 | ||||
| func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *stateObject) { | ||||
| 	if idx, found := csdb.addressToObjectIndex[addr]; found { | ||||
| 		// prefer 'live' (cached) objects
 | ||||
| 		if so := csdb.stateObjects[idx].stateObject; so != nil { | ||||
| 			if so.deleted { | ||||
| 				return nil | ||||
| 			} | ||||
| 
 | ||||
| 			return so | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// otherwise, attempt to fetch the account from the account mapper
 | ||||
| 	acc := csdb.accountKeeper.GetAccount(csdb.ctx, sdk.AccAddress(addr.Bytes())) | ||||
| 	if acc == nil { | ||||
| 		csdb.setError(fmt.Errorf("no account found for address: %s", addr.String())) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	evmDenom := csdb.GetParams().EvmDenom | ||||
| 	balance := csdb.bankKeeper.GetBalance(csdb.ctx, acc.GetAddress(), evmDenom) | ||||
| 
 | ||||
| 	// insert the state object into the live set
 | ||||
| 	so := newStateObject(csdb, acc, balance.Amount) | ||||
| 	csdb.setStateObject(so) | ||||
| 
 | ||||
| 	return so | ||||
| } | ||||
| 
 | ||||
| func (csdb *CommitStateDB) setStateObject(so *stateObject) { | ||||
| 	if idx, found := csdb.addressToObjectIndex[so.Address()]; found { | ||||
| 		// update the existing object
 | ||||
| 		csdb.stateObjects[idx].stateObject = so | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// append the new state object to the stateObjects slice
 | ||||
| 	se := stateEntry{ | ||||
| 		address:     so.Address(), | ||||
| 		stateObject: so, | ||||
| 	} | ||||
| 
 | ||||
| 	csdb.stateObjects = append(csdb.stateObjects, se) | ||||
| 	csdb.addressToObjectIndex[se.address] = len(csdb.stateObjects) - 1 | ||||
| } | ||||
| 
 | ||||
| // RawDump returns a raw state dump.
 | ||||
| //
 | ||||
| // TODO: Implement if we need it, especially for the RPC API.
 | ||||
| func (csdb *CommitStateDB) RawDump() ethstate.Dump { | ||||
| 	return ethstate.Dump{} | ||||
| } | ||||
| 
 | ||||
| type preimageEntry struct { | ||||
| 	// hash key of the preimage entry
 | ||||
| 	hash     ethcmn.Hash | ||||
| 	preimage []byte | ||||
| } | ||||
| @ -1,739 +0,0 @@ | ||||
| package types_test | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/suite" | ||||
| 
 | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||||
| 
 | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	ethtypes "github.com/ethereum/go-ethereum/core/types" | ||||
| 	ethcrypto "github.com/ethereum/go-ethereum/crypto" | ||||
| 
 | ||||
| 	"github.com/cosmos/ethermint/app" | ||||
| 	"github.com/cosmos/ethermint/crypto/ethsecp256k1" | ||||
| 	ethermint "github.com/cosmos/ethermint/types" | ||||
| 	"github.com/cosmos/ethermint/x/evm/types" | ||||
| 
 | ||||
| 	tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||||
| ) | ||||
| 
 | ||||
| type StateDBTestSuite struct { | ||||
| 	suite.Suite | ||||
| 
 | ||||
| 	ctx         sdk.Context | ||||
| 	app         *app.EthermintApp | ||||
| 	stateDB     *types.CommitStateDB | ||||
| 	address     ethcmn.Address | ||||
| 	stateObject types.StateObject | ||||
| } | ||||
| 
 | ||||
| func TestStateDBTestSuite(t *testing.T) { | ||||
| 	suite.Run(t, new(StateDBTestSuite)) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) SetupTest() { | ||||
| 	checkTx := false | ||||
| 
 | ||||
| 	suite.app = app.Setup(checkTx) | ||||
| 	suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1}) | ||||
| 	suite.stateDB = suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx) | ||||
| 
 | ||||
| 	privkey, err := ethsecp256k1.GenerateKey() | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	suite.address = ethcmn.BytesToAddress(privkey.PubKey().Address().Bytes()) | ||||
| 
 | ||||
| 	balance := ethermint.NewPhotonCoin(sdk.ZeroInt()) | ||||
| 	acc := ðermint.EthAccount{ | ||||
| 		BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0), | ||||
| 		CodeHash:    ethcrypto.Keccak256(nil), | ||||
| 	} | ||||
| 
 | ||||
| 	suite.app.AccountKeeper.SetAccount(suite.ctx, acc) | ||||
| 	err = suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), balance) | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestParams() { | ||||
| 	params := suite.stateDB.GetParams() | ||||
| 	suite.Require().Equal(types.DefaultParams(), params) | ||||
| 	params.EvmDenom = "inj" | ||||
| 	suite.stateDB.SetParams(params) | ||||
| 	newParams := suite.stateDB.GetParams() | ||||
| 	suite.Require().Equal(newParams, params) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestBloomFilter() { | ||||
| 	// Prepare db for logs
 | ||||
| 	tHash := ethcmn.BytesToHash([]byte{0x1}) | ||||
| 	suite.stateDB.Prepare(tHash, ethcmn.Hash{}, 0) | ||||
| 	contractAddress := ethcmn.BigToAddress(big.NewInt(1)) | ||||
| 	log := ethtypes.Log{Address: contractAddress} | ||||
| 
 | ||||
| 	testCase := []struct { | ||||
| 		name     string | ||||
| 		malleate func() | ||||
| 		numLogs  int | ||||
| 		isBloom  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"no logs", | ||||
| 			func() {}, | ||||
| 			0, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"add log", | ||||
| 			func() { | ||||
| 				suite.stateDB.AddLog(&log) | ||||
| 			}, | ||||
| 			1, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"bloom", | ||||
| 			func() {}, | ||||
| 			0, | ||||
| 			true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 		logs, err := suite.stateDB.GetLogs(tHash) | ||||
| 		if !tc.isBloom { | ||||
| 			suite.Require().NoError(err, tc.name) | ||||
| 			suite.Require().Len(logs, tc.numLogs, tc.name) | ||||
| 			if len(logs) != 0 { | ||||
| 				suite.Require().Equal(log, *logs[0], tc.name) | ||||
| 			} | ||||
| 		} else { | ||||
| 			// get logs bloom from the log
 | ||||
| 			bloomInt := ethtypes.LogsBloom(logs) | ||||
| 			bloomFilter := ethtypes.BytesToBloom(bloomInt) | ||||
| 			suite.Require().True(ethtypes.BloomLookup(bloomFilter, contractAddress), tc.name) | ||||
| 			suite.Require().False(ethtypes.BloomLookup(bloomFilter, ethcmn.BigToAddress(big.NewInt(2))), tc.name) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Balance() { | ||||
| 	testCase := []struct { | ||||
| 		name     string | ||||
| 		malleate func() | ||||
| 		balance  *big.Int | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"set balance", | ||||
| 			func() { | ||||
| 				suite.stateDB.SetBalance(suite.address, big.NewInt(100)) | ||||
| 			}, | ||||
| 			big.NewInt(100), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"sub balance", | ||||
| 			func() { | ||||
| 				suite.stateDB.SubBalance(suite.address, big.NewInt(100)) | ||||
| 			}, | ||||
| 			big.NewInt(0), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"add balance", | ||||
| 			func() { | ||||
| 				suite.stateDB.AddBalance(suite.address, big.NewInt(200)) | ||||
| 			}, | ||||
| 			big.NewInt(200), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"sub more than balance", | ||||
| 			func() { | ||||
| 				suite.stateDB.SubBalance(suite.address, big.NewInt(300)) | ||||
| 			}, | ||||
| 			big.NewInt(-100), | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 		suite.Require().Equal(tc.balance, suite.stateDB.GetBalance(suite.address), tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDBNonce() { | ||||
| 	nonce := uint64(123) | ||||
| 	suite.stateDB.SetNonce(suite.address, nonce) | ||||
| 	suite.Require().Equal(nonce, suite.stateDB.GetNonce(suite.address)) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Error() { | ||||
| 	nonce := suite.stateDB.GetNonce(ethcmn.Address{}) | ||||
| 	suite.Require().Equal(0, int(nonce)) | ||||
| 	suite.Require().Error(suite.stateDB.Error()) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Database() { | ||||
| 	suite.Require().Nil(suite.stateDB.Database()) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_State() { | ||||
| 	key := ethcmn.BytesToHash([]byte("foo")) | ||||
| 	val := ethcmn.BytesToHash([]byte("bar")) | ||||
| 	suite.stateDB.SetState(suite.address, key, val) | ||||
| 
 | ||||
| 	testCase := []struct { | ||||
| 		name    string | ||||
| 		address ethcmn.Address | ||||
| 		key     ethcmn.Hash | ||||
| 		value   ethcmn.Hash | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"found state", | ||||
| 			suite.address, | ||||
| 			ethcmn.BytesToHash([]byte("foo")), | ||||
| 			ethcmn.BytesToHash([]byte("bar")), | ||||
| 		}, | ||||
| 		{ | ||||
| 			"state not found", | ||||
| 			suite.address, | ||||
| 			ethcmn.BytesToHash([]byte("key")), | ||||
| 			ethcmn.Hash{}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"object not found", | ||||
| 			ethcmn.Address{}, | ||||
| 			ethcmn.BytesToHash([]byte("foo")), | ||||
| 			ethcmn.Hash{}, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tc := range testCase { | ||||
| 		value := suite.stateDB.GetState(tc.address, tc.key) | ||||
| 		suite.Require().Equal(tc.value, value, tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Code() { | ||||
| 	testCase := []struct { | ||||
| 		name     string | ||||
| 		address  ethcmn.Address | ||||
| 		code     []byte | ||||
| 		malleate func() | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"no stored code for state object", | ||||
| 			suite.address, | ||||
| 			nil, | ||||
| 			func() {}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"existing address", | ||||
| 			suite.address, | ||||
| 			[]byte("code"), | ||||
| 			func() { | ||||
| 				suite.stateDB.SetCode(suite.address, []byte("code")) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"state object not found", | ||||
| 			ethcmn.Address{}, | ||||
| 			nil, | ||||
| 			func() {}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 
 | ||||
| 		suite.Require().Equal(tc.code, suite.stateDB.GetCode(tc.address), tc.name) | ||||
| 		suite.Require().Equal(len(tc.code), suite.stateDB.GetCodeSize(tc.address), tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Logs() { | ||||
| 	testCase := []struct { | ||||
| 		name string | ||||
| 		log  ethtypes.Log | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"state db log", | ||||
| 			ethtypes.Log{ | ||||
| 				Address:     suite.address, | ||||
| 				Topics:      []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))}, | ||||
| 				Data:        []byte("data"), | ||||
| 				BlockNumber: 1, | ||||
| 				TxHash:      ethcmn.Hash{}, | ||||
| 				TxIndex:     1, | ||||
| 				BlockHash:   ethcmn.Hash{}, | ||||
| 				Index:       0, | ||||
| 				Removed:     false, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		hash := ethcmn.BytesToHash([]byte("hash")) | ||||
| 		logs := []*ethtypes.Log{&tc.log} | ||||
| 
 | ||||
| 		err := suite.stateDB.SetLogs(hash, logs) | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 		dbLogs, err := suite.stateDB.GetLogs(hash) | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 		suite.Require().Equal(logs, dbLogs, tc.name) | ||||
| 
 | ||||
| 		suite.stateDB.DeleteLogs(hash) | ||||
| 		dbLogs, err = suite.stateDB.GetLogs(hash) | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 		suite.Require().Empty(dbLogs, tc.name) | ||||
| 
 | ||||
| 		suite.stateDB.AddLog(&tc.log) | ||||
| 		suite.Require().Equal(logs, suite.stateDB.AllLogs(), tc.name) | ||||
| 
 | ||||
| 		//resets state but checking to see if storekey still persists.
 | ||||
| 		err = suite.stateDB.Reset(hash) | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 		suite.Require().Equal(logs, suite.stateDB.AllLogs(), tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Preimage() { | ||||
| 	hash := ethcmn.BytesToHash([]byte("hash")) | ||||
| 	preimage := []byte("preimage") | ||||
| 
 | ||||
| 	suite.stateDB.AddPreimage(hash, preimage) | ||||
| 	suite.Require().Equal(preimage, suite.stateDB.Preimages()[hash]) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Refund() { | ||||
| 	testCase := []struct { | ||||
| 		name      string | ||||
| 		addAmount uint64 | ||||
| 		subAmount uint64 | ||||
| 		expRefund uint64 | ||||
| 		expPanic  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"refund 0", | ||||
| 			0, 0, 0, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"refund positive amount", | ||||
| 			100, 0, 100, | ||||
| 			false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"refund panic", | ||||
| 			100, 200, 100, | ||||
| 			true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		suite.Run(tc.name, func() { | ||||
| 			suite.SetupTest() // reset
 | ||||
| 
 | ||||
| 			suite.stateDB.AddRefund(tc.addAmount) | ||||
| 			suite.Require().Equal(tc.addAmount, suite.stateDB.GetRefund()) | ||||
| 
 | ||||
| 			if tc.expPanic { | ||||
| 				suite.Panics(func() { | ||||
| 					suite.stateDB.SubRefund(tc.subAmount) | ||||
| 				}) | ||||
| 			} else { | ||||
| 				suite.stateDB.SubRefund(tc.subAmount) | ||||
| 				suite.Require().Equal(tc.expRefund, suite.stateDB.GetRefund()) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_CreateAccount() { | ||||
| 	prevBalance := big.NewInt(12) | ||||
| 
 | ||||
| 	testCase := []struct { | ||||
| 		name     string | ||||
| 		address  ethcmn.Address | ||||
| 		malleate func() | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"existing account", | ||||
| 			suite.address, | ||||
| 			func() { | ||||
| 				suite.stateDB.AddBalance(suite.address, prevBalance) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"new account", | ||||
| 			ethcmn.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b4c1"), | ||||
| 			func() { | ||||
| 				prevBalance = big.NewInt(0) | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 
 | ||||
| 		suite.stateDB.CreateAccount(tc.address) | ||||
| 		suite.Require().True(suite.stateDB.Exist(tc.address), tc.name) | ||||
| 		suite.Require().Equal(prevBalance, suite.stateDB.GetBalance(tc.address), tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_ClearStateObj() { | ||||
| 	priv, err := ethsecp256k1.GenerateKey() | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) | ||||
| 
 | ||||
| 	suite.stateDB.CreateAccount(addr) | ||||
| 	suite.Require().True(suite.stateDB.Exist(addr)) | ||||
| 
 | ||||
| 	suite.stateDB.ClearStateObjects() | ||||
| 	suite.Require().False(suite.stateDB.Exist(addr)) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestStateDB_Reset() { | ||||
| 	priv, err := ethsecp256k1.GenerateKey() | ||||
| 	suite.Require().NoError(err) | ||||
| 
 | ||||
| 	addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) | ||||
| 
 | ||||
| 	suite.stateDB.CreateAccount(addr) | ||||
| 	suite.Require().True(suite.stateDB.Exist(addr)) | ||||
| 
 | ||||
| 	err = suite.stateDB.Reset(ethcmn.BytesToHash(nil)) | ||||
| 	suite.Require().NoError(err) | ||||
| 	suite.Require().False(suite.stateDB.Exist(addr)) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestSuiteDB_Prepare() { | ||||
| 	thash := ethcmn.BytesToHash([]byte("thash")) | ||||
| 	bhash := ethcmn.BytesToHash([]byte("bhash")) | ||||
| 	txi := 1 | ||||
| 
 | ||||
| 	suite.stateDB.Prepare(thash, bhash, txi) | ||||
| 
 | ||||
| 	suite.Require().Equal(txi, suite.stateDB.TxIndex()) | ||||
| 	suite.Require().Equal(bhash, suite.stateDB.BlockHash()) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestSuiteDB_CopyState() { | ||||
| 	testCase := []struct { | ||||
| 		name string | ||||
| 		log  ethtypes.Log | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"copy state", | ||||
| 			ethtypes.Log{ | ||||
| 				Address:     suite.address, | ||||
| 				Topics:      []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))}, | ||||
| 				Data:        []byte("data"), | ||||
| 				BlockNumber: 1, | ||||
| 				TxHash:      ethcmn.Hash{}, | ||||
| 				TxIndex:     1, | ||||
| 				BlockHash:   ethcmn.Hash{}, | ||||
| 				Index:       0, | ||||
| 				Removed:     false, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		hash := ethcmn.BytesToHash([]byte("hash")) | ||||
| 		logs := []*ethtypes.Log{&tc.log} | ||||
| 
 | ||||
| 		err := suite.stateDB.SetLogs(hash, logs) | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 
 | ||||
| 		copyDB := suite.stateDB.Copy() | ||||
| 
 | ||||
| 		copiedDBLogs, err := copyDB.GetLogs(hash) | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 		suite.Require().Equal(logs, copiedDBLogs, tc.name) | ||||
| 		suite.Require().Equal(suite.stateDB.Exist(suite.address), copyDB.Exist(suite.address), tc.name) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestSuiteDB_Empty() { | ||||
| 	suite.Require().True(suite.stateDB.Empty(suite.address)) | ||||
| 
 | ||||
| 	suite.stateDB.SetBalance(suite.address, big.NewInt(100)) | ||||
| 	suite.Require().False(suite.stateDB.Empty(suite.address)) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestSuiteDB_Suicide() { | ||||
| 	testCase := []struct { | ||||
| 		name    string | ||||
| 		amount  *big.Int | ||||
| 		expPass bool | ||||
| 		delete  bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"suicide zero balance", | ||||
| 			big.NewInt(0), | ||||
| 			false, false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"suicide with balance", | ||||
| 			big.NewInt(100), | ||||
| 			true, false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"delete", | ||||
| 			big.NewInt(0), | ||||
| 			true, true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		if tc.delete { | ||||
| 			_, err := suite.stateDB.Commit(tc.delete) | ||||
| 			suite.Require().NoError(err, tc.name) | ||||
| 			suite.Require().False(suite.stateDB.Exist(suite.address), tc.name) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if tc.expPass { | ||||
| 			suite.stateDB.SetBalance(suite.address, tc.amount) | ||||
| 			suicide := suite.stateDB.Suicide(suite.address) | ||||
| 			suite.Require().True(suicide, tc.name) | ||||
| 			suite.Require().True(suite.stateDB.HasSuicided(suite.address), tc.name) | ||||
| 		} else { | ||||
| 			//Suicide only works for an account with non-zero balance/nonce
 | ||||
| 			priv, err := ethsecp256k1.GenerateKey() | ||||
| 			suite.Require().NoError(err) | ||||
| 
 | ||||
| 			addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) | ||||
| 			suicide := suite.stateDB.Suicide(addr) | ||||
| 			suite.Require().False(suicide, tc.name) | ||||
| 			suite.Require().False(suite.stateDB.HasSuicided(addr), tc.name) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestCommitStateDB_Commit() { | ||||
| 	testCase := []struct { | ||||
| 		name       string | ||||
| 		malleate   func() | ||||
| 		deleteObjs bool | ||||
| 		expPass    bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"commit suicided", | ||||
| 			func() { | ||||
| 				ok := suite.stateDB.Suicide(suite.address) | ||||
| 				suite.Require().True(ok) | ||||
| 			}, | ||||
| 			true, true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"commit with dirty value", | ||||
| 			func() { | ||||
| 				suite.stateDB.SetCode(suite.address, []byte("code")) | ||||
| 			}, | ||||
| 			false, true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"faled to update state object", | ||||
| 			func() { | ||||
| 				suite.stateDB.SubBalance(suite.address, big.NewInt(10)) | ||||
| 			}, | ||||
| 			false, false, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 
 | ||||
| 		hash, err := suite.stateDB.Commit(tc.deleteObjs) | ||||
| 		suite.Require().Equal(ethcmn.Hash{}, hash) | ||||
| 
 | ||||
| 		if !tc.expPass { | ||||
| 			suite.Require().Error(err, tc.name) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 		acc := suite.app.AccountKeeper.GetAccount(suite.ctx, sdk.AccAddress(suite.address.Bytes())) | ||||
| 
 | ||||
| 		if tc.deleteObjs { | ||||
| 			suite.Require().Nil(acc, tc.name) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		suite.Require().NotNil(acc, tc.name) | ||||
| 		ethAcc, ok := acc.(*ethermint.EthAccount) | ||||
| 		suite.Require().True(ok) | ||||
| 		suite.Require().Equal(ethcrypto.Keccak256([]byte("code")), ethAcc.CodeHash) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestCommitStateDB_Finalize() { | ||||
| 	testCase := []struct { | ||||
| 		name       string | ||||
| 		malleate   func() | ||||
| 		deleteObjs bool | ||||
| 		expPass    bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"finalize suicided", | ||||
| 			func() { | ||||
| 				ok := suite.stateDB.Suicide(suite.address) | ||||
| 				suite.Require().True(ok) | ||||
| 			}, | ||||
| 			true, true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"finalize, not suicided", | ||||
| 			func() { | ||||
| 				suite.stateDB.AddBalance(suite.address, big.NewInt(5)) | ||||
| 			}, | ||||
| 			false, true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"finalize, dirty storage", | ||||
| 			func() { | ||||
| 				suite.stateDB.SetState(suite.address, ethcmn.BytesToHash([]byte("key")), ethcmn.BytesToHash([]byte("value"))) | ||||
| 			}, | ||||
| 			false, true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"faled to update state object", | ||||
| 			func() { | ||||
| 				suite.stateDB.SubBalance(suite.address, big.NewInt(10)) | ||||
| 			}, | ||||
| 			false, false, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		tc.malleate() | ||||
| 
 | ||||
| 		err := suite.stateDB.Finalise(tc.deleteObjs) | ||||
| 
 | ||||
| 		if !tc.expPass { | ||||
| 			suite.Require().Error(err, tc.name) | ||||
| 			hash := suite.stateDB.GetCommittedState(suite.address, ethcmn.BytesToHash([]byte("key"))) | ||||
| 			suite.Require().NotEqual(ethcmn.Hash{}, hash, tc.name) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		suite.Require().NoError(err, tc.name) | ||||
| 		acc := suite.app.AccountKeeper.GetAccount(suite.ctx, sdk.AccAddress(suite.address.Bytes())) | ||||
| 
 | ||||
| 		if tc.deleteObjs { | ||||
| 			suite.Require().Nil(acc, tc.name) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		suite.Require().NotNil(acc, tc.name) | ||||
| 	} | ||||
| } | ||||
| func (suite *StateDBTestSuite) TestCommitStateDB_GetCommittedState() { | ||||
| 	hash := suite.stateDB.GetCommittedState(ethcmn.Address{}, ethcmn.BytesToHash([]byte("key"))) | ||||
| 	suite.Require().Equal(ethcmn.Hash{}, hash) | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestCommitStateDB_Snapshot() { | ||||
| 	id := suite.stateDB.Snapshot() | ||||
| 	suite.Require().NotPanics(func() { | ||||
| 		suite.stateDB.RevertToSnapshot(id) | ||||
| 	}) | ||||
| 
 | ||||
| 	suite.Require().Panics(func() { | ||||
| 		suite.stateDB.RevertToSnapshot(-1) | ||||
| 	}, "invalid revision should panic") | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestCommitStateDB_ForEachStorage() { | ||||
| 	var storage types.Storage | ||||
| 
 | ||||
| 	testCase := []struct { | ||||
| 		name      string | ||||
| 		malleate  func() | ||||
| 		callback  func(key, value ethcmn.Hash) (stop bool) | ||||
| 		expValues []ethcmn.Hash | ||||
| 	}{ | ||||
| 		{ | ||||
| 			"aggregate state", | ||||
| 			func() { | ||||
| 				for i := 0; i < 5; i++ { | ||||
| 					suite.stateDB.SetState(suite.address, ethcmn.BytesToHash([]byte(fmt.Sprintf("key%d", i))), ethcmn.BytesToHash([]byte(fmt.Sprintf("value%d", i)))) | ||||
| 				} | ||||
| 			}, | ||||
| 			func(key, value ethcmn.Hash) bool { | ||||
| 				storage = append(storage, types.NewState(key, value)) | ||||
| 				return false | ||||
| 			}, | ||||
| 			[]ethcmn.Hash{ | ||||
| 				ethcmn.BytesToHash([]byte("value0")), | ||||
| 				ethcmn.BytesToHash([]byte("value1")), | ||||
| 				ethcmn.BytesToHash([]byte("value2")), | ||||
| 				ethcmn.BytesToHash([]byte("value3")), | ||||
| 				ethcmn.BytesToHash([]byte("value4")), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"filter state", | ||||
| 			func() { | ||||
| 				suite.stateDB.SetState(suite.address, ethcmn.BytesToHash([]byte("key")), ethcmn.BytesToHash([]byte("value"))) | ||||
| 				suite.stateDB.SetState(suite.address, ethcmn.BytesToHash([]byte("filterkey")), ethcmn.BytesToHash([]byte("filtervalue"))) | ||||
| 			}, | ||||
| 			func(key, value ethcmn.Hash) bool { | ||||
| 				if value == ethcmn.BytesToHash([]byte("filtervalue")) { | ||||
| 					storage = append(storage, types.NewState(key, value)) | ||||
| 					return true | ||||
| 				} | ||||
| 				return false | ||||
| 			}, | ||||
| 			[]ethcmn.Hash{ | ||||
| 				ethcmn.BytesToHash([]byte("filtervalue")), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, tc := range testCase { | ||||
| 		suite.Run(tc.name, func() { | ||||
| 			suite.SetupTest() // reset
 | ||||
| 			tc.malleate() | ||||
| 			suite.stateDB.Finalise(false) | ||||
| 
 | ||||
| 			err := suite.stateDB.ForEachStorage(suite.address, tc.callback) | ||||
| 			suite.Require().NoError(err) | ||||
| 			suite.Require().Equal(len(tc.expValues), len(storage), fmt.Sprintf("Expected values:\n%v\nStorage Values\n%v", tc.expValues, storage)) | ||||
| 
 | ||||
| 			vals := make([]string, len(storage)) | ||||
| 			for i := range storage { | ||||
| 				vals[i] = storage[i].Value | ||||
| 			} | ||||
| 
 | ||||
| 			suite.Require().ElementsMatch(tc.expValues, vals) | ||||
| 		}) | ||||
| 		storage = types.Storage{} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (suite *StateDBTestSuite) TestCommitStateDB_AccessList() { | ||||
| 	addr := ethcmn.Address([20]byte{77}) | ||||
| 	hash := ethcmn.Hash([32]byte{99}) | ||||
| 
 | ||||
| 	suite.Require().False(suite.stateDB.AddressInAccessList(addr)) | ||||
| 
 | ||||
| 	suite.stateDB.AddAddressToAccessList(addr) | ||||
| 	suite.Require().True(suite.stateDB.AddressInAccessList(addr)) | ||||
| 	addrIn, slotIn := suite.stateDB.SlotInAccessList(addr, hash) | ||||
| 	suite.Require().True(addrIn) | ||||
| 	suite.Require().False(slotIn) | ||||
| 
 | ||||
| 	suite.stateDB.AddSlotToAccessList(addr, hash) | ||||
| 	addrIn, slotIn = suite.stateDB.SlotInAccessList(addr, hash) | ||||
| 	suite.Require().True(addrIn) | ||||
| 	suite.Require().True(slotIn) | ||||
| } | ||||
| @ -5,20 +5,13 @@ import ( | ||||
| 
 | ||||
| 	"github.com/gogo/protobuf/proto" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"golang.org/x/crypto/sha3" | ||||
| 
 | ||||
| 	sdk "github.com/cosmos/cosmos-sdk/types" | ||||
| 	ethcmn "github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| ) | ||||
| 
 | ||||
| func rlpHash(x interface{}) (hash ethcmn.Hash) { | ||||
| 	hasher := sha3.NewLegacyKeccak256() | ||||
| 	_ = rlp.Encode(hasher, x) | ||||
| 	_ = hasher.Sum(hash[:0]) | ||||
| 
 | ||||
| 	return hash | ||||
| } | ||||
| var EmptyCodeHash = crypto.Keccak256(nil) | ||||
| 
 | ||||
| // EncodeTxResponse takes all of the necessary data from the EVM execution
 | ||||
| // and returns the data as a byte slice encoded with protobuf.
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user