9227e78c79
* use stack of contexts to implement snapshot revert Closes #338 add exception revert test case verify partial revert mutate state after the reverted subcall polish update comments name the module after the type name remove the unnecessary Snapshot in outer layer and add snapshot unit test assert context stack is clean after tx processing cleanups fix context revert fix comments update comments it's ok to commit in failed case too Update x/evm/keeper/context_stack.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Update x/evm/keeper/context_stack.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Update x/evm/keeper/context_stack.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> update comment and error message add comment to cacheContext k -> cs Update x/evm/keeper/context_stack.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> evm can handle state revert renames and unit tests * use table driven tests * keep all the cosmos events * changelog * check for if commit function is nil * fix changelog * Update x/evm/keeper/context_stack.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
758 lines
18 KiB
Go
758 lines
18 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
|
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/tharsis/ethermint/tests"
|
|
"github.com/tharsis/ethermint/x/evm/types"
|
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
|
)
|
|
|
|
func (suite *KeeperTestSuite) TestCreateAccount() {
|
|
testCases := []struct {
|
|
name string
|
|
addr common.Address
|
|
malleate func(common.Address)
|
|
callback func(common.Address)
|
|
}{
|
|
{
|
|
"reset account (keep balance)",
|
|
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().Equal(suite.app.EvmKeeper.GetBalance(addr).Int64(), int64(100))
|
|
},
|
|
},
|
|
{
|
|
"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) TestCommittedState() {
|
|
suite.SetupTest()
|
|
|
|
var key = common.BytesToHash([]byte("key"))
|
|
var value1 = common.BytesToHash([]byte("value1"))
|
|
var value2 = common.BytesToHash([]byte("value2"))
|
|
|
|
suite.app.EvmKeeper.SetState(suite.address, key, value1)
|
|
|
|
suite.app.EvmKeeper.Snapshot()
|
|
|
|
suite.app.EvmKeeper.SetState(suite.address, key, value2)
|
|
tmp := suite.app.EvmKeeper.GetState(suite.address, key)
|
|
suite.Require().Equal(value2, tmp)
|
|
tmp = suite.app.EvmKeeper.GetCommittedState(suite.address, key)
|
|
suite.Require().Equal(value1, tmp)
|
|
|
|
suite.app.EvmKeeper.CommitCachedContexts()
|
|
|
|
tmp = suite.app.EvmKeeper.GetCommittedState(suite.address, key)
|
|
suite.Require().Equal(value2, tmp)
|
|
}
|
|
|
|
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() {
|
|
|
|
var key = common.BytesToHash([]byte("key"))
|
|
var value1 = common.BytesToHash([]byte("value1"))
|
|
var value2 = common.BytesToHash([]byte("value2"))
|
|
|
|
testCases := []struct {
|
|
name string
|
|
malleate func()
|
|
}{
|
|
{"simple revert", func() {
|
|
revision := suite.app.EvmKeeper.Snapshot()
|
|
suite.Require().Zero(revision)
|
|
|
|
suite.app.EvmKeeper.SetState(suite.address, key, value1)
|
|
suite.Require().Equal(value1, suite.app.EvmKeeper.GetState(suite.address, key))
|
|
|
|
suite.app.EvmKeeper.RevertToSnapshot(revision)
|
|
|
|
// reverted
|
|
suite.Require().Equal(common.Hash{}, suite.app.EvmKeeper.GetState(suite.address, key))
|
|
}},
|
|
{"nested snapshot/revert", func() {
|
|
revision1 := suite.app.EvmKeeper.Snapshot()
|
|
suite.Require().Zero(revision1)
|
|
|
|
suite.app.EvmKeeper.SetState(suite.address, key, value1)
|
|
|
|
revision2 := suite.app.EvmKeeper.Snapshot()
|
|
|
|
suite.app.EvmKeeper.SetState(suite.address, key, value2)
|
|
suite.Require().Equal(value2, suite.app.EvmKeeper.GetState(suite.address, key))
|
|
|
|
suite.app.EvmKeeper.RevertToSnapshot(revision2)
|
|
suite.Require().Equal(value1, suite.app.EvmKeeper.GetState(suite.address, key))
|
|
|
|
suite.app.EvmKeeper.RevertToSnapshot(revision1)
|
|
suite.Require().Equal(common.Hash{}, suite.app.EvmKeeper.GetState(suite.address, key))
|
|
}},
|
|
{"jump revert", func() {
|
|
revision1 := suite.app.EvmKeeper.Snapshot()
|
|
suite.app.EvmKeeper.SetState(suite.address, key, value1)
|
|
suite.app.EvmKeeper.Snapshot()
|
|
suite.app.EvmKeeper.SetState(suite.address, key, value2)
|
|
suite.app.EvmKeeper.RevertToSnapshot(revision1)
|
|
suite.Require().Equal(common.Hash{}, suite.app.EvmKeeper.GetState(suite.address, key))
|
|
}},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.SetupTest()
|
|
tc.malleate()
|
|
// the test case should finish in clean state
|
|
suite.Require().True(suite.app.EvmKeeper.CachedContextsEmpty())
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) CreateTestTx(msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey) authsigning.Tx {
|
|
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
|
|
suite.Require().NoError(err)
|
|
|
|
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
|
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
|
|
suite.Require().True(ok)
|
|
|
|
builder.SetExtensionOptions(option)
|
|
|
|
err = msg.Sign(suite.ethSigner, tests.NewSigner(priv))
|
|
suite.Require().NoError(err)
|
|
|
|
err = txBuilder.SetMsgs(msg)
|
|
suite.Require().NoError(err)
|
|
|
|
return txBuilder.GetTx()
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestAddLog() {
|
|
addr, privKey := tests.NewAddrKey()
|
|
msg := types.NewTx(big.NewInt(1), 0, &suite.address, big.NewInt(1), 100000, big.NewInt(1), []byte("test"), nil)
|
|
msg.From = addr.Hex()
|
|
|
|
tx := suite.CreateTestTx(msg, privKey)
|
|
msg, _ = tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
|
txHash := msg.AsTransaction().Hash()
|
|
|
|
msg2 := types.NewTx(big.NewInt(1), 1, &suite.address, big.NewInt(1), 100000, big.NewInt(1), []byte("test"), nil)
|
|
msg2.From = addr.Hex()
|
|
|
|
tx2 := suite.CreateTestTx(msg2, privKey)
|
|
msg2, _ = tx2.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
|
txHash2 := msg2.AsTransaction().Hash()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
hash common.Hash
|
|
log, expLog *ethtypes.Log // pre and post populating log fields
|
|
malleate func()
|
|
}{
|
|
{
|
|
"tx hash from message",
|
|
txHash,
|
|
ðtypes.Log{
|
|
Address: addr,
|
|
},
|
|
ðtypes.Log{
|
|
Address: addr,
|
|
TxHash: txHash,
|
|
},
|
|
func() {},
|
|
},
|
|
{
|
|
"log index keep increasing in new tx",
|
|
txHash2,
|
|
ðtypes.Log{
|
|
Address: addr,
|
|
},
|
|
ðtypes.Log{
|
|
Address: addr,
|
|
TxHash: txHash2,
|
|
TxIndex: 1,
|
|
Index: 1,
|
|
},
|
|
func() {
|
|
suite.app.EvmKeeper.SetTxHashTransient(txHash)
|
|
suite.app.EvmKeeper.AddLog(ðtypes.Log{
|
|
Address: addr,
|
|
})
|
|
suite.app.EvmKeeper.IncreaseTxIndexTransient()
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.SetupTest()
|
|
tc.malleate()
|
|
|
|
suite.app.EvmKeeper.SetTxHashTransient(tc.hash)
|
|
suite.app.EvmKeeper.AddLog(tc.log)
|
|
logs := suite.app.EvmKeeper.GetTxLogs(tc.hash)
|
|
suite.Require().Equal(1, len(logs))
|
|
suite.Require().Equal(tc.expLog, logs[0])
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestPrepareAccessList() {
|
|
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, access.Address.Hex())
|
|
suite.Require().True(slotOK, key.Hex())
|
|
}
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestAddAddressToAccessList() {
|
|
testCases := []struct {
|
|
name string
|
|
addr common.Address
|
|
}{
|
|
{"new address", suite.address},
|
|
{"existing address", suite.address},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.app.EvmKeeper.AddAddressToAccessList(tc.addr)
|
|
addrOk := suite.app.EvmKeeper.AddressInAccessList(tc.addr)
|
|
suite.Require().True(addrOk, tc.addr.Hex())
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) AddSlotToAccessList() {
|
|
testCases := []struct {
|
|
name string
|
|
addr common.Address
|
|
slot common.Hash
|
|
}{
|
|
{"new address and slot (1)", tests.GenerateAddress(), common.BytesToHash([]byte("hash"))},
|
|
{"new address and slot (2)", suite.address, common.Hash{}},
|
|
{"existing address and slot", suite.address, common.Hash{}},
|
|
{"existing address, new slot", suite.address, common.BytesToHash([]byte("hash"))},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.app.EvmKeeper.AddSlotToAccessList(tc.addr, tc.slot)
|
|
addrOk, slotOk := suite.app.EvmKeeper.SlotInAccessList(tc.addr, tc.slot)
|
|
suite.Require().True(addrOk, tc.addr.Hex())
|
|
suite.Require().True(slotOk, tc.slot.Hex())
|
|
})
|
|
}
|
|
}
|
|
|
|
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{}
|
|
}
|
|
}
|