42fc796595
* x/evm: state_object tests * tests * commit tests * finalize tests * update
437 lines
11 KiB
Go
437 lines
11 KiB
Go
package types_test
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
|
|
|
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"
|
|
ethermint "github.com/cosmos/ethermint/types"
|
|
"github.com/cosmos/ethermint/x/evm/keeper"
|
|
"github.com/cosmos/ethermint/x/evm/types"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
)
|
|
|
|
type StateDBTestSuite struct {
|
|
suite.Suite
|
|
|
|
ctx sdk.Context
|
|
querier sdk.Querier
|
|
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, abci.Header{Height: 1})
|
|
suite.querier = keeper.NewQuerier(suite.app.EvmKeeper)
|
|
suite.stateDB = suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx)
|
|
|
|
privkey, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
suite.address = ethcmn.BytesToAddress(privkey.PubKey().Address().Bytes())
|
|
acc := ðermint.EthAccount{
|
|
BaseAccount: auth.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
|
|
CodeHash: ethcrypto.Keccak256(nil),
|
|
}
|
|
|
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
|
suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address)
|
|
}
|
|
|
|
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))
|
|
|
|
// Generate and add a log to test
|
|
log := ethtypes.Log{Address: contractAddress}
|
|
suite.stateDB.AddLog(&log)
|
|
|
|
// Get log from db
|
|
logs, err := suite.stateDB.GetLogs(tHash)
|
|
suite.Require().NoError(err)
|
|
suite.Require().Len(logs, 1)
|
|
suite.Require().Equal(log, *logs[0])
|
|
|
|
// get logs bloom from the log
|
|
bloomInt := ethtypes.LogsBloom(logs)
|
|
bloomFilter := ethtypes.BytesToBloom(bloomInt.Bytes())
|
|
|
|
// Check to make sure bloom filter will succeed on
|
|
suite.Require().True(ethtypes.BloomLookup(bloomFilter, contractAddress))
|
|
suite.Require().False(ethtypes.BloomLookup(bloomFilter, ethcmn.BigToAddress(big.NewInt(2))))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBBalance() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
value := big.NewInt(100)
|
|
suite.stateDB.SetBalance(addr, value)
|
|
suite.Require().Equal(value, suite.stateDB.GetBalance(addr))
|
|
|
|
suite.stateDB.SubBalance(addr, value)
|
|
suite.Require().Equal(big.NewInt(0), suite.stateDB.GetBalance(addr))
|
|
|
|
suite.stateDB.AddBalance(addr, value)
|
|
suite.Require().Equal(value, suite.stateDB.GetBalance(addr))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBNonce() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
|
|
nonce := uint64(123)
|
|
suite.stateDB.SetNonce(addr, nonce)
|
|
|
|
suite.Require().Equal(nonce, suite.stateDB.GetNonce(addr))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBState() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
key := ethcmn.BytesToHash([]byte("foo"))
|
|
val := ethcmn.BytesToHash([]byte("bar"))
|
|
|
|
suite.stateDB.SetState(addr, key, val)
|
|
|
|
suite.Require().Equal(val, suite.stateDB.GetState(addr, key))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBCode() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
code := []byte("foobar")
|
|
|
|
suite.stateDB.SetCode(addr, code)
|
|
|
|
suite.Require().Equal(code, suite.stateDB.GetCode(addr))
|
|
|
|
codelen := len(code)
|
|
suite.Require().Equal(codelen, suite.stateDB.GetCodeSize(addr))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBLogs() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
|
|
hash := ethcmn.BytesToHash([]byte("hash"))
|
|
log := ethtypes.Log{
|
|
Address: addr,
|
|
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
|
|
Data: []byte("data"),
|
|
BlockNumber: 1,
|
|
TxHash: ethcmn.Hash{},
|
|
TxIndex: 1,
|
|
BlockHash: ethcmn.Hash{},
|
|
Index: 1,
|
|
Removed: false,
|
|
}
|
|
logs := []*ethtypes.Log{&log}
|
|
|
|
err = suite.stateDB.SetLogs(hash, logs)
|
|
suite.Require().NoError(err)
|
|
dbLogs, err := suite.stateDB.GetLogs(hash)
|
|
suite.Require().NoError(err)
|
|
suite.Require().Equal(logs, dbLogs)
|
|
|
|
suite.stateDB.DeleteLogs(hash)
|
|
dbLogs, err = suite.stateDB.GetLogs(hash)
|
|
suite.Require().NoError(err)
|
|
suite.Require().Empty(dbLogs)
|
|
|
|
suite.stateDB.AddLog(&log)
|
|
suite.Require().Equal(logs, suite.stateDB.AllLogs())
|
|
|
|
//resets state but checking to see if storekey still persists.
|
|
err = suite.stateDB.Reset(hash)
|
|
suite.Require().NoError(err)
|
|
suite.Require().Equal(logs, suite.stateDB.AllLogs())
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBPreimage() {
|
|
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() {
|
|
value := uint64(100)
|
|
|
|
suite.stateDB.AddRefund(value)
|
|
suite.Require().Equal(value, suite.stateDB.GetRefund())
|
|
|
|
suite.stateDB.SubRefund(value)
|
|
suite.Require().Equal(uint64(0), suite.stateDB.GetRefund())
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBCreateAcct() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
|
|
suite.stateDB.CreateAccount(addr)
|
|
suite.Require().True(suite.stateDB.Exist(addr))
|
|
|
|
value := big.NewInt(100)
|
|
suite.stateDB.AddBalance(addr, value)
|
|
|
|
suite.stateDB.CreateAccount(addr)
|
|
suite.Require().Equal(value, suite.stateDB.GetBalance(addr))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBClearStateOjb() {
|
|
priv, err := crypto.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) TestStateDBReset() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
|
|
hash := ethcmn.BytesToHash([]byte("hash"))
|
|
|
|
suite.stateDB.CreateAccount(addr)
|
|
suite.Require().True(suite.stateDB.Exist(addr))
|
|
|
|
err = suite.stateDB.Reset(hash)
|
|
suite.Require().NoError(err)
|
|
suite.Require().False(suite.stateDB.Exist(addr))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestStateDBUpdateAcct() {
|
|
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestSuiteDBPrepare() {
|
|
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) TestSuiteDBCopyState() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
|
|
hash := ethcmn.BytesToHash([]byte("hash"))
|
|
log := ethtypes.Log{
|
|
Address: addr,
|
|
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
|
|
Data: []byte("data"),
|
|
BlockNumber: 1,
|
|
TxHash: ethcmn.Hash{},
|
|
TxIndex: 1,
|
|
BlockHash: ethcmn.Hash{},
|
|
Index: 1,
|
|
Removed: false,
|
|
}
|
|
logs := []*ethtypes.Log{&log}
|
|
|
|
err = suite.stateDB.SetLogs(hash, logs)
|
|
suite.Require().NoError(err)
|
|
|
|
copyDB := suite.stateDB.Copy()
|
|
|
|
copiedDBLogs, err := copyDB.GetLogs(hash)
|
|
suite.Require().NoError(err)
|
|
suite.Require().Equal(logs, copiedDBLogs)
|
|
suite.Require().Equal(suite.stateDB.Exist(addr), copyDB.Exist(addr))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestSuiteDBEmpty() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
|
|
suite.Require().True(suite.stateDB.Empty(addr))
|
|
|
|
suite.stateDB.SetBalance(addr, big.NewInt(100))
|
|
|
|
suite.Require().False(suite.stateDB.Empty(addr))
|
|
}
|
|
|
|
func (suite *StateDBTestSuite) TestSuiteDBSuicide() {
|
|
priv, err := crypto.GenerateKey()
|
|
suite.Require().NoError(err)
|
|
|
|
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
|
|
|
|
suicide := suite.stateDB.Suicide(addr)
|
|
suite.Require().False(suicide)
|
|
suite.Require().False(suite.stateDB.HasSuicided(addr))
|
|
|
|
//Suicide only works for an account with non-zero balance/nonce
|
|
suite.stateDB.SetBalance(addr, big.NewInt(100))
|
|
suicide = suite.stateDB.Suicide(addr)
|
|
|
|
suite.Require().True(suicide)
|
|
suite.Require().True(suite.stateDB.HasSuicided(addr))
|
|
|
|
delete := true
|
|
_, err = suite.stateDB.Commit(delete)
|
|
suite.Require().NoError(err)
|
|
suite.Require().False(suite.stateDB.Exist(addr))
|
|
}
|
|
|
|
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,
|
|
},
|
|
{
|
|
"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)
|
|
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)
|
|
}
|
|
}
|