Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add indexer tests #115

Merged
merged 16 commits into from
Dec 3, 2024
4 changes: 4 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,10 @@
return err
}

if app.evmIndexer != nil {
app.evmIndexer.Stop()
}

Check warning on line 607 in app/app.go

View check run for this annotation

Codecov / codecov/patch

app/app.go#L605-L607

Added lines #L605 - L607 were not covered by tests

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion app/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func setupIndexer(
indexerDB, kvindexerDB dbm.DB,
) (evmindexer.EVMIndexer, *kvindexerkeeper.Keeper, *kvindexermodule.AppModuleBasic, *storetypes.StreamingManager, error) {
// setup evm indexer
evmIndexer, err := evmindexer.NewEVMIndexer(indexerDB, app.appCodec, app.Logger(), app.txConfig, app.EVMKeeper, app.OPChildKeeper)
evmIndexer, err := evmindexer.NewEVMIndexer(indexerDB, app.appCodec, app.Logger(), app.txConfig, app.EVMKeeper)
if err != nil {
return nil, nil, nil, nil, err
}
Expand Down
12 changes: 11 additions & 1 deletion app/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
tmtypes "github.com/cometbft/cometbft/types"
dbm "github.com/cosmos/cosmos-db"

"cosmossdk.io/math"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
Expand All @@ -22,7 +23,9 @@ import (

opchildtypes "github.com/initia-labs/OPinit/x/opchild/types"

"github.com/initia-labs/minievm/types"
evmconfig "github.com/initia-labs/minievm/x/evm/config"
evmtypes "github.com/initia-labs/minievm/x/evm/types"
)

// defaultConsensusParams defines the default Tendermint consensus params used in
Expand Down Expand Up @@ -65,7 +68,7 @@ func setup(db *dbm.DB, withGenesis bool) (*MinitiaApp, GenesisState) {
)

if withGenesis {
return app, NewDefaultGenesisState(encCdc.Codec, app.BasicModuleManager, sdk.DefaultBondDenom)
return app, NewDefaultGenesisState(encCdc.Codec, app.BasicModuleManager, types.BaseDenom)
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
}

return app, GenesisState{}
Expand Down Expand Up @@ -128,11 +131,18 @@ func SetupWithGenesisAccounts(
app.AppCodec().MustUnmarshalJSON(genesisState[opchildtypes.ModuleName], &opchildGenesis)
opchildGenesis.Params.Admin = sdk.AccAddress(valSet.Validators[0].Address.Bytes()).String()
opchildGenesis.Params.BridgeExecutors = []string{sdk.AccAddress(valSet.Validators[0].Address.Bytes()).String()}
opchildGenesis.Params.MinGasPrices = sdk.NewDecCoins(sdk.NewDecCoin(types.BaseDenom, math.NewInt(1_000_000_000)))

// set validators and delegations
opchildGenesis = *opchildtypes.NewGenesisState(opchildGenesis.Params, validators, nil)
genesisState[opchildtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&opchildGenesis)

// set evm genesis params
var evmGenesis evmtypes.GenesisState
app.AppCodec().MustUnmarshalJSON(genesisState[evmtypes.ModuleName], &evmGenesis)
evmGenesis.Params.GasRefundRatio = math.LegacyZeroDec()
genesisState[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&evmGenesis)

// update total supply
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}, []banktypes.SendEnabled{})
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
Expand Down
119 changes: 119 additions & 0 deletions indexer/abci_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package indexer_test

import (
"math/big"
"sync"
"testing"

"github.com/stretchr/testify/require"

storetypes "cosmossdk.io/store/types"

evmtypes "github.com/initia-labs/minievm/x/evm/types"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)

func Test_ListenFinalizeBlock(t *testing.T) {
app, indexer, addrs, privKeys := setupIndexer(t)
defer app.Close()

tx, evmTxHash := generateCreateERC20Tx(t, app, privKeys[0])
finalizeReq, finalizeRes := executeTxs(t, app, tx)
checkTxResult(t, finalizeRes.TxResults[0], true)

events := finalizeRes.TxResults[0].Events
createEvent := events[len(events)-3]
require.Equal(t, evmtypes.EventTypeContractCreated, createEvent.GetType())

contractAddr, err := hexutil.Decode(createEvent.Attributes[0].Value)
require.NoError(t, err)

// listen finalize block
ctx, err := app.CreateQueryContext(0, false)
require.NoError(t, err)

err = indexer.ListenFinalizeBlock(ctx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()), *finalizeReq, *finalizeRes)
require.NoError(t, err)

// check the tx is indexed
evmTx, err := indexer.TxByHash(ctx, evmTxHash)
require.NoError(t, err)
require.NotNil(t, evmTx)

// mint 1_000_000 tokens to the first address
tx, evmTxHash = generateMintERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[0], new(big.Int).SetUint64(1_000_000_000_000))
finalizeReq, finalizeRes = executeTxs(t, app, tx)
checkTxResult(t, finalizeRes.TxResults[0], true)

// listen finalize block
ctx, err = app.CreateQueryContext(0, false)
require.NoError(t, err)

err = indexer.ListenFinalizeBlock(ctx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()), *finalizeReq, *finalizeRes)
require.NoError(t, err)

// check the tx is indexed
evmTx, err = indexer.TxByHash(ctx, evmTxHash)
require.NoError(t, err)
require.NotNil(t, evmTx)
beer-1 marked this conversation as resolved.
Show resolved Hide resolved

// check the block header is indexed
header, err := indexer.BlockHeaderByNumber(ctx, uint64(finalizeReq.Height))
require.NoError(t, err)
require.NotNil(t, header)
require.Equal(t, finalizeReq.Height, header.Number.Int64())

}

func Test_ListenFinalizeBlock_Subscribe(t *testing.T) {
app, indexer, _, privKeys := setupIndexer(t)
defer app.Close()

blockChan, logsChan, pendChan := indexer.Subscribe()
close(pendChan)

tx, evmTxHash := generateCreateERC20Tx(t, app, privKeys[0])
finalizeReq, finalizeRes := executeTxs(t, app, tx)
checkTxResult(t, finalizeRes.TxResults[0], true)

events := finalizeRes.TxResults[0].Events
createEvent := events[len(events)-3]
require.Equal(t, evmtypes.EventTypeContractCreated, createEvent.GetType())

contractAddr, err := hexutil.Decode(createEvent.Attributes[0].Value)
require.NoError(t, err)

// listen finalize block
ctx, err := app.CreateQueryContext(0, false)
require.NoError(t, err)

wg := sync.WaitGroup{}
wg.Add(2)
go func() {
for {
select {
case block := <-blockChan:
require.NotNil(t, block)
require.Equal(t, finalizeReq.Height, block.Number.Int64())
wg.Done()
case logs := <-logsChan:
require.NotNil(t, logs)

for _, log := range logs {
if log.Address == common.BytesToAddress(contractAddr) {
require.Equal(t, evmTxHash, log.TxHash)
require.Equal(t, uint64(finalizeReq.Height), log.BlockNumber)
wg.Done()
}
}
}
}
}()

err = indexer.ListenFinalizeBlock(ctx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()), *finalizeReq, *finalizeRes)
require.NoError(t, err)

wg.Wait()
}
21 changes: 12 additions & 9 deletions indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
"github.com/ethereum/go-ethereum/common"
coretypes "github.com/ethereum/go-ethereum/core/types"

opchildkeeper "github.com/initia-labs/OPinit/x/opchild/keeper"

rpctypes "github.com/initia-labs/minievm/jsonrpc/types"
evmconfig "github.com/initia-labs/minievm/x/evm/config"
evmkeeper "github.com/initia-labs/minievm/x/evm/keeper"
Expand All @@ -37,7 +35,7 @@

// tx receipt
TxReceiptByHash(ctx context.Context, hash common.Hash) (*coretypes.Receipt, error)
IterateBlockTxRecepts(ctx context.Context, blockHeight uint64, cb func(tx *coretypes.Receipt) (bool, error)) error
IterateBlockTxReceipts(ctx context.Context, blockHeight uint64, cb func(tx *coretypes.Receipt) (bool, error)) error

// block
BlockHashToNumber(ctx context.Context, hash common.Hash) (uint64, error)
Expand All @@ -53,6 +51,9 @@
// mempool
MempoolWrapper(mempool mempool.Mempool) mempool.Mempool
TxInMempool(hash common.Hash) *rpctypes.RPCTransaction

// Stop
Stop()
}

// EVMIndexerImpl implements EVMIndexer.
Expand All @@ -62,9 +63,8 @@
txConfig client.TxConfig
appCodec codec.Codec

store *CacheStore
evmKeeper *evmkeeper.Keeper
opChildKeeper *opchildkeeper.Keeper
store *CacheStore
evmKeeper *evmkeeper.Keeper

schema collections.Schema
TxMap collections.Map[[]byte, rpctypes.RPCTransaction]
Expand All @@ -89,7 +89,6 @@
logger log.Logger,
txConfig client.TxConfig,
evmKeeper *evmkeeper.Keeper,
opChildKeeper *opchildkeeper.Keeper,
) (EVMIndexer, error) {
cfg := evmKeeper.Config()
if cfg.IndexerCacheSize == 0 {
Expand All @@ -110,8 +109,7 @@
txConfig: txConfig,
appCodec: appCodec,

evmKeeper: evmKeeper,
opChildKeeper: opChildKeeper,
evmKeeper: evmKeeper,

TxMap: collections.NewMap(sb, prefixTx, "tx", collections.BytesKey, CollJsonVal[rpctypes.RPCTransaction]()),
TxReceiptMap: collections.NewMap(sb, prefixTxReceipt, "tx_receipt", collections.BytesKey, CollJsonVal[coretypes.Receipt]()),
Expand Down Expand Up @@ -181,3 +179,8 @@

close(done)
}

// Stop stops the indexer.
func (e *EVMIndexerImpl) Stop() {
e.txPendingMap.Stop()

Check warning on line 185 in indexer/indexer.go

View check run for this annotation

Codecov / codecov/patch

indexer/indexer.go#L184-L185

Added lines #L184 - L185 were not covered by tests
}
70 changes: 70 additions & 0 deletions indexer/indexer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package indexer_test

import (
"crypto/ecdsa"
"testing"

"github.com/ethereum/go-ethereum/common"
minitiaapp "github.com/initia-labs/minievm/app"
minievmtypes "github.com/initia-labs/minievm/types"

"github.com/stretchr/testify/require"

"cosmossdk.io/math"
dbm "github.com/cosmos/cosmos-db"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

abci "github.com/cometbft/cometbft/abci/types"

"github.com/initia-labs/minievm/indexer"
)

// Bond denom should be set for staking test
const baseDenom = minievmtypes.BaseDenom

var (
genCoins = sdk.NewCoins(sdk.NewCoin(baseDenom, math.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000))).Sort()
)

func checkBalance(t *testing.T, app *minitiaapp.MinitiaApp, addr common.Address, balances sdk.Coins) {
ctxCheck := app.BaseApp.NewContext(true)
require.True(t, balances.Equal(app.BankKeeper.GetAllBalances(ctxCheck, addr.Bytes())))
}

func createApp(t *testing.T) (*minitiaapp.MinitiaApp, []common.Address, []*ecdsa.PrivateKey) {
addrs, privKeys := generateKeys(t, 2)
genAccs := authtypes.GenesisAccounts{}
for _, addr := range addrs {

genAccs = append(genAccs, &authtypes.BaseAccount{Address: sdk.AccAddress(addr.Bytes()).String()})
}

genBalances := []banktypes.Balance{}
for _, addr := range addrs {
genBalances = append(genBalances, banktypes.Balance{Address: sdk.AccAddress(addr.Bytes()).String(), Coins: genCoins})
}

app := minitiaapp.SetupWithGenesisAccounts(nil, genAccs, genBalances...)
for _, addr := range addrs {
checkBalance(t, app, addr, genCoins)
}

_, err := app.FinalizeBlock(&abci.RequestFinalizeBlock{Height: app.LastBlockHeight() + 1})
require.NoError(t, err)

app.Commit()

return app, addrs, privKeys
}

func setupIndexer(t *testing.T) (*minitiaapp.MinitiaApp, indexer.EVMIndexer, []common.Address, []*ecdsa.PrivateKey) {
app, addrs, privKeys := createApp(t)

db := dbm.NewMemDB()
indexer, err := indexer.NewEVMIndexer(db, app.AppCodec(), app.Logger(), app.TxConfig(), app.EVMKeeper)
require.NoError(t, err)

return app, indexer, addrs, privKeys
}
beer-1 marked this conversation as resolved.
Show resolved Hide resolved
44 changes: 44 additions & 0 deletions indexer/mempool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package indexer_test

import (
"sync"
"testing"

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/types/mempool"
)

func Test_Mempool_Subscribe(t *testing.T) {
app, indexer, _, privKeys := setupIndexer(t)
defer app.Close()

blockChan, logsChan, pendChan := indexer.Subscribe()
close(blockChan)
close(logsChan)

tx, evmTxHash := generateCreateERC20Tx(t, app, privKeys[0])

wg := sync.WaitGroup{}
wg.Add(1)
go func() {
pendingTx := <-pendChan
require.NotNil(t, pendingTx)
require.Equal(t, evmTxHash, pendingTx.Hash)
wg.Done()
}()

beer-1 marked this conversation as resolved.
Show resolved Hide resolved
noopMempool := &mempool.NoOpMempool{}
mempool := indexer.MempoolWrapper(noopMempool)

// insert tx into mempool
ctx, err := app.CreateQueryContext(0, false)
require.NoError(t, err)
err = mempool.Insert(ctx, tx)
require.NoError(t, err)

rpcTx := indexer.TxInMempool(evmTxHash)
require.Equal(t, evmTxHash, rpcTx.Hash)

wg.Wait()
}
2 changes: 1 addition & 1 deletion indexer/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (e *EVMIndexerImpl) IterateBlockTxs(ctx context.Context, blockHeight uint64
}

// IterateBlockTxs implements EVMIndexer.
func (e *EVMIndexerImpl) IterateBlockTxRecepts(ctx context.Context, blockHeight uint64, cb func(tx *coretypes.Receipt) (bool, error)) error {
func (e *EVMIndexerImpl) IterateBlockTxReceipts(ctx context.Context, blockHeight uint64, cb func(tx *coretypes.Receipt) (bool, error)) error {
return e.BlockAndIndexToTxHashMap.Walk(ctx, collections.NewPrefixedPairRange[uint64, uint64](blockHeight), func(key collections.Pair[uint64, uint64], txHashBz []byte) (bool, error) {
txHash := common.BytesToHash(txHashBz)
txRecept, err := e.TxReceiptByHash(ctx, txHash)
Expand Down
Loading
Loading