Skip to content

Synthetic events in separate sei endpoints #1867

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

Merged
merged 14 commits into from
Sep 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions contracts/test/CW20toERC20PointerTest.js
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ const {getAdmin, queryWasm, executeWasm, associateWasm, deployEvmContract, setup
proposeCW20toERC20Upgrade
} = require("./lib");
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("CW20 to ERC20 Pointer", function () {
let accounts;
@@ -102,18 +103,24 @@ describe("CW20 to ERC20 Pointer", function () {
const txHash = res["txhash"];
const receipt = await ethers.provider.getTransactionReceipt(`0x${txHash}`);
expect(receipt).not.to.be.null;
console.log("receipt[\"blockNumber\"]", receipt["blockNumber"]);
const bn = receipt["blockNumber"];
const filter = {
fromBlock: receipt["blockNumber"],
fromBlock: '0x' + bn.toString(16),
toBlock: 'latest',
address: receipt["to"],
topics: [ethers.id("Transfer(address,address,uint256)")]
};
const logs = await ethers.provider.getLogs(filter);
expect(logs.length).to.equal(1);
expect(logs[0]["topics"][0]).to.equal(ethers.id("Transfer(address,address,uint256)"));
// send via eth_ endpoint - synthetic event doesn't show up
const ethlogs = await ethers.provider.send('eth_getLogs', [filter]);
expect(ethlogs.length).to.equal(0);

// send via sei_ endpoint - synthetic event shows up
const seilogs = await ethers.provider.send('sei_getLogs', [filter]);
expect(seilogs.length).to.equal(1);
expect(seilogs[0]["topics"][0]).to.equal(ethers.id("Transfer(address,address,uint256)"));
const respAfter = await queryWasm(pointer, "balance", {address: accounts[1].seiAddress});
const balanceAfter = respAfter.data.balance;

expect(balanceAfter).to.equal((parseInt(balanceBefore) + 100).toString());
});

39 changes: 25 additions & 14 deletions contracts/test/ERC20toCW20PointerTest.js
Original file line number Diff line number Diff line change
@@ -102,17 +102,23 @@ describe("ERC20 to CW20 Pointer", function () {

// check logs
const filter = {
fromBlock: blockNumber,
fromBlock: '0x' + blockNumber.toString(16),
toBlock: 'latest',
address: await pointer.getAddress(),
topics: [ethers.id("Transfer(address,address,uint256)")]
};
const logs = await ethers.provider.getLogs(filter);
expect(logs.length).to.equal(1);
expect(logs[0]["address"]).to.equal(await pointer.getAddress());
expect(logs[0]["topics"][0]).to.equal(ethers.id("Transfer(address,address,uint256)"));
expect(logs[0]["topics"][1].substring(26)).to.equal(sender.evmAddress.substring(2).toLowerCase());
expect(logs[0]["topics"][2].substring(26)).to.equal(recipient.evmAddress.substring(2).toLowerCase());
// send via eth_ endpoint - synthetic event doesn't show up
const ethlogs = await ethers.provider.send('eth_getLogs', [filter]);
expect(ethlogs.length).to.equal(0);

// send via sei_ endpoint - synthetic event shows up
const seilogs = await ethers.provider.send('sei_getLogs', [filter]);
expect(seilogs.length).to.equal(1);
expect(seilogs.length).to.equal(1);
expect(seilogs[0]["address"].toLowerCase()).to.equal((await pointer.getAddress()).toLowerCase());
expect(seilogs[0]["topics"][0]).to.equal(ethers.id("Transfer(address,address,uint256)"));
expect(seilogs[0]["topics"][1].substring(26)).to.equal(sender.evmAddress.substring(2).toLowerCase());
expect(seilogs[0]["topics"][2].substring(26)).to.equal(recipient.evmAddress.substring(2).toLowerCase());

const cleanupTx = await pointer.connect(recipient.signer).transfer(sender.evmAddress, 1);
await cleanupTx.wait();
@@ -147,17 +153,22 @@ describe("ERC20 to CW20 Pointer", function () {

// check logs
const filter = {
fromBlock: blockNumber,
fromBlock: '0x' + blockNumber.toString(16),
toBlock: 'latest',
address: await pointer.getAddress(),
topics: [ethers.id("Approval(address,address,uint256)")]
};
const logs = await ethers.provider.getLogs(filter);
expect(logs.length).to.equal(1);
expect(logs[0]["address"]).to.equal(await pointer.getAddress());
expect(logs[0]["topics"][0]).to.equal(ethers.id("Approval(address,address,uint256)"));
expect(logs[0]["topics"][1].substring(26)).to.equal(owner.substring(2).toLowerCase());
expect(logs[0]["topics"][2].substring(26)).to.equal(spender.substring(2).toLowerCase());
// send via eth_ endpoint - synthetic event doesn't show up
const ethlogs = await ethers.provider.send('eth_getLogs', [filter]);
expect(ethlogs.length).to.equal(0);

// send via sei_ endpoint - synthetic event shows up
const seilogs = await ethers.provider.send('sei_getLogs', [filter]);
expect(seilogs.length).to.equal(1);
expect(seilogs[0]["address"].toLowerCase()).to.equal((await pointer.getAddress()).toLowerCase());
expect(seilogs[0]["topics"][0]).to.equal(ethers.id("Approval(address,address,uint256)"));
expect(seilogs[0]["topics"][1].substring(26)).to.equal(owner.substring(2).toLowerCase());
expect(seilogs[0]["topics"][2].substring(26)).to.equal(spender.substring(2).toLowerCase());
});

it("should lower approval", async function () {
37 changes: 23 additions & 14 deletions contracts/test/ERC721toCW721PointerTest.js
Original file line number Diff line number Diff line change
@@ -89,17 +89,22 @@ describe("ERC721 to CW721 Pointer", function () {
expect(approved).to.equal(accounts[1].evmAddress);

const filter = {
fromBlock: blockNumber,
fromBlock: '0x' + blockNumber.toString(16),
toBlock: 'latest',
address: await pointerAcc1.getAddress(),
topics: [ethers.id("Approval(address,address,uint256)")]
};
const logs = await ethers.provider.getLogs(filter);
expect(logs.length).to.equal(1);
expect(logs[0]["address"]).to.equal(await pointerAcc1.getAddress());
expect(logs[0]["topics"][0]).to.equal(ethers.id("Approval(address,address,uint256)"));
expect(logs[0]["topics"][1].substring(26)).to.equal(accounts[0].evmAddress.substring(2).toLowerCase());
expect(logs[0]["topics"][2].substring(26)).to.equal(accounts[1].evmAddress.substring(2).toLowerCase());
// send via eth_ endpoint - synthetic event doesn't show up
const ethlogs = await ethers.provider.send('eth_getLogs', [filter]);
expect(ethlogs.length).to.equal(0);

// send via sei_ endpoint - synthetic event shows up
const seilogs = await ethers.provider.send('sei_getLogs', [filter]);
expect(seilogs.length).to.equal(1);
expect(seilogs[0]["address"].toLowerCase()).to.equal((await pointerAcc1.getAddress()).toLowerCase());
expect(seilogs[0]["topics"][0]).to.equal(ethers.id("Approval(address,address,uint256)"));
expect(seilogs[0]["topics"][1].substring(26)).to.equal(accounts[0].evmAddress.substring(2).toLowerCase());
expect(seilogs[0]["topics"][2].substring(26)).to.equal(accounts[1].evmAddress.substring(2).toLowerCase());
});

it("cannot approve token you don't own", async function () {
@@ -113,17 +118,21 @@ describe("ERC721 to CW721 Pointer", function () {
transferTxResp = await pointerAcc1.transferFrom(accounts[0].evmAddress, accounts[1].evmAddress, 2);
await transferTxResp.wait();
const filter = {
fromBlock: blockNumber,
fromBlock: '0x' + blockNumber.toString(16),
toBlock: 'latest',
address: await pointerAcc1.getAddress(),
topics: [ethers.id("Transfer(address,address,uint256)")]
};
const logs = await ethers.provider.getLogs(filter);
expect(logs.length).to.equal(1);
expect(logs[0]["address"]).to.equal(await pointerAcc1.getAddress());
expect(logs[0]["topics"][0]).to.equal(ethers.id("Transfer(address,address,uint256)"));
expect(logs[0]["topics"][1].substring(26)).to.equal(accounts[1].evmAddress.substring(2).toLowerCase());
expect(logs[0]["topics"][2].substring(26)).to.equal(accounts[1].evmAddress.substring(2).toLowerCase());
// send via eth_ endpoint - synthetic event doesn't show up
const ethlogs = await ethers.provider.send('eth_getLogs', [filter]);
expect(ethlogs.length).to.equal(0);

const seilogs = await ethers.provider.send('sei_getLogs', [filter]);
expect(seilogs.length).to.equal(1);
expect(seilogs[0]["address"].toLowerCase()).to.equal((await pointerAcc1.getAddress()).toLowerCase());
expect(seilogs[0]["topics"][0]).to.equal(ethers.id("Transfer(address,address,uint256)"));
expect(seilogs[0]["topics"][1].substring(26)).to.equal(accounts[1].evmAddress.substring(2).toLowerCase());
expect(seilogs[0]["topics"][2].substring(26)).to.equal(accounts[1].evmAddress.substring(2).toLowerCase());
const balance0 = await pointerAcc0.balanceOf(accounts[0].evmAddress);
expect(balance0).to.equal(0);
const balance1 = await pointerAcc0.balanceOf(accounts[1].evmAddress);
102 changes: 87 additions & 15 deletions evmrpc/block.go
Original file line number Diff line number Diff line change
@@ -2,12 +2,15 @@

import (
"context"
"crypto/sha256"
"errors"
"fmt"
"math/big"
"strings"
"sync"
"time"

wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
@@ -23,20 +26,22 @@
)

type BlockAPI struct {
tmClient rpcclient.Client
keeper *keeper.Keeper
ctxProvider func(int64) sdk.Context
txConfig client.TxConfig
connectionType ConnectionType
tmClient rpcclient.Client
keeper *keeper.Keeper
ctxProvider func(int64) sdk.Context
txConfig client.TxConfig
connectionType ConnectionType
namespace string
includeSyntheticTxs bool
}

func NewBlockAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txConfig client.TxConfig, connectionType ConnectionType) *BlockAPI {
return &BlockAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txConfig: txConfig, connectionType: connectionType}
func NewBlockAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txConfig client.TxConfig, connectionType ConnectionType, namespace string) *BlockAPI {
return &BlockAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txConfig: txConfig, connectionType: connectionType, includeSyntheticTxs: shouldIncludeSynthetic(namespace)}
}

func (a *BlockAPI) GetBlockTransactionCountByNumber(ctx context.Context, number rpc.BlockNumber) (result *hexutil.Uint, returnErr error) {
startTime := time.Now()
defer recordMetrics("eth_getBlockTransactionCountByNumber", a.connectionType, startTime, returnErr == nil)
defer recordMetrics(fmt.Sprintf("%s_getBlockTransactionCountByNumber", a.namespace), a.connectionType, startTime, returnErr == nil)
numberPtr, err := getBlockNumber(ctx, a.tmClient, number)
if err != nil {
return nil, err
@@ -50,7 +55,7 @@

func (a *BlockAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) (result *hexutil.Uint, returnErr error) {
startTime := time.Now()
defer recordMetrics("eth_getBlockTransactionCountByHash", a.connectionType, startTime, returnErr == nil)
defer recordMetrics(fmt.Sprintf("%s_getBlockTransactionCountByHash", a.namespace), a.connectionType, startTime, returnErr == nil)
block, err := blockByHashWithRetry(ctx, a.tmClient, blockHash[:], 1)
if err != nil {
return nil, err
@@ -60,7 +65,11 @@

func (a *BlockAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (result map[string]interface{}, returnErr error) {
startTime := time.Now()
defer recordMetrics("eth_getBlockByHash", a.connectionType, startTime, returnErr == nil)
defer recordMetrics(fmt.Sprintf("%s_getBlockByHash", a.namespace), a.connectionType, startTime, returnErr == nil)
return a.getBlockByHash(ctx, blockHash, fullTx)
}

func (a *BlockAPI) getBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (result map[string]interface{}, returnErr error) {
block, err := blockByHashWithRetry(ctx, a.tmClient, blockHash[:], 1)
if err != nil {
return nil, err
@@ -70,12 +79,41 @@
return nil, err
}
blockBloom := a.keeper.GetBlockBloom(a.ctxProvider(block.Block.Height))
return EncodeTmBlock(a.ctxProvider(LatestCtxHeight), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx)
return EncodeTmBlock(a.ctxProvider(LatestCtxHeight), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx, a.includeSyntheticTxs)
}

func (a *BlockAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (result map[string]interface{}, returnErr error) {
startTime := time.Now()
defer recordMetrics("eth_getBlockByNumber", a.connectionType, startTime, returnErr == nil)
defer recordMetrics(fmt.Sprintf("%s_getBlockByNumber", a.namespace), a.connectionType, startTime, returnErr == nil)
if number == 0 {
// for compatibility with the graph, always return genesis block
return map[string]interface{}{
"number": (*hexutil.Big)(big.NewInt(0)),
"hash": common.HexToHash("F9D3845DF25B43B1C6926F3CEDA6845C17F5624E12212FD8847D0BA01DA1AB9E"),
"parentHash": common.Hash{},
"nonce": ethtypes.BlockNonce{}, // inapplicable to Sei
"mixHash": common.Hash{}, // inapplicable to Sei
"sha3Uncles": ethtypes.EmptyUncleHash, // inapplicable to Sei
"logsBloom": ethtypes.Bloom{},
"stateRoot": common.Hash{},
"miner": common.Address{},
"difficulty": (*hexutil.Big)(big.NewInt(0)), // inapplicable to Sei
"extraData": hexutil.Bytes{}, // inapplicable to Sei
"gasLimit": hexutil.Uint64(0),
"gasUsed": hexutil.Uint64(0),
"timestamp": hexutil.Uint64(0),
"transactionsRoot": common.Hash{},
"receiptsRoot": common.Hash{},
"size": hexutil.Uint64(0),
"uncles": []common.Hash{}, // inapplicable to Sei
"transactions": []interface{}{},
"baseFeePerGas": (*hexutil.Big)(big.NewInt(0)),
}, nil
}
return a.getBlockByNumber(ctx, number, fullTx)
}

func (a *BlockAPI) getBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (result map[string]interface{}, returnErr error) {
numberPtr, err := getBlockNumber(ctx, a.tmClient, number)
if err != nil {
return nil, err
@@ -89,12 +127,12 @@
return nil, err
}
blockBloom := a.keeper.GetBlockBloom(a.ctxProvider(block.Block.Height))
return EncodeTmBlock(a.ctxProvider(LatestCtxHeight), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx)
return EncodeTmBlock(a.ctxProvider(LatestCtxHeight), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx, a.includeSyntheticTxs)
}

func (a *BlockAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (result []map[string]interface{}, returnErr error) {
startTime := time.Now()
defer recordMetrics("eth_getBlockReceipts", a.connectionType, startTime, returnErr == nil)
defer recordMetrics(fmt.Sprintf("%s_getBlockReceipts", a.namespace), a.connectionType, startTime, returnErr == nil)
// Get height from params
heightPtr, err := GetBlockNumberByNrOrHash(ctx, a.tmClient, blockNrOrHash)
if err != nil {
@@ -130,6 +168,9 @@
mtx.Unlock()
}
} else {
if !a.includeSyntheticTxs && len(receipt.Logs) > 0 && receipt.Logs[0].Synthetic {
return
}
encodedReceipt, err := encodeReceipt(receipt, a.txConfig.TxDecoder(), block, func(h common.Hash) bool {
_, err := a.keeper.GetReceipt(a.ctxProvider(height), h)
return err == nil
@@ -144,10 +185,16 @@
}(i, hash)
}
wg.Wait()
compactReceipts := make([]map[string]interface{}, 0)
for _, r := range allReceipts {
if len(r) > 0 {
compactReceipts = append(compactReceipts, r)
}
}
if returnErr != nil {
return nil, returnErr
}
return allReceipts, nil
return compactReceipts, nil
}

func EncodeTmBlock(
@@ -158,6 +205,7 @@
k *keeper.Keeper,
txDecoder sdk.TxDecoder,
fullTx bool,
includeSyntheticTxs bool,
) (map[string]interface{}, error) {
number := big.NewInt(block.Block.Height)
blockhash := common.HexToHash(block.BlockID.Hash.String())
@@ -196,6 +244,30 @@
newTx := ethapi.NewRPCTransaction(ethtx, blockhash, number.Uint64(), uint64(blockTime.Second()), uint64(receipt.TransactionIndex), baseFeePerGas, chainConfig)
transactions = append(transactions, newTx)
}
case *wasmtypes.MsgExecuteContract:
if !includeSyntheticTxs {
continue

Check warning on line 249 in evmrpc/block.go

Codecov / codecov/patch

evmrpc/block.go#L249

Added line #L249 was not covered by tests
}
th := sha256.Sum256(block.Block.Txs[i])
receipt, err := k.GetReceipt(ctx, th)
if err != nil {
continue

Check warning on line 254 in evmrpc/block.go

Codecov / codecov/patch

evmrpc/block.go#L254

Added line #L254 was not covered by tests
}
if !fullTx {
transactions = append(transactions, th)

Check warning on line 257 in evmrpc/block.go

Codecov / codecov/patch

evmrpc/block.go#L257

Added line #L257 was not covered by tests
} else {
ti := uint64(receipt.TransactionIndex)
to := k.GetEVMAddressOrDefault(ctx, sdk.MustAccAddressFromBech32(m.Contract))
transactions = append(transactions, &ethapi.RPCTransaction{
BlockHash: &blockhash,
BlockNumber: (*hexutil.Big)(number),
From: common.HexToAddress(receipt.From),
To: &to,
Input: m.Msg.Bytes(),
Hash: th,
TransactionIndex: (*hexutil.Uint64)(&ti),
})
}
}
}
}
121 changes: 117 additions & 4 deletions evmrpc/block_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package evmrpc_test

import (
"crypto/sha256"
"math/big"
"testing"
"time"

wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
types2 "github.com/tendermint/tendermint/proto/tendermint/types"

sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/lib/ethapi"
"github.com/sei-protocol/sei-chain/evmrpc"
testkeeper "github.com/sei-protocol/sei-chain/testutil/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/rpc/coretypes"
@@ -22,8 +29,15 @@ func TestGetBlockByHash(t *testing.T) {
verifyBlockResult(t, resObj)
}

func TestGetSeiBlockByHash(t *testing.T) {
resObj := sendSeiRequestGood(t, "getBlockByHash", "0x0000000000000000000000000000000000000000000000000000000000000001", true)
verifyBlockResult(t, resObj)
}

func TestGetBlockByNumber(t *testing.T) {
for _, num := range []string{"0x8", "earliest", "latest", "pending", "finalized", "safe"} {
resObjEarliest := sendSeiRequestGood(t, "getBlockByNumber", "earliest", true)
verifyGenesisBlockResult(t, resObjEarliest)
for _, num := range []string{"0x8", "latest", "pending", "finalized", "safe"} {
resObj := sendRequestGood(t, "getBlockByNumber", num, true)
verifyBlockResult(t, resObj)
}
@@ -32,6 +46,18 @@ func TestGetBlockByNumber(t *testing.T) {
require.Equal(t, "invalid argument 0: hex string without 0x prefix", resObj["error"].(map[string]interface{})["message"])
}

func TestGetSeiBlockByNumber(t *testing.T) {
resObjEarliest := sendSeiRequestGood(t, "getBlockByNumber", "earliest", true)
verifyGenesisBlockResult(t, resObjEarliest)
for _, num := range []string{"0x8", "latest", "pending", "finalized", "safe"} {
resObj := sendSeiRequestGood(t, "getBlockByNumber", num, true)
verifyBlockResult(t, resObj)
}

resObj := sendSeiRequestBad(t, "getBlockByNumber", "bad_num", true)
require.Equal(t, "invalid argument 0: hex string without 0x prefix", resObj["error"].(map[string]interface{})["message"])
}

func TestGetBlockTransactionCount(t *testing.T) {
// get by block number
for _, num := range []string{"0x8", "earliest", "latest", "pending", "finalized", "safe"} {
@@ -95,6 +121,30 @@ func TestGetBlockReceipts(t *testing.T) {
require.Equal(t, multiTxBlockTx4.Hash().Hex(), receipt1["transactionHash"])
}

func verifyGenesisBlockResult(t *testing.T, resObj map[string]interface{}) {
resObj = resObj["result"].(map[string]interface{})
require.Equal(t, "0x0", resObj["baseFeePerGas"])
require.Equal(t, "0x0", resObj["difficulty"])
require.Equal(t, "0x", resObj["extraData"])
require.Equal(t, "0x0", resObj["gasLimit"])
require.Equal(t, "0x0", resObj["gasUsed"])
require.Equal(t, "0xf9d3845df25b43b1c6926f3ceda6845c17f5624e12212fd8847d0ba01da1ab9e", resObj["hash"])
require.Equal(t, "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", resObj["logsBloom"])
require.Equal(t, "0x0000000000000000000000000000000000000000", resObj["miner"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["mixHash"])
require.Equal(t, "0x0000000000000000", resObj["nonce"])
require.Equal(t, "0x0", resObj["number"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["parentHash"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["receiptsRoot"])
require.Equal(t, "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", resObj["sha3Uncles"])
require.Equal(t, "0x0", resObj["size"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["stateRoot"])
require.Equal(t, "0x0", resObj["timestamp"])
require.Equal(t, []interface{}{}, resObj["transactions"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["transactionsRoot"])
require.Equal(t, []interface{}{}, resObj["uncles"])
}

func verifyBlockResult(t *testing.T, resObj map[string]interface{}) {
resObj = resObj["result"].(map[string]interface{})
require.Equal(t, "0x0", resObj["difficulty"])
@@ -103,7 +153,7 @@ func verifyBlockResult(t *testing.T, resObj map[string]interface{}) {
require.Equal(t, "0x5", resObj["gasUsed"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", resObj["hash"])
// see setup_tests.go, which have one transaction for block 0x8 (latest)
require.Equal(t, "0x00002000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000", resObj["logsBloom"])
require.Equal(t, "0x00002000040000000000000000000080000000200000000000000000000000080000000000000000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000100000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010200000000000000", resObj["logsBloom"])
require.Equal(t, "0x0000000000000000000000000000000000000005", resObj["miner"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["mixHash"])
require.Equal(t, "0x0000000000000000", resObj["nonce"])
@@ -163,7 +213,7 @@ func TestEncodeTmBlock_EmptyTransactions(t *testing.T) {
}

// Call EncodeTmBlock with empty transactions
result, err := evmrpc.EncodeTmBlock(ctx, block, blockRes, ethtypes.Bloom{}, k, Decoder, true)
result, err := evmrpc.EncodeTmBlock(ctx, block, blockRes, ethtypes.Bloom{}, k, Decoder, true, false)
require.Nil(t, err)

// Assert txHash is equal to ethtypes.EmptyTxsHash
@@ -209,8 +259,71 @@ func TestEncodeBankMsg(t *testing.T) {
},
},
}
res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, ethtypes.Bloom{}, k, Decoder, true)
res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, ethtypes.Bloom{}, k, Decoder, true, false)
require.Nil(t, err)
txs := res["transactions"].([]interface{})
require.Equal(t, 0, len(txs))
}

func TestEncodeWasmExecuteMsg(t *testing.T) {
k := &testkeeper.EVMTestApp.EvmKeeper
ctx := testkeeper.EVMTestApp.GetContextForDeliverTx(nil)
fromSeiAddr, fromEvmAddr := testkeeper.MockAddressPair()
toSeiAddr, _ := testkeeper.MockAddressPair()
b := TxConfig.NewTxBuilder()
b.SetMsgs(&wasmtypes.MsgExecuteContract{
Sender: fromSeiAddr.String(),
Contract: toSeiAddr.String(),
Msg: []byte{1, 2, 3},
})
tx := b.GetTx()
bz, _ := Encoder(tx)
k.MockReceipt(ctx, sha256.Sum256(bz), &types.Receipt{
TransactionIndex: 1,
From: fromEvmAddr.Hex(),
})
resBlock := coretypes.ResultBlock{
BlockID: MockBlockID,
Block: &tmtypes.Block{
Header: mockBlockHeader(MockHeight),
Data: tmtypes.Data{
Txs: []tmtypes.Tx{bz},
},
LastCommit: &tmtypes.Commit{
Height: MockHeight - 1,
},
},
}
resBlockRes := coretypes.ResultBlockResults{
TxsResults: []*abci.ExecTxResult{
{
Data: bz,
},
},
ConsensusParamUpdates: &types2.ConsensusParams{
Block: &types2.BlockParams{
MaxBytes: 100000000,
MaxGas: 200000000,
},
},
}
res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, ethtypes.Bloom{}, k, Decoder, true, true)
require.Nil(t, err)
txs := res["transactions"].([]interface{})
require.Equal(t, 1, len(txs))
ti := uint64(1)
bh := common.HexToHash(MockBlockID.Hash.String())
to := common.Address(toSeiAddr)
require.Equal(t, &ethapi.RPCTransaction{
BlockHash: &bh,
BlockNumber: (*hexutil.Big)(big.NewInt(MockHeight)),
From: fromEvmAddr,
To: &to,
Input: []byte{1, 2, 3},
Hash: common.Hash(sha256.Sum256(bz)),
TransactionIndex: (*hexutil.Uint64)(&ti),
V: nil,
R: nil,
S: nil,
}, txs[0].(*ethapi.RPCTransaction))
}
39 changes: 27 additions & 12 deletions evmrpc/filter.go
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@
filterConfig *FilterConfig
logFetcher *LogFetcher
connectionType ConnectionType
namespace string
}

type FilterConfig struct {
@@ -62,10 +63,11 @@
Value json.RawMessage `json:"value"`
}

func NewFilterAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, filterConfig *FilterConfig, connectionType ConnectionType) *FilterAPI {
logFetcher.filterConfig = filterConfig
func NewFilterAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, filterConfig *FilterConfig, connectionType ConnectionType, namespace string) *FilterAPI {
logFetcher := &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider, filterConfig: filterConfig, includeSynthetic: shouldIncludeSynthetic(namespace)}
filters := make(map[ethrpc.ID]filter)
api := &FilterAPI{
namespace: namespace,
tmClient: tmClient,
filtersMu: sync.Mutex{},
filters: filters,
@@ -101,7 +103,7 @@
_ context.Context,
crit filters.FilterCriteria,
) (id ethrpc.ID, err error) {
defer recordMetrics("eth_newFilter", a.connectionType, time.Now(), err == nil)
defer recordMetrics(fmt.Sprintf("%s_newFilter", a.namespace), a.connectionType, time.Now(), err == nil)

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
a.filtersMu.Lock()
defer a.filtersMu.Unlock()
curFilterID := ethrpc.NewID()
@@ -117,7 +119,7 @@
func (a *FilterAPI) NewBlockFilter(
_ context.Context,
) (id ethrpc.ID, err error) {
defer recordMetrics("eth_newBlockFilter", a.connectionType, time.Now(), err == nil)
defer recordMetrics(fmt.Sprintf("%s_newBlockFilter", a.namespace), a.connectionType, time.Now(), err == nil)

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
a.filtersMu.Lock()
defer a.filtersMu.Unlock()
curFilterID := ethrpc.NewID()
@@ -133,7 +135,7 @@
ctx context.Context,
filterID ethrpc.ID,
) (res interface{}, err error) {
defer recordMetrics("eth_getFilterChanges", a.connectionType, time.Now(), err == nil)
defer recordMetrics(fmt.Sprintf("%s_getFilterChanges", a.namespace), a.connectionType, time.Now(), err == nil)

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
a.filtersMu.Lock()
defer a.filtersMu.Unlock()
filter, ok := a.filters[filterID]
@@ -184,7 +186,7 @@
ctx context.Context,
filterID ethrpc.ID,
) (res []*ethtypes.Log, err error) {
defer recordMetrics("eth_getFilterLogs", a.connectionType, time.Now(), err == nil)
defer recordMetrics(fmt.Sprintf("%s_getFilterLogs", a.namespace), a.connectionType, time.Now(), err == nil)

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
a.filtersMu.Lock()
defer a.filtersMu.Unlock()
filter, ok := a.filters[filterID]
@@ -209,11 +211,12 @@
return logs, nil
}

// JEREMYFLAG
func (a *FilterAPI) GetLogs(
ctx context.Context,
crit filters.FilterCriteria,
) (res []*ethtypes.Log, err error) {
defer recordMetrics("eth_getLogs", a.connectionType, time.Now(), err == nil)
defer recordMetrics(fmt.Sprintf("%s_getLogs", a.namespace), a.connectionType, time.Now(), err == nil)

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
logs, _, err := a.logFetcher.GetLogsByFilters(ctx, crit, 0)
return logs, err
}
@@ -260,7 +263,7 @@
_ context.Context,
filterID ethrpc.ID,
) (res bool) {
defer recordMetrics("eth_uninstallFilter", a.connectionType, time.Now(), res)
defer recordMetrics(fmt.Sprintf("%s_uninstallFilter", a.namespace), a.connectionType, time.Now(), res)

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
a.filtersMu.Lock()
defer a.filtersMu.Unlock()
_, found := a.filters[filterID]
@@ -272,10 +275,11 @@
}

type LogFetcher struct {
tmClient rpcclient.Client
k *keeper.Keeper
ctxProvider func(int64) sdk.Context
filterConfig *FilterConfig
tmClient rpcclient.Client
k *keeper.Keeper
ctxProvider func(int64) sdk.Context
filterConfig *FilterConfig
includeSynthetic bool
}

func (f *LogFetcher) GetLogsByFilters(ctx context.Context, crit filters.FilterCriteria, lastToHeight int64) ([]*ethtypes.Log, int64, error) {
@@ -362,6 +366,17 @@
ctx.Logger().Error(fmt.Sprintf("FindLogsByBloom: unable to find receipt for hash %s", hash.Hex()))
continue
}
// fmt.Println("JEREMYDEBUG: in find logs by bloom, receipt: ", receipt)
// fmt.Println("JEREMYDEBUG: in find logs by bloom, receipt.EffectiveGasPrice: ", receipt.EffectiveGasPrice)
if !f.includeSynthetic && len(receipt.Logs) > 0 && receipt.Logs[0].Synthetic {
// fmt.Println("JEREMYDEBUG: in find logs by bloom: skipping synthetic log")
continue
}
if !f.includeSynthetic && receipt.EffectiveGasPrice == 0 {
// fmt.Println("JEREMYDEBUG: in find logs by bloom: skipping zero gas price")
return
}

Check warning on line 378 in evmrpc/filter.go

Codecov / codecov/patch

evmrpc/filter.go#L376-L378

Added lines #L376 - L378 were not covered by tests
// fmt.Println("JEREMYDEBUG: in find logs by bloom: checking logs bloom")
if len(receipt.LogsBloom) > 0 && MatchFilters(ethtypes.Bloom(receipt.LogsBloom), filters) {
res = append(res, keeper.GetLogsForTx(receipt)...)
}
114 changes: 74 additions & 40 deletions evmrpc/filter_test.go
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/sei-protocol/sei-chain/x/evm/types"
// ethtypes "github.com/ethereum/go-ethereum/core/types"
// "github.com/sei-protocol/sei-chain/x/evm/types"
"github.com/stretchr/testify/require"
)

@@ -93,18 +93,20 @@ func TestFilterUninstall(t *testing.T) {
require.False(t, uninstallSuccess)
}

func TestFilterGetLogs(t *testing.T) {
tests := []struct {
name string
blockHash *common.Hash
fromBlock string
toBlock string
addrs []common.Address
topics [][]common.Hash
wantErr bool
wantLen int
check func(t *testing.T, log map[string]interface{})
}{
type GetFilterLogTests struct {
name string
blockHash *common.Hash
fromBlock string
toBlock string
addrs []common.Address
topics [][]common.Hash
wantErr bool
wantLen int
check func(t *testing.T, log map[string]interface{})
}

func getCommonFilterLogTests() []GetFilterLogTests {
tests := []GetFilterLogTests{
{
name: "filter by single address",
fromBlock: "0x2",
@@ -183,7 +185,57 @@ func TestFilterGetLogs(t *testing.T) {
wantLen: 3,
},
}
return tests
}

func TestFilterGetLogs(t *testing.T) {
testFilterGetLogs(t, "eth", getCommonFilterLogTests())
}

func TestSeiFilterGetLogs(t *testing.T) {
// make sure we pass all the eth_ namespace tests
testFilterGetLogs(t, "sei", getCommonFilterLogTests())

// test where we get a synthetic log
testFilterGetLogs(t, "sei", []GetFilterLogTests{
{
name: "filter by single synthetic address",
fromBlock: "0x8",
toBlock: "0x8",
addrs: []common.Address{common.HexToAddress("0x1111111111111111111111111111111111111116")},
wantErr: false,
check: func(t *testing.T, log map[string]interface{}) {
require.Equal(t, "0x1111111111111111111111111111111111111116", log["address"].(string))
},
wantLen: 1,
},
{
name: "filter by single topic with default range, include synethetic logs",
topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000234")}},
wantErr: false,
check: func(t *testing.T, log map[string]interface{}) {
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000234", log["topics"].([]interface{})[0].(string))
},
wantLen: 1,
},
})
}

func TestEthEndpointShouldNotReturnSyntheticLogs(t *testing.T) {
testFilterGetLogs(t, "eth", []GetFilterLogTests{
{
name: "filter by single topic with default range, exclude synethetic logs",
topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000234")}},
wantErr: false,
check: func(t *testing.T, log map[string]interface{}) {
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000234", log["topics"].([]interface{})[0].(string))
},
wantLen: 0,
},
})
}

func testFilterGetLogs(t *testing.T, namespace string, tests []GetFilterLogTests) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fmt.Println(tt.name)
@@ -198,7 +250,14 @@ func TestFilterGetLogs(t *testing.T) {
filterCriteria["fromBlock"] = tt.fromBlock
filterCriteria["toBlock"] = tt.toBlock
}
resObj := sendRequestGood(t, "getLogs", filterCriteria)
var resObj map[string]interface{}
if namespace == "eth" {
resObj = sendRequestGood(t, "getLogs", filterCriteria)
} else if namespace == "sei" {
resObj = sendSeiRequestGood(t, "getLogs", filterCriteria)
} else {
panic("unknown namespace")
}
if tt.wantErr {
_, ok := resObj["error"]
require.True(t, ok)
@@ -250,31 +309,6 @@ func TestFilterGetFilterChanges(t *testing.T) {
logObj := logs[0].(map[string]interface{})
require.Equal(t, "0x2", logObj["blockNumber"].(string))

// another query
bloom := ethtypes.CreateBloom(ethtypes.Receipts{&ethtypes.Receipt{Logs: []*ethtypes.Log{{
Address: common.HexToAddress("0x1111111111111111111111111111111111111112"),
Topics: []common.Hash{},
}}}})
Ctx = Ctx.WithBlockHeight(9)
EVMKeeper.MockReceipt(Ctx, common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900005"), &types.Receipt{
BlockNumber: 9,
LogsBloom: bloom[:],
Logs: []*types.Log{{
Address: "0x1111111111111111111111111111111111111114",
}},
})
EVMKeeper.SetTxHashesOnHeight(Ctx, 9, []common.Hash{
common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900005"),
})
EVMKeeper.SetBlockBloom(Ctx, []ethtypes.Bloom{bloom})
Ctx = Ctx.WithBlockHeight(9)
resObj = sendRequest(t, TestPort, "getFilterChanges", filterId)
Ctx = Ctx.WithBlockHeight(8)
logs = resObj["result"].([]interface{})
require.Equal(t, 1, len(logs))
logObj = logs[0].(map[string]interface{})
require.Equal(t, "0x9", logObj["blockNumber"].(string))

// error: filter id does not exist
nonExistingFilterId := 1000
resObj = sendRequest(t, TestPort, "getFilterChanges", nonExistingFilterId)
19 changes: 15 additions & 4 deletions evmrpc/server.go
Original file line number Diff line number Diff line change
@@ -45,18 +45,25 @@ func NewEVMHTTPServer(
sendAPI := NewSendAPI(tmClient, txConfig, &SendConfig{slow: config.Slow}, k, ctxProvider, homeDir, simulateConfig, ConnectionTypeHTTP)
ctx := ctxProvider(LatestCtxHeight)

txAPI := NewTransactionAPI(tmClient, k, ctxProvider, txConfig, homeDir, ConnectionTypeHTTP)
// filterAPI := NewFilterAPI(tmClient, &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider}, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP)

apis := []rpc.API{
{
Namespace: "echo",
Service: NewEchoAPI(),
},
{
Namespace: "eth",
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeHTTP),
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeHTTP, "eth"),
},
{
Namespace: "sei",
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeHTTP, "sei"),
},
{
Namespace: "eth",
Service: NewTransactionAPI(tmClient, k, ctxProvider, txConfig, homeDir, ConnectionTypeHTTP),
Service: txAPI,
},
{
Namespace: "eth",
@@ -80,7 +87,11 @@ func NewEVMHTTPServer(
},
{
Namespace: "eth",
Service: NewFilterAPI(tmClient, &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider}, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP),
Service: NewFilterAPI(tmClient, k, ctxProvider, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP, "eth"),
},
{
Namespace: "sei",
Service: NewFilterAPI(tmClient, k, ctxProvider, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP, "sei"),
},
{
Namespace: "sei",
@@ -145,7 +156,7 @@ func NewEVMWebSocketServer(
},
{
Namespace: "eth",
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeWS),
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeWS, "eth"),
},
{
Namespace: "eth",
59 changes: 57 additions & 2 deletions evmrpc/setup_test.go
Original file line number Diff line number Diff line change
@@ -66,11 +66,13 @@ var MultiTxBlockTx1 sdk.Tx
var MultiTxBlockTx2 sdk.Tx
var MultiTxBlockTx3 sdk.Tx
var MultiTxBlockTx4 sdk.Tx
var MultiTxBlockSynthTx sdk.Tx
var tx1 *ethtypes.Transaction
var multiTxBlockTx1 *ethtypes.Transaction
var multiTxBlockTx2 *ethtypes.Transaction
var multiTxBlockTx3 *ethtypes.Transaction
var multiTxBlockTx4 *ethtypes.Transaction
var multiTxBlockSynthTx *ethtypes.Transaction

var DebugTraceTx sdk.Tx
var TxNonEvm sdk.Tx
@@ -151,6 +153,10 @@ func (c *MockClient) mockBlock(height int64) *coretypes.ResultBlock {
bz, _ := Encoder(MultiTxBlockTx3)
return bz
}(),
func() []byte {
bz, _ := Encoder(MultiTxBlockSynthTx)
return bz
}(),
},
},
LastCommit: &tmtypes.Commit{
@@ -486,7 +492,7 @@ func init() {
func generateTxData() {
chainId := big.NewInt(config.DefaultChainID)
to := common.HexToAddress("010203")
var txBuilder1, txBuilder1_5, txBuilder2, txBuilder3, txBuilder4 client.TxBuilder
var txBuilder1, txBuilder1_5, txBuilder2, txBuilder3, txBuilder4, synthTxBuilder client.TxBuilder
txBuilder1, tx1 = buildTx(ethtypes.DynamicFeeTx{
Nonce: 1,
GasFeeCap: big.NewInt(10),
@@ -532,6 +538,15 @@ func generateTxData() {
Data: []byte("abc"),
ChainID: chainId,
})
synthTxBuilder, multiTxBlockSynthTx = buildTx(ethtypes.DynamicFeeTx{
Nonce: 6,
GasFeeCap: big.NewInt(20),
Gas: 1000,
To: &to,
Value: big.NewInt(1000),
Data: []byte("synthetic"),
ChainID: chainId,
})
debugTraceTxBuilder, _ := buildTx(ethtypes.DynamicFeeTx{
Nonce: 0,
GasFeeCap: big.NewInt(10),
@@ -546,6 +561,7 @@ func generateTxData() {
MultiTxBlockTx2 = txBuilder2.GetTx()
MultiTxBlockTx3 = txBuilder3.GetTx()
MultiTxBlockTx4 = txBuilder4.GetTx()
MultiTxBlockSynthTx = synthTxBuilder.GetTx()
DebugTraceTx = debugTraceTxBuilder.GetTx()
TxNonEvm = app.TestTx{}
if err := EVMKeeper.MockReceipt(Ctx, tx1.Hash(), &types.Receipt{
@@ -666,6 +682,7 @@ func setupLogs() {
Address: "0x1111111111111111111111111111111111111112",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123"},
}},
EffectiveGasPrice: 100,
})
bloom2 := ethtypes.CreateBloom(ethtypes.Receipts{&ethtypes.Receipt{Logs: []*ethtypes.Log{{
Address: common.HexToAddress("0x1111111111111111111111111111111111111113"),
@@ -683,6 +700,7 @@ func setupLogs() {
Address: "0x1111111111111111111111111111111111111113",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"},
}},
EffectiveGasPrice: 100,
})
bloom3 := ethtypes.CreateBloom(ethtypes.Receipts{&ethtypes.Receipt{Logs: []*ethtypes.Log{{
Address: common.HexToAddress("0x1111111111111111111111111111111111111114"),
@@ -700,6 +718,7 @@ func setupLogs() {
Address: "0x1111111111111111111111111111111111111114",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"},
}},
EffectiveGasPrice: 100,
})
bloom4 := ethtypes.CreateBloom(ethtypes.Receipts{&ethtypes.Receipt{Logs: []*ethtypes.Log{{
Address: common.HexToAddress("0x1111111111111111111111111111111111111115"),
@@ -717,6 +736,27 @@ func setupLogs() {
Address: "0x1111111111111111111111111111111111111115",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"},
}},
EffectiveGasPrice: 100,
})
// create a receipt with a synthetic log
bloomSynth := ethtypes.CreateBloom(ethtypes.Receipts{&ethtypes.Receipt{Logs: []*ethtypes.Log{{
Address: common.HexToAddress("0x1111111111111111111111111111111111111116"),
Topics: []common.Hash{
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000234"),
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"),
},
}}}})
EVMKeeper.MockReceipt(Ctx, multiTxBlockSynthTx.Hash(), &types.Receipt{
BlockNumber: MockHeight,
TransactionIndex: 0,
TxHashHex: multiTxBlockSynthTx.Hash().Hex(),
LogsBloom: bloomSynth[:],
Logs: []*types.Log{{
Address: "0x1111111111111111111111111111111111111116",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000234", "0x0000000000000000000000000000000000000000000000000000000000000789"},
Synthetic: true,
}},
EffectiveGasPrice: 100,
})
EVMKeeper.MockReceipt(Ctx, common.HexToHash(DebugTraceHashHex), &types.Receipt{
BlockNumber: DebugTraceMockHeight,
@@ -730,21 +770,32 @@ func setupLogs() {
})
EVMKeeper.SetTxHashesOnHeight(Ctx, MockHeight, []common.Hash{
multiTxBlockTx4.Hash(),
multiTxBlockSynthTx.Hash(),
})
EVMKeeper.SetBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3})
EVMKeeper.SetBlockBloom(Ctx, []ethtypes.Bloom{bloom4})
EVMKeeper.SetBlockBloom(Ctx, []ethtypes.Bloom{bloom4, bloomSynth})
}

//nolint:deadcode
func sendRequestGood(t *testing.T, method string, params ...interface{}) map[string]interface{} {
return sendRequest(t, TestPort, method, params...)
}

//nolint:deadcode
func sendSeiRequestGood(t *testing.T, method string, params ...interface{}) map[string]interface{} {
return sendSeiRequest(t, TestPort, method, params...)
}

//nolint:deadcode
func sendRequestBad(t *testing.T, method string, params ...interface{}) map[string]interface{} {
return sendRequest(t, TestBadPort, method, params...)
}

//nolint:deadcode
func sendSeiRequestBad(t *testing.T, method string, params ...interface{}) map[string]interface{} {
return sendSeiRequest(t, TestBadPort, method, params...)
}

// nolint:deadcode
func sendRequestGoodWithNamespace(t *testing.T, namespace string, method string, params ...interface{}) map[string]interface{} {
return sendRequestWithNamespace(t, namespace, TestPort, method, params...)
@@ -754,6 +805,10 @@ func sendRequest(t *testing.T, port int, method string, params ...interface{}) m
return sendRequestWithNamespace(t, "eth", port, method, params...)
}

func sendSeiRequest(t *testing.T, port int, method string, params ...interface{}) map[string]interface{} {
return sendRequestWithNamespace(t, "sei", port, method, params...)
}

func sendRequestWithNamespace(t *testing.T, namespace string, port int, method string, params ...interface{}) map[string]interface{} {
paramsFormatted := ""
if len(params) > 0 {
35 changes: 12 additions & 23 deletions evmrpc/tx_test.go
Original file line number Diff line number Diff line change
@@ -21,12 +21,16 @@ import (
)

func TestGetTxReceipt(t *testing.T) {
testGetTxReceipt(t, "eth")
}

func testGetTxReceipt(t *testing.T, namespace string) {
receipt, err := EVMKeeper.GetReceipt(Ctx, common.HexToHash("0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e"))
require.Nil(t, err)
receipt.To = ""
EVMKeeper.MockReceipt(Ctx, common.HexToHash("0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e"), receipt)

body := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionReceipt\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}"
body := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"%s_getTransactionReceipt\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}", namespace)
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body))
require.Nil(t, err)
req.Header.Set("Content-Type", "application/json")
@@ -64,25 +68,6 @@ func TestGetTxReceipt(t *testing.T) {
require.Equal(t, "0x1", resObj["type"].(string))
require.Equal(t, "0x1234567890123456789012345678901234567890", resObj["contractAddress"].(string))

receipt, err = EVMKeeper.GetReceipt(Ctx, common.HexToHash("0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e"))
require.Nil(t, err)
receipt.ContractAddress = ""
receipt.To = "0x1234567890123456789012345678901234567890"
EVMKeeper.MockReceipt(Ctx, common.HexToHash("0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e"), receipt)
body = "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionReceipt\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}"
req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body))
require.Nil(t, err)
req.Header.Set("Content-Type", "application/json")
res, err = http.DefaultClient.Do(req)
require.Nil(t, err)
resBody, err = io.ReadAll(res.Body)
require.Nil(t, err)
resObj = map[string]interface{}{}
require.Nil(t, json.Unmarshal(resBody, &resObj))
resObj = resObj["result"].(map[string]interface{})
require.Nil(t, resObj["contractAddress"])
require.Equal(t, "0x1234567890123456789012345678901234567890", resObj["to"].(string))

req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestBadPort), strings.NewReader(body))
require.Nil(t, err)
req.Header.Set("Content-Type", "application/json")
@@ -101,9 +86,13 @@ func TestGetTxReceipt(t *testing.T) {
}

func TestGetTransaction(t *testing.T) {
bodyByBlockNumberAndIndex := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionByBlockNumberAndIndex\",\"params\":[\"0x8\",\"0x0\"],\"id\":\"test\"}"
bodyByBlockHashAndIndex := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionByBlockHashAndIndex\",\"params\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0\"],\"id\":\"test\"}"
bodyByHash := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionByHash\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}"
testGetTransaction(t, "eth")
}

func testGetTransaction(t *testing.T, namespace string) {
bodyByBlockNumberAndIndex := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"%s_getTransactionByBlockNumberAndIndex\",\"params\":[\"0x8\",\"0x0\"],\"id\":\"test\"}", namespace)
bodyByBlockHashAndIndex := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"%s_getTransactionByBlockHashAndIndex\",\"params\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0\"],\"id\":\"test\"}", namespace)
bodyByHash := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"%s_getTransactionByHash\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}", namespace)
for _, body := range []string{bodyByBlockNumberAndIndex, bodyByBlockHashAndIndex, bodyByHash} {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body))
require.Nil(t, err)
7 changes: 7 additions & 0 deletions evmrpc/utils.go
Original file line number Diff line number Diff line change
@@ -196,3 +196,10 @@
func evmExists(ctx sdk.Context, k *keeper.Keeper) bool {
return ctx.KVStore(k.GetStoreKey()).VersionExists(ctx.BlockHeight())
}

func shouldIncludeSynthetic(namespace string) bool {
if namespace != "eth" && namespace != "sei" {
panic(fmt.Sprintf("unknown namespace %s", namespace))

Check warning on line 202 in evmrpc/utils.go

Codecov / codecov/patch

evmrpc/utils.go#L202

Added line #L202 was not covered by tests
}
return namespace == "sei"
}