Skip to content

Commit

Permalink
add jsonrpc tests
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed Nov 26, 2024
1 parent 299b81e commit 28f152a
Show file tree
Hide file tree
Showing 31 changed files with 1,979 additions and 170 deletions.
1 change: 1 addition & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ ignore:
- "x/ibc/testing"
- "x/evm/contracts"
- "**/*.sol"
- "tests/"
7 changes: 7 additions & 0 deletions app/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ func (suite *AnteTestSuite) createTestApp(tempDir string) (*minievmapp.MinitiaAp
err = app.EVMKeeper.Params.Set(ctx, params)
suite.NoError(err)

err = app.EVMKeeper.Initialize(ctx)
suite.NoError(err)

return app, ctx
}

Expand Down Expand Up @@ -131,3 +134,7 @@ func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []
func TestAnteTestSuite(t *testing.T) {
suite.Run(t, new(AnteTestSuite))
}

func noopAnteHandler(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
return ctx, nil
}
27 changes: 15 additions & 12 deletions app/ante/fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

// feeDeductionGasAmount is a estimated gas amount of fee payment
const feeDeductionGasAmount = 250_000

// GasFreeFeeDecorator is a decorator that sets the gas meter to infinite before calling the inner DeductFeeDecorator
// and then resets the gas meter to the original value after the inner DeductFeeDecorator is called.
//
Expand All @@ -34,6 +31,9 @@ func NewGasFreeFeeDecorator(
}
}

// gasLimitForFeeDeduction is the gas limit used for fee deduction.
const gasLimitForFeeDeduction = 1_000_000

func (fd GasFreeFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
Expand All @@ -43,19 +43,22 @@ func (fd GasFreeFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
fees := feeTx.GetFee()
feeDenom, err := fd.ek.GetFeeDenom(ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()))
if !(err == nil && len(fees) == 1 && fees[0].Denom == feeDenom) {
if simulate && fees.IsZero() {
// Charge gas for fee deduction simulation
//
// At gas simulation normally gas amount is zero, so the gas is not charged in the simulation.
ctx.GasMeter().ConsumeGas(feeDeductionGasAmount, "fee deduction")
}

return fd.inner.AnteHandle(ctx, tx, simulate, next)
}

// If the fee contains only one denom and it is the fee denom, set the gas meter to infinite
// to avoid gas consumption for fee deduction.
gasMeter := ctx.GasMeter()
ctx, err = fd.inner.AnteHandle(ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()), tx, simulate, next)
return ctx.WithGasMeter(gasMeter), err
ctx, err = fd.inner.AnteHandle(ctx.WithGasMeter(storetypes.NewGasMeter(gasLimitForFeeDeduction)), tx, simulate, noopAnteHandler)
// restore the original gas meter
ctx = ctx.WithGasMeter(gasMeter)
if err != nil {
return ctx, err
}

return next(ctx, tx, simulate)
}

func noopAnteHandler(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
return ctx, nil
}
19 changes: 11 additions & 8 deletions app/ante/fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ func (suite *AnteTestSuite) Test_NotSpendingGasForTxWithFeeDenom() {
gasLimit := uint64(200_000)
atomFeeAmount := sdk.NewCoins(sdk.NewCoin("atom", math.NewInt(200)))

suite.app.EVMKeeper.ERC20Keeper().MintCoins(suite.ctx, addr1, feeAmount.MulInt(math.NewInt(10)))
suite.app.EVMKeeper.ERC20Keeper().MintCoins(suite.ctx, addr1, atomFeeAmount.MulInt(math.NewInt(10)))
err := suite.app.EVMKeeper.ERC20Keeper().MintCoins(suite.ctx, addr1, feeAmount.MulInt(math.NewInt(10)))
suite.Require().NoError(err)
err = suite.app.EVMKeeper.ERC20Keeper().MintCoins(suite.ctx, addr1, atomFeeAmount.MulInt(math.NewInt(10)))
suite.Require().NoError(err)

// Case 1. only fee denom
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
Expand All @@ -40,34 +42,35 @@ func (suite *AnteTestSuite) Test_NotSpendingGasForTxWithFeeDenom() {
suite.Require().NoError(err)

gasMeter := storetypes.NewGasMeter(500000)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, nil)
_, err = feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, noopAnteHandler)
suite.Require().NoError(err)
suite.Require().Zero(gasMeter.GasConsumed(), "should not consume gas for fee deduction")

// Case 2. fee denom and other denom
suite.txBuilder.SetFeeAmount(feeAmount.Add(atomFeeAmount...))

gasMeter = storetypes.NewGasMeter(500000)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, nil)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, noopAnteHandler)
suite.Require().NotZero(gasMeter.GasConsumed(), "should consume gas for fee deduction")

// Case 3. other denom
suite.txBuilder.SetFeeAmount(feeAmount.Add(atomFeeAmount...))

gasMeter = storetypes.NewGasMeter(500000)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, nil)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, noopAnteHandler)
suite.Require().NotZero(gasMeter.GasConsumed(), "should consume gas for fee deduction")

// Case 4. no fee
suite.txBuilder.SetFeeAmount(sdk.NewCoins())

gasMeter = storetypes.NewGasMeter(500000)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, nil)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, false, noopAnteHandler)
suite.Require().NotZero(gasMeter.GasConsumed(), "should consume gas for fee deduction")

// Case 5. simulate gas consumption
suite.txBuilder.SetFeeAmount(sdk.NewCoins())

gasMeter = storetypes.NewGasMeter(500000)
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, true, nil)
suite.Require().Greater(gasMeter.GasConsumed(), uint64(250000), "should consume gas for fee deduction")
feeAnte.AnteHandle(suite.ctx.WithGasMeter(gasMeter), tx, true, noopAnteHandler)
suite.Require().NotZero(gasMeter.GasConsumed(), "should consume gas for fee deduction")
}
15 changes: 8 additions & 7 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,18 +249,19 @@ func NewMinitiaApp(
}

// setup indexer
if evmIndexer, kvIndexerKeeper, kvIndexerModule, streamingManager, err := setupIndexer(app, appOpts, indexerDB, kvindexerDB); err != nil {
evmIndexer, kvIndexerKeeper, kvIndexerModule, streamingManager, err := setupIndexer(app, appOpts, indexerDB, kvindexerDB)
if err != nil {
tmos.Exit(err.Error())
} else if kvIndexerKeeper != nil && kvIndexerModule != nil && streamingManager != nil {
} else if kvIndexerKeeper != nil && kvIndexerModule != nil {
// register kvindexer keeper and module, and register services.
app.SetKVIndexer(kvIndexerKeeper, kvIndexerModule)
}

// register evm indexer
app.SetEVMIndexer(evmIndexer)
// register evm indexer
app.SetEVMIndexer(evmIndexer)

// override base-app's streaming manager
app.SetStreamingManager(*streamingManager)
}
// override base-app's streaming manager
app.SetStreamingManager(*streamingManager)

// register upgrade handler for later use
app.RegisterUpgradeHandlers(app.configurator)
Expand Down
3 changes: 0 additions & 3 deletions app/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,4 @@ const (
moveMsgPublishModuleBundle = "/initia.move.v1.MsgPublish"
moveMsgExecuteEntryFunction = "/initia.move.v1.MsgExecute"
moveMsgExecuteScript = "/initia.move.v1.MsgScript"

// UpgradeName gov proposal name
UpgradeName = "0.0.0"
)
78 changes: 31 additions & 47 deletions indexer/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import (

"github.com/stretchr/testify/require"

storetypes "cosmossdk.io/store/types"

"github.com/initia-labs/minievm/tests"
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)
app, addrs, privKeys := tests.CreateApp(t)
indexer := app.EVMIndexer()
defer app.Close()

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

events := finalizeRes.TxResults[0].Events
createEvent := events[len(events)-3]
Expand All @@ -35,26 +35,20 @@ func Test_ListenFinalizeBlock(t *testing.T) {
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)
tx, evmTxHash = tests.GenerateMintERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[0], new(big.Int).SetUint64(1_000_000_000_000))
finalizeReq, finalizeRes := tests.ExecuteTxs(t, app, tx)
tests.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)
Expand All @@ -69,66 +63,60 @@ func Test_ListenFinalizeBlock(t *testing.T) {
}

func Test_ListenFinalizeBlock_Subscribe(t *testing.T) {
app, indexer, _, privKeys := setupIndexer(t)
app, _, privKeys := tests.CreateApp(t)
indexer := app.EVMIndexer()
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)
tx, evmTxHash := tests.GenerateCreateERC20Tx(t, app, privKeys[0])

reqHeight := app.LastBlockHeight() + 1
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())
require.Equal(t, reqHeight, 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()
}
require.Equal(t, evmTxHash, log.TxHash)
require.Equal(t, uint64(reqHeight), log.BlockNumber)
}

wg.Done()
case <-time.After(10 * time.Second):
t.Error("timeout waiting for pending transaction")
wg.Done()
}
}
}()

err = indexer.ListenFinalizeBlock(ctx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()), *finalizeReq, *finalizeRes)
require.NoError(t, err)
finalizeReq, finalizeRes := tests.ExecuteTxs(t, app, tx)
require.Equal(t, reqHeight, finalizeReq.Height)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

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

wg.Wait()
}

func Test_ListenFinalizeBlock_ContractCreation(t *testing.T) {
app, indexer, _, privKeys := setupIndexer(t)
app, _, privKeys := tests.CreateApp(t)
indexer := app.EVMIndexer()
defer app.Close()

tx, evmTxHash := generateCreateInitiaERC20Tx(t, app, privKeys[0])
finalizeReq, finalizeRes := executeTxs(t, app, tx)
checkTxResult(t, finalizeRes.TxResults[0], true)
tx, evmTxHash := tests.GenerateCreateInitiaERC20Tx(t, app, privKeys[0])
_, finalizeRes := tests.ExecuteTxs(t, app, tx)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

events := finalizeRes.TxResults[0].Events
createEvent := events[len(events)-3]
Expand All @@ -137,14 +125,10 @@ func Test_ListenFinalizeBlock_ContractCreation(t *testing.T) {
contractAddr, err := hexutil.Decode(createEvent.Attributes[0].Value)
require.NoError(t, err)

// listen finalize block
// check the tx is indexed
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
receipt, err := indexer.TxReceiptByHash(ctx, evmTxHash)
require.NoError(t, err)
require.NotNil(t, receipt)
Expand Down
14 changes: 8 additions & 6 deletions indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,25 +162,27 @@ type blockEvents struct {

// blockEventsEmitter emits block events to subscribers.
func (e *EVMIndexerImpl) blockEventsEmitter(blockEvents *blockEvents, done chan struct{}) {
defer close(done)
if blockEvents == nil {
return
}

// emit logs first; use unbuffered channel to ensure logs are emitted before block header
for _, logs := range blockEvents.logs {
for _, logsChan := range e.logsChans {
logsChan <- logs
}
}
for _, logsChan := range e.logsChans {
logsChan <- []*coretypes.Log{}
}

// emit block header
for _, blockChan := range e.blockChans {
blockChan <- blockEvents.header
}

close(done)
}

// Stop stops the indexer.
func (e *EVMIndexerImpl) Stop() {
e.txPendingMap.Stop()
if e.txPendingMap != nil {
e.txPendingMap.Stop()
}
}
5 changes: 5 additions & 0 deletions indexer/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,8 @@ func (m *MempoolWrapper) Remove(tx sdk.Tx) error {
func (m *MempoolWrapper) Select(ctx context.Context, txs [][]byte) mempool.Iterator {
return m.mempool.Select(ctx, txs)
}

// Inner returns the inner mempool.
func (m *MempoolWrapper) Inner() mempool.Mempool {
return m.mempool
}
6 changes: 4 additions & 2 deletions indexer/mempool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ import (
"testing"
"time"

"github.com/initia-labs/minievm/tests"
"github.com/stretchr/testify/require"

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

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

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

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

wg := sync.WaitGroup{}
wg.Add(1)
Expand Down
Loading

0 comments on commit 28f152a

Please sign in to comment.