Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Synthetic events in separate sei endpoints #1867

Merged
merged 14 commits into from
Sep 24, 2024
Merged
17 changes: 12 additions & 5 deletions contracts/test/CW20toERC20PointerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
});

Expand Down
39 changes: 25 additions & 14 deletions contracts/test/ERC20toCW20PointerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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 () {
Expand Down
37 changes: 23 additions & 14 deletions contracts/test/ERC721toCW721PointerTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -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);
Expand Down
102 changes: 87 additions & 15 deletions evmrpc/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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(
Expand All @@ -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())
Expand Down Expand Up @@ -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

View check run for this annotation

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

View check run for this annotation

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

View check run for this annotation

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),
})
}
}
}
}
Expand Down
Loading
Loading