Skip to content

Commit

Permalink
Use in-memory map for deferred info (#1345)
Browse files Browse the repository at this point in the history
wip
  • Loading branch information
codchen authored and udpatil committed Apr 17, 2024
1 parent a5c6016 commit 7ad2897
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 65 deletions.
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,7 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ
for relativeOtherIndex, originalIndex := range otherIndices {
txResults[originalIndex] = otherResults[relativeOtherIndex]
}
app.EvmKeeper.SetTxResults(txResults)

// Finalize all Bank Module Transfers here so that events are included
lazyWriteEvents := app.BankKeeper.WriteDeferredBalances(ctx)
Expand Down
78 changes: 22 additions & 56 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package keeper

import (
"encoding/binary"
"fmt"
"math"
"math/big"
Expand All @@ -19,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/sei-protocol/sei-chain/x/evm/types"
Expand All @@ -29,6 +29,9 @@ type Keeper struct {
memStoreKey sdk.StoreKey
Paramstore paramtypes.Subspace

deferredInfo *sync.Map
txResults []*abci.ExecTxResult

bankKeeper bankkeeper.Keeper
accountKeeper *authkeeper.AccountKeeper
stakingKeeper *stakingkeeper.Keeper
Expand Down Expand Up @@ -68,6 +71,7 @@ func NewKeeper(
nonceMx: &sync.RWMutex{},
cachedFeeCollectorAddressMtx: &sync.RWMutex{},
keyToNonce: make(map[tmtypes.TxKey]*addressNoncePair),
deferredInfo: &sync.Map{},
}
return k
}
Expand Down Expand Up @@ -142,69 +146,27 @@ func (k *Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc {
}

func (k *Keeper) GetEVMTxDeferredInfo(ctx sdk.Context) (res []EvmTxDeferredInfo) {
hashMap, bloomMap := map[int]common.Hash{}, map[int]ethtypes.Bloom{}
hashIter := prefix.NewStore(ctx.KVStore(k.memStoreKey), types.TxHashPrefix).Iterator(nil, nil)
for ; hashIter.Valid(); hashIter.Next() {
h := common.Hash{}
h.SetBytes(hashIter.Value())
hashMap[int(binary.BigEndian.Uint32(hashIter.Key()))] = h
}
hashIter.Close()
bloomIter := prefix.NewStore(ctx.KVStore(k.memStoreKey), types.TxBloomPrefix).Iterator(nil, nil)
for ; bloomIter.Valid(); bloomIter.Next() {
b := ethtypes.Bloom{}
b.SetBytes(bloomIter.Value())
bloomMap[int(binary.BigEndian.Uint32(bloomIter.Key()))] = b
}
bloomIter.Close()
for idx, h := range hashMap {
i := EvmTxDeferredInfo{TxIndx: idx, TxHash: h}
if b, ok := bloomMap[idx]; ok {
i.TxBloom = b
delete(bloomMap, idx)
k.deferredInfo.Range(func(key, value any) bool {
txIdx := key.(int)
if txIdx >= 0 && txIdx < len(k.txResults) && k.txResults[txIdx].Code == 0 {
res = append(res, *(value.(*EvmTxDeferredInfo)))
}
res = append(res, i)
}
for idx, b := range bloomMap {
res = append(res, EvmTxDeferredInfo{TxIndx: idx, TxBloom: b})
}
return true
})
sort.SliceStable(res, func(i, j int) bool { return res[i].TxIndx < res[j].TxIndx })
return
}

func (k *Keeper) AppendToEvmTxDeferredInfo(ctx sdk.Context, bloom ethtypes.Bloom, txHash common.Hash) {
key := make([]byte, 8)
binary.BigEndian.PutUint32(key, uint32(ctx.TxIndex()))
prefix.NewStore(ctx.KVStore(k.memStoreKey), types.TxHashPrefix).Set(key, txHash[:])
prefix.NewStore(ctx.KVStore(k.memStoreKey), types.TxBloomPrefix).Set(key, bloom[:])
k.deferredInfo.Store(ctx.TxIndex(), &EvmTxDeferredInfo{
TxIndx: ctx.TxIndex(),
TxBloom: bloom,
TxHash: txHash,
})
}

func (k *Keeper) ClearEVMTxDeferredInfo(ctx sdk.Context) {
hashStore := prefix.NewStore(ctx.KVStore(k.memStoreKey), types.TxHashPrefix)
hashIterator := hashStore.Iterator(nil, nil)
defer hashIterator.Close()
hashKeysToDelete := [][]byte{}
for ; hashIterator.Valid(); hashIterator.Next() {
hashKeysToDelete = append(hashKeysToDelete, hashIterator.Key())
}
// close the first iterator for safety
hashIterator.Close()
for _, key := range hashKeysToDelete {
hashStore.Delete(key)
}

bloomStore := prefix.NewStore(ctx.KVStore(k.memStoreKey), types.TxBloomPrefix)
bloomIterator := bloomStore.Iterator(nil, nil)
bloomKeysToDelete := [][]byte{}
defer bloomIterator.Close()
for ; bloomIterator.Valid(); bloomIterator.Next() {
bloomKeysToDelete = append(bloomKeysToDelete, bloomIterator.Key())
}
// close the second iterator for safety
bloomIterator.Close()
for _, key := range bloomKeysToDelete {
bloomStore.Delete(key)
}
func (k *Keeper) ClearEVMTxDeferredInfo() {
k.deferredInfo = &sync.Map{}
}

func (k *Keeper) getHistoricalHash(ctx sdk.Context, h int64) common.Hash {
Expand Down Expand Up @@ -295,6 +257,10 @@ func (k *Keeper) RemovePendingNonce(key tmtypes.TxKey) {
}
}

func (k *Keeper) SetTxResults(txResults []*abci.ExecTxResult) {
k.txResults = txResults
}

func uint64Cmp(a, b uint64) int {
if a < b {
return -1
Expand Down
8 changes: 6 additions & 2 deletions x/evm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper"
"github.com/sei-protocol/sei-chain/x/evm/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/rand"
tmtypes "github.com/tendermint/tendermint/types"
)
Expand Down Expand Up @@ -191,7 +192,10 @@ func TestDeferredInfo(t *testing.T) {
ctx = ctx.WithTxIndex(1)
k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{1, 2, 3}, common.Hash{4, 5, 6})
ctx = ctx.WithTxIndex(2)
k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{7, 8}, common.Hash{9.0})
k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{7, 8}, common.Hash{9, 0})
ctx = ctx.WithTxIndex(3) // should be ignored because txResult has non-zero code
k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{11, 12}, common.Hash{13, 14})
k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}, {Code: 1}})
infoList := k.GetEVMTxDeferredInfo(ctx)
require.Equal(t, 2, len(infoList))
require.Equal(t, 1, infoList[0].TxIndx)
Expand All @@ -201,7 +205,7 @@ func TestDeferredInfo(t *testing.T) {
require.Equal(t, ethtypes.Bloom{7, 8}, infoList[1].TxBloom)
require.Equal(t, common.Hash{9, 0}, infoList[1].TxHash)
// test clear tx deferred info
k.ClearEVMTxDeferredInfo(ctx)
k.ClearEVMTxDeferredInfo()
infoList = k.GetEVMTxDeferredInfo(ctx)
require.Empty(t, len(infoList))
}
6 changes: 4 additions & 2 deletions x/evm/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ func (AppModule) ConsensusVersion() uint64 { return 3 }

// BeginBlock executes all ABCI BeginBlock logic respective to the capability module.
func (am AppModule) BeginBlock(sdk.Context, abci.RequestBeginBlock) {
// clear tx responses from last block
am.keeper.SetTxResults([]*abci.ExecTxResult{})
// clear the TxDeferredInfo
am.keeper.ClearEVMTxDeferredInfo()
}

// EndBlock executes all ABCI EndBlock logic respective to the capability module. It
Expand Down Expand Up @@ -189,7 +193,5 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val
}
am.keeper.SetTxHashesOnHeight(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) common.Hash { return i.TxHash }))
am.keeper.SetBlockBloom(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) ethtypes.Bloom { return i.TxBloom }))
// clear the TxDeferredInfo
am.keeper.ClearEVMTxDeferredInfo(ctx)
return []abci.ValidatorUpdate{}
}
6 changes: 2 additions & 4 deletions x/evm/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ func TestABCI(t *testing.T) {
s.AddBalance(evmAddr1, big.NewInt(5000000000000))
require.Nil(t, s.Finalize())
k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(3), ethtypes.Bloom{}, common.Hash{})
k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}, {Code: 0}})
m.EndBlock(ctx, abci.RequestEndBlock{})
deferredInfo := k.GetEVMTxDeferredInfo(ctx)
require.Empty(t, deferredInfo)
require.Equal(t, uint64(0), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64())
require.Equal(t, uint64(2), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName), "usei").Amount.Uint64())

Expand All @@ -55,9 +54,8 @@ func TestABCI(t *testing.T) {
s.AddBalance(evmAddr1, big.NewInt(2000000000000))
require.Nil(t, s.Finalize())
k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(2), ethtypes.Bloom{}, common.Hash{})
k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}})
m.EndBlock(ctx, abci.RequestEndBlock{})
require.Equal(t, uint64(1), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64())
require.Equal(t, uint64(2), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName), "usei").Amount.Uint64())
deferredInfo = k.GetEVMTxDeferredInfo(ctx)
require.Empty(t, deferredInfo)
}

0 comments on commit 7ad2897

Please sign in to comment.