Skip to content

Commit

Permalink
feat: Replace transient store from evm module to object store
Browse files Browse the repository at this point in the history
  • Loading branch information
dudong2 committed Oct 18, 2024
1 parent 0be5835 commit 2c65555
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 152 deletions.
2 changes: 0 additions & 2 deletions app/ante/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ type EVMKeeper interface {
NewEVM(ctx sdk.Context, msg core.Message, cfg *statedb.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) *big.Int
ResetTransientGasUsed(ctx sdk.Context)
GetTxIndexTransient(ctx sdk.Context) uint64
GetParams(ctx sdk.Context) evmtypes.Params
}

Expand Down
8 changes: 1 addition & 7 deletions app/ante/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package ante

import (
"errors"
"strconv"

errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
Expand Down Expand Up @@ -53,9 +52,6 @@ func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
WithKVGasConfig(storetypes.GasConfig{}).
WithTransientKVGasConfig(storetypes.GasConfig{})

// Reset transient gas used to prepare the execution of current cosmos tx.
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
esc.evmKeeper.ResetTransientGasUsed(ctx)
return next(newCtx, tx, simulate)
}

Expand All @@ -73,8 +69,7 @@ func NewEthEmitEventDecorator(evmKeeper EVMKeeper) EthEmitEventDecorator {
func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// After eth tx passed ante handler, the fee is deducted and nonce increased, it shouldn't be ignored by json-rpc,
// we need to emit some basic events at the very end of ante handler to be indexed by tendermint.
txIndex := eeed.evmKeeper.GetTxIndexTransient(ctx)
for i, msg := range tx.GetMsgs() {
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
Expand All @@ -85,7 +80,6 @@ func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat
ctx.EventManager().EmitEvent(sdk.NewEvent(
evmtypes.EventTypeEthereumTx,
sdk.NewAttribute(evmtypes.AttributeKeyEthereumTxHash, msgEthTx.Hash),
sdk.NewAttribute(evmtypes.AttributeKeyTxIndex, strconv.FormatUint(txIndex+uint64(i), 10)), //#nosec G115
))
}

Expand Down
6 changes: 3 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ func NewEthermintApp(
}

// Add the EVM transient store key
tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey)
tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey)
memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey)
okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey, evmtypes.ObjectStoreKey)
app := &EthermintApp{
BaseApp: bApp,
legacyAmino: legacyAmino,
Expand Down Expand Up @@ -576,7 +576,7 @@ func NewEthermintApp(
app.EvmKeeper = evmkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[evmtypes.StoreKey]),
tkeys[evmtypes.TransientKey],
okeys[evmtypes.ObjectStoreKey],
authtypes.NewModuleAddress(govtypes.ModuleName),
app.AccountKeeper,
app.BankKeeper,
Expand Down
9 changes: 4 additions & 5 deletions tests/importer/importer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,9 @@ func (suite *ImporterTestSuite) TestImportBlocks() {
applyDAOHardFork(vmdb)
}

for _, tx := range block.Transactions() {

for i, tx := range block.Transactions() {
receipt, gas, err := applyTransaction(
ctx, chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, vmdb, header, tx, usedGas, vmConfig,
ctx, chainConfig, chainContext, nil, gp, suite.app.EvmKeeper, vmdb, header, tx, usedGas, vmConfig, uint(i),
)
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)
Expand Down Expand Up @@ -230,7 +229,7 @@ func applyDAOHardFork(vmdb ethvm.StateDB) {
func applyTransaction(
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,
tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, index uint,
) (*ethtypes.Receipt, uint64, error) {
msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number), sdkmath.ZeroInt().BigInt())
if err != nil {
Expand Down Expand Up @@ -271,7 +270,7 @@ func applyTransaction(
receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt})
receipt.BlockHash = header.Hash()
receipt.BlockNumber = header.Number
receipt.TransactionIndex = uint(evmKeeper.GetTxIndexTransient(ctx))
receipt.TransactionIndex = index

return receipt, execResult.UsedGas, err
}
7 changes: 7 additions & 0 deletions types/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ func SafeInt64(value uint64) (int64, error) {
return int64(value), nil //#nosec G115
}

func SafeIntToUint64(value int) (uint64, error) {
if value < 0 {
return 0, fmt.Errorf("invalid value: %d", value)
}
return uint64(value), nil
}

// SafeNewIntFromBigInt constructs Int from big.Int, return error if more than 256bits
func SafeNewIntFromBigInt(i *big.Int) (sdkmath.Int, error) {
if !IsValidInt256(i) {
Expand Down
9 changes: 1 addition & 8 deletions x/evm/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ package keeper
import (
"context"

storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"

ethtypes "github.com/ethereum/go-ethereum/core/types"
)

// BeginBlock sets the sdk Context and EIP155 chain id to the Keeper.
Expand All @@ -37,11 +34,7 @@ func (k *Keeper) BeginBlock(ctx context.Context) error {
func (k *Keeper) EndBlock(ctx context.Context) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)

// Gas costs are handled within msg handler so costs should be ignored
infCtx := sdkCtx.WithGasMeter(storetypes.NewInfiniteGasMeter())

bloom := ethtypes.BytesToBloom(k.GetBlockBloomTransient(infCtx).Bytes())
k.EmitBlockBloomEvent(infCtx, bloom)
k.CollectTxBloom(sdkCtx)

return nil
}
27 changes: 27 additions & 0 deletions x/evm/keeper/bloom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package keeper

import (
"math/big"

"cosmossdk.io/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/evmos/ethermint/x/evm/types"
)

func (k Keeper) SetTxBloom(ctx sdk.Context, bloom *big.Int) {
store := ctx.ObjectStore(k.objectKey)
store.Set(types.ObjectBloomKey(ctx.TxIndex(), ctx.MsgIndex()), bloom)
}

func (k Keeper) CollectTxBloom(ctx sdk.Context) {
store := prefix.NewObjStore(ctx.ObjectStore(k.objectKey), types.KeyPrefixObjectBloom)
it := store.Iterator(nil, nil)
defer it.Close()

bloom := new(big.Int)
for ; it.Valid(); it.Next() {
bloom.Or(bloom, it.Value().(*big.Int))
}

k.EmitBlockBloomEvent(ctx, bloom.Bytes())
}
3 changes: 1 addition & 2 deletions x/evm/keeper/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig
return statedb.NewTxConfig(
common.BytesToHash(ctx.HeaderHash()), // BlockHash
txHash, // TxHash
uint(k.GetTxIndexTransient(ctx)), // TxIndex
uint(k.GetLogSizeTransient(ctx)), // LogIndex
0, 0,
)
}

Expand Down
95 changes: 12 additions & 83 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -50,8 +49,8 @@ type Keeper struct {
// - storing Bloom filters by block height. Needed for the Web3 API.
storeService store.KVStoreService

// key to access the transient store, which is reset on every block during Commit
transientKey storetypes.StoreKey
// key to access the object store, which is reset on every block during Commit
objectKey storetypes.StoreKey

// the address capable of executing a MsgUpdateParams message. Typically, this should be the x/gov module account.
authority sdk.AccAddress
Expand Down Expand Up @@ -86,7 +85,7 @@ type Keeper struct {
func NewKeeper(
cdc codec.BinaryCodec,
storeService store.KVStoreService,
transientKey storetypes.StoreKey,
objectKey storetypes.StoreKey,
authority sdk.AccAddress,
ak types.AccountKeeper,
bankKeeper types.BankKeeper,
Expand Down Expand Up @@ -116,7 +115,7 @@ func NewKeeper(
stakingKeeper: sk,
feeMarketKeeper: fmk,
storeService: storeService,
transientKey: transientKey,
objectKey: objectKey,
customPrecompiles: customPrecompiles,
evmConstructor: evmConstructor,
tracer: tracer,
Expand Down Expand Up @@ -154,11 +153,11 @@ func (k Keeper) ChainID() *big.Int {
// ----------------------------------------------------------------------------

// EmitBlockBloomEvent emit block bloom events
func (k Keeper) EmitBlockBloomEvent(ctx sdk.Context, bloom ethtypes.Bloom) {
func (k Keeper) EmitBlockBloomEvent(ctx sdk.Context, bloom []byte) {
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeBlockBloom,
sdk.NewAttribute(types.AttributeKeyEthereumBloom, string(bloom.Bytes())),
sdk.NewAttribute(types.AttributeKeyEthereumBloom, string(bloom)),
),
)
}
Expand All @@ -168,69 +167,6 @@ func (k Keeper) GetAuthority() sdk.AccAddress {
return k.authority
}

// GetBlockBloomTransient returns bloom bytes for the current block height
func (k Keeper) GetBlockBloomTransient(ctx sdk.Context) *big.Int {
store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom)
heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight())) //#nosec G115
bz := store.Get(heightBz)
if len(bz) == 0 {
return big.NewInt(0)
}

return new(big.Int).SetBytes(bz)
}

// SetBlockBloomTransient sets the given bloom bytes to the transient store. This value is reset on
// every block.
func (k Keeper) SetBlockBloomTransient(ctx sdk.Context, bloom *big.Int) {
store := prefix.NewStore(ctx.TransientStore(k.transientKey), types.KeyPrefixTransientBloom)
heightBz := sdk.Uint64ToBigEndian(uint64(ctx.BlockHeight())) //#nosec G115
store.Set(heightBz, bloom.Bytes())
}

// ----------------------------------------------------------------------------
// Tx
// ----------------------------------------------------------------------------

// SetTxIndexTransient set the index of processing transaction
func (k Keeper) SetTxIndexTransient(ctx sdk.Context, index uint64) {
store := ctx.TransientStore(k.transientKey)
store.Set(types.KeyPrefixTransientTxIndex, sdk.Uint64ToBigEndian(index))
}

// GetTxIndexTransient returns EVM transaction index on the current block.
func (k Keeper) GetTxIndexTransient(ctx sdk.Context) uint64 {
store := ctx.TransientStore(k.transientKey)
bz := store.Get(types.KeyPrefixTransientTxIndex)
if len(bz) == 0 {
return 0
}

return sdk.BigEndianToUint64(bz)
}

// ----------------------------------------------------------------------------
// Log
// ----------------------------------------------------------------------------

// GetLogSizeTransient returns EVM log index on the current block.
func (k Keeper) GetLogSizeTransient(ctx sdk.Context) uint64 {
store := ctx.TransientStore(k.transientKey)
bz := store.Get(types.KeyPrefixTransientLogSize)
if len(bz) == 0 {
return 0
}

return sdk.BigEndianToUint64(bz)
}

// SetLogSizeTransient fetches the current EVM log index from the transient store, increases its
// value by one and then sets the new index back to the transient store.
func (k Keeper) SetLogSizeTransient(ctx sdk.Context, logSize uint64) {
store := ctx.TransientStore(k.transientKey)
store.Set(types.KeyPrefixTransientLogSize, sdk.Uint64ToBigEndian(logSize))
}

// ----------------------------------------------------------------------------
// Storage
// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -367,27 +303,20 @@ func (k Keeper) GetMinGasMultiplier(ctx sdk.Context) sdkmath.LegacyDec {
return fmkParmas.MinGasMultiplier
}

// ResetTransientGasUsed reset gas used to prepare for execution of current cosmos tx, called in ante handler.
func (k Keeper) ResetTransientGasUsed(ctx sdk.Context) {
store := ctx.TransientStore(k.transientKey)
store.Delete(types.KeyPrefixTransientGasUsed)
}

// GetTransientGasUsed returns the gas used by current cosmos tx.
func (k Keeper) GetTransientGasUsed(ctx sdk.Context) uint64 {
store := ctx.TransientStore(k.transientKey)
bz := store.Get(types.KeyPrefixTransientGasUsed)
if len(bz) == 0 {
store := ctx.ObjectStore(k.objectKey)
v := store.Get(types.ObjectGasUsedKey(ctx.TxIndex()))
if v == nil {
return 0
}
return sdk.BigEndianToUint64(bz)
return v.(uint64)
}

// SetTransientGasUsed sets the gas used by current cosmos tx.
func (k Keeper) SetTransientGasUsed(ctx sdk.Context, gasUsed uint64) {
store := ctx.TransientStore(k.transientKey)
bz := sdk.Uint64ToBigEndian(gasUsed)
store.Set(types.KeyPrefixTransientGasUsed, bz)
store := ctx.ObjectStore(k.objectKey)
store.Set(types.ObjectGasUsedKey(ctx.TxIndex()), gasUsed)
}

// AddTransientGasUsed accumulate gas used by each eth msgs included in current cosmos tx.
Expand Down
3 changes: 0 additions & 3 deletions x/evm/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t
ctx := sdk.UnwrapSDKContext(goCtx)

tx := msg.AsTransaction()
txIndex := k.GetTxIndexTransient(ctx)

labels := []metrics.Label{
telemetry.NewLabel("tx_type", fmt.Sprintf("%d", tx.Type())),
Expand Down Expand Up @@ -93,8 +92,6 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t
sdk.NewAttribute(sdk.AttributeKeyAmount, tx.Value().String()),
// add event for ethereum transaction hash format
sdk.NewAttribute(types.AttributeKeyEthereumTxHash, response.Hash),
// add event for index of valid ethereum tx
sdk.NewAttribute(types.AttributeKeyTxIndex, strconv.FormatUint(txIndex, 10)),
// add event for eth tx gas used, we can't get it from cosmos tx result when it contains multiple eth tx msgs.
sdk.NewAttribute(types.AttributeKeyTxGasUsed, strconv.FormatUint(response.GasUsed, 10)),
}
Expand Down
Loading

0 comments on commit 2c65555

Please sign in to comment.