Skip to content

Commit

Permalink
add filter test
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed Nov 27, 2024
1 parent 71a14bd commit 7f81b42
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 0 deletions.
64 changes: 64 additions & 0 deletions jsonrpc/backend/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package backend_test
import (
"context"
"crypto/ecdsa"
"math/big"
"sync"
"testing"
"time"

"github.com/stretchr/testify/require"

Expand All @@ -12,12 +15,15 @@ import (
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

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

minitiaapp "github.com/initia-labs/minievm/app"
"github.com/initia-labs/minievm/indexer"
"github.com/initia-labs/minievm/jsonrpc/backend"
"github.com/initia-labs/minievm/jsonrpc/config"
"github.com/initia-labs/minievm/tests"
evmtypes "github.com/initia-labs/minievm/x/evm/types"
)

type testInput struct {
Expand Down Expand Up @@ -59,3 +65,61 @@ func setupBackend(t *testing.T) testInput {
cometRPC: mockCometRPC,
}
}

func Test_FloodingQuery(t *testing.T) {
input := setupBackend(t)
app, _, backend, addrs, privKeys := input.app, input.addrs, input.backend, input.addrs, input.privKeys

tx, _ := 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]
require.Equal(t, evmtypes.EventTypeContractCreated, createEvent.GetType())

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

// mint 1_000_000 tokens to the first address
tx, _ = tests.GenerateMintERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[0], new(big.Int).SetUint64(1_000_000_000_000))
_, finalizeRes = tests.ExecuteTxs(t, app, tx)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

time.Sleep(3 * time.Second)

ctx, cancel := context.WithCancel(context.Background())
queryFn := func() {
for {
select {
case <-ctx.Done():
return
default:
_, err := backend.GetBalance(addrs[0], rpc.BlockNumberOrHashWithNumber(-1))
require.NoError(t, err)

time.Sleep(5 * time.Millisecond)
}
}
}

for i := 0; i < 100; i++ {
go queryFn()
}

wg := sync.WaitGroup{}
wg.Add(1)
go func() {
for i := 0; i < 1000; i++ {
tx, _ = tests.GenerateTransferERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[1], new(big.Int).SetUint64(1_000_000))
_, finalizeRes = tests.ExecuteTxs(t, app, tx)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

time.Sleep(5 * time.Millisecond)
}
wg.Done()
}()

wg.Wait()
cancel()
}
3 changes: 3 additions & 0 deletions jsonrpc/namespaces/eth/filters/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package filters
import (
"context"
"errors"
"fmt"
"sync"
"time"

Expand Down Expand Up @@ -339,7 +340,9 @@ func (api *FilterAPI) NewFilter(crit ethfilters.FilterCriteria) (rpc.ID, error)
for {
select {
case logs := <-logsChan:
fmt.Println(logs)
logs = filterLogs(logs, s.crit.FromBlock, s.crit.ToBlock, s.crit.Addresses, s.crit.Topics)
fmt.Println(logs)
api.filtersMut.Lock()
if f, found := api.filters[id]; found {
f.logs = append(f.logs, logs...)
Expand Down
213 changes: 213 additions & 0 deletions jsonrpc/namespaces/eth/filters/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package filters_test
import (
"context"
"crypto/ecdsa"
"math/big"
"testing"
"time"

Expand All @@ -13,13 +14,19 @@ import (
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
coretypes "github.com/ethereum/go-ethereum/core/types"
ethfilters "github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/rpc"

minitiaapp "github.com/initia-labs/minievm/app"
"github.com/initia-labs/minievm/indexer"
"github.com/initia-labs/minievm/jsonrpc/backend"
"github.com/initia-labs/minievm/jsonrpc/config"
"github.com/initia-labs/minievm/jsonrpc/namespaces/eth/filters"
rpctypes "github.com/initia-labs/minievm/jsonrpc/types"
"github.com/initia-labs/minievm/tests"
evmtypes "github.com/initia-labs/minievm/x/evm/types"
)

type testInput struct {
Expand Down Expand Up @@ -67,6 +74,79 @@ func setupFilterAPI(t *testing.T) testInput {
}
}

func Test_NewPendingTransactionFilter_FullTx(t *testing.T) {
input := setupFilterAPI(t)
defer input.app.Close()

fullTx := true
filterID, err := input.filterAPI.NewPendingTransactionFilter(&fullTx)
require.NoError(t, err)
require.NotEmpty(t, filterID)

app, backend, addrs, privKeys := input.app, input.backend, input.addrs, input.privKeys

ctx, err := app.CreateQueryContext(0, false)
require.NoError(t, err)

tx, _ := tests.GenerateCreateERC20Tx(t, app, privKeys[0])
evmTx, _, err := app.EVMKeeper.TxUtils().ConvertCosmosTxToEthereumTx(ctx, tx)
require.NoError(t, err)

txBz, err := evmTx.MarshalBinary()
require.NoError(t, err)
txHash1, err := backend.SendRawTransaction(txBz)
require.NoError(t, err)

_, finalizeRes := tests.ExecuteTxs(t, app, tx)
tests.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)

// mint 1_000_000 tokens to the first address
tx2, _ := tests.GenerateMintERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[0], new(big.Int).SetUint64(1_000_000_000_000))
evmTx2, _, err := app.EVMKeeper.TxUtils().ConvertCosmosTxToEthereumTx(ctx, tx2)
require.NoError(t, err)

txBz, err = evmTx2.MarshalBinary()
require.NoError(t, err)
txHash2, err := backend.SendRawTransaction(txBz)
require.NoError(t, err)

_, finalizeRes = tests.ExecuteTxs(t, app, tx2)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

rpcTx1, err := backend.GetTransactionByHash(txHash1)
require.NoError(t, err)
rpcTx2, err := backend.GetTransactionByHash(txHash2)
require.NoError(t, err)

// there should be 2 changes
changes, err := input.filterAPI.GetFilterChanges(filterID)
require.NoError(t, err)
require.Len(t, changes, 2)

// to compare with pending tx filter, we need to remove block hash, block number, and transaction index
rpcTx1.BlockHash = nil
rpcTx1.BlockNumber = nil
rpcTx1.TransactionIndex = nil
rpcTx2.BlockHash = nil
rpcTx2.BlockNumber = nil
rpcTx2.TransactionIndex = nil

res := []string{}
for i := 0; i < 2; i++ {
rpcTx := changes.([]*rpctypes.RPCTransaction)[i]
res = append(res, rpcTx.String())
}

require.Equal(t, []string{rpcTx1.String(), rpcTx2.String()}, res)
}

func Test_NewPendingTransactionFilter(t *testing.T) {
input := setupFilterAPI(t)
defer input.app.Close()
Expand All @@ -75,4 +155,137 @@ func Test_NewPendingTransactionFilter(t *testing.T) {
filterID, err := input.filterAPI.NewPendingTransactionFilter(&fullTx)
require.NoError(t, err)
require.NotEmpty(t, filterID)

app, backend, addrs, privKeys := input.app, input.backend, input.addrs, input.privKeys

ctx, err := app.CreateQueryContext(0, false)
require.NoError(t, err)

tx, _ := tests.GenerateCreateERC20Tx(t, app, privKeys[0])
evmTx, _, err := app.EVMKeeper.TxUtils().ConvertCosmosTxToEthereumTx(ctx, tx)
require.NoError(t, err)

txBz, err := evmTx.MarshalBinary()
require.NoError(t, err)
txHash1, err := backend.SendRawTransaction(txBz)
require.NoError(t, err)

_, finalizeRes := tests.ExecuteTxs(t, app, tx)
tests.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)

// mint 1_000_000 tokens to the first address
tx2, _ := tests.GenerateMintERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[0], new(big.Int).SetUint64(1_000_000_000_000))
evmTx2, _, err := app.EVMKeeper.TxUtils().ConvertCosmosTxToEthereumTx(ctx, tx2)
require.NoError(t, err)

txBz, err = evmTx2.MarshalBinary()
require.NoError(t, err)
txHash2, err := backend.SendRawTransaction(txBz)
require.NoError(t, err)

_, finalizeRes = tests.ExecuteTxs(t, app, tx2)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

// there should be 2 changes
changes, err := input.filterAPI.GetFilterChanges(filterID)
require.NoError(t, err)
require.Len(t, changes, 2)
require.Equal(t, []common.Hash{txHash1, txHash2}, changes.([]common.Hash))
}

func Test_NewBlockFilter(t *testing.T) {
input := setupFilterAPI(t)
defer input.app.Close()

filterID, err := input.filterAPI.NewBlockFilter()
require.NoError(t, err)
require.NotEmpty(t, filterID)

app, backend, addrs, privKeys := input.app, input.backend, input.addrs, input.privKeys

tx, _ := 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]
require.Equal(t, evmtypes.EventTypeContractCreated, createEvent.GetType())

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

// mint 1_000_000 tokens to the first address
tx2, _ := tests.GenerateMintERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[0], new(big.Int).SetUint64(1_000_000_000_000))
_, finalizeRes = tests.ExecuteTxs(t, app, tx2)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

// there should be 2 changes
changes, err := input.filterAPI.GetFilterChanges(filterID)
require.NoError(t, err)
require.Len(t, changes, 2)

blockHash := changes.([]common.Hash)[0]
header, err := backend.GetHeaderByHash(blockHash)
require.NoError(t, err)
require.Equal(t, app.LastBlockHeight()-1, header.Number.Int64())

blockHash = changes.([]common.Hash)[1]
header, err = backend.GetHeaderByHash(blockHash)
require.NoError(t, err)
require.Equal(t, app.LastBlockHeight(), header.Number.Int64())
}

func Test_NewFilter(t *testing.T) {
input := setupFilterAPI(t)
defer input.app.Close()

app, addrs, privKeys := input.app, input.addrs, input.privKeys

// invalid block range
_, err := input.filterAPI.NewFilter(ethfilters.FilterCriteria{
FromBlock: big.NewInt(100),
ToBlock: big.NewInt(10),
})
require.Error(t, err)

// start tracking after 2 blocks
filterID, err := input.filterAPI.NewFilter(ethfilters.FilterCriteria{
FromBlock: big.NewInt(app.LastBlockHeight() + 2),
ToBlock: big.NewInt(int64(rpc.LatestBlockNumber)),
})
require.NoError(t, err)
require.NotEmpty(t, filterID)

// this should not tracked
tx, _ := 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]
require.Equal(t, evmtypes.EventTypeContractCreated, createEvent.GetType())

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

// this should be tracked
// mint 1_000_000 tokens to the first address
tx2, txHash2 := tests.GenerateMintERC20Tx(t, app, privKeys[0], common.BytesToAddress(contractAddr), addrs[0], new(big.Int).SetUint64(1_000_000_000_000))
_, finalizeRes = tests.ExecuteTxs(t, app, tx2)
tests.CheckTxResult(t, finalizeRes.TxResults[0], true)

changes, err := input.filterAPI.GetFilterChanges(filterID)
require.NoError(t, err)
require.NotEmpty(t, changes)
for _, change := range changes.([]*coretypes.Log) {
require.Equal(t, txHash2, change.TxHash)
t.Logf("%v", change)
}
}
8 changes: 8 additions & 0 deletions jsonrpc/types/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package types
import (
"math/big"

"gopkg.in/yaml.v3"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
coretypes "github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -133,3 +135,9 @@ func (rpcTx RPCTransaction) ToTransaction() *coretypes.Transaction {
return nil
}
}

// String implements the fmt.Stringer interface
func (rpcTx RPCTransaction) String() string {
yamlBytes, _ := yaml.Marshal(rpcTx)
return string(yamlBytes)
}
2 changes: 2 additions & 0 deletions jsonrpc/types/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ func TestDynamicFeeTxTypeRPCTransaction(t *testing.T) {

err = matchTx(signedTx, ethTx)
require.NoError(t, err)

_ = rpcTx.String()
}

func matchTx(signedTx *coretypes.Transaction, ethTx *coretypes.Transaction) error {
Expand Down

0 comments on commit 7f81b42

Please sign in to comment.