evm: benchmark state DB (#514)
* evm: benchmark state DB * add more bech funcs * rm func from interface
This commit is contained in:
parent
9a8827e790
commit
87c4ea2dc2
@ -26,7 +26,6 @@ type EVMKeeper interface {
|
||||
GetParams(ctx sdk.Context) evmtypes.Params
|
||||
WithContext(ctx sdk.Context)
|
||||
ResetRefundTransient(ctx sdk.Context)
|
||||
GetCoinbaseAddress() (common.Address, error)
|
||||
NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer vm.Tracer) *vm.EVM
|
||||
GetCodeHash(addr common.Address) common.Hash
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms
|
||||
params := k.GetParams(ctx)
|
||||
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
|
||||
|
||||
coinbase, err := k.GetCoinbaseAddress()
|
||||
coinbase, err := k.GetCoinbaseAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
@ -394,7 +394,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type
|
||||
params := k.GetParams(ctx)
|
||||
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
|
||||
|
||||
coinbase, err := k.GetCoinbaseAddress()
|
||||
coinbase, err := k.GetCoinbaseAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
@ -69,39 +69,40 @@ func (k Keeper) VMConfig(msg core.Message, params types.Params, tracer vm.Tracer
|
||||
func (k Keeper) GetHashFn() vm.GetHashFunc {
|
||||
return func(height uint64) common.Hash {
|
||||
h := int64(height)
|
||||
ctx := k.Ctx()
|
||||
switch {
|
||||
case k.Ctx().BlockHeight() == h:
|
||||
case ctx.BlockHeight() == h:
|
||||
// Case 1: The requested height matches the one from the context so we can retrieve the header
|
||||
// hash directly from the context.
|
||||
// Note: The headerHash is only set at begin block, it will be nil in case of a query context
|
||||
headerHash := k.Ctx().HeaderHash()
|
||||
headerHash := ctx.HeaderHash()
|
||||
if len(headerHash) != 0 {
|
||||
return common.BytesToHash(headerHash)
|
||||
}
|
||||
|
||||
// only recompute the hash if not set (eg: checkTxState)
|
||||
contextBlockHeader := k.Ctx().BlockHeader()
|
||||
contextBlockHeader := ctx.BlockHeader()
|
||||
header, err := tmtypes.HeaderFromProto(&contextBlockHeader)
|
||||
if err != nil {
|
||||
k.Logger(k.Ctx()).Error("failed to cast tendermint header from proto", "error", err)
|
||||
k.Logger(ctx).Error("failed to cast tendermint header from proto", "error", err)
|
||||
return common.Hash{}
|
||||
}
|
||||
|
||||
headerHash = header.Hash()
|
||||
return common.BytesToHash(headerHash)
|
||||
|
||||
case k.Ctx().BlockHeight() > h:
|
||||
case ctx.BlockHeight() > h:
|
||||
// Case 2: if the chain is not the current height we need to retrieve the hash from the store for the
|
||||
// current chain epoch. This only applies if the current height is greater than the requested height.
|
||||
histInfo, found := k.stakingKeeper.GetHistoricalInfo(k.Ctx(), h)
|
||||
histInfo, found := k.stakingKeeper.GetHistoricalInfo(ctx, h)
|
||||
if !found {
|
||||
k.Logger(k.Ctx()).Debug("historical info not found", "height", h)
|
||||
k.Logger(ctx).Debug("historical info not found", "height", h)
|
||||
return common.Hash{}
|
||||
}
|
||||
|
||||
header, err := tmtypes.HeaderFromProto(&histInfo.Header)
|
||||
if err != nil {
|
||||
k.Logger(k.Ctx()).Error("failed to cast tendermint header from proto", "error", err)
|
||||
k.Logger(ctx).Error("failed to cast tendermint header from proto", "error", err)
|
||||
return common.Hash{}
|
||||
}
|
||||
|
||||
@ -133,7 +134,8 @@ func (k Keeper) GetHashFn() vm.GetHashFunc {
|
||||
func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumTxResponse, error) {
|
||||
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), types.MetricKeyTransitionDB)
|
||||
|
||||
params := k.GetParams(k.Ctx())
|
||||
ctx := k.Ctx()
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
// return error if contract creation or call are disabled through governance
|
||||
if !params.EnableCreate && tx.To() == nil {
|
||||
@ -145,7 +147,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
|
||||
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
|
||||
|
||||
// get the latest signer according to the chain rules from the config
|
||||
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(k.Ctx().BlockHeight()))
|
||||
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
|
||||
|
||||
msg, err := tx.AsMessage(signer)
|
||||
if err != nil {
|
||||
@ -153,13 +155,13 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
|
||||
}
|
||||
|
||||
// get the coinbase address from the block proposer
|
||||
coinbase, err := k.GetCoinbaseAddress()
|
||||
coinbase, err := k.GetCoinbaseAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, stacktrace.Propagate(err, "failed to obtain coinbase address")
|
||||
}
|
||||
|
||||
// create an ethereum EVM instance and run the message
|
||||
tracer := types.NewTracer(k.tracer, msg, ethCfg, k.Ctx().BlockHeight(), k.debug)
|
||||
tracer := types.NewTracer(k.tracer, msg, ethCfg, ctx.BlockHeight(), k.debug)
|
||||
evm := k.NewEVM(msg, ethCfg, params, coinbase, tracer)
|
||||
|
||||
txHash := tx.Hash()
|
||||
@ -368,14 +370,15 @@ func (k *Keeper) RefundGas(msg core.Message, leftoverGas, refundQuotient uint64)
|
||||
// 'gasUsed'
|
||||
func (k *Keeper) resetGasMeterAndConsumeGas(gasUsed uint64) {
|
||||
// reset the gas count
|
||||
k.Ctx().GasMeter().RefundGas(k.Ctx().GasMeter().GasConsumed(), "reset the gas count")
|
||||
k.Ctx().GasMeter().ConsumeGas(gasUsed, "apply evm transaction")
|
||||
ctx := k.Ctx()
|
||||
ctx.GasMeter().RefundGas(ctx.GasMeter().GasConsumed(), "reset the gas count")
|
||||
ctx.GasMeter().ConsumeGas(gasUsed, "apply evm transaction")
|
||||
}
|
||||
|
||||
// GetCoinbaseAddress returns the block proposer's validator operator address.
|
||||
func (k Keeper) GetCoinbaseAddress() (common.Address, error) {
|
||||
consAddr := sdk.ConsAddress(k.Ctx().BlockHeader().ProposerAddress)
|
||||
validator, found := k.stakingKeeper.GetValidatorByConsAddr(k.Ctx(), consAddr)
|
||||
func (k Keeper) GetCoinbaseAddress(ctx sdk.Context) (common.Address, error) {
|
||||
consAddr := sdk.ConsAddress(ctx.BlockHeader().ProposerAddress)
|
||||
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr)
|
||||
if !found {
|
||||
return common.Address{}, stacktrace.Propagate(
|
||||
sdkerrors.Wrap(stakingtypes.ErrNoValidatorFound, consAddr.String()),
|
||||
|
@ -65,7 +65,7 @@ func (suite *KeeperTestSuite) TestGetCoinbaseAddress() {
|
||||
|
||||
tc.malleate()
|
||||
|
||||
coinbase, err := suite.app.EvmKeeper.GetCoinbaseAddress()
|
||||
coinbase, err := suite.app.EvmKeeper.GetCoinbaseAddress(suite.ctx)
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(valOpAddr, coinbase)
|
||||
|
@ -29,8 +29,8 @@ var _ vm.StateDB = &Keeper{}
|
||||
// address.
|
||||
func (k *Keeper) CreateAccount(addr common.Address) {
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
|
||||
account := k.accountKeeper.GetAccount(k.Ctx(), cosmosAddr)
|
||||
ctx := k.Ctx()
|
||||
account := k.accountKeeper.GetAccount(ctx, cosmosAddr)
|
||||
log := ""
|
||||
if account == nil {
|
||||
log = "account created"
|
||||
@ -39,10 +39,10 @@ func (k *Keeper) CreateAccount(addr common.Address) {
|
||||
k.ResetAccount(addr)
|
||||
}
|
||||
|
||||
account = k.accountKeeper.NewAccountWithAddress(k.Ctx(), cosmosAddr)
|
||||
k.accountKeeper.SetAccount(k.Ctx(), account)
|
||||
account = k.accountKeeper.NewAccountWithAddress(ctx, cosmosAddr)
|
||||
k.accountKeeper.SetAccount(ctx, account)
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
log,
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -57,8 +57,10 @@ func (k *Keeper) CreateAccount(addr common.Address) {
|
||||
// coins and transferring them to the address. The coin denomination is obtained
|
||||
// from the module parameters.
|
||||
func (k *Keeper) AddBalance(addr common.Address, amount *big.Int) {
|
||||
ctx := k.Ctx()
|
||||
|
||||
if amount.Sign() != 1 {
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"ignored non-positive amount addition",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"amount", amount.Int64(),
|
||||
@ -67,12 +69,18 @@ func (k *Keeper) AddBalance(addr common.Address, amount *big.Int) {
|
||||
}
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
params := k.GetParams(k.Ctx())
|
||||
coins := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(amount))}
|
||||
// Coin denom and amount already validated
|
||||
coins := sdk.Coins{
|
||||
{
|
||||
Denom: params.EvmDenom,
|
||||
Amount: sdk.NewIntFromBigInt(amount),
|
||||
},
|
||||
}
|
||||
|
||||
if err := k.bankKeeper.MintCoins(k.Ctx(), types.ModuleName, coins); err != nil {
|
||||
k.Logger(k.Ctx()).Error(
|
||||
if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil {
|
||||
k.Logger(ctx).Error(
|
||||
"failed to mint coins when adding balance",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -81,8 +89,8 @@ func (k *Keeper) AddBalance(addr common.Address, amount *big.Int) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := k.bankKeeper.SendCoinsFromModuleToAccount(k.Ctx(), types.ModuleName, cosmosAddr, coins); err != nil {
|
||||
k.Logger(k.Ctx()).Error(
|
||||
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, cosmosAddr, coins); err != nil {
|
||||
k.Logger(ctx).Error(
|
||||
"failed to send from module to account when adding balance",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -91,7 +99,7 @@ func (k *Keeper) AddBalance(addr common.Address, amount *big.Int) {
|
||||
return
|
||||
}
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"balance addition",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -103,8 +111,10 @@ func (k *Keeper) AddBalance(addr common.Address, amount *big.Int) {
|
||||
// from the module parameters. This function performs a no-op if the amount is negative
|
||||
// or the user doesn't have enough funds for the transfer.
|
||||
func (k *Keeper) SubBalance(addr common.Address, amount *big.Int) {
|
||||
ctx := k.Ctx()
|
||||
|
||||
if amount.Sign() != 1 {
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"ignored non-positive amount addition",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"amount", amount.Int64(),
|
||||
@ -114,11 +124,18 @@ func (k *Keeper) SubBalance(addr common.Address, amount *big.Int) {
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
|
||||
params := k.GetParams(k.Ctx())
|
||||
coins := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(amount))}
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
if err := k.bankKeeper.SendCoinsFromAccountToModule(k.Ctx(), cosmosAddr, types.ModuleName, coins); err != nil {
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
// Coin denom and amount already validated
|
||||
coins := sdk.Coins{
|
||||
{
|
||||
Denom: params.EvmDenom,
|
||||
Amount: sdk.NewIntFromBigInt(amount),
|
||||
},
|
||||
}
|
||||
|
||||
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, cosmosAddr, types.ModuleName, coins); err != nil {
|
||||
k.Logger(ctx).Debug(
|
||||
"failed to send from account to module when subtracting balance",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -128,8 +145,8 @@ func (k *Keeper) SubBalance(addr common.Address, amount *big.Int) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := k.bankKeeper.BurnCoins(k.Ctx(), types.ModuleName, coins); err != nil {
|
||||
k.Logger(k.Ctx()).Error(
|
||||
if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins); err != nil {
|
||||
k.Logger(ctx).Error(
|
||||
"failed to burn coins when subtracting balance",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -138,7 +155,7 @@ func (k *Keeper) SubBalance(addr common.Address, amount *big.Int) {
|
||||
return
|
||||
}
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"balance subtraction",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -148,9 +165,11 @@ func (k *Keeper) SubBalance(addr common.Address, amount *big.Int) {
|
||||
// GetBalance returns the EVM denomination balance of the provided address. The
|
||||
// denomination is obtained from the module parameters.
|
||||
func (k *Keeper) GetBalance(addr common.Address) *big.Int {
|
||||
ctx := k.Ctx()
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
params := k.GetParams(k.Ctx())
|
||||
balance := k.bankKeeper.GetBalance(k.Ctx(), cosmosAddr, params.EvmDenom)
|
||||
params := k.GetParams(ctx)
|
||||
balance := k.bankKeeper.GetBalance(ctx, cosmosAddr, params.EvmDenom)
|
||||
|
||||
return balance.Amount.BigInt()
|
||||
}
|
||||
@ -162,10 +181,12 @@ func (k *Keeper) GetBalance(addr common.Address) *big.Int {
|
||||
// GetNonce retrieves the account with the given address and returns the tx
|
||||
// sequence (i.e nonce). The function performs a no-op if the account is not found.
|
||||
func (k *Keeper) GetNonce(addr common.Address) uint64 {
|
||||
ctx := k.Ctx()
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
nonce, err := k.accountKeeper.GetSequence(k.Ctx(), cosmosAddr)
|
||||
nonce, err := k.accountKeeper.GetSequence(ctx, cosmosAddr)
|
||||
if err != nil {
|
||||
k.Logger(k.Ctx()).Error(
|
||||
k.Logger(ctx).Error(
|
||||
"account not found",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -179,21 +200,23 @@ func (k *Keeper) GetNonce(addr common.Address) uint64 {
|
||||
// SetNonce sets the given nonce as the sequence of the address' account. If the
|
||||
// account doesn't exist, a new one will be created from the address.
|
||||
func (k *Keeper) SetNonce(addr common.Address, nonce uint64) {
|
||||
ctx := k.Ctx()
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
account := k.accountKeeper.GetAccount(k.Ctx(), cosmosAddr)
|
||||
account := k.accountKeeper.GetAccount(ctx, cosmosAddr)
|
||||
if account == nil {
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"account not found",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
)
|
||||
|
||||
// create address if it doesn't exist
|
||||
account = k.accountKeeper.NewAccountWithAddress(k.Ctx(), cosmosAddr)
|
||||
account = k.accountKeeper.NewAccountWithAddress(ctx, cosmosAddr)
|
||||
}
|
||||
|
||||
if err := account.SetSequence(nonce); err != nil {
|
||||
k.Logger(k.Ctx()).Error(
|
||||
k.Logger(ctx).Error(
|
||||
"failed to set nonce",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -204,9 +227,9 @@ func (k *Keeper) SetNonce(addr common.Address, nonce uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
k.accountKeeper.SetAccount(k.Ctx(), account)
|
||||
k.accountKeeper.SetAccount(ctx, account)
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"nonce set",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -221,8 +244,10 @@ func (k *Keeper) SetNonce(addr common.Address, nonce uint64) {
|
||||
// GetCodeHash fetches the account from the store and returns its code hash. If the account doesn't
|
||||
// exist or is not an EthAccount type, GetCodeHash returns the empty code hash value.
|
||||
func (k *Keeper) GetCodeHash(addr common.Address) common.Hash {
|
||||
ctx := k.Ctx()
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
account := k.accountKeeper.GetAccount(k.Ctx(), cosmosAddr)
|
||||
|
||||
account := k.accountKeeper.GetAccount(ctx, cosmosAddr)
|
||||
if account == nil {
|
||||
return common.BytesToHash(types.EmptyCodeHash)
|
||||
}
|
||||
@ -238,17 +263,18 @@ func (k *Keeper) GetCodeHash(addr common.Address) common.Hash {
|
||||
// GetCode returns the code byte array associated with the given address.
|
||||
// If the code hash from the account is empty, this function returns nil.
|
||||
func (k *Keeper) GetCode(addr common.Address) []byte {
|
||||
ctx := k.Ctx()
|
||||
hash := k.GetCodeHash(addr)
|
||||
|
||||
if bytes.Equal(hash.Bytes(), common.BytesToHash(types.EmptyCodeHash).Bytes()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
store := prefix.NewStore(k.Ctx().KVStore(k.storeKey), types.KeyPrefixCode)
|
||||
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixCode)
|
||||
code := store.Get(hash.Bytes())
|
||||
|
||||
if len(code) == 0 {
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"code not found",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"code-hash", hash.Hex(),
|
||||
@ -261,21 +287,23 @@ func (k *Keeper) GetCode(addr common.Address) []byte {
|
||||
// SetCode stores the code byte array to the application KVStore and sets the
|
||||
// code hash to the given account. The code is deleted from the store if it is empty.
|
||||
func (k *Keeper) SetCode(addr common.Address, code []byte) {
|
||||
ctx := k.Ctx()
|
||||
|
||||
if bytes.Equal(code, types.EmptyCodeHash) {
|
||||
k.Logger(k.Ctx()).Debug("passed in EmptyCodeHash, but expected empty code")
|
||||
k.Logger(ctx).Debug("passed in EmptyCodeHash, but expected empty code")
|
||||
}
|
||||
hash := crypto.Keccak256Hash(code)
|
||||
|
||||
// update account code hash
|
||||
account := k.accountKeeper.GetAccount(k.Ctx(), addr.Bytes())
|
||||
account := k.accountKeeper.GetAccount(ctx, addr.Bytes())
|
||||
if account == nil {
|
||||
account = k.accountKeeper.NewAccountWithAddress(k.Ctx(), addr.Bytes())
|
||||
k.accountKeeper.SetAccount(k.Ctx(), account)
|
||||
account = k.accountKeeper.NewAccountWithAddress(ctx, addr.Bytes())
|
||||
k.accountKeeper.SetAccount(ctx, account)
|
||||
}
|
||||
|
||||
ethAccount, isEthAccount := account.(*ethermint.EthAccount)
|
||||
if !isEthAccount {
|
||||
k.Logger(k.Ctx()).Error(
|
||||
k.Logger(ctx).Error(
|
||||
"invalid account type",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"code-hash", hash.Hex(),
|
||||
@ -284,9 +312,9 @@ func (k *Keeper) SetCode(addr common.Address, code []byte) {
|
||||
}
|
||||
|
||||
ethAccount.CodeHash = hash.Hex()
|
||||
k.accountKeeper.SetAccount(k.Ctx(), ethAccount)
|
||||
k.accountKeeper.SetAccount(ctx, ethAccount)
|
||||
|
||||
store := prefix.NewStore(k.Ctx().KVStore(k.storeKey), types.KeyPrefixCode)
|
||||
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixCode)
|
||||
|
||||
action := "updated"
|
||||
|
||||
@ -298,7 +326,7 @@ func (k *Keeper) SetCode(addr common.Address, code []byte) {
|
||||
store.Set(hash.Bytes(), code)
|
||||
}
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
fmt.Sprintf("code %s", action),
|
||||
"ethereum-address", addr.Hex(),
|
||||
"code-hash", hash.Hex(),
|
||||
@ -323,17 +351,19 @@ func (k *Keeper) GetCodeSize(addr common.Address) int {
|
||||
|
||||
// AddRefund adds the given amount of gas to the refund transient value.
|
||||
func (k *Keeper) AddRefund(gas uint64) {
|
||||
ctx := k.Ctx()
|
||||
refund := k.GetRefund()
|
||||
|
||||
refund += gas
|
||||
|
||||
store := k.Ctx().TransientStore(k.transientKey)
|
||||
store := ctx.TransientStore(k.transientKey)
|
||||
store.Set(types.KeyPrefixTransientRefund, sdk.Uint64ToBigEndian(refund))
|
||||
}
|
||||
|
||||
// SubRefund subtracts the given amount of gas from the transient refund value. This function
|
||||
// will panic if gas amount is greater than the stored refund.
|
||||
func (k *Keeper) SubRefund(gas uint64) {
|
||||
ctx := k.Ctx()
|
||||
refund := k.GetRefund()
|
||||
|
||||
if gas > refund {
|
||||
@ -343,14 +373,15 @@ func (k *Keeper) SubRefund(gas uint64) {
|
||||
|
||||
refund -= gas
|
||||
|
||||
store := k.Ctx().TransientStore(k.transientKey)
|
||||
store := ctx.TransientStore(k.transientKey)
|
||||
store.Set(types.KeyPrefixTransientRefund, sdk.Uint64ToBigEndian(refund))
|
||||
}
|
||||
|
||||
// GetRefund returns the amount of gas available for return after the tx execution
|
||||
// finalizes. This value is reset to 0 on every transaction.
|
||||
func (k *Keeper) GetRefund() uint64 {
|
||||
store := k.Ctx().TransientStore(k.transientKey)
|
||||
ctx := k.Ctx()
|
||||
store := ctx.TransientStore(k.transientKey)
|
||||
|
||||
bz := store.Get(types.KeyPrefixTransientRefund)
|
||||
if len(bz) == 0 {
|
||||
@ -385,13 +416,15 @@ func (k *Keeper) GetCommittedState(addr common.Address, hash common.Hash) common
|
||||
// GetState returns the committed state for the given key hash, as all changes are committed directly
|
||||
// to the KVStore.
|
||||
func (k *Keeper) GetState(addr common.Address, hash common.Hash) common.Hash {
|
||||
return doGetState(k.Ctx(), k.storeKey, addr, hash)
|
||||
ctx := k.Ctx()
|
||||
return doGetState(ctx, k.storeKey, addr, hash)
|
||||
}
|
||||
|
||||
// SetState sets the given hashes (key, value) to the KVStore. If the value hash is empty, this
|
||||
// function deletes the key from the store.
|
||||
func (k *Keeper) SetState(addr common.Address, key, value common.Hash) {
|
||||
store := prefix.NewStore(k.Ctx().KVStore(k.storeKey), types.AddressStoragePrefix(addr))
|
||||
ctx := k.Ctx()
|
||||
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.AddressStoragePrefix(addr))
|
||||
key = types.KeyAddressStorage(addr, key)
|
||||
|
||||
action := "updated"
|
||||
@ -402,7 +435,7 @@ func (k *Keeper) SetState(addr common.Address, key, value common.Hash) {
|
||||
store.Set(key.Bytes(), value.Bytes())
|
||||
}
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
fmt.Sprintf("state %s", action),
|
||||
"ethereum-address", addr.Hex(),
|
||||
"key", key.Hex(),
|
||||
@ -416,6 +449,8 @@ func (k *Keeper) SetState(addr common.Address, key, value common.Hash) {
|
||||
// Suicide marks the given account as suicided and clears the account balance of
|
||||
// the EVM tokens.
|
||||
func (k *Keeper) Suicide(addr common.Address) bool {
|
||||
ctx := k.Ctx()
|
||||
|
||||
prev := k.HasSuicided(addr)
|
||||
if prev {
|
||||
return true
|
||||
@ -425,7 +460,7 @@ func (k *Keeper) Suicide(addr common.Address) bool {
|
||||
|
||||
_, err := k.ClearBalance(cosmosAddr)
|
||||
if err != nil {
|
||||
k.Logger(k.Ctx()).Error(
|
||||
k.Logger(ctx).Error(
|
||||
"failed to subtract balance on suicide",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -436,12 +471,9 @@ func (k *Keeper) Suicide(addr common.Address) bool {
|
||||
}
|
||||
|
||||
// TODO: (@fedekunze) do we also need to delete the storage state and the code?
|
||||
k.setSuicided(ctx, addr)
|
||||
|
||||
// Set a single byte to the transient store
|
||||
store := prefix.NewStore(k.Ctx().TransientStore(k.transientKey), types.KeyPrefixTransientSuicided)
|
||||
store.Set(addr.Bytes(), []byte{1})
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"account suicided",
|
||||
"ethereum-address", addr.Hex(),
|
||||
"cosmos-address", cosmosAddr.String(),
|
||||
@ -450,11 +482,19 @@ func (k *Keeper) Suicide(addr common.Address) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// setSuicided sets a single byte to the transient store and marks the address as suicided
|
||||
func (k Keeper) setSuicided(ctx sdk.Context, addr common.Address) {
|
||||
|
||||
store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientSuicided)
|
||||
store.Set(addr.Bytes(), []byte{1})
|
||||
}
|
||||
|
||||
// HasSuicided queries the transient store to check if the account has been marked as suicided in the
|
||||
// current block. Accounts that are suicided will be returned as non-nil during queries and "cleared"
|
||||
// after the block has been committed.
|
||||
func (k *Keeper) HasSuicided(addr common.Address) bool {
|
||||
store := prefix.NewStore(k.Ctx().TransientStore(k.transientKey), types.KeyPrefixTransientSuicided)
|
||||
ctx := k.Ctx()
|
||||
store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientSuicided)
|
||||
return store.Has(addr.Bytes())
|
||||
}
|
||||
|
||||
@ -465,13 +505,14 @@ func (k *Keeper) HasSuicided(addr common.Address) bool {
|
||||
// Exist returns true if the given account exists in store or if it has been
|
||||
// marked as suicided in the transient store.
|
||||
func (k *Keeper) Exist(addr common.Address) bool {
|
||||
ctx := k.Ctx()
|
||||
// return true if the account has suicided
|
||||
if k.HasSuicided(addr) {
|
||||
return true
|
||||
}
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
account := k.accountKeeper.GetAccount(k.Ctx(), cosmosAddr)
|
||||
account := k.accountKeeper.GetAccount(ctx, cosmosAddr)
|
||||
return account != nil
|
||||
}
|
||||
|
||||
@ -482,11 +523,12 @@ func (k *Keeper) Exist(addr common.Address) bool {
|
||||
//
|
||||
// Non-ethereum accounts are considered not empty
|
||||
func (k *Keeper) Empty(addr common.Address) bool {
|
||||
ctx := k.Ctx()
|
||||
nonce := uint64(0)
|
||||
codeHash := types.EmptyCodeHash
|
||||
|
||||
cosmosAddr := sdk.AccAddress(addr.Bytes())
|
||||
account := k.accountKeeper.GetAccount(k.Ctx(), cosmosAddr)
|
||||
account := k.accountKeeper.GetAccount(ctx, cosmosAddr)
|
||||
|
||||
if account != nil {
|
||||
nonce = account.GetSequence()
|
||||
@ -537,7 +579,8 @@ func (k *Keeper) PrepareAccessList(sender common.Address, dest *common.Address,
|
||||
|
||||
// AddressInAccessList returns true if the address is registered on the transient store.
|
||||
func (k *Keeper) AddressInAccessList(addr common.Address) bool {
|
||||
ts := prefix.NewStore(k.Ctx().TransientStore(k.transientKey), types.KeyPrefixTransientAccessListAddress)
|
||||
ctx := k.Ctx()
|
||||
ts := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientAccessListAddress)
|
||||
return ts.Has(addr.Bytes())
|
||||
}
|
||||
|
||||
@ -550,7 +593,8 @@ func (k *Keeper) SlotInAccessList(addr common.Address, slot common.Hash) (addres
|
||||
|
||||
// addressSlotInAccessList returns true if the address's slot is registered on the transient store.
|
||||
func (k *Keeper) addressSlotInAccessList(addr common.Address, slot common.Hash) bool {
|
||||
ts := prefix.NewStore(k.Ctx().TransientStore(k.transientKey), types.KeyPrefixTransientAccessListSlot)
|
||||
ctx := k.Ctx()
|
||||
ts := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientAccessListSlot)
|
||||
key := append(addr.Bytes(), slot.Bytes()...)
|
||||
return ts.Has(key)
|
||||
}
|
||||
@ -562,7 +606,8 @@ func (k *Keeper) AddAddressToAccessList(addr common.Address) {
|
||||
return
|
||||
}
|
||||
|
||||
ts := prefix.NewStore(k.Ctx().TransientStore(k.transientKey), types.KeyPrefixTransientAccessListAddress)
|
||||
ctx := k.Ctx()
|
||||
ts := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientAccessListAddress)
|
||||
ts.Set(addr.Bytes(), []byte{0x1})
|
||||
}
|
||||
|
||||
@ -574,7 +619,8 @@ func (k *Keeper) AddSlotToAccessList(addr common.Address, slot common.Hash) {
|
||||
return
|
||||
}
|
||||
|
||||
ts := prefix.NewStore(k.Ctx().TransientStore(k.transientKey), types.KeyPrefixTransientAccessListSlot)
|
||||
ctx := k.Ctx()
|
||||
ts := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientAccessListSlot)
|
||||
key := append(addr.Bytes(), slot.Bytes()...)
|
||||
ts.Set(key, []byte{0x1})
|
||||
}
|
||||
@ -601,7 +647,9 @@ func (k *Keeper) RevertToSnapshot(target int) {
|
||||
// context. This function also fills in the tx hash, block hash, tx index and log index fields before setting the log
|
||||
// to store.
|
||||
func (k *Keeper) AddLog(log *ethtypes.Log) {
|
||||
log.BlockHash = common.BytesToHash(k.Ctx().HeaderHash())
|
||||
ctx := k.Ctx()
|
||||
|
||||
log.BlockHash = common.BytesToHash(ctx.HeaderHash())
|
||||
log.TxIndex = uint(k.GetTxIndexTransient())
|
||||
log.TxHash = k.GetTxHashTransient()
|
||||
|
||||
@ -609,7 +657,7 @@ func (k *Keeper) AddLog(log *ethtypes.Log) {
|
||||
k.IncreaseLogSizeTransient()
|
||||
k.SetLog(log)
|
||||
|
||||
k.Logger(k.Ctx()).Debug(
|
||||
k.Logger(ctx).Debug(
|
||||
"log added",
|
||||
"tx-hash-ethereum", log.TxHash.Hex(),
|
||||
"log-index", int(log.Index),
|
||||
@ -632,7 +680,8 @@ func (k *Keeper) AddPreimage(_ common.Hash, _ []byte) {}
|
||||
// ForEachStorage uses the store iterator to iterate over all the state keys and perform a callback
|
||||
// function on each of them.
|
||||
func (k *Keeper) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error {
|
||||
store := k.Ctx().KVStore(k.storeKey)
|
||||
ctx := k.Ctx()
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
prefix := types.AddressStoragePrefix(addr)
|
||||
|
||||
iterator := sdk.KVStorePrefixIterator(store, prefix)
|
||||
|
128
x/evm/keeper/statedb_benchmark_test.go
Normal file
128
x/evm/keeper/statedb_benchmark_test.go
Normal file
@ -0,0 +1,128 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func BenchmarkCreateAccountNew(b *testing.B) {
|
||||
suite := KeeperTestSuite{}
|
||||
suite.DoSetupTest(b)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
addr := tests.GenerateAddress()
|
||||
b.StartTimer()
|
||||
suite.app.EvmKeeper.CreateAccount(addr)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCreateAccountExisting(b *testing.B) {
|
||||
suite := KeeperTestSuite{}
|
||||
suite.DoSetupTest(b)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
suite.app.EvmKeeper.CreateAccount(suite.address)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddBalance(b *testing.B) {
|
||||
suite := KeeperTestSuite{}
|
||||
suite.DoSetupTest(b)
|
||||
|
||||
amt := big.NewInt(10)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
suite.app.EvmKeeper.AddBalance(suite.address, amt)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSetCode(b *testing.B) {
|
||||
suite := KeeperTestSuite{}
|
||||
suite.DoSetupTest(b)
|
||||
|
||||
hash := crypto.Keccak256Hash([]byte("code")).Bytes()
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
suite.app.EvmKeeper.SetCode(suite.address, hash)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSetState(b *testing.B) {
|
||||
suite := KeeperTestSuite{}
|
||||
suite.DoSetupTest(b)
|
||||
|
||||
hash := crypto.Keccak256Hash([]byte("topic")).Bytes()
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
suite.app.EvmKeeper.SetCode(suite.address, hash)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddLog(b *testing.B) {
|
||||
suite := KeeperTestSuite{}
|
||||
suite.DoSetupTest(b)
|
||||
|
||||
topic := crypto.Keccak256Hash([]byte("topic"))
|
||||
txHash := crypto.Keccak256Hash([]byte("tx_hash"))
|
||||
blockHash := crypto.Keccak256Hash([]byte("block_hash"))
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
suite.app.EvmKeeper.AddLog(ðtypes.Log{
|
||||
Address: suite.address,
|
||||
Topics: []common.Hash{topic},
|
||||
Data: []byte("data"),
|
||||
BlockNumber: 1,
|
||||
TxHash: txHash,
|
||||
TxIndex: 1,
|
||||
BlockHash: blockHash,
|
||||
Index: 1,
|
||||
Removed: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSnapshot(b *testing.B) {
|
||||
suite := KeeperTestSuite{}
|
||||
suite.DoSetupTest(b)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
target := suite.app.EvmKeeper.Snapshot()
|
||||
require.Equal(b, i, target)
|
||||
}
|
||||
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
require.NotPanics(b, func() {
|
||||
suite.app.EvmKeeper.RevertToSnapshot(i)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user