x/evm: StateBD tests (#407)
* draft state_transition * working test * keeper test * statedb rewrite * fix tests * add keeper statedb test * minor changes * x/evm: StateBD tests * try fix * fix stateObject.setState * Update x/evm/types/state_object.go * update stateObject.setState * uncomment test * increase coverage * fix test-import * update rpc tests Co-authored-by: Justin Thompson <justin.thompson12@hotmail.com> Co-authored-by: noot <elizabethjbinks@gmail.com>
This commit is contained in:
parent
7b4f712f66
commit
de8d8acf77
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
branches:
|
||||
- development
|
||||
jobs:
|
||||
rpc-tests:
|
||||
test-rpc:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
@ -19,7 +19,7 @@ jobs:
|
||||
.go
|
||||
.mod
|
||||
.sum
|
||||
- name: rpc-test
|
||||
- name: test-rpc
|
||||
run: |
|
||||
make test-rpc
|
||||
if: "env.GIT_DIFF != ''"
|
||||
|
@ -360,9 +360,9 @@ func applyTransaction(
|
||||
|
||||
// Apply the transaction to the current state (included in the env)
|
||||
execResult, err := ethcore.ApplyMessage(vmenv, msg, gp)
|
||||
// NOTE: ignore vm execution error (eg: tx out of gas) as we care only about state transition errors
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
// NOTE: ignore vm execution error (eg: tx out of gas at block 51169) as we care only about state transition errors
|
||||
return ðtypes.Receipt{}, 0, nil
|
||||
}
|
||||
|
||||
// Update the state with pending changes
|
||||
|
@ -532,6 +532,7 @@ func TestEth_GetFilterChanges_NoTopics(t *testing.T) {
|
||||
|
||||
// instantiate new filter
|
||||
rpcRes = call(t, "eth_newFilter", param)
|
||||
require.Nil(t, rpcRes.Error)
|
||||
var ID hexutil.Bytes
|
||||
err = json.Unmarshal(rpcRes.Result, &ID)
|
||||
require.NoError(t, err)
|
||||
|
@ -142,6 +142,10 @@ func (so *stateObject) setState(key, value ethcmn.Hash) {
|
||||
so.dirtyStorage = append(so.dirtyStorage, NewState(key, value))
|
||||
idx = len(so.dirtyStorage) - 1
|
||||
so.keyToDirtyStorageIndex[key] = idx
|
||||
|
||||
so.originStorage = append(so.originStorage, State{})
|
||||
idx = len(so.originStorage) - 1
|
||||
so.keyToOriginStorageIndex[key] = idx
|
||||
}
|
||||
|
||||
// SetCode sets the state object's code.
|
||||
@ -242,9 +246,8 @@ func (so *stateObject) commitState() {
|
||||
ctx := so.stateDB.ctx
|
||||
store := prefix.NewStore(ctx.KVStore(so.stateDB.storeKey), AddressStoragePrefix(so.Address()))
|
||||
|
||||
for i, state := range so.dirtyStorage {
|
||||
for _, state := range so.dirtyStorage {
|
||||
delete(so.keyToDirtyStorageIndex, state.Key)
|
||||
so.dirtyStorage = append(so.dirtyStorage[:i], so.dirtyStorage[i+1:]...)
|
||||
|
||||
// skip no-op changes, persist actual changes
|
||||
idx, ok := so.keyToOriginStorageIndex[state.Key]
|
||||
@ -268,6 +271,8 @@ func (so *stateObject) commitState() {
|
||||
|
||||
store.Set(state.Key.Bytes(), state.Value.Bytes())
|
||||
}
|
||||
// clean storage as all entries are dirty
|
||||
so.dirtyStorage = Storage{}
|
||||
}
|
||||
|
||||
// commitCode persists the state object's code to the KVStore.
|
||||
|
@ -16,7 +16,6 @@ import (
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
ethvm "github.com/ethereum/go-ethereum/core/vm"
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -745,13 +744,8 @@ func (csdb *CommitStateDB) ForEachStorage(addr ethcmn.Address, cb func(key, valu
|
||||
continue
|
||||
}
|
||||
|
||||
_, content, _, err := rlp.Split(value.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if iteration stops
|
||||
if cb(key, ethcmn.BytesToHash(content)) {
|
||||
if cb(key, value) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
@ -111,7 +112,7 @@ func (suite *StateDBTestSuite) TestBloomFilter() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBBalance() {
|
||||
func (suite *StateDBTestSuite) TestStateDB_Balance() {
|
||||
testCase := []struct {
|
||||
name string
|
||||
malleate func()
|
||||
@ -159,7 +160,17 @@ func (suite *StateDBTestSuite) TestStateDBNonce() {
|
||||
suite.Require().Equal(nonce, suite.stateDB.GetNonce(suite.address))
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBState() {
|
||||
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)
|
||||
@ -195,7 +206,7 @@ func (suite *StateDBTestSuite) TestStateDBState() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBCode() {
|
||||
func (suite *StateDBTestSuite) TestStateDB_Code() {
|
||||
testCase := []struct {
|
||||
name string
|
||||
address ethcmn.Address
|
||||
@ -232,7 +243,7 @@ func (suite *StateDBTestSuite) TestStateDBCode() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBLogs() {
|
||||
func (suite *StateDBTestSuite) TestStateDB_Logs() {
|
||||
testCase := []struct {
|
||||
name string
|
||||
log ethtypes.Log
|
||||
@ -278,16 +289,15 @@ func (suite *StateDBTestSuite) TestStateDBLogs() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBPreimage() {
|
||||
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) TestStateDBRefund() {
|
||||
func (suite *StateDBTestSuite) TestStateDB_Refund() {
|
||||
testCase := []struct {
|
||||
name string
|
||||
addAmount uint64
|
||||
@ -331,7 +341,7 @@ func (suite *StateDBTestSuite) TestStateDBRefund() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBCreateAcct() {
|
||||
func (suite *StateDBTestSuite) TestStateDB_CreateAccount() {
|
||||
prevBalance := big.NewInt(12)
|
||||
|
||||
testCase := []struct {
|
||||
@ -364,7 +374,7 @@ func (suite *StateDBTestSuite) TestStateDBCreateAcct() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBClearStateOjb() {
|
||||
func (suite *StateDBTestSuite) TestStateDB_ClearStateObj() {
|
||||
priv, err := crypto.GenerateKey()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
@ -377,7 +387,7 @@ func (suite *StateDBTestSuite) TestStateDBClearStateOjb() {
|
||||
suite.Require().False(suite.stateDB.Exist(addr))
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestStateDBReset() {
|
||||
func (suite *StateDBTestSuite) TestStateDB_Reset() {
|
||||
priv, err := crypto.GenerateKey()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
@ -391,7 +401,7 @@ func (suite *StateDBTestSuite) TestStateDBReset() {
|
||||
suite.Require().False(suite.stateDB.Exist(addr))
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestSuiteDBPrepare() {
|
||||
func (suite *StateDBTestSuite) TestSuiteDB_Prepare() {
|
||||
thash := ethcmn.BytesToHash([]byte("thash"))
|
||||
bhash := ethcmn.BytesToHash([]byte("bhash"))
|
||||
txi := 1
|
||||
@ -402,7 +412,7 @@ func (suite *StateDBTestSuite) TestSuiteDBPrepare() {
|
||||
suite.Require().Equal(bhash, suite.stateDB.BlockHash())
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestSuiteDBCopyState() {
|
||||
func (suite *StateDBTestSuite) TestSuiteDB_CopyState() {
|
||||
testCase := []struct {
|
||||
name string
|
||||
log ethtypes.Log
|
||||
@ -439,16 +449,14 @@ func (suite *StateDBTestSuite) TestSuiteDBCopyState() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *StateDBTestSuite) TestSuiteDBEmpty() {
|
||||
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) TestSuiteDBSuicide() {
|
||||
|
||||
func (suite *StateDBTestSuite) TestSuiteDB_Suicide() {
|
||||
testCase := []struct {
|
||||
name string
|
||||
amount *big.Int
|
||||
@ -600,6 +608,8 @@ func (suite *StateDBTestSuite) TestCommitStateDB_Finalize() {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -614,3 +624,86 @@ func (suite *StateDBTestSuite) TestCommitStateDB_Finalize() {
|
||||
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([]ethcmn.Hash, len(storage))
|
||||
for i := range storage {
|
||||
vals[i] = storage[i].Value
|
||||
}
|
||||
|
||||
suite.Require().ElementsMatch(tc.expValues, vals)
|
||||
})
|
||||
storage = types.Storage{}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user