keeper: StateDB
unit tests (#47)
* keeper: statedb unit tests * evm: balance tests * evm: nonce and code tests * evm: refund test * evm: fix tx encoding * storage and access list tests
This commit is contained in:
parent
8e7ebe80e9
commit
c08dcfad0c
@ -7,9 +7,11 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
"github.com/cosmos/ethermint/codec"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
// MakeEncodingConfig creates an EncodingConfig for testing
|
||||
@ -49,9 +51,9 @@ func NewTxConfig(marshaler amino.ProtoCodecMarshaler) client.TxConfig {
|
||||
// TxEncoder overwrites sdk.TxEncoder to support MsgEthereumTx
|
||||
func (g txConfig) TxEncoder() sdk.TxEncoder {
|
||||
return func(tx sdk.Tx) ([]byte, error) {
|
||||
ethtx, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
msg, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
if ok {
|
||||
return g.cdc.MarshalBinaryBare(ethtx)
|
||||
return msg.AsTransaction().MarshalBinary()
|
||||
}
|
||||
return g.TxConfig.TxEncoder()(tx)
|
||||
}
|
||||
@ -60,11 +62,13 @@ func (g txConfig) TxEncoder() sdk.TxEncoder {
|
||||
// TxDecoder overwrites sdk.TxDecoder to support MsgEthereumTx
|
||||
func (g txConfig) TxDecoder() sdk.TxDecoder {
|
||||
return func(txBytes []byte) (sdk.Tx, error) {
|
||||
var ethtx evmtypes.MsgEthereumTx
|
||||
tx := ðtypes.Transaction{}
|
||||
|
||||
err := g.cdc.UnmarshalBinaryBare(txBytes, ðtx)
|
||||
err := tx.UnmarshalBinary(txBytes)
|
||||
if err == nil {
|
||||
return ðtx, nil
|
||||
msg := &evmtypes.MsgEthereumTx{}
|
||||
msg.FromEthereumTx(tx)
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
return g.TxConfig.TxDecoder()(txBytes)
|
||||
|
@ -3,6 +3,9 @@ package tests
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -10,6 +13,20 @@ import (
|
||||
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
|
||||
)
|
||||
|
||||
// NewAddrKey generates an Ethereum address and its corresponding private key.
|
||||
func NewAddrKey() (common.Address, cryptotypes.PrivKey) {
|
||||
privkey, _ := ethsecp256k1.GenerateKey()
|
||||
addr := crypto.PubkeyToAddress(privkey.ToECDSA().PublicKey)
|
||||
|
||||
return addr, privkey
|
||||
}
|
||||
|
||||
// GenerateAddress generates an Ethereum address.
|
||||
func GenerateAddress() common.Address {
|
||||
addr, _ := NewAddrKey()
|
||||
return addr
|
||||
}
|
||||
|
||||
var _ keyring.Signer = &Signer{}
|
||||
|
||||
// Signer defines a type that is used on testing for signing MsgEthereumTx
|
||||
|
@ -1,7 +1,6 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -16,7 +15,6 @@ import (
|
||||
"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"
|
||||
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
@ -43,7 +41,7 @@ func (suite *KeeperTestSuite) 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.address = ethcmn.HexToAddress(addrHex)
|
||||
|
||||
@ -65,82 +63,6 @@ func TestKeeperTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(KeeperTestSuite))
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestTransactionLogs() {
|
||||
ethHash := ethcmn.BytesToHash(hash)
|
||||
log := ðtypes.Log{
|
||||
Address: suite.address,
|
||||
Data: []byte("log"),
|
||||
BlockNumber: 10,
|
||||
}
|
||||
log2 := ðtypes.Log{
|
||||
Address: suite.address,
|
||||
Data: []byte("log2"),
|
||||
BlockNumber: 11,
|
||||
}
|
||||
expLogs := []*ethtypes.Log{log}
|
||||
|
||||
err := suite.app.EvmKeeper.CommitStateDB.SetLogs(ethHash, expLogs)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
logs, err := suite.app.EvmKeeper.CommitStateDB.GetLogs(ethHash)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(expLogs, logs)
|
||||
|
||||
expLogs = []*ethtypes.Log{log2, log}
|
||||
|
||||
// add another log under the zero hash
|
||||
suite.app.EvmKeeper.CommitStateDB.AddLog(log2)
|
||||
logs = suite.app.EvmKeeper.CommitStateDB.AllLogs()
|
||||
suite.Require().Equal(expLogs, logs)
|
||||
|
||||
// add another log under the zero hash
|
||||
log3 := ðtypes.Log{
|
||||
Address: suite.address,
|
||||
Data: []byte("log3"),
|
||||
BlockNumber: 10,
|
||||
}
|
||||
suite.app.EvmKeeper.CommitStateDB.AddLog(log3)
|
||||
|
||||
txLogs := suite.app.EvmKeeper.GetAllTxLogs(suite.ctx)
|
||||
suite.Require().Equal(2, len(txLogs))
|
||||
|
||||
suite.Require().Equal(ethcmn.Hash{}.String(), txLogs[0].Hash)
|
||||
suite.Require().Equal([]*ethtypes.Log{log2, log3}, txLogs[0].Logs)
|
||||
|
||||
suite.Require().Equal(ethHash.String(), txLogs[1].Hash)
|
||||
suite.Require().Equal([]*ethtypes.Log{log}, txLogs[1].Logs)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestDBStorage() {
|
||||
// Perform state transitions
|
||||
suite.app.EvmKeeper.CommitStateDB.CreateAccount(suite.address)
|
||||
suite.app.EvmKeeper.CommitStateDB.SetBalance(suite.address, big.NewInt(5))
|
||||
suite.app.EvmKeeper.CommitStateDB.SetNonce(suite.address, 4)
|
||||
suite.app.EvmKeeper.CommitStateDB.SetState(suite.address, ethcmn.HexToHash("0x2"), ethcmn.HexToHash("0x3"))
|
||||
suite.app.EvmKeeper.CommitStateDB.SetCode(suite.address, []byte{0x1})
|
||||
|
||||
// Test block height mapping functionality
|
||||
testBloom := ethtypes.BytesToBloom([]byte{0x1, 0x3})
|
||||
suite.app.EvmKeeper.SetBlockBloom(suite.ctx, 4, testBloom)
|
||||
|
||||
// Get those state transitions
|
||||
suite.Require().Equal(suite.app.EvmKeeper.CommitStateDB.GetBalance(suite.address).Cmp(big.NewInt(5)), 0)
|
||||
suite.Require().Equal(suite.app.EvmKeeper.CommitStateDB.GetNonce(suite.address), uint64(4))
|
||||
suite.Require().Equal(suite.app.EvmKeeper.CommitStateDB.GetState(suite.address, ethcmn.HexToHash("0x2")), ethcmn.HexToHash("0x3"))
|
||||
suite.Require().Equal(suite.app.EvmKeeper.CommitStateDB.GetCode(suite.address), []byte{0x1})
|
||||
|
||||
bloom, found := suite.app.EvmKeeper.GetBlockBloom(suite.ctx, 4)
|
||||
suite.Require().True(found)
|
||||
suite.Require().Equal(bloom, testBloom)
|
||||
|
||||
// commit stateDB
|
||||
_, err := suite.app.EvmKeeper.CommitStateDB.Commit(false)
|
||||
suite.Require().NoError(err, "failed to commit StateDB")
|
||||
|
||||
// simulate BaseApp EndBlocker commitment
|
||||
suite.app.Commit()
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestChainConfig() {
|
||||
config, found := suite.app.EvmKeeper.GetChainConfig(suite.ctx)
|
||||
suite.Require().True(found)
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -37,7 +36,8 @@ func (k *Keeper) CreateAccount(addr common.Address) {
|
||||
k.ResetAccount(addr)
|
||||
}
|
||||
|
||||
_ = k.accountKeeper.NewAccountWithAddress(k.ctx, cosmosAddr)
|
||||
account = k.accountKeeper.NewAccountWithAddress(k.ctx, cosmosAddr)
|
||||
k.accountKeeper.SetAccount(k.ctx, account)
|
||||
|
||||
k.Logger(k.ctx).Debug(
|
||||
log,
|
||||
@ -52,6 +52,15 @@ func (k *Keeper) CreateAccount(addr common.Address) {
|
||||
|
||||
// AddBalance calls CommitStateDB.AddBalance using the passed in context
|
||||
func (k *Keeper) AddBalance(addr common.Address, amount *big.Int) {
|
||||
if amount.Sign() != 1 {
|
||||
k.Logger(k.ctx).Debug(
|
||||
"ignored non-positive amount addition",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"amount", amount.Int64(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
|
||||
params := k.GetParams(k.ctx)
|
||||
@ -76,6 +85,15 @@ func (k *Keeper) AddBalance(addr common.Address, amount *big.Int) {
|
||||
|
||||
// SubBalance calls CommitStateDB.SubBalance using the passed in context
|
||||
func (k *Keeper) SubBalance(addr common.Address, amount *big.Int) {
|
||||
if amount.Sign() != 1 {
|
||||
k.Logger(k.ctx).Debug(
|
||||
"ignored non-positive amount addition",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"amount", amount.Int64(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
|
||||
params := k.GetParams(k.ctx)
|
||||
@ -128,7 +146,8 @@ func (k *Keeper) GetNonce(addr common.Address) uint64 {
|
||||
return nonce
|
||||
}
|
||||
|
||||
// SetNonce calls CommitStateDB.SetNonce using the passed in context
|
||||
// SetNonce sets the given nonce as the sequence of the address' account. If the
|
||||
// account doesn't exist, a new one will be created from the address.
|
||||
func (k *Keeper) SetNonce(addr common.Address, nonce uint64) {
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
account := k.accountKeeper.GetAccount(k.ctx, cosmosAddr)
|
||||
@ -215,6 +234,7 @@ func (k *Keeper) SetCode(addr common.Address, code []byte) {
|
||||
account := k.accountKeeper.GetAccount(k.ctx, addr.Bytes())
|
||||
if account == nil {
|
||||
account = k.accountKeeper.NewAccountWithAddress(k.ctx, addr.Bytes())
|
||||
k.accountKeeper.SetAccount(k.ctx, account)
|
||||
}
|
||||
|
||||
ethAccount, isEthAccount := account.(*ethermint.EthAccount)
|
||||
@ -306,7 +326,8 @@ func (k *Keeper) GetRefund() uint64 {
|
||||
// State
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// GetCommittedState calls CommitStateDB.GetCommittedState using the passed in context
|
||||
// GetCommittedState returns the value set in store for the given key hash. If the key is not registered
|
||||
// this function returns the empty hash.
|
||||
func (k *Keeper) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
|
||||
store := prefix.NewStore(k.ctx.KVStore(k.storeKey), types.AddressStoragePrefix(addr))
|
||||
|
||||
@ -319,13 +340,14 @@ func (k *Keeper) GetCommittedState(addr common.Address, hash common.Hash) common
|
||||
return common.BytesToHash(value)
|
||||
}
|
||||
|
||||
// GetState calls CommitStateDB.GetState using the passed in context
|
||||
// GetState returns the commited state for the given key hash, as all changes are commited directly
|
||||
// to the KVStore.
|
||||
func (k *Keeper) GetState(addr common.Address, hash common.Hash) common.Hash {
|
||||
// All state is committed directly
|
||||
return k.GetCommittedState(addr, hash)
|
||||
}
|
||||
|
||||
// SetState calls CommitStateDB.SetState using the passed in context
|
||||
// SetState sets the given hashes (key, value) to the KVStore. If the value hash is empty, this
|
||||
// function deletes the key from the store.
|
||||
func (k *Keeper) SetState(addr common.Address, key, value common.Hash) {
|
||||
store := prefix.NewStore(k.ctx.KVStore(k.storeKey), types.AddressStoragePrefix(addr))
|
||||
key = types.KeyAddressStorage(addr, key)
|
||||
@ -415,6 +437,8 @@ func (k *Keeper) Exist(addr common.Address) bool {
|
||||
// - nonce is 0
|
||||
// - balance amount for evm denom is 0
|
||||
// - account code hash is empty
|
||||
//
|
||||
// Non-ethereum accounts are considered not empty
|
||||
func (k *Keeper) Empty(addr common.Address) bool {
|
||||
nonce := uint64(0)
|
||||
codeHash := types.EmptyCodeHash
|
||||
@ -426,7 +450,6 @@ func (k *Keeper) Empty(addr common.Address) bool {
|
||||
nonce = account.GetSequence()
|
||||
ethAccount, isEthAccount := account.(*ethermint.EthAccount)
|
||||
if !isEthAccount {
|
||||
// NOTE: non-ethereum accounts are considered not empty
|
||||
return false
|
||||
}
|
||||
|
||||
@ -526,20 +549,31 @@ func (k *Keeper) RevertToSnapshot(_ int) {}
|
||||
// context. This function also fills in the tx hash, block hash, tx index and log index fields before setting the log
|
||||
// to store.
|
||||
func (k *Keeper) AddLog(log *ethtypes.Log) {
|
||||
txHash := common.BytesToHash(tmtypes.Tx(k.ctx.TxBytes()).Hash())
|
||||
if len(k.ctx.TxBytes()) > 0 {
|
||||
tx := ðtypes.Transaction{}
|
||||
if err := tx.UnmarshalBinary(k.ctx.TxBytes()); err != nil {
|
||||
k.Logger(k.ctx).Error(
|
||||
"ethereum tx unmarshaling failed",
|
||||
"error", err,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
log.TxHash = tx.Hash()
|
||||
}
|
||||
|
||||
log.BlockHash = k.headerHash
|
||||
log.TxHash = txHash
|
||||
log.TxIndex = uint(k.GetTxIndexTransient())
|
||||
|
||||
logs := k.GetTxLogs(txHash)
|
||||
logs := k.GetTxLogs(log.TxHash)
|
||||
|
||||
log.Index = uint(len(logs))
|
||||
logs = append(logs, log)
|
||||
k.SetLogs(txHash, logs)
|
||||
k.SetLogs(log.TxHash, logs)
|
||||
|
||||
k.Logger(k.ctx).Debug(
|
||||
"log added",
|
||||
"tx-hash", txHash.Hex(),
|
||||
"tx-hash", log.TxHash.Hex(),
|
||||
"log-index", int(log.Index),
|
||||
)
|
||||
}
|
||||
|
@ -1 +1,601 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
"github.com/cosmos/ethermint/tests"
|
||||
"github.com/cosmos/ethermint/x/evm/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) TestCreateAccount() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
addr common.Address
|
||||
malleate func(common.Address)
|
||||
callback func(common.Address)
|
||||
}{
|
||||
{
|
||||
"reset account",
|
||||
suite.address,
|
||||
func(addr common.Address) {
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(100))
|
||||
suite.Require().NotZero(suite.app.EvmKeeper.GetBalance(addr).Int64())
|
||||
},
|
||||
func(addr common.Address) {
|
||||
suite.Require().Zero(suite.app.EvmKeeper.GetBalance(addr).Int64())
|
||||
},
|
||||
},
|
||||
{
|
||||
"create account",
|
||||
tests.GenerateAddress(),
|
||||
func(addr common.Address) {
|
||||
acc := suite.app.AccountKeeper.GetAccount(suite.ctx, addr.Bytes())
|
||||
suite.Require().Nil(acc)
|
||||
},
|
||||
func(addr common.Address) {
|
||||
acc := suite.app.AccountKeeper.GetAccount(suite.ctx, addr.Bytes())
|
||||
suite.Require().NotNil(acc)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate(tc.addr)
|
||||
suite.app.EvmKeeper.CreateAccount(tc.addr)
|
||||
tc.callback(tc.addr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestAddBalance() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
amount *big.Int
|
||||
isNoOp bool
|
||||
}{
|
||||
{
|
||||
"positive amount",
|
||||
big.NewInt(100),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"zero amount",
|
||||
big.NewInt(0),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"negative amount",
|
||||
big.NewInt(-1),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
prev := suite.app.EvmKeeper.GetBalance(suite.address)
|
||||
suite.app.EvmKeeper.AddBalance(suite.address, tc.amount)
|
||||
post := suite.app.EvmKeeper.GetBalance(suite.address)
|
||||
|
||||
if tc.isNoOp {
|
||||
suite.Require().Equal(prev.Int64(), post.Int64())
|
||||
} else {
|
||||
suite.Require().Equal(new(big.Int).Add(prev, tc.amount).Int64(), post.Int64())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSubBalance() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
amount *big.Int
|
||||
malleate func()
|
||||
isNoOp bool
|
||||
}{
|
||||
{
|
||||
"positive amount, below zero",
|
||||
big.NewInt(100),
|
||||
func() {},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"positive amount, below zero",
|
||||
big.NewInt(50),
|
||||
func() {
|
||||
suite.app.EvmKeeper.AddBalance(suite.address, big.NewInt(100))
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"zero amount",
|
||||
big.NewInt(0),
|
||||
func() {},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"negative amount",
|
||||
big.NewInt(-1),
|
||||
func() {},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
|
||||
prev := suite.app.EvmKeeper.GetBalance(suite.address)
|
||||
suite.app.EvmKeeper.SubBalance(suite.address, tc.amount)
|
||||
post := suite.app.EvmKeeper.GetBalance(suite.address)
|
||||
|
||||
if tc.isNoOp {
|
||||
suite.Require().Equal(prev.Int64(), post.Int64())
|
||||
} else {
|
||||
suite.Require().Equal(new(big.Int).Sub(prev, tc.amount).Int64(), post.Int64())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestGetNonce() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
address common.Address
|
||||
expectedNonce uint64
|
||||
malleate func()
|
||||
}{
|
||||
{
|
||||
"account not found",
|
||||
tests.GenerateAddress(),
|
||||
0,
|
||||
func() {},
|
||||
},
|
||||
{
|
||||
"existing account",
|
||||
suite.address,
|
||||
1,
|
||||
func() {
|
||||
suite.app.EvmKeeper.SetNonce(suite.address, 1)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
|
||||
nonce := suite.app.EvmKeeper.GetNonce(tc.address)
|
||||
suite.Require().Equal(tc.expectedNonce, nonce)
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSetNonce() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
address common.Address
|
||||
nonce uint64
|
||||
malleate func()
|
||||
}{
|
||||
{
|
||||
"new account",
|
||||
tests.GenerateAddress(),
|
||||
10,
|
||||
func() {},
|
||||
},
|
||||
{
|
||||
"existing account",
|
||||
suite.address,
|
||||
99,
|
||||
func() {},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.app.EvmKeeper.SetNonce(tc.address, tc.nonce)
|
||||
nonce := suite.app.EvmKeeper.GetNonce(tc.address)
|
||||
suite.Require().Equal(tc.nonce, nonce)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestGetCodeHash() {
|
||||
addr := tests.GenerateAddress()
|
||||
baseAcc := &authtypes.BaseAccount{Address: sdk.AccAddress(addr.Bytes()).String()}
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, baseAcc)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
address common.Address
|
||||
expHash common.Hash
|
||||
malleate func()
|
||||
}{
|
||||
{
|
||||
"account not found",
|
||||
tests.GenerateAddress(),
|
||||
common.BytesToHash(types.EmptyCodeHash),
|
||||
func() {},
|
||||
},
|
||||
{
|
||||
"account not EthAccount type",
|
||||
addr,
|
||||
common.BytesToHash(types.EmptyCodeHash),
|
||||
func() {},
|
||||
},
|
||||
{
|
||||
"existing account",
|
||||
suite.address,
|
||||
crypto.Keccak256Hash([]byte("codeHash")),
|
||||
func() {
|
||||
suite.app.EvmKeeper.SetCode(suite.address, []byte("codeHash"))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
|
||||
tc.malleate()
|
||||
|
||||
hash := suite.app.EvmKeeper.GetCodeHash(tc.address)
|
||||
suite.Require().Equal(tc.expHash, hash)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSetCode() {
|
||||
addr := tests.GenerateAddress()
|
||||
baseAcc := &authtypes.BaseAccount{Address: sdk.AccAddress(addr.Bytes()).String()}
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, baseAcc)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
address common.Address
|
||||
code []byte
|
||||
isNoOp bool
|
||||
}{
|
||||
{
|
||||
"account not found",
|
||||
tests.GenerateAddress(),
|
||||
[]byte("code"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"account not EthAccount type",
|
||||
addr,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"existing account",
|
||||
suite.address,
|
||||
[]byte("code"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"existing account, code deleted from store",
|
||||
suite.address,
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
|
||||
prev := suite.app.EvmKeeper.GetCode(tc.address)
|
||||
suite.app.EvmKeeper.SetCode(tc.address, tc.code)
|
||||
post := suite.app.EvmKeeper.GetCode(tc.address)
|
||||
|
||||
if tc.isNoOp {
|
||||
suite.Require().Equal(prev, post)
|
||||
} else {
|
||||
suite.Require().Equal(tc.code, post)
|
||||
}
|
||||
|
||||
suite.Require().Equal(len(post), suite.app.EvmKeeper.GetCodeSize(tc.address))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestRefund() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
expRefund uint64
|
||||
expPanic bool
|
||||
}{
|
||||
{
|
||||
"success - add and subtract refund",
|
||||
func() {
|
||||
suite.app.EvmKeeper.AddRefund(11)
|
||||
},
|
||||
1,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - subtract amount > current refund",
|
||||
func() {
|
||||
},
|
||||
0,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
|
||||
tc.malleate()
|
||||
|
||||
if tc.expPanic {
|
||||
suite.Require().Panics(func() { suite.app.EvmKeeper.SubRefund(10) })
|
||||
} else {
|
||||
suite.app.EvmKeeper.SubRefund(10)
|
||||
suite.Require().Equal(tc.expRefund, suite.app.EvmKeeper.GetRefund())
|
||||
}
|
||||
|
||||
// clear and reset refund from store
|
||||
suite.app.EvmKeeper.ResetRefundTransient(suite.ctx)
|
||||
suite.Require().Zero(suite.app.EvmKeeper.GetRefund())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestState() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
key, value common.Hash
|
||||
}{
|
||||
{
|
||||
"set state - delete from store",
|
||||
common.BytesToHash([]byte("key")),
|
||||
common.Hash{},
|
||||
},
|
||||
{
|
||||
"set state - update value",
|
||||
common.BytesToHash([]byte("key")),
|
||||
common.BytesToHash([]byte("value")),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
|
||||
suite.app.EvmKeeper.SetState(suite.address, tc.key, tc.value)
|
||||
value := suite.app.EvmKeeper.GetState(suite.address, tc.key)
|
||||
suite.Require().Equal(tc.value, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSuicide() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
suicided bool
|
||||
}{
|
||||
{"success, first time suicided", true},
|
||||
{"success, already suicided", true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.Require().Equal(tc.suicided, suite.app.EvmKeeper.Suicide(suite.address))
|
||||
suite.Require().Equal(tc.suicided, suite.app.EvmKeeper.HasSuicided(suite.address))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestExist() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
address common.Address
|
||||
malleate func()
|
||||
exists bool
|
||||
}{
|
||||
{"success, account exists", suite.address, func() {}, true},
|
||||
{"success, has suicided", suite.address, func() {
|
||||
suite.app.EvmKeeper.Suicide(suite.address)
|
||||
}, true},
|
||||
{"success, account doesn't exist", tests.GenerateAddress(), func() {}, false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
|
||||
suite.Require().Equal(tc.exists, suite.app.EvmKeeper.Exist(tc.address))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestEmpty() {
|
||||
addr := tests.GenerateAddress()
|
||||
baseAcc := &authtypes.BaseAccount{Address: sdk.AccAddress(addr.Bytes()).String()}
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, baseAcc)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
address common.Address
|
||||
malleate func()
|
||||
empty bool
|
||||
}{
|
||||
{"empty, account exists", suite.address, func() {}, true},
|
||||
{"not empty, non ethereum account", addr, func() {}, false},
|
||||
{"not empty, positive balance", suite.address, func() {
|
||||
suite.app.EvmKeeper.AddBalance(suite.address, big.NewInt(100))
|
||||
}, false},
|
||||
{"empty, account doesn't exist", tests.GenerateAddress(), func() {}, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
|
||||
suite.Require().Equal(tc.empty, suite.app.EvmKeeper.Empty(tc.address))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSnapshot() {
|
||||
revision := suite.app.EvmKeeper.Snapshot()
|
||||
suite.Require().Zero(revision)
|
||||
suite.app.EvmKeeper.RevertToSnapshot(revision) // no-op
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestAddLog() {
|
||||
addr := tests.GenerateAddress()
|
||||
msg := types.NewMsgEthereumTx(big.NewInt(1), 0, &suite.address, big.NewInt(1), 100000, big.NewInt(1), []byte("test"), nil)
|
||||
tx := msg.AsTransaction()
|
||||
txBz, err := tx.MarshalBinary()
|
||||
suite.Require().NoError(err)
|
||||
txHash := tx.Hash()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
log, expLog *ethtypes.Log // pre and post populating log fields
|
||||
malleate func()
|
||||
}{
|
||||
{
|
||||
"block hash not found",
|
||||
ðtypes.Log{
|
||||
Address: addr,
|
||||
},
|
||||
ðtypes.Log{
|
||||
Address: addr,
|
||||
},
|
||||
func() {},
|
||||
},
|
||||
{
|
||||
"tx hash from message",
|
||||
ðtypes.Log{
|
||||
Address: addr,
|
||||
},
|
||||
ðtypes.Log{
|
||||
Address: addr,
|
||||
TxHash: txHash,
|
||||
},
|
||||
func() {
|
||||
suite.app.EvmKeeper.WithContext(suite.ctx.WithTxBytes(txBz))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
|
||||
prev := suite.app.EvmKeeper.GetTxLogs(tc.expLog.TxHash)
|
||||
suite.app.EvmKeeper.AddLog(tc.log)
|
||||
post := suite.app.EvmKeeper.GetTxLogs(tc.expLog.TxHash)
|
||||
|
||||
suite.Require().NotZero(len(post), tc.expLog.TxHash.Hex())
|
||||
suite.Require().Equal(len(prev)+1, len(post))
|
||||
suite.Require().NotNil(post[len(post)-1])
|
||||
suite.Require().Equal(tc.log, post[len(post)-1])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestAccessList() {
|
||||
dest := tests.GenerateAddress()
|
||||
precompiles := []common.Address{tests.GenerateAddress(), tests.GenerateAddress()}
|
||||
accesses := ethtypes.AccessList{
|
||||
{Address: tests.GenerateAddress(), StorageKeys: []common.Hash{common.BytesToHash([]byte("key"))}},
|
||||
{Address: tests.GenerateAddress(), StorageKeys: []common.Hash{common.BytesToHash([]byte("key1"))}},
|
||||
}
|
||||
|
||||
suite.app.EvmKeeper.PrepareAccessList(suite.address, &dest, precompiles, accesses)
|
||||
|
||||
suite.Require().True(suite.app.EvmKeeper.AddressInAccessList(suite.address))
|
||||
suite.Require().True(suite.app.EvmKeeper.AddressInAccessList(dest))
|
||||
|
||||
for _, precompile := range precompiles {
|
||||
suite.Require().True(suite.app.EvmKeeper.AddressInAccessList(precompile))
|
||||
}
|
||||
|
||||
for _, access := range accesses {
|
||||
for _, key := range access.StorageKeys {
|
||||
addrOK, slotOK := suite.app.EvmKeeper.SlotInAccessList(access.Address, key)
|
||||
suite.Require().True(addrOK)
|
||||
suite.Require().True(slotOK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestForEachStorage() {
|
||||
var storage types.Storage
|
||||
|
||||
testCase := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
callback func(key, value common.Hash) (stop bool)
|
||||
expValues []common.Hash
|
||||
}{
|
||||
{
|
||||
"aggregate state",
|
||||
func() {
|
||||
for i := 0; i < 5; i++ {
|
||||
suite.app.EvmKeeper.SetState(suite.address, common.BytesToHash([]byte(fmt.Sprintf("key%d", i))), common.BytesToHash([]byte(fmt.Sprintf("value%d", i))))
|
||||
}
|
||||
},
|
||||
func(key, value common.Hash) bool {
|
||||
storage = append(storage, types.NewState(key, value))
|
||||
return false
|
||||
},
|
||||
[]common.Hash{
|
||||
common.BytesToHash([]byte("value0")),
|
||||
common.BytesToHash([]byte("value1")),
|
||||
common.BytesToHash([]byte("value2")),
|
||||
common.BytesToHash([]byte("value3")),
|
||||
common.BytesToHash([]byte("value4")),
|
||||
},
|
||||
},
|
||||
{
|
||||
"filter state",
|
||||
func() {
|
||||
suite.app.EvmKeeper.SetState(suite.address, common.BytesToHash([]byte("key")), common.BytesToHash([]byte("value")))
|
||||
suite.app.EvmKeeper.SetState(suite.address, common.BytesToHash([]byte("filterkey")), common.BytesToHash([]byte("filtervalue")))
|
||||
},
|
||||
func(key, value common.Hash) bool {
|
||||
if value == common.BytesToHash([]byte("filtervalue")) {
|
||||
storage = append(storage, types.NewState(key, value))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
[]common.Hash{
|
||||
common.BytesToHash([]byte("filtervalue")),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCase {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.malleate()
|
||||
|
||||
err := suite.app.EvmKeeper.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([]common.Hash, len(storage))
|
||||
for i := range storage {
|
||||
vals[i] = common.HexToHash(storage[i].Value)
|
||||
}
|
||||
|
||||
// TODO: not sure why Equals fails
|
||||
suite.Require().ElementsMatch(tc.expValues, vals)
|
||||
})
|
||||
storage = types.Storage{}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
log "github.com/xlab/suplog"
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
@ -77,9 +75,9 @@ func (log *Log) Validate() error {
|
||||
|
||||
// ToEthereum returns the Ethereum type Log from a Ethermint-proto compatible Log.
|
||||
func (log *Log) ToEthereum() *ethtypes.Log {
|
||||
topics := make([]ethcmn.Hash, len(log.Topics))
|
||||
var topics []ethcmn.Hash // nolint: prealloc
|
||||
for i := range log.Topics {
|
||||
topics[i] = ethcmn.HexToHash(log.Topics[i])
|
||||
topics = append(topics, ethcmn.HexToHash(log.Topics[i]))
|
||||
}
|
||||
|
||||
return ðtypes.Log{
|
||||
@ -97,24 +95,18 @@ func (log *Log) ToEthereum() *ethtypes.Log {
|
||||
|
||||
// LogsToEthereum casts the Ethermint Logs to a slice of Ethereum Logs.
|
||||
func LogsToEthereum(logs []*Log) []*ethtypes.Log {
|
||||
ethLogs := make([]*ethtypes.Log, len(logs))
|
||||
var ethLogs []*ethtypes.Log // nolint: prealloc
|
||||
for i := range logs {
|
||||
err := logs[i].Validate()
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln("failed log validation", logs[i].String())
|
||||
continue
|
||||
}
|
||||
|
||||
ethLogs[i] = logs[i].ToEthereum()
|
||||
ethLogs = append(ethLogs, logs[i].ToEthereum())
|
||||
}
|
||||
return ethLogs
|
||||
}
|
||||
|
||||
// NewLogFromEth creates a new Log instance from a Ethereum type Log.
|
||||
func NewLogFromEth(log *ethtypes.Log) *Log {
|
||||
topics := make([]string, len(log.Topics))
|
||||
for i := range log.Topics {
|
||||
topics[i] = log.Topics[i].String()
|
||||
var topics []string // nolint: prealloc
|
||||
for _, topic := range log.Topics {
|
||||
topics = append(topics, topic.String())
|
||||
}
|
||||
|
||||
return &Log{
|
||||
|
@ -89,7 +89,7 @@ func newMsgEthereumTx(
|
||||
}
|
||||
|
||||
// fromEthereumTx populates the message fields from the given ethereum transaction
|
||||
func (msg *MsgEthereumTx) fromEthereumTx(tx *ethtypes.Transaction) {
|
||||
func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) {
|
||||
to := ""
|
||||
if tx.To() != nil {
|
||||
to = tx.To().Hex()
|
||||
@ -227,7 +227,7 @@ func (msg *MsgEthereumTx) DecodeRLP(stream *rlp.Stream) error {
|
||||
return err
|
||||
}
|
||||
|
||||
msg.fromEthereumTx(tx)
|
||||
msg.FromEthereumTx(tx)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -258,7 +258,7 @@ func (msg *MsgEthereumTx) Sign(ethSigner ethtypes.Signer, keyringSigner keyring.
|
||||
return err
|
||||
}
|
||||
|
||||
msg.fromEthereumTx(tx)
|
||||
msg.FromEthereumTx(tx)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user