diff --git a/contracts/test/CW20toERC20PointerTest.js b/contracts/test/CW20toERC20PointerTest.js index f1444fa5b..61ff0baa2 100644 --- a/contracts/test/CW20toERC20PointerTest.js +++ b/contracts/test/CW20toERC20PointerTest.js @@ -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()); }); diff --git a/contracts/test/ERC20toCW20PointerTest.js b/contracts/test/ERC20toCW20PointerTest.js index 7f6e84b6e..06d81fc4c 100644 --- a/contracts/test/ERC20toCW20PointerTest.js +++ b/contracts/test/ERC20toCW20PointerTest.js @@ -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 () { diff --git a/contracts/test/ERC721toCW721PointerTest.js b/contracts/test/ERC721toCW721PointerTest.js index e6d21f32a..2048c69f0 100644 --- a/contracts/test/ERC721toCW721PointerTest.js +++ b/contracts/test/ERC721toCW721PointerTest.js @@ -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); diff --git a/evmrpc/block.go b/evmrpc/block.go index 186b8d955..789275fb5 100644 --- a/evmrpc/block.go +++ b/evmrpc/block.go @@ -2,12 +2,15 @@ package evmrpc 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 @@ import ( ) 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) GetBlockTransactionCountByNumber(ctx context.Context, number 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) GetBlockTransactionCountByHash(ctx context.Context, blockHash 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 @@ func (a *BlockAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fu 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 @@ func (a *BlockAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, 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 @@ func (a *BlockAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.Block 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 @@ func (a *BlockAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.Block }(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 @@ func EncodeTmBlock( 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 @@ func EncodeTmBlock( 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 + } + th := sha256.Sum256(block.Block.Txs[i]) + receipt, err := k.GetReceipt(ctx, th) + if err != nil { + continue + } + if !fullTx { + transactions = append(transactions, th) + } else { + ti := uint64(receipt.TransactionIndex) + to := k.GetEVMAddressOrDefault(ctx, sdk.MustAccAddressFromBech32(m.Contract)) + transactions = append(transactions, ðapi.RPCTransaction{ + BlockHash: &blockhash, + BlockNumber: (*hexutil.Big)(number), + From: common.HexToAddress(receipt.From), + To: &to, + Input: m.Msg.Bytes(), + Hash: th, + TransactionIndex: (*hexutil.Uint64)(&ti), + }) + } } } } diff --git a/evmrpc/block_test.go b/evmrpc/block_test.go index c91798026..1a4c76d0f 100644 --- a/evmrpc/block_test.go +++ b/evmrpc/block_test.go @@ -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, ðapi.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)) +} diff --git a/evmrpc/filter.go b/evmrpc/filter.go index 04f5f561c..69122d81b 100644 --- a/evmrpc/filter.go +++ b/evmrpc/filter.go @@ -49,6 +49,7 @@ type FilterAPI struct { filterConfig *FilterConfig logFetcher *LogFetcher connectionType ConnectionType + namespace string } type FilterConfig struct { @@ -62,10 +63,11 @@ type EventItemDataWrapper struct { 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 @@ func (a *FilterAPI) NewFilter( _ 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) a.filtersMu.Lock() defer a.filtersMu.Unlock() curFilterID := ethrpc.NewID() @@ -117,7 +119,7 @@ func (a *FilterAPI) NewFilter( 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) a.filtersMu.Lock() defer a.filtersMu.Unlock() curFilterID := ethrpc.NewID() @@ -133,7 +135,7 @@ func (a *FilterAPI) GetFilterChanges( 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) a.filtersMu.Lock() defer a.filtersMu.Unlock() filter, ok := a.filters[filterID] @@ -184,7 +186,7 @@ func (a *FilterAPI) GetFilterLogs( 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) a.filtersMu.Lock() defer a.filtersMu.Unlock() filter, ok := a.filters[filterID] @@ -209,11 +211,12 @@ func (a *FilterAPI) GetFilterLogs( 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) logs, _, err := a.logFetcher.GetLogsByFilters(ctx, crit, 0) return logs, err } @@ -260,7 +263,7 @@ func (a *FilterAPI) UninstallFilter( _ 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) a.filtersMu.Lock() defer a.filtersMu.Unlock() _, found := a.filters[filterID] @@ -272,10 +275,11 @@ func (a *FilterAPI) UninstallFilter( } 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 @@ func (f *LogFetcher) FindLogsByBloom(height int64, filters [][]bloomIndexes) (re 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 + } + // 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)...) } diff --git a/evmrpc/filter_test.go b/evmrpc/filter_test.go index 94581979d..4f589d95d 100644 --- a/evmrpc/filter_test.go +++ b/evmrpc/filter_test.go @@ -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{ðtypes.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) diff --git a/evmrpc/server.go b/evmrpc/server.go index 11c1ba672..a76045e29 100644 --- a/evmrpc/server.go +++ b/evmrpc/server.go @@ -45,6 +45,9 @@ 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", @@ -52,11 +55,15 @@ func NewEVMHTTPServer( }, { 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", diff --git a/evmrpc/setup_test.go b/evmrpc/setup_test.go index 898e566ee..3449bb640 100644 --- a/evmrpc/setup_test.go +++ b/evmrpc/setup_test.go @@ -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{ðtypes.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{ðtypes.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{ðtypes.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{ðtypes.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,9 +770,10 @@ 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 @@ -740,11 +781,21 @@ func sendRequestGood(t *testing.T, method string, params ...interface{}) map[str 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 { diff --git a/evmrpc/tx_test.go b/evmrpc/tx_test.go index 3e36046da..b6695d05d 100644 --- a/evmrpc/tx_test.go +++ b/evmrpc/tx_test.go @@ -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) diff --git a/evmrpc/utils.go b/evmrpc/utils.go index 546f064ad..6fc9eb30d 100644 --- a/evmrpc/utils.go +++ b/evmrpc/utils.go @@ -196,3 +196,10 @@ func bankExists(ctx sdk.Context, k *keeper.Keeper) bool { 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)) + } + return namespace == "sei" +}