evm: refactor statedb implementation (#729)

* initial statedb module

unit tests

unit tests

keeper implementation

extract TxConfig

remove unused code

* keeper integration

* fix unit tests

* Apply suggestions from code review

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* fixup! initial statedb module

* changelog

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
yihuang
2022-01-05 08:28:27 +01:00
committed by GitHub
co-authored by Federico Kunze Küllmer
parent e9f1ab646c
commit ade84319e6
38 changed files with 2373 additions and 1710 deletions
+17 -16
View File
@@ -17,6 +17,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
"github.com/tharsis/ethermint/x/evm/statedb"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
@@ -139,23 +140,23 @@ func (suite *ImporterTestSuite) TestImportBlocks() {
})
ctx := suite.app.NewContext(false, tmheader)
ctx = ctx.WithBlockHeight(tmheader.Height)
suite.app.EvmKeeper.WithContext(ctx)
vmdb := statedb.New(ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 {
applyDAOHardFork(suite.app.EvmKeeper)
applyDAOHardFork(vmdb)
}
for _, tx := range block.Transactions() {
receipt, gas, err := applyTransaction(
chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, header, tx, usedGas, vmConfig,
ctx, chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, vmdb, header, tx, usedGas, vmConfig,
)
suite.Require().NoError(err, "failed to apply tx at block %d; tx: %X; gas %d; receipt:%v", block.NumberU64(), tx.Hash(), gas, receipt)
suite.Require().NotNil(receipt)
}
// apply mining rewards
accumulateRewards(chainConfig, suite.app.EvmKeeper, header, block.Uncles())
accumulateRewards(chainConfig, vmdb, header, block.Uncles())
// simulate BaseApp EndBlocker commitment
endBR := types.RequestEndBlock{Height: tmheader.Height}
@@ -173,7 +174,7 @@ func (suite *ImporterTestSuite) TestImportBlocks() {
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
func accumulateRewards(
config *ethparams.ChainConfig, evmKeeper *evmkeeper.Keeper,
config *ethparams.ChainConfig, vmdb ethvm.StateDB,
header *ethtypes.Header, uncles []*ethtypes.Header,
) {
// select the correct block reward based on chain progression
@@ -191,12 +192,12 @@ func accumulateRewards(
r.Sub(r, header.Number)
r.Mul(r, blockReward)
r.Div(r, rewardBig8)
evmKeeper.AddBalance(uncle.Coinbase, r)
vmdb.AddBalance(uncle.Coinbase, r)
r.Div(blockReward, rewardBig32)
reward.Add(reward, r)
}
evmKeeper.AddBalance(header.Coinbase, reward)
vmdb.AddBalance(header.Coinbase, reward)
}
// ApplyDAOHardFork modifies the state database according to the DAO hard-fork
@@ -205,15 +206,15 @@ func accumulateRewards(
// Code is pulled from go-ethereum 1.9 because the StateDB interface does not include the
// SetBalance function implementation
// Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/consensus/misc/dao.go#L74
func applyDAOHardFork(evmKeeper *evmkeeper.Keeper) {
func applyDAOHardFork(vmdb ethvm.StateDB) {
// Retrieve the contract to refund balances into
if !evmKeeper.Exist(ethparams.DAORefundContract) {
evmKeeper.CreateAccount(ethparams.DAORefundContract)
if !vmdb.Exist(ethparams.DAORefundContract) {
vmdb.CreateAccount(ethparams.DAORefundContract)
}
// Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range ethparams.DAODrainList() {
evmKeeper.AddBalance(ethparams.DAORefundContract, evmKeeper.GetBalance(addr))
vmdb.AddBalance(ethparams.DAORefundContract, vmdb.GetBalance(addr))
}
}
@@ -224,8 +225,8 @@ func applyDAOHardFork(evmKeeper *evmkeeper.Keeper) {
// Function is also pulled from go-ethereum 1.9 because of the incompatible usage
// Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88
func applyTransaction(
config *ethparams.ChainConfig, bc ethcore.ChainContext, author *common.Address,
gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, header *ethtypes.Header,
ctx sdk.Context, config *ethparams.ChainConfig, bc ethcore.ChainContext, author *common.Address,
gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, vmdb *statedb.StateDB, header *ethtypes.Header,
tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config,
) (*ethtypes.Receipt, uint64, error) {
msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number), sdk.ZeroInt().BigInt())
@@ -239,7 +240,7 @@ func applyTransaction(
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := ethvm.NewEVM(blockCtx, txCtx, evmKeeper, config, cfg)
vmenv := ethvm.NewEVM(blockCtx, txCtx, vmdb, config, cfg)
// Apply the transaction to the current state (included in the env)
execResult, err := ethcore.ApplyMessage(vmenv, msg, gp)
@@ -263,11 +264,11 @@ func applyTransaction(
}
// Set the receipt logs and create a bloom for filtering
receipt.Logs = evmKeeper.GetTxLogsTransient(tx.Hash())
receipt.Logs = vmdb.Logs()
receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt})
receipt.BlockHash = header.Hash()
receipt.BlockNumber = header.Number
receipt.TransactionIndex = uint(evmKeeper.GetTxIndexTransient())
receipt.TransactionIndex = uint(evmKeeper.GetTxIndexTransient(ctx))
return receipt, execResult.UsedGas, err
}