x/evm: stateDB and keeper tests (#396)

* draft state_transition

* working test

* keeper test

* statedb rewrite

* fix tests

* add keeper statedb test

* minor changes

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
This commit is contained in:
Justin Thompson 2020-07-23 12:30:31 -06:00 committed by GitHub
parent e0d3655eed
commit d69aad2016
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 763 additions and 156 deletions

View File

@ -0,0 +1,435 @@
package keeper_test
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/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/crypto"
ethermint "github.com/cosmos/ethermint/types"
)
func (suite *KeeperTestSuite) TestBloomFilter() {
// Prepare db for logs
tHash := ethcmn.BytesToHash([]byte{0x1})
suite.app.EvmKeeper.Prepare(suite.ctx, 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.app.EvmKeeper.AddLog(suite.ctx, &log)
},
1,
false,
},
{
"bloom",
func() {},
0,
true,
},
}
for _, tc := range testCase {
tc.malleate()
logs, err := suite.app.EvmKeeper.GetLogs(suite.ctx, 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.Bytes())
suite.Require().True(ethtypes.BloomLookup(bloomFilter, contractAddress), tc.name)
suite.Require().False(ethtypes.BloomLookup(bloomFilter, ethcmn.BigToAddress(big.NewInt(2))), tc.name)
}
}
}
func (suite *KeeperTestSuite) TestStateDBBalance() {
testCase := []struct {
name string
malleate func()
balance *big.Int
}{
{
"set balance",
func() {
suite.app.EvmKeeper.SetBalance(suite.ctx, suite.address, big.NewInt(100))
},
big.NewInt(100),
},
{
"sub balance",
func() {
suite.app.EvmKeeper.SubBalance(suite.ctx, suite.address, big.NewInt(100))
},
big.NewInt(0),
},
{
"add balance",
func() {
suite.app.EvmKeeper.AddBalance(suite.ctx, suite.address, big.NewInt(200))
},
big.NewInt(200),
},
{
"sub more than balance",
func() {
suite.app.EvmKeeper.SubBalance(suite.ctx, suite.address, big.NewInt(300))
},
big.NewInt(-100),
},
}
for _, tc := range testCase {
tc.malleate()
suite.Require().Equal(tc.balance, suite.app.EvmKeeper.GetBalance(suite.ctx, suite.address), tc.name)
}
}
func (suite *KeeperTestSuite) TestStateDBNonce() {
nonce := uint64(123)
suite.app.EvmKeeper.SetNonce(suite.ctx, suite.address, nonce)
suite.Require().Equal(nonce, suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address))
}
func (suite *KeeperTestSuite) TestStateDBState() {
key := ethcmn.BytesToHash([]byte("foo"))
val := ethcmn.BytesToHash([]byte("bar"))
suite.app.EvmKeeper.SetState(suite.ctx, suite.address, key, val)
suite.Require().Equal(val, suite.app.EvmKeeper.GetState(suite.ctx, suite.address, key))
}
func (suite *KeeperTestSuite) TestStateDBCode() {
code := []byte("foobar")
suite.app.EvmKeeper.SetCode(suite.ctx, suite.address, code)
suite.Require().Equal(code, suite.app.EvmKeeper.GetCode(suite.ctx, suite.address))
codelen := len(code)
suite.Require().Equal(codelen, suite.app.EvmKeeper.GetCodeSize(suite.ctx, suite.address))
}
func (suite *KeeperTestSuite) TestStateDBLogs() {
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: 1,
Removed: false,
},
},
}
for _, tc := range testCase {
hash := ethcmn.BytesToHash([]byte("hash"))
logs := []*ethtypes.Log{&tc.log}
err := suite.app.EvmKeeper.SetLogs(suite.ctx, hash, logs)
suite.Require().NoError(err, tc.name)
dbLogs, err := suite.app.EvmKeeper.GetLogs(suite.ctx, hash)
suite.Require().NoError(err, tc.name)
suite.Require().Equal(logs, dbLogs, tc.name)
suite.Require().Equal(logs, suite.app.EvmKeeper.AllLogs(suite.ctx), tc.name)
//resets state but checking to see if storekey still persists.
err = suite.app.EvmKeeper.Reset(suite.ctx, hash)
suite.Require().NoError(err, tc.name)
suite.Require().Equal(logs, suite.app.EvmKeeper.AllLogs(suite.ctx), tc.name)
}
}
func (suite *KeeperTestSuite) TestStateDBPreimage() {
hash := ethcmn.BytesToHash([]byte("hash"))
preimage := []byte("preimage")
suite.app.EvmKeeper.AddPreimage(suite.ctx, hash, preimage)
suite.Require().Equal(preimage, suite.app.EvmKeeper.Preimages(suite.ctx)[hash])
}
func (suite *KeeperTestSuite) TestStateDBRefund() {
testCase := []struct {
name string
amount uint64
}{
{
"refund",
100,
},
}
for _, tc := range testCase {
suite.app.EvmKeeper.AddRefund(suite.ctx, tc.amount)
suite.Require().Equal(tc.amount, suite.app.EvmKeeper.GetRefund(suite.ctx), tc.name)
suite.app.EvmKeeper.SubRefund(suite.ctx, tc.amount)
suite.Require().Equal(uint64(0), suite.app.EvmKeeper.GetRefund(suite.ctx), tc.name)
}
}
func (suite *KeeperTestSuite) TestStateDBCreateAcct() {
suite.app.EvmKeeper.CreateAccount(suite.ctx, suite.address)
suite.Require().True(suite.app.EvmKeeper.Exist(suite.ctx, suite.address))
value := big.NewInt(100)
suite.app.EvmKeeper.AddBalance(suite.ctx, suite.address, value)
suite.app.EvmKeeper.CreateAccount(suite.ctx, suite.address)
suite.Require().Equal(value, suite.app.EvmKeeper.GetBalance(suite.ctx, suite.address))
}
func (suite *KeeperTestSuite) TestStateDBClearStateOjb() {
suite.app.EvmKeeper.CreateAccount(suite.ctx, suite.address)
suite.Require().True(suite.app.EvmKeeper.Exist(suite.ctx, suite.address))
suite.app.EvmKeeper.ClearStateObjects(suite.ctx)
suite.Require().False(suite.app.EvmKeeper.Exist(suite.ctx, suite.address))
}
func (suite *KeeperTestSuite) TestStateDBReset() {
hash := ethcmn.BytesToHash([]byte("hash"))
suite.app.EvmKeeper.CreateAccount(suite.ctx, suite.address)
suite.Require().True(suite.app.EvmKeeper.Exist(suite.ctx, suite.address))
err := suite.app.EvmKeeper.Reset(suite.ctx, hash)
suite.Require().NoError(err)
suite.Require().False(suite.app.EvmKeeper.Exist(suite.ctx, suite.address))
}
func (suite *KeeperTestSuite) TestStateDBUpdateAcct() {
}
func (suite *KeeperTestSuite) TestSuiteDBPrepare() {
thash := ethcmn.BytesToHash([]byte("thash"))
bhash := ethcmn.BytesToHash([]byte("bhash"))
txi := 1
suite.app.EvmKeeper.Prepare(suite.ctx, thash, bhash, txi)
suite.Require().Equal(txi, suite.app.EvmKeeper.TxIndex(suite.ctx))
suite.Require().Equal(bhash, suite.app.EvmKeeper.BlockHash(suite.ctx))
}
func (suite *KeeperTestSuite) TestSuiteDBCopyState() {
copyDB := suite.app.EvmKeeper.Copy(suite.ctx)
suite.Require().Equal(suite.app.EvmKeeper.Exist(suite.ctx, suite.address), copyDB.Exist(suite.address))
}
func (suite *KeeperTestSuite) TestSuiteDBEmpty() {
suite.Require().True(suite.app.EvmKeeper.Empty(suite.ctx, suite.address))
suite.app.EvmKeeper.SetBalance(suite.ctx, suite.address, big.NewInt(100))
suite.Require().False(suite.app.EvmKeeper.Empty(suite.ctx, suite.address))
}
func (suite *KeeperTestSuite) TestSuiteDBSuicide() {
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.app.EvmKeeper.Commit(suite.ctx, tc.delete)
suite.Require().NoError(err, tc.name)
suite.Require().False(suite.app.EvmKeeper.Exist(suite.ctx, suite.address), tc.name)
continue
}
if tc.expPass {
suite.app.EvmKeeper.SetBalance(suite.ctx, suite.address, tc.amount)
suicide := suite.app.EvmKeeper.Suicide(suite.ctx, suite.address)
suite.Require().True(suicide, tc.name)
suite.Require().True(suite.app.EvmKeeper.HasSuicided(suite.ctx, suite.address), tc.name)
} else {
//Suicide only works for an account with non-zero balance/nonce
priv, err := crypto.GenerateKey()
suite.Require().NoError(err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
suicide := suite.app.EvmKeeper.Suicide(suite.ctx, addr)
suite.Require().False(suicide, tc.name)
suite.Require().False(suite.app.EvmKeeper.HasSuicided(suite.ctx, addr), tc.name)
}
}
}
func (suite *KeeperTestSuite) TestCommitStateDB_Commit() {
suite.app.EvmKeeper.AddBalance(suite.ctx, suite.address, big.NewInt(100))
testCase := []struct {
name string
malleate func()
deleteObjs bool
expPass bool
}{
{
"commit suicided",
func() {
ok := suite.app.EvmKeeper.Suicide(suite.ctx, suite.address)
suite.Require().True(ok)
},
true, true,
},
{
"commit with dirty value",
func() {
suite.app.EvmKeeper.SetCode(suite.ctx, suite.address, []byte("code"))
},
false, true,
},
{
"faled to update state object",
func() {
suite.app.EvmKeeper.SubBalance(suite.ctx, suite.address, big.NewInt(10))
},
false, false,
},
}
for _, tc := range testCase {
tc.malleate()
hash, err := suite.app.EvmKeeper.Commit(suite.ctx, 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 *KeeperTestSuite) TestCommitStateDB_Finalize() {
suite.app.EvmKeeper.AddBalance(suite.ctx, suite.address, big.NewInt(100))
testCase := []struct {
name string
malleate func()
deleteObjs bool
expPass bool
}{
{
"finalize suicided",
func() {
ok := suite.app.EvmKeeper.Suicide(suite.ctx, suite.address)
suite.Require().True(ok)
},
true, true,
},
{
"finalize, not suicided",
func() {
suite.app.EvmKeeper.AddBalance(suite.ctx, suite.address, big.NewInt(5))
},
false, true,
},
{
"finalize, dirty storage",
func() {
suite.app.EvmKeeper.SetState(suite.ctx, suite.address, ethcmn.BytesToHash([]byte("key")), ethcmn.BytesToHash([]byte("value")))
},
false, true,
},
{
"faled to update state object",
func() {
suite.app.EvmKeeper.SubBalance(suite.ctx, suite.address, big.NewInt(10))
},
false, false,
},
}
for _, tc := range testCase {
tc.malleate()
err := suite.app.EvmKeeper.Finalise(suite.ctx, 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)
}
}

View File

@ -292,7 +292,6 @@ func (csdb *CommitStateDB) GetCodeSize(addr ethcmn.Address) int {
return len(so.code) return len(so.code)
} }
// TODO: we may need to cache these lookups directly
return len(so.Code(nil)) return len(so.Code(nil))
} }

View File

@ -57,97 +57,190 @@ func (suite *StateDBTestSuite) SetupTest() {
suite.app.AccountKeeper.SetAccount(suite.ctx, acc) suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address) suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address)
} }
func (suite *StateDBTestSuite) TestBloomFilter() { func (suite *StateDBTestSuite) TestBloomFilter() {
// Prepare db for logs // Prepare db for logs
tHash := ethcmn.BytesToHash([]byte{0x1}) tHash := ethcmn.BytesToHash([]byte{0x1})
suite.stateDB.Prepare(tHash, ethcmn.Hash{}, 0) suite.stateDB.Prepare(tHash, ethcmn.Hash{}, 0)
contractAddress := ethcmn.BigToAddress(big.NewInt(1)) contractAddress := ethcmn.BigToAddress(big.NewInt(1))
// Generate and add a log to test
log := ethtypes.Log{Address: contractAddress} 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) suite.stateDB.AddLog(&log)
},
1,
false,
},
{
"bloom",
func() {},
0,
true,
},
}
// Get log from db for _, tc := range testCase {
tc.malleate()
logs, err := suite.stateDB.GetLogs(tHash) logs, err := suite.stateDB.GetLogs(tHash)
suite.Require().NoError(err) if !tc.isBloom {
suite.Require().Len(logs, 1) suite.Require().NoError(err, tc.name)
suite.Require().Equal(log, *logs[0]) 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 // get logs bloom from the log
bloomInt := ethtypes.LogsBloom(logs) bloomInt := ethtypes.LogsBloom(logs)
bloomFilter := ethtypes.BytesToBloom(bloomInt.Bytes()) bloomFilter := ethtypes.BytesToBloom(bloomInt.Bytes())
suite.Require().True(ethtypes.BloomLookup(bloomFilter, contractAddress), tc.name)
// Check to make sure bloom filter will succeed on suite.Require().False(ethtypes.BloomLookup(bloomFilter, ethcmn.BigToAddress(big.NewInt(2))), tc.name)
suite.Require().True(ethtypes.BloomLookup(bloomFilter, contractAddress)) }
suite.Require().False(ethtypes.BloomLookup(bloomFilter, ethcmn.BigToAddress(big.NewInt(2)))) }
} }
func (suite *StateDBTestSuite) TestStateDBBalance() { func (suite *StateDBTestSuite) TestStateDBBalance() {
priv, err := crypto.GenerateKey() testCase := []struct {
suite.Require().NoError(err) 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),
},
}
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) for _, tc := range testCase {
value := big.NewInt(100) tc.malleate()
suite.stateDB.SetBalance(addr, value) suite.Require().Equal(tc.balance, suite.stateDB.GetBalance(suite.address), tc.name)
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() { func (suite *StateDBTestSuite) TestStateDBNonce() {
priv, err := crypto.GenerateKey()
suite.Require().NoError(err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
nonce := uint64(123) nonce := uint64(123)
suite.stateDB.SetNonce(addr, nonce) suite.stateDB.SetNonce(suite.address, nonce)
suite.Require().Equal(nonce, suite.stateDB.GetNonce(suite.address))
suite.Require().Equal(nonce, suite.stateDB.GetNonce(addr))
} }
func (suite *StateDBTestSuite) TestStateDBState() { func (suite *StateDBTestSuite) TestStateDBState() {
priv, err := crypto.GenerateKey()
suite.Require().NoError(err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
key := ethcmn.BytesToHash([]byte("foo")) key := ethcmn.BytesToHash([]byte("foo"))
val := ethcmn.BytesToHash([]byte("bar")) val := ethcmn.BytesToHash([]byte("bar"))
suite.stateDB.SetState(suite.address, key, val)
suite.stateDB.SetState(addr, key, val) testCase := []struct {
name string
suite.Require().Equal(val, suite.stateDB.GetState(addr, key)) 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) TestStateDBCode() { func (suite *StateDBTestSuite) TestStateDBCode() {
priv, err := crypto.GenerateKey() testCase := []struct {
suite.Require().NoError(err) 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() {},
},
}
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) for _, tc := range testCase {
code := []byte("foobar") tc.malleate()
suite.stateDB.SetCode(addr, code) 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)
suite.Require().Equal(code, suite.stateDB.GetCode(addr)) }
codelen := len(code)
suite.Require().Equal(codelen, suite.stateDB.GetCodeSize(addr))
} }
func (suite *StateDBTestSuite) TestStateDBLogs() { func (suite *StateDBTestSuite) TestStateDBLogs() {
priv, err := crypto.GenerateKey() testCase := []struct {
suite.Require().NoError(err) name string
log ethtypes.Log
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) }{
{
hash := ethcmn.BytesToHash([]byte("hash")) "state db log",
log := ethtypes.Log{ ethtypes.Log{
Address: addr, Address: suite.address,
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))}, Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
Data: []byte("data"), Data: []byte("data"),
BlockNumber: 1, BlockNumber: 1,
@ -156,27 +249,33 @@ func (suite *StateDBTestSuite) TestStateDBLogs() {
BlockHash: ethcmn.Hash{}, BlockHash: ethcmn.Hash{},
Index: 1, Index: 1,
Removed: false, Removed: false,
},
},
} }
logs := []*ethtypes.Log{&log}
err = suite.stateDB.SetLogs(hash, logs) for _, tc := range testCase {
suite.Require().NoError(err) 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) dbLogs, err := suite.stateDB.GetLogs(hash)
suite.Require().NoError(err) suite.Require().NoError(err, tc.name)
suite.Require().Equal(logs, dbLogs) suite.Require().Equal(logs, dbLogs, tc.name)
suite.stateDB.DeleteLogs(hash) suite.stateDB.DeleteLogs(hash)
dbLogs, err = suite.stateDB.GetLogs(hash) dbLogs, err = suite.stateDB.GetLogs(hash)
suite.Require().NoError(err) suite.Require().NoError(err, tc.name)
suite.Require().Empty(dbLogs) suite.Require().Empty(dbLogs, tc.name)
suite.stateDB.AddLog(&log) suite.stateDB.AddLog(&tc.log)
suite.Require().Equal(logs, suite.stateDB.AllLogs()) suite.Require().Equal(logs, suite.stateDB.AllLogs(), tc.name)
//resets state but checking to see if storekey still persists. //resets state but checking to see if storekey still persists.
err = suite.stateDB.Reset(hash) err = suite.stateDB.Reset(hash)
suite.Require().NoError(err) suite.Require().NoError(err, tc.name)
suite.Require().Equal(logs, suite.stateDB.AllLogs()) suite.Require().Equal(logs, suite.stateDB.AllLogs(), tc.name)
}
} }
func (suite *StateDBTestSuite) TestStateDBPreimage() { func (suite *StateDBTestSuite) TestStateDBPreimage() {
@ -189,29 +288,80 @@ func (suite *StateDBTestSuite) TestStateDBPreimage() {
} }
func (suite *StateDBTestSuite) TestStateDBRefund() { func (suite *StateDBTestSuite) TestStateDBRefund() {
value := uint64(100) 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,
},
}
suite.stateDB.AddRefund(value) for _, tc := range testCase {
suite.Require().Equal(value, suite.stateDB.GetRefund()) suite.Run(tc.name, func() {
suite.SetupTest() // reset
suite.stateDB.SubRefund(value) suite.stateDB.AddRefund(tc.addAmount)
suite.Require().Equal(uint64(0), suite.stateDB.GetRefund()) 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) TestStateDBCreateAcct() { func (suite *StateDBTestSuite) TestStateDBCreateAcct() {
priv, err := crypto.GenerateKey() prevBalance := big.NewInt(12)
suite.Require().NoError(err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) 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)
},
},
}
suite.stateDB.CreateAccount(addr) for _, tc := range testCase {
suite.Require().True(suite.stateDB.Exist(addr)) tc.malleate()
value := big.NewInt(100) suite.stateDB.CreateAccount(tc.address)
suite.stateDB.AddBalance(addr, value) suite.Require().True(suite.stateDB.Exist(tc.address), tc.name)
suite.Require().Equal(prevBalance, suite.stateDB.GetBalance(tc.address), tc.name)
suite.stateDB.CreateAccount(addr) }
suite.Require().Equal(value, suite.stateDB.GetBalance(addr))
} }
func (suite *StateDBTestSuite) TestStateDBClearStateOjb() { func (suite *StateDBTestSuite) TestStateDBClearStateOjb() {
@ -233,20 +383,14 @@ func (suite *StateDBTestSuite) TestStateDBReset() {
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
hash := ethcmn.BytesToHash([]byte("hash"))
suite.stateDB.CreateAccount(addr) suite.stateDB.CreateAccount(addr)
suite.Require().True(suite.stateDB.Exist(addr)) suite.Require().True(suite.stateDB.Exist(addr))
err = suite.stateDB.Reset(hash) err = suite.stateDB.Reset(ethcmn.BytesToHash(nil))
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().False(suite.stateDB.Exist(addr)) suite.Require().False(suite.stateDB.Exist(addr))
} }
func (suite *StateDBTestSuite) TestStateDBUpdateAcct() {
}
func (suite *StateDBTestSuite) TestSuiteDBPrepare() { func (suite *StateDBTestSuite) TestSuiteDBPrepare() {
thash := ethcmn.BytesToHash([]byte("thash")) thash := ethcmn.BytesToHash([]byte("thash"))
bhash := ethcmn.BytesToHash([]byte("bhash")) bhash := ethcmn.BytesToHash([]byte("bhash"))
@ -259,14 +403,14 @@ func (suite *StateDBTestSuite) TestSuiteDBPrepare() {
} }
func (suite *StateDBTestSuite) TestSuiteDBCopyState() { func (suite *StateDBTestSuite) TestSuiteDBCopyState() {
priv, err := crypto.GenerateKey() testCase := []struct {
suite.Require().NoError(err) name string
log ethtypes.Log
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) }{
{
hash := ethcmn.BytesToHash([]byte("hash")) "copy state",
log := ethtypes.Log{ ethtypes.Log{
Address: addr, Address: suite.address,
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))}, Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
Data: []byte("data"), Data: []byte("data"),
BlockNumber: 1, BlockNumber: 1,
@ -275,54 +419,83 @@ func (suite *StateDBTestSuite) TestSuiteDBCopyState() {
BlockHash: ethcmn.Hash{}, BlockHash: ethcmn.Hash{},
Index: 1, Index: 1,
Removed: false, Removed: false,
},
},
} }
logs := []*ethtypes.Log{&log}
err = suite.stateDB.SetLogs(hash, logs) for _, tc := range testCase {
suite.Require().NoError(err) 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() copyDB := suite.stateDB.Copy()
copiedDBLogs, err := copyDB.GetLogs(hash) copiedDBLogs, err := copyDB.GetLogs(hash)
suite.Require().NoError(err) suite.Require().NoError(err, tc.name)
suite.Require().Equal(logs, copiedDBLogs) suite.Require().Equal(logs, copiedDBLogs, tc.name)
suite.Require().Equal(suite.stateDB.Exist(addr), copyDB.Exist(addr)) suite.Require().Equal(suite.stateDB.Exist(suite.address), copyDB.Exist(suite.address), tc.name)
}
} }
func (suite *StateDBTestSuite) TestSuiteDBEmpty() { func (suite *StateDBTestSuite) TestSuiteDBEmpty() {
priv, err := crypto.GenerateKey() suite.Require().True(suite.stateDB.Empty(suite.address))
suite.Require().NoError(err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) suite.stateDB.SetBalance(suite.address, big.NewInt(100))
suite.Require().True(suite.stateDB.Empty(addr)) suite.Require().False(suite.stateDB.Empty(suite.address))
suite.stateDB.SetBalance(addr, big.NewInt(100))
suite.Require().False(suite.stateDB.Empty(addr))
} }
func (suite *StateDBTestSuite) TestSuiteDBSuicide() { func (suite *StateDBTestSuite) TestSuiteDBSuicide() {
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 := crypto.GenerateKey() priv, err := crypto.GenerateKey()
suite.Require().NoError(err) suite.Require().NoError(err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey) addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
suicide := suite.stateDB.Suicide(addr) suicide := suite.stateDB.Suicide(addr)
suite.Require().False(suicide) suite.Require().False(suicide, tc.name)
suite.Require().False(suite.stateDB.HasSuicided(addr)) suite.Require().False(suite.stateDB.HasSuicided(addr), tc.name)
}
//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() { func (suite *StateDBTestSuite) TestCommitStateDB_Commit() {