From 981aa0203145ce75afc2f6028cdc06d71a061f25 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Mon, 30 Sep 2024 17:30:28 +0800 Subject: [PATCH 01/23] subscription tests --- .github/workflows/test.yml | 4 + .gitignore | 5 +- codecov.yml | 2 +- ...greeter.ts => upgradeable-greeter.test.ts} | 0 packages/eth-rpc-adapter/package.json | 2 + .../src/__tests__/abis/IERC20.json | 260 ++++++++++++++++++ .../src/__tests__/endpoint.test.ts | 6 +- .../src/__tests__/errors.test.ts | 3 +- .../src/__tests__/signer.test.ts | 4 +- .../src/__tests__/subscription.test.ts | 162 +++++++++++ .../src/__tests__/utils/SubsManager.ts | 106 +++++++ .../src/__tests__/{ => utils}/consts.ts | 11 - .../src/__tests__/utils/evmAccounts.ts | 22 ++ .../src/__tests__/utils/index.ts | 4 + .../{utils.ts => utils/test-utils.ts} | 2 +- packages/eth-rpc-adapter/vitest.config.ts | 5 +- yarn.lock | 3 +- 17 files changed, 576 insertions(+), 25 deletions(-) rename e2e-tests/e2e-hardhat/test/{upgradeable-greeter.ts => upgradeable-greeter.test.ts} (100%) create mode 100644 packages/eth-rpc-adapter/src/__tests__/abis/IERC20.json create mode 100644 packages/eth-rpc-adapter/src/__tests__/subscription.test.ts create mode 100644 packages/eth-rpc-adapter/src/__tests__/utils/SubsManager.ts rename packages/eth-rpc-adapter/src/__tests__/{ => utils}/consts.ts (98%) create mode 100644 packages/eth-rpc-adapter/src/__tests__/utils/evmAccounts.ts create mode 100644 packages/eth-rpc-adapter/src/__tests__/utils/index.ts rename packages/eth-rpc-adapter/src/__tests__/{utils.ts => utils/test-utils.ts} (99%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 27330ce41..e3582998a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,6 +42,10 @@ jobs: if: matrix.project == 'eth-providers' run: yarn workspace @acala-network/eth-rpc-adapter run start:coverage + - name: generate typechain for eth-rpc-adapter tests + if: matrix.project == 'eth-rpc-adapter' + run: yarn workspace @acala-network/eth-rpc-adapter run typegen + - name: run tests run: yarn workspace @acala-network/${{ matrix.project }} run test:coverage diff --git a/.gitignore b/.gitignore index 88d80723e..fe1379dfb 100644 --- a/.gitignore +++ b/.gitignore @@ -76,4 +76,7 @@ lib **/.yarn/install-state.gz ## openzeppelin cache -**/.openzeppelin/ \ No newline at end of file +**/.openzeppelin/ + +## typechain files +**/types diff --git a/codecov.yml b/codecov.yml index d8a67846f..4fddbfe15 100644 --- a/codecov.yml +++ b/codecov.yml @@ -13,7 +13,7 @@ coverage: comment: layout: "reach, diff, flags, files" - behavior: default + behavior: new require_changes: false require_base: false require_head: false diff --git a/e2e-tests/e2e-hardhat/test/upgradeable-greeter.ts b/e2e-tests/e2e-hardhat/test/upgradeable-greeter.test.ts similarity index 100% rename from e2e-tests/e2e-hardhat/test/upgradeable-greeter.ts rename to e2e-tests/e2e-hardhat/test/upgradeable-greeter.test.ts diff --git a/packages/eth-rpc-adapter/package.json b/packages/eth-rpc-adapter/package.json index cb3af050a..7a5a4d99c 100644 --- a/packages/eth-rpc-adapter/package.json +++ b/packages/eth-rpc-adapter/package.json @@ -7,6 +7,7 @@ "scripts": { "build": "tsc", "ncc:pack": "ncc build src/index.ts -t --target es2020", + "typegen": "typechain --target=ethers-v5 --out-dir=./src/__tests__/types src/__tests__/abis/*.json", "dev": "ts-node-dev -T -r tsconfig-paths/register src/index.ts -l | pino-pretty --singleLine --colorize --ignore time,hostname,jsonrpc,dd", "clean": "rm -rf tsconfig.tsbuildinfo .nyc_output coverage/ lib/", "health-check": "./scripts/health-check.sh", @@ -47,6 +48,7 @@ "pm2": "^5.4.2", "ts-node": "^10.9.1", "ts-node-dev": "^2.0.0", + "typechain": "^8.3.2", "vitest": "^2.1.1" }, "files": [ diff --git a/packages/eth-rpc-adapter/src/__tests__/abis/IERC20.json b/packages/eth-rpc-adapter/src/__tests__/abis/IERC20.json new file mode 100644 index 000000000..b3dca0b70 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/abis/IERC20.json @@ -0,0 +1,260 @@ +{ + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "evm": { + "bytecode": { + "linkReferences": {}, + "object": "", + "opcodes": "", + "sourceMap": "" + }, + "deployedBytecode": { + "linkReferences": {}, + "object": "", + "opcodes": "", + "sourceMap": "" + } + }, + "metadata": "{\"compiler\":{\"version\":\"0.5.16+commit.9c3226ce\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/interfaces/IERC20.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"contracts/interfaces/IERC20.sol\":{\"keccak256\":\"0x61db17aebc5d812c7002d15c1da954065e56abe49d64b14c034abe5604d70eb3\",\"urls\":[\"bzz-raw://b006685e753f9120469f10b09c159f222d4cb8b507a6c1f0c14ed50c883ebe66\",\"dweb:/ipfs/QmSyY7iTugbczPwfGK67etiyPULenYGzzRYbt8aabwwkUb\"]}},\"version\":1}", + "bytecode": "" +} diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts index 93ced210b..d28957e5f 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts @@ -67,9 +67,7 @@ import { toDeterministic, waitForHeight, eth_estimateGas, -} from './utils'; -import { ADDRESS_ALICE, DETERMINISTIC_SETUP_DEX_ADDRESS, GAS_MONSTER_GAS_REQUIRED, @@ -81,8 +79,8 @@ import { deployHelloWorldData, evmAccounts, log22_0, - log22_1, -} from './consts'; + log22_1 } from './utils'; + const subql = new SubqlProvider(SUBQL_URL); diff --git a/packages/eth-rpc-adapter/src/__tests__/errors.test.ts b/packages/eth-rpc-adapter/src/__tests__/errors.test.ts index 396577d6c..3253fe33a 100644 --- a/packages/eth-rpc-adapter/src/__tests__/errors.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/errors.test.ts @@ -7,8 +7,7 @@ import ADDRESS from '@acala-network/contracts/utils/MandalaAddress'; import TokenABI from '@acala-network/contracts/build/contracts/Token.json'; import axios from 'axios'; -import { RPC_URL, eth_call, eth_chainId, eth_estimateGas, eth_getEthGas, eth_sendRawTransaction } from './utils'; -import { evmAccounts } from './consts'; +import { RPC_URL, eth_call, eth_chainId, eth_estimateGas, eth_getEthGas, eth_sendRawTransaction , evmAccounts } from './utils'; describe('errors', () => { const POOR_ACCOUNT = '0xa872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd570'; diff --git a/packages/eth-rpc-adapter/src/__tests__/signer.test.ts b/packages/eth-rpc-adapter/src/__tests__/signer.test.ts index 60daa31cf..9136f65ce 100644 --- a/packages/eth-rpc-adapter/src/__tests__/signer.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/signer.test.ts @@ -1,10 +1,8 @@ -import { Eip1193Bridge } from '../eip1193-bridge'; import { EvmRpcProvider } from '@acala-network/eth-providers'; import { Wallet, verifyMessage } from '@ethersproject/wallet'; import { afterAll, describe, expect, it } from 'vitest'; -import dotenv from 'dotenv'; -dotenv.config(); +import { Eip1193Bridge } from '../eip1193-bridge'; const endpoint = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; diff --git a/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts b/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts new file mode 100644 index 000000000..7b7b07d57 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts @@ -0,0 +1,162 @@ +import { ACA } from '@acala-network/contracts/utils/AcalaAddress'; +import { AcalaJsonRpcProvider, sleep } from '@acala-network/eth-providers'; +import { JsonRpcProvider } from '@ethersproject/providers'; +import { Wallet } from 'ethers'; +import { afterAll, beforeAll, beforeEach, describe, it } from 'vitest'; +import { expect } from 'chai'; +import { parseUnits } from 'ethers/lib/utils'; + +import { IERC20, IERC20__factory } from './types'; +import { SubsManager, evmAccounts, getAddrSelector } from './utils'; + +const oneAcaErc20 = parseUnits('1', 12); +const TRANSFER_SELECTOR = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; + +const ETH_RPC_URL = process.env.ENDPOINT_URL || 'http://localhost:8545'; +const ETH_RPC_URL_WS = ETH_RPC_URL.replace('http', 'ws'); + +describe('eth subscription', () => { + let deployer: Wallet; + let user: Wallet; + let provider: JsonRpcProvider; + let aca: IERC20; + + let subId0: string; + let subId1: string; + let subId2: string; + let subId3: string; + let sm: SubsManager; + + beforeAll(async () => { + console.log('setting up subscription ...'); + + provider = new AcalaJsonRpcProvider(ETH_RPC_URL); + deployer = new Wallet(evmAccounts[0].privateKey, provider); + user = new Wallet(evmAccounts[1].privateKey, provider); + aca = IERC20__factory.connect(ACA, deployer); + + sm = new SubsManager(ETH_RPC_URL_WS); + await sm.isReady; + + const userAddrSelector = getAddrSelector(user.address); + + const sub0 = sm.subscribeNewHeads(); + const sub1 = sm.subscribeLogs({}); + const sub2 = sm.subscribeLogs({ + topics: [ + TRANSFER_SELECTOR, + null, + [userAddrSelector], + ], + }); + const sub3 = sm.subscribeLogs({ + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55aaaaaaaaaaa', // shouldn't match + ], + }); + + ([subId0, subId1, subId2, subId3] = await Promise.all([sub0, sub1, sub2, sub3])); + + console.log('subscription finished!'); + }); + + beforeEach(() => { + sm.clear(); + }); + + afterAll(() => { + sm.close(); + }); + + it('get correct subscrption notification', async () => { + const receipt = await (await aca.transfer(user.address, oneAcaErc20.mul(8))).wait(); + const txBlockInfo = await provider.send('eth_getBlockByNumber', [receipt.blockNumber, false]); + + const msg0 = await sm.waitForMsg(subId0, data => data.hash === receipt.blockHash); // new block + const msg1 = await sm.waitForMsg(subId1); // ACA transfer + const msg2 = await sm.waitForMsg(subId2); // ACA transfer + const msg3 = await sm.waitForMsg(subId3); // no match + + expect(msg0).to.not.be.undefined; + expect(msg1).to.not.be.undefined; + expect(msg2).to.not.be.undefined; + expect(msg3).to.be.null; + + expect(msg0).to.deep.contains({ + jsonrpc: '2.0', + method: 'eth_subscription', + params: { + subscription: subId0, + result: txBlockInfo, + }, + }); + + const expectedLog = await provider.send('eth_getLogs', [{ blockHash: receipt.blockHash }]); + + expect(expectedLog.length).to.equal(1); + delete (expectedLog[0] as any).removed; + + expect(msg1).to.deep.contains({ + jsonrpc: '2.0', + method: 'eth_subscription', + params: { + subscription: subId1, + result: expectedLog[0], + }, + }); + + expect(msg2).to.deep.contains({ + jsonrpc: '2.0', + method: 'eth_subscription', + params: { + subscription: subId2, + result: expectedLog[0], + }, + }); + + }); + + it('unsubscribe works', async () => { + const unsubRes = await Promise.all([ + sm.unSubscribe(subId0), + sm.unSubscribe(subId1), + sm.unSubscribe(subId3), + sm.unSubscribe(Wallet.createRandom().address), + ]); + + expect(unsubRes).to.deep.equal([ + true, + true, + true, + false, + ]); + + // only sub2 is left + const receipt = await (await aca.transfer(user.address, oneAcaErc20.mul(3))).wait(); + const txBlockInfo = await provider.send('eth_getBlockByNumber', [receipt.blockNumber, false]); + + const msg0 = await sm.waitForMsg(subId0, data => data.hash === receipt.blockHash); // new block + const msg1 = await sm.waitForMsg(subId1); // ACA transfer + const msg2 = await sm.waitForMsg(subId2); // ACA transfer + const msg3 = await sm.waitForMsg(subId3); // no match + + // after unsubscribe they should not be notified anymore + expect(msg0).to.be.null; + expect(msg1).to.be.null; + expect(msg3).to.be.null; + + const expectedLog = await provider.send('eth_getLogs', [{ blockHash: txBlockInfo.hash }]); + + expect(expectedLog.length).to.equal(1); + delete (expectedLog[0] as any).removed; + + expect(msg2).to.deep.contains({ + jsonrpc: '2.0', + method: 'eth_subscription', + params: { + subscription: subId2, + result: expectedLog[0], + }, + }); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/SubsManager.ts b/packages/eth-rpc-adapter/src/__tests__/utils/SubsManager.ts new file mode 100644 index 000000000..538a3e08d --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/utils/SubsManager.ts @@ -0,0 +1,106 @@ +import { hexZeroPad } from 'ethers/lib/utils'; +import WebSocket from 'ws'; + +export class SubsManager { + curReqId = 0; + msgs: any[] = []; + ws: WebSocket; + isReady: Promise; + + constructor(url: string) { + this.ws = new WebSocket(url); + + this.isReady = new Promise(resolve => { + this.ws.on('open', () => { + this.ws.on('message', data => { + const parsedData = JSON.parse(data.toString()); + this.msgs.push(parsedData); + }); + resolve(); + }); + }); + } + + clear() { + this.msgs.length = 0; + } + + buildRequest(params: any[], method = 'eth_subscribe') { + return JSON.stringify({ + jsonrpc: '2.0', + id: ++this.curReqId, + method, + params, + }); + } + + async waitForMsg( + subId: string, + filterFn = (_msg: any) => true, + timeout = 5000, + ) { + return new Promise(resolve => { + const interval = setInterval(() => { + const msg = this.msgs + .filter(msg => msg.params?.subscription === subId) + .find(msg => filterFn(msg.params.result)); + + if (msg) { + clearInterval(interval); + resolve(msg); + } + }, 1000); + + setTimeout(() => { + clearInterval(interval); + resolve(null); + }, timeout); + }); + } + + async waitForSubs(reqId: number) { + return new Promise(resolve => { + const interval = setInterval(() => { + const msg = this.msgs.find(msg => msg.id === reqId); + + if (msg) { + clearInterval(interval); + resolve(msg); + } + }, 1000); + }); + } + + async subscribeNewHeads() { + this.ws.send( + this.buildRequest(['newHeads']) + ); + + const resp = await this.waitForSubs(this.curReqId); + return resp.result as string; + } + + async subscribeLogs(params: any) { + this.ws.send( + this.buildRequest(['logs', params]) + ); + + const resp = await this.waitForSubs(this.curReqId); + return resp.result as string; + } + + async unSubscribe(subId: string) { + this.ws.send( + this.buildRequest([subId], 'eth_unsubscribe') + ); + + const resp = await this.waitForSubs(this.curReqId); + return resp.result as string; + } + + close() { + this.ws.close(); + } +} + +export const getAddrSelector = (addr: string) => hexZeroPad(addr, 32); diff --git a/packages/eth-rpc-adapter/src/__tests__/consts.ts b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts similarity index 98% rename from packages/eth-rpc-adapter/src/__tests__/consts.ts rename to packages/eth-rpc-adapter/src/__tests__/utils/consts.ts index 0ba702cd8..f57243a9c 100644 --- a/packages/eth-rpc-adapter/src/__tests__/consts.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts @@ -10,17 +10,6 @@ export interface LogHexified { logIndex: string; } -export const evmAccounts = [ - { - privateKey: '0xa872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f', - evmAddress: '0x75E480dB528101a381Ce68544611C169Ad7EB342', - }, - { - privateKey: '0x4daddf7d5d2a9059e8065cb3ec50beabe2c23c7d6b3e380c1de8c40269acd85c', - evmAddress: '0xb00cB924ae22b2BBb15E10c17258D6a2af980421', - }, -]; - export const ADDRESS_ALICE = '0x82a258cb20e2adb4788153cd5eb5839615ece9a0'; export const DETERMINISTIC_SETUP_DEX_ADDRESS = '0x532394de2ca885b7e0306a2e258074cca4e42449'; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/evmAccounts.ts b/packages/eth-rpc-adapter/src/__tests__/utils/evmAccounts.ts new file mode 100644 index 000000000..90f7eb24f --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/utils/evmAccounts.ts @@ -0,0 +1,22 @@ +export const evmAccounts = [ + { + privateKey: '0xa872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd57f', + evmAddress: '0x75E480dB528101a381Ce68544611C169Ad7EB342', + defaultSubstrateAddress: '5EMjsczjoEZaNbWzoXDcZtZDSHN1SLmu4ArJcEJVorNDfUH3', + }, + { + privateKey: '0xefb03e3f4fd8b3d7f9b14de6c6fb95044e2321d6bcb9dfe287ba987920254044', + evmAddress: '0xe3234f433914d4cfCF846491EC5a7831ab9f0bb3', + defaultSubstrateAddress: '5EMjsd17gquqfcU6NJ7bT7A7DTGpMhM3J6TwwYRGmkMBknM8', + }, + { + privateKey: '0x4daddf7d5d2a9059e8065cb3ec50beabe2c23c7d6b3e380c1de8c40269acd85c', + evmAddress: '0xb00cB924ae22b2BBb15E10c17258D6a2af980421', + defaultSubstrateAddress: '5EMjsczwT7eJ4qYuJVQQgVYdkTArXmeLZbm9JM1QzQeQvGbi', + }, + { + privateKey: '0x01392cd1a09fc0f4857742f0f0daa3ebd5a0f44a7dab48c23ccd331717b97b10', + evmAddress: '0x0085560b24769dAC4ed057F1B2ae40746AA9aAb6', + defaultSubstrateAddress: '5EMjsczLHBZqbroMR4nZH6NvQQWHsVRFU9fbwQ14vBQCQx9H', + }, +]; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/index.ts b/packages/eth-rpc-adapter/src/__tests__/utils/index.ts new file mode 100644 index 000000000..4fc73a37b --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/utils/index.ts @@ -0,0 +1,4 @@ +export * from './SubsManager'; +export * from './test-utils'; +export * from './evmAccounts'; +export * from './consts'; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils.ts b/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts similarity index 99% rename from packages/eth-rpc-adapter/src/__tests__/utils.ts rename to packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts index 8ebd236eb..727b09fb6 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts @@ -7,7 +7,7 @@ import { parseEther } from 'ethers/lib/utils'; import axios from 'axios'; import { ERC20_ABI, ERC20_BYTECODE, GASMONSTER_ABI, GASMONSTER_BYTECODE, LogHexified } from './consts'; -import { JsonRpcError } from '../server'; +import { JsonRpcError } from '../../server'; export const NODE_RPC_URL = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; export const KARURA_ETH_RPC_URL = process.env.KARURA_ETH_RPC_URL || 'http://127.0.0.1:8546'; diff --git a/packages/eth-rpc-adapter/vitest.config.ts b/packages/eth-rpc-adapter/vitest.config.ts index becca8f07..1517a6fc1 100644 --- a/packages/eth-rpc-adapter/vitest.config.ts +++ b/packages/eth-rpc-adapter/vitest.config.ts @@ -6,7 +6,10 @@ export default mergeConfig( { test: { // include: ['**/*.test.ts'], // TODO: run all tests - include: ['src/__tests__/signer.test.ts'], + include: [ + 'src/__tests__/signer.test.ts', + 'src/__tests__/subscription.test.ts', + ], }, } ); diff --git a/yarn.lock b/yarn.lock index 08a0a2552..e9f88cd86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -99,6 +99,7 @@ __metadata: pm2: ^5.4.2 ts-node: ^10.9.1 ts-node-dev: ^2.0.0 + typechain: ^8.3.2 vitest: ^2.1.1 ws: ~8.2.3 yargs: 16.2.0 @@ -15135,7 +15136,7 @@ __metadata: languageName: node linkType: hard -"typechain@npm:^8.3.1": +"typechain@npm:^8.3.1, typechain@npm:^8.3.2": version: 8.3.2 resolution: "typechain@npm:8.3.2" dependencies: From ae416a03cb147b4e9ce1ba9fd422e0d7ffe19ea7 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Sat, 5 Oct 2024 00:31:10 +0800 Subject: [PATCH 02/23] errors test --- .../src/__tests__/errors.test.ts | 45 +-- .../src/__tests__/subscription.test.ts | 7 +- .../src/__tests__/utils/consts.ts | 289 +----------------- .../src/__tests__/utils/test-utils.ts | 22 +- 4 files changed, 46 insertions(+), 317 deletions(-) diff --git a/packages/eth-rpc-adapter/src/__tests__/errors.test.ts b/packages/eth-rpc-adapter/src/__tests__/errors.test.ts index 3253fe33a..b73d74eec 100644 --- a/packages/eth-rpc-adapter/src/__tests__/errors.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/errors.test.ts @@ -7,16 +7,24 @@ import ADDRESS from '@acala-network/contracts/utils/MandalaAddress'; import TokenABI from '@acala-network/contracts/build/contracts/Token.json'; import axios from 'axios'; -import { RPC_URL, eth_call, eth_chainId, eth_estimateGas, eth_getEthGas, eth_sendRawTransaction , evmAccounts } from './utils'; +import { + ETH_RPC_URL, + eth_call, + eth_chainId, + eth_estimateGas, + eth_getEthGas, + eth_sendRawTransaction , + evmAccounts, +} from './utils'; describe('errors', () => { const POOR_ACCOUNT = '0xa872f6cbd25a0e04a08b1e21098017a9e6194d101d75e13111f71410c59cd570'; - const poorWallet = new Wallet(POOR_ACCOUNT, new JsonRpcProvider(RPC_URL)); + const poorWallet = new Wallet(POOR_ACCOUNT, new JsonRpcProvider(ETH_RPC_URL)); it('invalid request', async () => { const id = 12345; - const res = await axios.get(RPC_URL, { + const res = await axios.get(ETH_RPC_URL, { data: { id, methodddddddd: 'vdhgkjshdbfksdh', @@ -34,8 +42,7 @@ describe('errors', () => { }); }); - // TODO: after the banned pool is disabled in dev mode, mayve change the endpoint to public one? or manually setup the banned pool time to positive to enable it - it('tx banned', async () => { + it('not enough balance', async () => { const [gasRes, chainIdRes, nonce] = await Promise.all([ eth_getEthGas(), eth_chainId(), @@ -55,26 +62,26 @@ describe('errors', () => { }; const rawTx = await poorWallet.signTransaction(tx); - let res = await eth_sendRawTransaction([rawTx]); + const res = await eth_sendRawTransaction([rawTx]); expect(res.data).to.deep.equal({ id: 0, jsonrpc: '2.0', error: { code: -32603, - data: 'Inability to pay some fees (e.g. account balance too low)', - message: '1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low', + message: '1010: {\"invalid\":{\"payment\":null}}', }, }); - res = await eth_sendRawTransaction([rawTx]); - expect(res.data).to.deep.equal({ - id: 0, - jsonrpc: '2.0', - error: { - code: -32603, - message: '1012: Transaction is temporarily banned', - }, - }); + // chopsticks does not support this + // res = await eth_sendRawTransaction([rawTx]); + // expect(res.data).to.deep.equal({ + // id: 0, + // jsonrpc: '2.0', + // error: { + // code: -32603, + // message: '1012: Transaction is temporarily banned', + // }, + // }); }); it('internal json rpc error', async () => { @@ -98,7 +105,7 @@ describe('errors', () => { const rawTx = await poorWallet.signTransaction(tx); const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error.message).to.contain('Invalid decimals'); + expect(res.data.error.message).to.contain('evm.InvalidDecimals'); }); it('correct error format for contract revert', async () => { @@ -115,7 +122,7 @@ describe('errors', () => { }); describe('throws outOfGas error when gaslimit too small', () => { - const provider = new AcalaJsonRpcProvider(RPC_URL); + const provider = new AcalaJsonRpcProvider(ETH_RPC_URL); const wallet = new Wallet(evmAccounts[0].privateKey, provider); const aca = new Contract(ADDRESS.ACA, TokenABI.abi, wallet); diff --git a/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts b/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts index 7b7b07d57..0505fe307 100644 --- a/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts @@ -1,20 +1,17 @@ import { ACA } from '@acala-network/contracts/utils/AcalaAddress'; -import { AcalaJsonRpcProvider, sleep } from '@acala-network/eth-providers'; +import { AcalaJsonRpcProvider } from '@acala-network/eth-providers'; import { JsonRpcProvider } from '@ethersproject/providers'; import { Wallet } from 'ethers'; import { afterAll, beforeAll, beforeEach, describe, it } from 'vitest'; import { expect } from 'chai'; import { parseUnits } from 'ethers/lib/utils'; +import { ETH_RPC_URL, ETH_RPC_URL_WS, SubsManager, evmAccounts, getAddrSelector } from './utils'; import { IERC20, IERC20__factory } from './types'; -import { SubsManager, evmAccounts, getAddrSelector } from './utils'; const oneAcaErc20 = parseUnits('1', 12); const TRANSFER_SELECTOR = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; -const ETH_RPC_URL = process.env.ENDPOINT_URL || 'http://localhost:8545'; -const ETH_RPC_URL_WS = ETH_RPC_URL.replace('http', 'ws'); - describe('eth subscription', () => { let deployer: Wallet; let user: Wallet; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts index f57243a9c..943663bbf 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts @@ -1,3 +1,9 @@ +export const NODE_RPC_URL = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; +export const KARURA_ETH_RPC_URL = process.env.KARURA_ETH_RPC_URL || 'http://127.0.0.1:8546'; +export const ETH_RPC_URL = process.env.ETH_RPC_URL || 'http://127.0.0.1:8545'; +export const ETH_RPC_URL_WS = process.env.ETH_RPC_URL_WS || ETH_RPC_URL.replace('http', 'ws'); +export const SUBQL_URL = process.env.SUBQL_URL || 'http://127.0.0.1:3001'; + export interface LogHexified { blockNumber: string; blockHash: string; @@ -218,289 +224,6 @@ export const allLogs = [ export const ERC20_BYTECODE = '6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029'; -export const ERC20_ABI = [ - { - constant: true, - inputs: [], - name: 'name', - outputs: [ - { - name: '', - type: 'string', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_spender', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'approve', - outputs: [ - { - name: 'success', - type: 'bool', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'totalSupply', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_from', - type: 'address', - }, - { - name: '_to', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'transferFrom', - outputs: [ - { - name: 'success', - type: 'bool', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '', - type: 'address', - }, - ], - name: 'balances', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'decimals', - outputs: [ - { - name: '', - type: 'uint8', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '', - type: 'address', - }, - { - name: '', - type: 'address', - }, - ], - name: 'allowed', - outputs: [ - { - name: '', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '_owner', - type: 'address', - }, - ], - name: 'balanceOf', - outputs: [ - { - name: 'balance', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: true, - inputs: [], - name: 'symbol', - outputs: [ - { - name: '', - type: 'string', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - constant: false, - inputs: [ - { - name: '_to', - type: 'address', - }, - { - name: '_value', - type: 'uint256', - }, - ], - name: 'transfer', - outputs: [ - { - name: 'success', - type: 'bool', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'function', - }, - { - constant: true, - inputs: [ - { - name: '_owner', - type: 'address', - }, - { - name: '_spender', - type: 'address', - }, - ], - name: 'allowance', - outputs: [ - { - name: 'remaining', - type: 'uint256', - }, - ], - payable: false, - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - name: '_initialAmount', - type: 'uint256', - }, - { - name: '_tokenName', - type: 'string', - }, - { - name: '_decimalUnits', - type: 'uint8', - }, - { - name: '_tokenSymbol', - type: 'string', - }, - ], - payable: false, - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: '_from', - type: 'address', - }, - { - indexed: true, - name: '_to', - type: 'address', - }, - { - indexed: false, - name: '_value', - type: 'uint256', - }, - ], - name: 'Transfer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: '_owner', - type: 'address', - }, - { - indexed: true, - name: '_spender', - type: 'address', - }, - { - indexed: false, - name: '_value', - type: 'uint256', - }, - ], - name: 'Approval', - type: 'event', - }, -]; - /* ----- contract GasMonster { uint256 x = 1; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts b/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts index 727b09fb6..7fc031e93 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts @@ -5,18 +5,20 @@ import { expect } from 'vitest'; import { hexValue } from '@ethersproject/bytes'; import { parseEther } from 'ethers/lib/utils'; import axios from 'axios'; - -import { ERC20_ABI, ERC20_BYTECODE, GASMONSTER_ABI, GASMONSTER_BYTECODE, LogHexified } from './consts'; +import erc20Abi from '../abis/IERC20.json'; + +import { + ERC20_BYTECODE, + ETH_RPC_URL, + GASMONSTER_ABI, + GASMONSTER_BYTECODE, + KARURA_ETH_RPC_URL, + LogHexified, +} from './consts'; import { JsonRpcError } from '../../server'; -export const NODE_RPC_URL = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; -export const KARURA_ETH_RPC_URL = process.env.KARURA_ETH_RPC_URL || 'http://127.0.0.1:8546'; -export const RPC_URL = process.env.RPC_URL || 'http://127.0.0.1:8545'; -export const WS_URL = process.env.WS_URL || 'ws://127.0.0.1:8545'; -export const SUBQL_URL = process.env.SUBQL_URL || 'http://127.0.0.1:3001'; - export const rpcGet = - (method: string, url: string = RPC_URL) => + (method: string, url: string = ETH_RPC_URL) => (params: any[] = []) => axios.get(url, { data: { @@ -111,7 +113,7 @@ export const expectLogsEqual = (a: LogHexified[], b: LogHexified[]): void => { }; export const deployErc20 = async (wallet: Signer) => { - const Token = new ContractFactory(ERC20_ABI, ERC20_BYTECODE, wallet); + const Token = new ContractFactory(erc20Abi.abi, ERC20_BYTECODE, wallet); const token = await Token.deploy(parseEther('1000000000'), 'TestToken', 18, 'TT'); await token.deployed(); From 6a0dac78a6735aeb599c382db50ebfe3b688ca92 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 09:37:23 +0800 Subject: [PATCH 03/23] utils refactor and eth_estimate gas tests --- packages/eth-rpc-adapter/package.json | 2 +- .../src/__tests__/bridge.test.ts | 13 +- .../endpoint.ts} | 87 +-- .../endpoint-tests/eth_estimateGas.test.ts | 117 ++++ .../src/__tests__/endpoint.test.ts.snap | 592 ------------------ .../src/__tests__/utils/consts.ts | 222 +------ .../src/__tests__/utils/erc20.ts | 295 +++++++++ .../src/__tests__/utils/eth-rpc-apis.ts | 57 ++ .../utils/{evmAccounts.ts => evm-accounts.ts} | 0 .../src/__tests__/utils/gas-monster.ts | 32 + .../src/__tests__/utils/index.ts | 7 +- .../utils/{SubsManager.ts => subs-manager.ts} | 0 .../src/__tests__/utils/test-utils.ts | 97 +-- packages/eth-rpc-adapter/vitest.config.ts | 10 +- 14 files changed, 520 insertions(+), 1011 deletions(-) rename packages/eth-rpc-adapter/src/__tests__/{endpoint.test.ts => endpoint-tests/endpoint.ts} (94%) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts delete mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts.snap create mode 100644 packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts create mode 100644 packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts rename packages/eth-rpc-adapter/src/__tests__/utils/{evmAccounts.ts => evm-accounts.ts} (100%) create mode 100644 packages/eth-rpc-adapter/src/__tests__/utils/gas-monster.ts rename packages/eth-rpc-adapter/src/__tests__/utils/{SubsManager.ts => subs-manager.ts} (100%) diff --git a/packages/eth-rpc-adapter/package.json b/packages/eth-rpc-adapter/package.json index 7a5a4d99c..3f3350032 100644 --- a/packages/eth-rpc-adapter/package.json +++ b/packages/eth-rpc-adapter/package.json @@ -14,7 +14,7 @@ "start": "ts-node -r tsconfig-paths/register src/index.ts", "start:coverage": "COVERAGE_DIR=${COVERAGE_DIR:-eth-rpc-adapter/coverage} pm2 start --name eth-rpc 'nyc --report-dir=$COVERAGE_DIR node -r ts-node/register -r tsconfig-paths/register src/index.ts' && yarn health-check", "stop:coverage": "pm2 stop eth-rpc && pm2 delete eth-rpc", - "test": "vitest", + "test": "vitest --no-file-parallelism", "test:coverage": "COVERAGE_DIR=${COVERAGE_DIR:-eth-rpc-adapter/coverage} yarn start:coverage && COVERAGE_DIR=${COVERAGE_DIR:-eth-rpc-adapter/coverage} yarn test --run && yarn stop:coverage" }, "peerDependencies": { diff --git a/packages/eth-rpc-adapter/src/__tests__/bridge.test.ts b/packages/eth-rpc-adapter/src/__tests__/bridge.test.ts index 6432f9870..8b0124aed 100644 --- a/packages/eth-rpc-adapter/src/__tests__/bridge.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/bridge.test.ts @@ -2,15 +2,12 @@ import { Eip1193Bridge } from '../eip1193-bridge'; import { EvmRpcProvider } from '@acala-network/eth-providers'; import { Wallet } from '@ethersproject/wallet'; import { afterAll, describe, expect, it } from 'vitest'; -import dotenv from 'dotenv'; -dotenv.config(); - -const endpoint = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; +import { NODE_URL, evmAccounts } from './utils'; describe('e2e test', async () => { - const signer = new Wallet('0x5a214c9bcb10dfe58af9b349cad6f4564cd6f10d880bdfcf780e5812c3cbc855'); - const provider = EvmRpcProvider.from(endpoint); + const signer = new Wallet(evmAccounts[0].privateKey); + const provider = EvmRpcProvider.from(NODE_URL); await provider.isReady(); afterAll(async () => { @@ -34,10 +31,6 @@ describe('e2e test', async () => { }); it('eth_getBlockByHash', async () => { - await expect( - bridge.send('eth_getBlockByHash', ['0xff2d5d74f16df09b810225ffd9e1442250914ae6de9459477118d675713c732c', false]) - ).resolves.toBeNull(); - const latest = await bridge.send('eth_getBlockByNumber', ['latest', false]); const block = await bridge.send('eth_getBlockByHash', [latest.hash, false]); expect(block.hash).equal(latest.hash); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts similarity index 94% rename from packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts rename to packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index d28957e5f..73ef5e6da 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -79,7 +79,7 @@ import { deployHelloWorldData, evmAccounts, log22_0, - log22_1 } from './utils'; + log22_1 } from '../utils'; const subql = new SubqlProvider(SUBQL_URL); @@ -1982,89 +1982,4 @@ describe('endpoint', () => { expect(res).to.deep.equal(true); }); }); - - describe('eth_estimateGas', () => { - const provider = new AcalaJsonRpcProvider(RPC_URL); - const wallet = new Wallet(evmAccounts[0].privateKey, provider); - - it('can deal with weird gas contract', async () => { - const gm = await deployGasMonster(wallet); - const tx = await gm.populateTransaction.run(); - - const { gasLimit } = await estimateGas(tx); - const bbb = (gasLimit.toNumber() % 100000) / 100; - - /* ---------- should work with latest and pending tag ---------- */ - const { gasLimit: gasLimitLatest } = await estimateGas(tx, 'latest'); - const { gasLimit: gasLimitPending } = await estimateGas(tx, 'pending'); - - expect(gasLimitLatest.toBigInt()).to.equal(gasLimit.toBigInt()); - expect(gasLimitPending.toBigInt()).to.equal(gasLimit.toBigInt()); - /* -------------------------------------------------------------- */ - - // should be passing gasLimit instead of usedGas - expect(bbb).to.gt(GAS_MONSTER_GAS_REQUIRED / 30000); - - await (await gm.run()).wait(); // make sure running has no error - }); - - describe('works with gas overrides', () => { - let token: Contract; - - beforeAll(async () => { - token = await deployErc20(wallet); - }); - - it('works with valid gas overrides', async () => { - const tx = await token.populateTransaction.transfer(evmAccounts[1].evmAddress, 1000); - const { gasLimit: realGasLimit, gasPrice } = await estimateGas(tx); - - const resps = await Promise.all([ - eth_estimateGas([{ ...tx, gasPrice, gas: realGasLimit }]), - eth_estimateGas([{ ...tx, gasPrice }]), - eth_estimateGas([{ ...tx, gas: realGasLimit }]), - - eth_estimateGas([{ ...tx, gas: 101520 }]), // increase gas and storagelimits - eth_estimateGas([{ ...tx, gasPrice: parseUnits('234.001298752', 'gwei') }]), // increase tip and valid until - eth_estimateGas([{ ...tx, gasPrice: parseUnits('321.001000000', 'gwei'), gas: 102518 }]), // increase everything - ]); - - const errs = resps.map(r => r.data.error); - if (errs.some(e => e !== undefined)) { - expect.fail(`some of the requests failed: ${JSON.stringify(errs, null, 2) }`); - } - - const results = resps.map(r => r.data.result) - .slice(0, 4); // last request has slightly different estimated gaslimit since it has different gasPrice - if (results.some(e => BigInt(e) !== realGasLimit.toBigInt())) { - expect.fail(`some of the requests returned wrong gasLimit: ${JSON.stringify(results, null, 2) }`); - } - }); - - it('throws error with invalid gas overrides', async () => { - const tx = await token.populateTransaction.transfer(Wallet.createRandom().address, 100000); - - const resps = await Promise.all([ - eth_estimateGas([{ ...tx, gasPrice: parseUnits('100.000000001', 'gwei') }]), // too low valid until - eth_estimateGas([{ ...tx, gasPrice: parseUnits('38.0000090000', 'gwei') }]), // invalid gasPrice - eth_estimateGas([{ ...tx, gas: 20100 }]), // too low storagelimit - eth_estimateGas([{ ...tx, gas: 200109 }]), // too low gaslimit - eth_estimateGas([{ ...tx, gas: 200301 }]), // too low gaslimit + storagelimit - eth_estimateGas([{ ...tx, gasPrice: parseUnits('100.000000001', 'gwei'), gas: 200301 }]), // too low everything - ]); - - const errs = resps.map(r => r.data.error?.message); - if (errs.some(e => e === undefined)) { - expect.fail(`some of the requests didn't fail when it should: ${JSON.stringify(errs, null, 2) }`); - } - - expect(errs[0]).to.contain('Error: invalid gasPrice'); - expect(errs[1]).to.contain('Error: invalid gasPrice'); - expect(errs[2]).to.contain('evm.OutOfStorage'); - expect(errs[3]).to.contain('execution error: outOfGas'); - expect(errs[4]).to.contain('evm.OutOfStorage'); - expect(errs[5]).to.contain('Error: invalid gasPrice'); - }); - }); - }); }); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts new file mode 100644 index 000000000..87730bba0 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts @@ -0,0 +1,117 @@ +import { AcalaJsonRpcProvider, BlockTagish } from '@acala-network/eth-providers'; +import { BigNumber, Contract, Wallet } from 'ethers'; +import { TransactionRequest } from '@ethersproject/abstract-provider'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { parseUnits } from 'ethers/lib/utils'; + +import { + ETH_RPC_URL, + GAS_MONSTER_GAS_REQUIRED, + deployErc20, + deployGasMonster, + eth_estimateGas, + eth_gasPrice, + evmAccounts, +} from '../utils'; + +export const estimateGas = async ( + tx: TransactionRequest, + blockTag?: BlockTagish +) => { + const gasPrice = (await eth_gasPrice([])).data.result; + const res = await eth_estimateGas([{ ...tx, gasPrice }, blockTag]); + if (res.data.error) { + throw new Error(res.data.error.message); + } + const gasLimit = res.data.result; + + return { + gasPrice: BigNumber.from(gasPrice), + gasLimit: BigNumber.from(gasLimit), + }; +}; + +const provider = new AcalaJsonRpcProvider(ETH_RPC_URL); +const wallet = new Wallet(evmAccounts[0].privateKey, provider); + +describe('eth_estimateGas', () => { + it('can deal with weird gas contract', async () => { + const gm = await deployGasMonster(wallet); + const tx = await gm.populateTransaction.run(); + + const { gasLimit } = await estimateGas(tx); + const bbb = (gasLimit.toNumber() % 100000) / 100; + + /* ---------- should work with latest and pending tag ---------- */ + const { gasLimit: gasLimitLatest } = await estimateGas(tx, 'latest'); + const { gasLimit: gasLimitPending } = await estimateGas(tx, 'pending'); + + expect(gasLimitLatest.toBigInt()).to.equal(gasLimit.toBigInt()); + expect(gasLimitPending.toBigInt()).to.equal(gasLimit.toBigInt()); + /* -------------------------------------------------------------- */ + + // should be passing gasLimit instead of usedGas + expect(bbb).to.gt(GAS_MONSTER_GAS_REQUIRED / 30000); + + await (await gm.run()).wait(); // make sure running has no error + }); + + describe('works with gas overrides', () => { + let token: Contract; + + beforeAll(async () => { + token = await deployErc20(wallet); + }); + + it('works with valid gas overrides', async () => { + const tx = await token.populateTransaction.transfer(evmAccounts[1].evmAddress, 1000); + const { gasLimit: realGasLimit, gasPrice } = await estimateGas(tx); + + const resps = await Promise.all([ + eth_estimateGas([{ ...tx, gasPrice, gas: realGasLimit }]), + eth_estimateGas([{ ...tx, gasPrice }]), + eth_estimateGas([{ ...tx, gas: realGasLimit }]), + + eth_estimateGas([{ ...tx, gas: 101520 }]), // increase gas and storagelimits + eth_estimateGas([{ ...tx, gasPrice: parseUnits('234.001298752', 'gwei') }]), // increase tip and valid until + eth_estimateGas([{ ...tx, gasPrice: parseUnits('321.001000000', 'gwei'), gas: 102518 }]), // increase everything + ]); + + const errs = resps.map(r => r.data.error); + if (errs.some(e => e !== undefined)) { + expect.fail(`some of the requests failed: ${JSON.stringify(errs, null, 2)}`); + } + + const results = resps.map(r => r.data.result) + .slice(0, 4); // last request has slightly different estimated gaslimit since it has different gasPrice + if (results.some(e => BigInt(e) !== realGasLimit.toBigInt())) { + expect.fail(`some of the requests returned wrong gasLimit: ${JSON.stringify(results, null, 2)}`); + } + }); + + it('throws error with invalid gas overrides', async () => { + const tx = await token.populateTransaction.transfer(Wallet.createRandom().address, 100000); + + const resps = await Promise.all([ + eth_estimateGas([{ ...tx, gasPrice: parseUnits('100.000000001', 'gwei') }]), // too low valid until + eth_estimateGas([{ ...tx, gasPrice: parseUnits('38.0000090000', 'gwei') }]), // invalid gasPrice + eth_estimateGas([{ ...tx, gas: 20100 }]), // too low storagelimit + eth_estimateGas([{ ...tx, gas: 200109 }]), // too low gaslimit + eth_estimateGas([{ ...tx, gas: 200301 }]), // too low gaslimit + storagelimit + eth_estimateGas([{ ...tx, gasPrice: parseUnits('100.000000001', 'gwei'), gas: 200301 }]), // too low everything + ]); + + const errs = resps.map(r => r.data.error?.message); + if (errs.some(e => e === undefined)) { + expect.fail(`some of the requests didn't fail when it should: ${JSON.stringify(errs, null, 2)}`); + } + + expect(errs[0]).to.contain('Error: invalid gasPrice'); + expect(errs[1]).to.contain('Error: invalid gasPrice'); + expect(errs[2]).to.contain('evm.OutOfStorage'); + expect(errs[3]).to.contain('execution error: outOfGas'); + expect(errs[4]).to.contain('evm.OutOfStorage'); + expect(errs[5]).to.contain('Error: invalid gasPrice'); + }); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts.snap b/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts.snap deleted file mode 100644 index bafb6209a..000000000 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint.test.ts.snap +++ /dev/null @@ -1,592 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`endpoint > eth_getBlockByNumber > for very old runtime 1`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x0", - "hash": "0x000643ffd6bbb04682ae1675e2e478e4c8ecd7c7b9d7e9d1eafe1b6095f751e3", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0x8ce1cab8e0d55252720728bc495d05841ea3dc23", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x5ae2c", - "parentHash": "0xe2ebe9eb139f9bc88862615f6a0c5095417595a0f80bd4f7f94c1c3753499973", - "receiptsRoot": "0xd3596ebbbb67ac571735047e856cecb63f3d8a519af4699ecc4505de59d570e5", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0xa80", - "stateRoot": "0xd440bfe07178304657083255758ec74358a3ed592720a8484015d1d89950e81e", - "timestamp": "0x611f2b1e", - "totalDifficulty": "0x0", - "transactions": [], - "transactionsRoot": "0xd3596ebbbb67ac571735047e856cecb63f3d8a519af4699ecc4505de59d570e5", - "uncles": [], -} -`; - -exports[`endpoint > eth_getBlockByNumber > for very old runtime 2`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x0", - "hash": "0x000643ffd6bbb04682ae1675e2e478e4c8ecd7c7b9d7e9d1eafe1b6095f751e3", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0x8ce1cab8e0d55252720728bc495d05841ea3dc23", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x5ae2c", - "parentHash": "0xe2ebe9eb139f9bc88862615f6a0c5095417595a0f80bd4f7f94c1c3753499973", - "receiptsRoot": "0xd3596ebbbb67ac571735047e856cecb63f3d8a519af4699ecc4505de59d570e5", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0xa80", - "stateRoot": "0xd440bfe07178304657083255758ec74358a3ed592720a8484015d1d89950e81e", - "timestamp": "0x611f2b1e", - "totalDifficulty": "0x0", - "transactions": [], - "transactionsRoot": "0xd3596ebbbb67ac571735047e856cecb63f3d8a519af4699ecc4505de59d570e5", - "uncles": [], -} -`; - -exports[`endpoint > eth_getBlockByNumber > when there are >= 2 EVM transactions 1`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x36c64", - "hash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0xaa8b848056f89fc7f3bcc7c0a790ab8280423100", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x25623f", - "parentHash": "0xfd3443eda6f3c9406b31175d9d8b9d497a0d3163f093d122ccb7d6c373e22fff", - "receiptsRoot": "0xdbed29fd64f319f13f6c58311eb910fdc3c2e7aa686d58b822afee9469eee766", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0x398e", - "stateRoot": "0x86203b2bd6ae7978c1f53cca5a57bf216b83f247fbcdb26ca55c760e39741074", - "timestamp": "0x62f8bc54", - "totalDifficulty": "0x0", - "transactions": [ - { - "blockHash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", - "blockNumber": "0x25623f", - "from": "0x9cb3b68e0c48c53b70f465bda3ba6481a9cb7720", - "gas": "0x2b3e6", - "gasPrice": "0x15fde28667", - "hash": "0x7b0361f47dc0be798cb9f7d115d74d68960e685714c515df81dd1a17e3db0cff", - "input": "0x36877dceeac06b4f60edb2a940a2170eea5cef018dc569f5d98b8176f5da7ea640c9bd2700000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000fef000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000000000000008400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000001550f7dca7000000000000000000000000000000000000000000000000000000000000000000d64a08aa86bbf7225c35a44854c181d80022883dc9dde1976f77aa984c841d7a8410102cd33c78438b8f2d7c1eb1b053c0630ebc5787b1dfcab0c019811dc32fbb532aa57f8293f2be947ac467d9d8dae7e700fba81a21745eb1bfbbdff26785b26edd7f83ddfb4c64a8e95afb16d4567f4899ebf1b12fddfeee80b89c755943ed8e9c4bec1dbd12cb450b8cedb4b622744e376cc0da08225111572522010fd0d49e12e0b6acb81cb419c3f4c187b0b4c15377be15efa1f3b23b60d73263eb10c87abdcafb6b60c06f42145596c0eeecacb8d86e69e4210787250f7eef601c96163f1d8a0aa98b7cd67da0b8f69fcaa70e4649b0107d65a86e8940fb4197578b903a43eeca16395c04cc9bd080ed66ba205706331b9572f1bf2c528e7af23f46b637b37a59a219b36fed2c4ae586bfdec199ae0b3cc261dae4854dca625a6a79913258b595af6a8abbabb043bb5d6ca6f0553ed59e05cc8b25a6f10b40ffe598c36bad9b6f945a1e85d980c5bf5b016059e0aee384a32a729d393b5214f2638a08918e3dea5e9eded8b0060a49195b0e18e4c698fb9dfe8f2d16bc47494b70ceb", - "nonce": "0x3", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0x30385059196602a1498f5f8ef91f3450e3a7b27a", - "transactionIndex": "0x0", - "v": "0x25", - "value": "0x0", - }, - { - "blockHash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", - "blockNumber": "0x25623f", - "from": "0xc760da3c525c8511938c35613684c3f6175c01a5", - "gas": "0x200b20", - "gasPrice": "0xb460f6718", - "hash": "0x9824e1111ba926db7df3091ec45344f224a3086daf5580eaf7ab3e6bf5a6dde6", - "input": "0x", - "nonce": "0x65", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0x1f3a10587a20114ea25ba1b388ee2dd4a337ce27", - "transactionIndex": "0x1", - "v": "0x25", - "value": "0x0", - }, - ], - "transactionsRoot": "0xdbed29fd64f319f13f6c58311eb910fdc3c2e7aa686d58b822afee9469eee766", - "uncles": [], -} -`; - -exports[`endpoint > eth_getBlockByNumber > when there are >= 2 EVM transactions 2`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x36c64", - "hash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0xaa8b848056f89fc7f3bcc7c0a790ab8280423100", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x25623f", - "parentHash": "0xfd3443eda6f3c9406b31175d9d8b9d497a0d3163f093d122ccb7d6c373e22fff", - "receiptsRoot": "0xdbed29fd64f319f13f6c58311eb910fdc3c2e7aa686d58b822afee9469eee766", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0x398e", - "stateRoot": "0x86203b2bd6ae7978c1f53cca5a57bf216b83f247fbcdb26ca55c760e39741074", - "timestamp": "0x62f8bc54", - "totalDifficulty": "0x0", - "transactions": [ - "0x7b0361f47dc0be798cb9f7d115d74d68960e685714c515df81dd1a17e3db0cff", - "0x9824e1111ba926db7df3091ec45344f224a3086daf5580eaf7ab3e6bf5a6dde6", - ], - "transactionsRoot": "0xdbed29fd64f319f13f6c58311eb910fdc3c2e7aa686d58b822afee9469eee766", - "uncles": [], -} -`; - -exports[`endpoint > eth_getBlockByNumber > when there are 0 EVM transactions 1`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x0", - "hash": "0x5108a4f02624cc0fca4d68ab3429503249525218a1c23f38a2cf40b1f3456fab", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0x520425df7e86cb8dffd8fd140b075140b28f9629", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x1bbe4c", - "parentHash": "0x0af99e49b978dfeddc023f32a96fc4907aa99409c1804380fca5e0767ca5624f", - "receiptsRoot": "0x9482be879e7e6984d5c4071ef21fff39232c95331f12b14c0ca70e7eb6ef9df4", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0x1e5f", - "stateRoot": "0xb234e197e811f9402fc3cc9b46a953d7c20ff54fbe5a65fa89315d786a6839fe", - "timestamp": "0x626b3a76", - "totalDifficulty": "0x0", - "transactions": [], - "transactionsRoot": "0x9482be879e7e6984d5c4071ef21fff39232c95331f12b14c0ca70e7eb6ef9df4", - "uncles": [], -} -`; - -exports[`endpoint > eth_getBlockByNumber > when there are 0 EVM transactions 2`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x0", - "hash": "0x5108a4f02624cc0fca4d68ab3429503249525218a1c23f38a2cf40b1f3456fab", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0x520425df7e86cb8dffd8fd140b075140b28f9629", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x1bbe4c", - "parentHash": "0x0af99e49b978dfeddc023f32a96fc4907aa99409c1804380fca5e0767ca5624f", - "receiptsRoot": "0x9482be879e7e6984d5c4071ef21fff39232c95331f12b14c0ca70e7eb6ef9df4", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0x1e5f", - "stateRoot": "0xb234e197e811f9402fc3cc9b46a953d7c20ff54fbe5a65fa89315d786a6839fe", - "timestamp": "0x626b3a76", - "totalDifficulty": "0x0", - "transactions": [], - "transactionsRoot": "0x9482be879e7e6984d5c4071ef21fff39232c95331f12b14c0ca70e7eb6ef9df4", - "uncles": [], -} -`; - -exports[`endpoint > eth_getBlockByNumber > when there are 1 EVM transactions 1`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x3181f", - "hash": "0xab9f0519e9f9885861da35765dad61161c5f939c66b4c4b7091f7e9555e9f92f", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0x576482c15d3e4ec12c0577c611d3ed05eadfed46", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x1bbf96", - "parentHash": "0xf7e284c6d581bb34c2234c5c0a60ed1303a88e905328f4b7fc76c93e2da15c51", - "receiptsRoot": "0xcf70602c561d49922720605e4a670cdacd0474477c126cb6459f0e3ae3c1fd4b", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0x1f5a", - "stateRoot": "0xa02039723e96992aca76880a27b3d3da63bcbef0e932f27a7180276a2033c040", - "timestamp": "0x626b5756", - "totalDifficulty": "0x0", - "transactions": [ - { - "blockHash": "0xab9f0519e9f9885861da35765dad61161c5f939c66b4c4b7091f7e9555e9f92f", - "blockNumber": "0x1bbf96", - "from": "0x0000000000000000000000000000000000000000", - "gas": "0x200b20", - "gasPrice": "0x4ced5668c50", - "hash": "0x79090e3e64da12012839fb40f95ad03703a6d3c999c262b4196796f9753861ca", - "input": "0x", - "nonce": "0x1cb", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": null, - "transactionIndex": "0x0", - "v": "0x25", - "value": "0x0", - }, - ], - "transactionsRoot": "0xcf70602c561d49922720605e4a670cdacd0474477c126cb6459f0e3ae3c1fd4b", - "uncles": [], -} -`; - -exports[`endpoint > eth_getBlockByNumber > when there are 1 EVM transactions 2`] = ` -{ - "difficulty": "0x0", - "extraData": "0x", - "gasLimit": "0x1c99c80", - "gasUsed": "0x3181f", - "hash": "0xab9f0519e9f9885861da35765dad61161c5f939c66b4c4b7091f7e9555e9f92f", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "miner": "0x576482c15d3e4ec12c0577c611d3ed05eadfed46", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "number": "0x1bbf96", - "parentHash": "0xf7e284c6d581bb34c2234c5c0a60ed1303a88e905328f4b7fc76c93e2da15c51", - "receiptsRoot": "0xcf70602c561d49922720605e4a670cdacd0474477c126cb6459f0e3ae3c1fd4b", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "size": "0x1f5a", - "stateRoot": "0xa02039723e96992aca76880a27b3d3da63bcbef0e932f27a7180276a2033c040", - "timestamp": "0x626b5756", - "totalDifficulty": "0x0", - "transactions": [ - "0x79090e3e64da12012839fb40f95ad03703a6d3c999c262b4196796f9753861ca", - ], - "transactionsRoot": "0xcf70602c561d49922720605e4a670cdacd0474477c126cb6459f0e3ae3c1fd4b", - "uncles": [], -} -`; - -exports[`endpoint > eth_getTransactionByHash > finds correct tx when hash exist for local transactions 1`] = ` -{ - "blockNumber": "0xa", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gas": "0x1fcfa", - "gasPrice": "0x25592c5c5f", - "input": "0x3d8d96200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000001", - "nonce": "0x6", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0x0230135fded668a3f7894966b14f42e65da322e4", - "transactionIndex": "0x0", - "v": "0x25", - "value": "0xde0b6b3a7640000", -} -`; - -exports[`endpoint > eth_getTransactionByHash > finds correct tx when hash exist for local transactions 2`] = ` -{ - "blockNumber": "0x9", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gas": "0x25a18", - "gasPrice": "0x22c1d12a54", - "input": "0x3d8d962000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000e8d4a510000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000010000000000000000000000000000000000000000000100000000000000000002", - "nonce": "0x5", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0x0230135fded668a3f7894966b14f42e65da322e4", - "transactionIndex": "0x0", - "v": "0x25", - "value": "0xde0b6b3a7640000", -} -`; - -exports[`endpoint > eth_getTransactionByHash > finds correct tx when hash exist for local transactions 3`] = ` -{ - "blockNumber": "0x6", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gas": "0x1fd26", - "gasPrice": "0x2557747a01", - "input": "0x6fc4b4e50000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000e8d4a510000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000001", - "nonce": "0x2", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0x0230135fded668a3f7894966b14f42e65da322e4", - "transactionIndex": "0x0", - "v": "0x25", - "value": "0xde0b6b3a7640000", -} -`; - -exports[`endpoint > eth_getTransactionByHash > finds correct tx when hash exist for local transactions 4`] = ` -{ - "blockNumber": "0x14", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gas": "0x200b20", - "gasPrice": "0x419514ca84", - "input": "0x", - "nonce": "0x10", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0x532394de2ca885b7e0306a2e258074cca4e42449", - "transactionIndex": "0x0", - "v": "0x25", - "value": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionByHash > returns correct result for public karura transactions 1`] = ` -{ - "blockNumber": "0x2ac207", - "from": "0x99537d82f6f4aad1419dd14952b512c7959a2904", - "gas": "0xc3500", - "gasPrice": "0xc691dc448", - "input": "0x29941edd7ba288a014555c9b1446b215605b4f6803e68a8b430bcbc08e75400e4b38a1a10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000002a8aa000000000000000000000000000000000000000000000000000000000002ac150", - "nonce": "0x98", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0xff066331be693be721994cf19905b2dc7475c5c9", - "transactionIndex": "0x0", - "v": "0x25", - "value": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionByHash > returns correct result for public karura transactions 2`] = ` -{ - "blockNumber": "0x1bd799", - "from": "0xe2e2d9e31d7e1cc1178fe0d1c5950f6c809816a3", - "gas": "0x1406f40", - "gasPrice": "0x2e73326680e", - "input": "0x608060405234801561001057600080fd5b5060405161078f38038061078f83398101604081905261002f91610314565b818161005c60017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd61042c565b6000805160206107488339815191521461008657634e487b7160e01b600052600160045260246000fd5b6100928282600061009b565b50505050610491565b6100a4836100d1565b6000825111806100b15750805b156100cc576100ca838361011160201b6100291760201c565b505b505050565b6100da8161013d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606101368383604051806060016040528060278152602001610768602791396101fd565b9392505050565b610150816102d260201b6100551760201c565b6101b75760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b806101dc60008051602061074883398151915260001b6102d860201b61005b1760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6060833b61025c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016101ae565b600080856001600160a01b03168560405161027791906103dd565b600060405180830381855af49150503d80600081146102b2576040519150601f19603f3d011682016040523d82523d6000602084013e6102b7565b606091505b5090925090506102c88282866102db565b9695505050505050565b3b151590565b90565b606083156102ea575081610136565b8251156102fa5782518084602001fd5b8160405162461bcd60e51b81526004016101ae91906103f9565b60008060408385031215610326578182fd5b82516001600160a01b038116811461033c578283fd5b60208401519092506001600160401b0380821115610358578283fd5b818501915085601f83011261036b578283fd5b81518181111561037d5761037d61047b565b604051601f8201601f19908116603f011681019083821181831017156103a5576103a561047b565b816040528281528860208487010111156103bd578586fd5b6103ce83602083016020880161044f565b80955050505050509250929050565b600082516103ef81846020870161044f565b9190910192915050565b602081526000825180602084015261041881604085016020870161044f565b601f01601f19169190910160400192915050565b60008282101561044a57634e487b7160e01b81526011600452602481fd5b500390565b60005b8381101561046a578181015183820152602001610452565b838111156100ca5750506000910152565b634e487b7160e01b600052604160045260246000fd5b6102a8806104a06000396000f3fe60806040523661001357610011610017565b005b6100115b61002761002261005e565b610096565b565b606061004e838360405180606001604052806027815260200161024c602791396100ba565b9392505050565b3b151590565b90565b60006100917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156100b5573d6000f35b3d6000fd5b6060833b61011e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b03168560405161013991906101cc565b600060405180830381855af49150503d8060008114610174576040519150601f19603f3d011682016040523d82523d6000602084013e610179565b606091505b5091509150610189828286610193565b9695505050505050565b606083156101a257508161004e565b8251156101b25782518084602001fd5b8160405162461bcd60e51b815260040161011591906101e8565b600082516101de81846020870161021b565b9190910192915050565b602081526000825180602084015261020781604085016020870161021b565b601f01601f19169190910160400192915050565b60005b8381101561023657818101518382015260200161021e565b83811115610245576000848401525b5050505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212203ee6993445d26cb1f3937811bd071a1164dee553ec2fc9b1ae9ba0be2a91946f64736f6c63430008040033360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564000000000000000000000000141fba8ad5d61bdab45a047cf60b5ad9784987fb000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e434a5fcd4000000000000000000000000c0946f51ddd63e12c51b23f5814b43c9bc8aa70000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000100000000000000000000000058cc3ae5c097b213ce3c81979e1b9f9570746aa500000000000000000000000000000000000000000000000000000000", - "nonce": "0x4", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": null, - "transactionIndex": "0x0", - "v": "0x25", - "value": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionByHash > returns correct result for public karura transactions 3`] = ` -{ - "blockNumber": "0x2ac93c", - "from": "0xffffd2ff9b840f6bd74f80df8e532b4d7886ffff", - "gas": "0x5728", - "gasPrice": "0x1bb7d40e19", - "input": "0x", - "nonce": "0x41", - "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", - "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", - "to": "0xffffd2ff9b840f6bd74f80df8e532b4d7886ffff", - "transactionIndex": "0x0", - "v": "0x25", - "value": "0x1121d33597384000", -} -`; - -exports[`endpoint > eth_getTransactionReceipt > returns correct result for public karura transactions 1`] = ` -{ - "blockNumber": "0x2ac207", - "contractAddress": null, - "cumulativeGasUsed": "0x0", - "effectiveGasPrice": "0xc691dc448", - "from": "0x99537d82f6f4aad1419dd14952b512c7959a2904", - "gasUsed": "0x12a44", - "logs": [ - { - "address": "0xff066331be693be721994cf19905b2dc7475c5c9", - "blockNumber": "0x2ac207", - "data": "0x00000000000000000000000000000000000000000000000000000000002a8aa000000000000000000000000000000000000000000000000000000000002ac150000000000000000000000000000000000000000000000000000000006340cef600000000000000000000000000000000000000000000000000000000002ac207", - "logIndex": "0x0", - "topics": [ - "0x9e6c2a5268879d41429e8c2d6f88e2c3d1a20752070e9afb3f6b9aa9dbb01a90", - "0x0000000000000000000000000000000000000000000000000000000000000012", - "0x7ba288a014555c9b1446b215605b4f6803e68a8b430bcbc08e75400e4b38a1a1", - "0x0000000000000000000000000000000000000000000000000000000000000000", - ], - "transactionIndex": "0x0", - }, - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "status": "0x1", - "to": "0xff066331be693be721994cf19905b2dc7475c5c9", - "transactionIndex": "0x0", - "type": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionReceipt > returns correct result for public karura transactions 2`] = ` -{ - "blockNumber": "0x1bd799", - "contractAddress": "0xa321448d90d4e5b0a732867c18ea198e75cac48e", - "cumulativeGasUsed": "0x0", - "effectiveGasPrice": "0x2e73326680e", - "from": "0xe2e2d9e31d7e1cc1178fe0d1c5950f6c809816a3", - "gasUsed": "0x560dc", - "logs": [ - { - "address": "0xa321448d90d4e5b0a732867c18ea198e75cac48e", - "blockNumber": "0x1bd799", - "data": "0x", - "logIndex": "0x0", - "topics": [ - "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000141fba8ad5d61bdab45a047cf60b5ad9784987fb", - ], - "transactionIndex": "0x0", - }, - { - "address": "0xa321448d90d4e5b0a732867c18ea198e75cac48e", - "blockNumber": "0x1bd799", - "data": "0x", - "logIndex": "0x1", - "topics": [ - "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", - "0x000000000000000000000000c0946f51ddd63e12c51b23f5814b43c9bc8aa700", - ], - "transactionIndex": "0x0", - }, - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "status": "0x1", - "to": null, - "transactionIndex": "0x0", - "type": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionReceipt > returns correct result for public karura transactions 3`] = ` -{ - "blockNumber": "0x2ac93c", - "contractAddress": null, - "cumulativeGasUsed": "0x0", - "effectiveGasPrice": "0x1bb7d40e19", - "from": "0xffffd2ff9b840f6bd74f80df8e532b4d7886ffff", - "gasUsed": "0x5208", - "logs": [], - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "status": "0x1", - "to": "0xffffd2ff9b840f6bd74f80df8e532b4d7886ffff", - "transactionIndex": "0x0", - "type": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionReceipt > returns correct result when hash exist for local transactions 1`] = ` -{ - "blockNumber": "0xa", - "contractAddress": null, - "cumulativeGasUsed": "0x0", - "effectiveGasPrice": "0x25592c5c5f", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gasUsed": "0x1a826", - "logs": [ - { - "address": "0x0000000000000000000000000000000000000803", - "blockNumber": "0xa", - "data": "0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000748849ea0c000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000001", - "logIndex": "0x0", - "topics": [ - "0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a", - "0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4", - ], - "transactionIndex": "0x0", - }, - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "status": "0x1", - "to": "0x0230135fded668a3f7894966b14f42e65da322e4", - "transactionIndex": "0x0", - "type": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionReceipt > returns correct result when hash exist for local transactions 2`] = ` -{ - "blockNumber": "0x9", - "contractAddress": null, - "cumulativeGasUsed": "0x0", - "effectiveGasPrice": "0x22c1d12a54", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gasUsed": "0x1f5bf", - "logs": [ - { - "address": "0x0000000000000000000000000000000000000803", - "blockNumber": "0x9", - "data": "0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000010000000000000000000000000000000000000000000100000000000000000002", - "logIndex": "0x0", - "topics": [ - "0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a", - "0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4", - ], - "transactionIndex": "0x0", - }, - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "status": "0x1", - "to": "0x0230135fded668a3f7894966b14f42e65da322e4", - "transactionIndex": "0x0", - "type": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionReceipt > returns correct result when hash exist for local transactions 3`] = ` -{ - "blockNumber": "0x6", - "contractAddress": null, - "cumulativeGasUsed": "0x0", - "effectiveGasPrice": "0x2557747a01", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gasUsed": "0x1a84b", - "logs": [ - { - "address": "0x0000000000000000000000000000000000000803", - "blockNumber": "0x6", - "data": "0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000001d131f6171f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000001", - "logIndex": "0x0", - "topics": [ - "0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a", - "0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4", - ], - "transactionIndex": "0x0", - }, - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "status": "0x1", - "to": "0x0230135fded668a3f7894966b14f42e65da322e4", - "transactionIndex": "0x0", - "type": "0x0", -} -`; - -exports[`endpoint > eth_getTransactionReceipt > returns correct result when hash exist for local transactions 4`] = ` -{ - "blockNumber": "0x14", - "contractAddress": null, - "cumulativeGasUsed": "0x0", - "effectiveGasPrice": "0x419514ca84", - "from": "0x82a258cb20e2adb4788153cd5eb5839615ece9a0", - "gasUsed": "0xcbbd", - "logs": [ - { - "address": "0x532394de2ca885b7e0306a2e258074cca4e42449", - "blockNumber": "0x14", - "data": "0x0000000000000000000000000000000000000000000000000000000000002710", - "logIndex": "0x0", - "topics": [ - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0", - "0x000000000000000000000000905c015e38c24ed973fd6075541a124c621fa743", - ], - "transactionIndex": "0x0", - }, - { - "address": "0xe85ef9063dd28f157eb97ca03f50f4a3bdecd37e", - "blockNumber": "0x14", - "data": "0x00000000000000000000000000000000000000000000000000000000000003e8", - "logIndex": "0x1", - "topics": [ - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0", - "0x000000000000000000000000905c015e38c24ed973fd6075541a124c621fa743", - ], - "transactionIndex": "0x0", - }, - ], - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "status": "0x1", - "to": "0x532394de2ca885b7e0306a2e258074cca4e42449", - "transactionIndex": "0x0", - "type": "0x0", -} -`; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts index 943663bbf..e57229101 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts @@ -1,4 +1,4 @@ -export const NODE_RPC_URL = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; +export const NODE_URL = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; export const KARURA_ETH_RPC_URL = process.env.KARURA_ETH_RPC_URL || 'http://127.0.0.1:8546'; export const ETH_RPC_URL = process.env.ETH_RPC_URL || 'http://127.0.0.1:8545'; export const ETH_RPC_URL_WS = process.env.ETH_RPC_URL_WS || ETH_RPC_URL.replace('http', 'ws'); @@ -26,223 +26,3 @@ export const KARURA_SEND_KAR_TX_HASH = '0x69493fd597760d5ad3a81ebbbb48abcc686d33 export const deployHelloWorldData = '0x60806040526040518060400160405280600c81526020017f48656c6c6f20576f726c642100000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610166565b82805461006e90610134565b90600052602060002090601f01602090048101928261009057600085556100d7565b82601f106100a957805160ff19168380011785556100d7565b828001600101855582156100d7579182015b828111156100d65782518255916020019190600101906100bb565b5b5090506100e491906100e8565b5090565b5b808211156101015760008160009055506001016100e9565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061014c57607f821691505b602082108114156101605761015f610105565b5b50919050565b61022e806101756000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c605f76c14610030575b600080fd5b61003861004e565b6040516100459190610175565b60405180910390f35b6000805461005b906101c6565b80601f0160208091040260200160405190810160405280929190818152602001828054610087906101c6565b80156100d45780601f106100a9576101008083540402835291602001916100d4565b820191906000526020600020905b8154815290600101906020018083116100b757829003601f168201915b505050505081565b600081519050919050565b600082825260208201905092915050565b60005b838110156101165780820151818401526020810190506100fb565b83811115610125576000848401525b50505050565b6000601f19601f8301169050919050565b6000610147826100dc565b61015181856100e7565b93506101618185602086016100f8565b61016a8161012b565b840191505092915050565b6000602082019050818103600083015261018f818461013c565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806101de57607f821691505b602082108114156101f2576101f1610197565b5b5091905056fea26469706673582212204d363ed34111d1be492d4fd086e9f2df62b3c625e89ade31f30e63201ed1e24f64736f6c63430008090033'; - -export const log6 = { - blockNumber: '0x6', - transactionIndex: '0x0', - address: '0x0000000000000000000000000000000000000803', - data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000001d131f6171f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000001', - logIndex: '0x0', - removed: false, - topics: [ - '0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a', - '0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4', - ], -}; - -export const log7 = { - blockNumber: '0x7', - transactionIndex: '0x0', - address: '0x0000000000000000000000000000000000000803', - data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000000094b686d800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000010000000000000000000000000000000000000000000100000000000000000002', - logIndex: '0x0', - removed: false, - topics: [ - '0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a', - '0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4', - ], -}; - -export const log8 = { - blockNumber: '0x8', - transactionIndex: '0x0', - address: '0x0000000000000000000000000000000000000803', - data: '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000001', - logIndex: '0x0', - removed: false, - topics: [ - '0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a', - '0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4', - ], -}; - -export const log9 = { - blockNumber: '0x9', - transactionIndex: '0x0', - address: '0x0000000000000000000000000000000000000803', - data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000010000000000000000000000000000000000000000000100000000000000000002', - logIndex: '0x0', - removed: false, - topics: [ - '0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a', - '0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4', - ], -}; - -export const log10 = { - blockNumber: '0xa', - transactionIndex: '0x0', - address: '0x0000000000000000000000000000000000000803', - data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000748849ea0c000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000001', - logIndex: '0x0', - removed: false, - topics: [ - '0x7b1ccce9b5299ff0ae3d9adc0855268a4ad3527b2bcde01ccadde2fb878ecb8a', - '0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4', - ], -}; - -export const log11 = { - blockNumber: '0xb', - transactionIndex: '0x0', - address: '0x0000000000000000000000000000000000000803', - data: '0x000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000000000000000000000000000000000e8d4a51000', - logIndex: '0x0', - removed: false, - topics: [ - '0x5b6f5f6550282279c4e72b95a8ba538bea92c64dec9e8c7c08a556d4457225c8', - '0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4', - '0x0000000000000000000000000000000000000000000100000000000000000000', - '0x0000000000000000000000000000000000000000000100000000000000000001', - ], -}; - -export const log12 = { - blockNumber: '0xc', - transactionIndex: '0x0', - address: '0x0000000000000000000000000000000000000803', - data: '0x000000000000000000000000000000000000000000000000000000174876e800', - logIndex: '0x0', - removed: false, - topics: [ - '0x038116623990e7d0fed04a27e35b5dc88000ea942b37360c5898ae750bfa5df6', - '0x0000000000000000000000000230135fded668a3f7894966b14f42e65da322e4', - '0x0000000000000000000000000000000000000000000100000000000000000000', - '0x0000000000000000000000000000000000000000000100000000000000000001', - ], -}; - -export const log13 = { - blockNumber: '0xd', - transactionIndex: '0x0', - removed: false, - address: '0xe85ef9063dd28f157eb97ca03f50f4a3bdecd37e', - data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0', - ], - logIndex: '0x0', -}; - -export const log14 = { - blockNumber: '0xe', - transactionIndex: '0x0', - removed: false, - address: '0x532394de2ca885b7e0306a2e258074cca4e42449', - data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - '0x0000000000000000000000000000000000000000000000000000000000000000', - '0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0', - ], - logIndex: '0x0', -}; - -export const log20_0 = { - blockNumber: '0x14', - transactionIndex: '0x0', - removed: false, - address: '0x532394de2ca885b7e0306a2e258074cca4e42449', - data: '0x0000000000000000000000000000000000000000000000000000000000002710', - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - '0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0', - '0x000000000000000000000000905c015e38c24ed973fd6075541a124c621fa743', - ], - logIndex: '0x0', -}; - -export const log20_1 = { - blockNumber: '0x14', - transactionIndex: '0x0', - removed: false, - address: '0xe85ef9063dd28f157eb97ca03f50f4a3bdecd37e', - data: '0x00000000000000000000000000000000000000000000000000000000000003e8', - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - '0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0', - '0x000000000000000000000000905c015e38c24ed973fd6075541a124c621fa743', - ], - logIndex: '0x1', -}; - -export const log22_0 = { - blockNumber: '0x16', - transactionIndex: '0x0', - removed: false, - address: '0xe85ef9063dd28f157eb97ca03f50f4a3bdecd37e', - data: '0x000000000000000000000000000000000000000000000000000000000000000a', - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - '0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0', - '0x000000000000000000000000905c015e38c24ed973fd6075541a124c621fa743', - ], - logIndex: '0x0', -}; - -export const log22_1 = { - blockNumber: '0x16', - transactionIndex: '0x0', - removed: false, - address: '0x532394de2ca885b7e0306a2e258074cca4e42449', - data: '0x0000000000000000000000000000000000000000000000000000000000000062', - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - '0x000000000000000000000000905c015e38c24ed973fd6075541a124c621fa743', - '0x00000000000000000000000082a258cb20e2adb4788153cd5eb5839615ece9a0', - ], - logIndex: '0x1', -}; - -export const allLogs = [ - log6, - log7, - log8, - log9, - log10, - log11, - log12, - log13, - log14, - log20_0, - log20_1, - log22_0, - log22_1, -] as LogHexified[]; - -export const ERC20_BYTECODE = '6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029'; - -/* ----- - contract GasMonster { - uint256 x = 1; - function run() external { - require(gasleft() > 1010000, "gaslimit not enough"); - x = x + 1; - } - } - ----- */ -export const GASMONSTER_BYTECODE = '6080604052600160005534801561001557600080fd5b506101d8806100256000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c040622614610030575b600080fd5b61003861003a565b005b620f69505a1161007f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610076906100b9565b60405180910390fd5b600160005461008e91906100ea565b600081905550565b60006100a36013836100d9565b91506100ae82610179565b602082019050919050565b600060208201905081810360008301526100d281610096565b9050919050565b600082825260208201905092915050565b60006100f582610140565b915061010083610140565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156101355761013461014a565b5b828201905092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f6761736c696d6974206e6f7420656e6f7567680000000000000000000000000060008201525056fea26469706673582212203f50c8d7ac2c3bcf6ebf8adbadba541fff53382a169109676559aabee8a78ddf64736f6c63430008070033'; - -export const GASMONSTER_ABI = [ - { - inputs: [], - name: 'run', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; - -export const GAS_MONSTER_GAS_REQUIRED = 1010000; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts b/packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts new file mode 100644 index 000000000..52fb6d652 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts @@ -0,0 +1,295 @@ +import { ContractFactory, Signer } from 'ethers'; +import { parseEther } from 'ethers/lib/utils'; + +export const ERC20_ABI = [ + { + constant: true, + inputs: [], + name: 'name', + outputs: [ + { + name: '', + type: 'string', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { + name: '_spender', + type: 'address', + }, + { + name: '_value', + type: 'uint256', + }, + ], + name: 'approve', + outputs: [ + { + name: 'success', + type: 'bool', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'totalSupply', + outputs: [ + { + name: '', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { + name: '_from', + type: 'address', + }, + { + name: '_to', + type: 'address', + }, + { + name: '_value', + type: 'uint256', + }, + ], + name: 'transferFrom', + outputs: [ + { + name: 'success', + type: 'bool', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: '', + type: 'address', + }, + ], + name: 'balances', + outputs: [ + { + name: '', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'decimals', + outputs: [ + { + name: '', + type: 'uint8', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: '', + type: 'address', + }, + { + name: '', + type: 'address', + }, + ], + name: 'allowed', + outputs: [ + { + name: '', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: '_owner', + type: 'address', + }, + ], + name: 'balanceOf', + outputs: [ + { + name: 'balance', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'symbol', + outputs: [ + { + name: '', + type: 'string', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: false, + inputs: [ + { + name: '_to', + type: 'address', + }, + { + name: '_value', + type: 'uint256', + }, + ], + name: 'transfer', + outputs: [ + { + name: 'success', + type: 'bool', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: '_owner', + type: 'address', + }, + { + name: '_spender', + type: 'address', + }, + ], + name: 'allowance', + outputs: [ + { + name: 'remaining', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + name: '_initialAmount', + type: 'uint256', + }, + { + name: '_tokenName', + type: 'string', + }, + { + name: '_decimalUnits', + type: 'uint8', + }, + { + name: '_tokenSymbol', + type: 'string', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: '_from', + type: 'address', + }, + { + indexed: true, + name: '_to', + type: 'address', + }, + { + indexed: false, + name: '_value', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: '_owner', + type: 'address', + }, + { + indexed: true, + name: '_spender', + type: 'address', + }, + { + indexed: false, + name: '_value', + type: 'uint256', + }, + ], + name: 'Approval', + type: 'event', + }, +]; + +export const ERC20_BYTECODE = '6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029'; + +export const deployErc20 = async (wallet: Signer) => { + const Token = new ContractFactory(ERC20_ABI, ERC20_BYTECODE, wallet); + const token = await Token.deploy(parseEther('1000000000'), 'TestToken', 18, 'TT'); + await token.deployed(); + + return token; +}; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts new file mode 100644 index 000000000..24dbaac52 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts @@ -0,0 +1,57 @@ +import axios from 'axios'; + +import { + ETH_RPC_URL, + KARURA_ETH_RPC_URL, + LogHexified, +} from './consts'; +import { JsonRpcError } from '../../server'; + +export const rpcGet = + (method: string, url: string = ETH_RPC_URL) => + (params: any[] = []) => + axios.get(url, { + data: { + id: 0, + jsonrpc: '2.0', + method, + params, + }, + }); + +/* ---------- local rpc methods ---------- */ +export const eth_call = rpcGet('eth_call'); +export const eth_blockNumber = rpcGet('eth_blockNumber'); +export const eth_getBlockByNumber = rpcGet('eth_getBlockByNumber'); +export const eth_getTransactionReceipt = rpcGet('eth_getTransactionReceipt'); +export const eth_getLogs = rpcGet<{ data: { result: LogHexified[]; error?: JsonRpcError } }>('eth_getLogs'); +export const eth_getTransactionByHash = rpcGet('eth_getTransactionByHash'); +export const eth_accounts = rpcGet('eth_accounts'); +export const eth_sendRawTransaction = rpcGet('eth_sendRawTransaction'); +export const eth_getTransactionCount = rpcGet('eth_getTransactionCount'); +export const eth_getBalance = rpcGet('eth_getBalance'); +export const eth_chainId = rpcGet('eth_chainId'); +export const eth_gasPrice = rpcGet('eth_gasPrice'); +export const eth_estimateGas = rpcGet('eth_estimateGas'); +export const eth_getEthGas = rpcGet('eth_getEthGas'); +export const eth_getCode = rpcGet('eth_getCode'); +export const net_runtimeVersion = rpcGet('net_runtimeVersion'); +export const eth_isBlockFinalized = rpcGet('eth_isBlockFinalized'); +export const eth_newFilter = rpcGet('eth_newFilter'); +export const eth_newBlockFilter = rpcGet('eth_newBlockFilter'); +export const eth_getFilterChanges = rpcGet('eth_getFilterChanges'); +export const eth_getFilterLogs = rpcGet<{ + data: { + result: LogHexified[]; + error?: JsonRpcError; + }; +}>('eth_getFilterLogs'); +export const eth_uninstallFilter = rpcGet('eth_uninstallFilter'); +export const net_listening = rpcGet('net_listening'); + +/* ---------- karura mainnet rpc methods ---------- */ +export const eth_blockNumber_karura = rpcGet('eth_blockNumber', KARURA_ETH_RPC_URL); +export const eth_getTransactionReceipt_karura = rpcGet('eth_getTransactionReceipt', KARURA_ETH_RPC_URL); +export const eth_getTransactionByHash_karura = rpcGet('eth_getTransactionByHash', KARURA_ETH_RPC_URL); +export const eth_getBlockByNumber_karura = rpcGet('eth_getBlockByNumber', KARURA_ETH_RPC_URL); +export const eth_getStorageAt_karura = rpcGet('eth_getStorageAt', KARURA_ETH_RPC_URL); diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/evmAccounts.ts b/packages/eth-rpc-adapter/src/__tests__/utils/evm-accounts.ts similarity index 100% rename from packages/eth-rpc-adapter/src/__tests__/utils/evmAccounts.ts rename to packages/eth-rpc-adapter/src/__tests__/utils/evm-accounts.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/gas-monster.ts b/packages/eth-rpc-adapter/src/__tests__/utils/gas-monster.ts new file mode 100644 index 000000000..c07b8cf1e --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/utils/gas-monster.ts @@ -0,0 +1,32 @@ +import { ContractFactory, Signer } from 'ethers'; + +/* ----- + contract GasMonster { + uint256 x = 1; + function run() external { + require(gasleft() > 1010000, "gaslimit not enough"); + x = x + 1; + } + } + ----- */ +export const GASMONSTER_BYTECODE = '6080604052600160005534801561001557600080fd5b506101d8806100256000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c040622614610030575b600080fd5b61003861003a565b005b620f69505a1161007f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610076906100b9565b60405180910390fd5b600160005461008e91906100ea565b600081905550565b60006100a36013836100d9565b91506100ae82610179565b602082019050919050565b600060208201905081810360008301526100d281610096565b9050919050565b600082825260208201905092915050565b60006100f582610140565b915061010083610140565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156101355761013461014a565b5b828201905092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f6761736c696d6974206e6f7420656e6f7567680000000000000000000000000060008201525056fea26469706673582212203f50c8d7ac2c3bcf6ebf8adbadba541fff53382a169109676559aabee8a78ddf64736f6c63430008070033'; + +export const GASMONSTER_ABI = [ + { + inputs: [], + name: 'run', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +]; + +export const GAS_MONSTER_GAS_REQUIRED = 1010000; + +export const deployGasMonster = async (wallet: Signer) => { + const GM = new ContractFactory(GASMONSTER_ABI, GASMONSTER_BYTECODE, wallet); + const gm = await GM.deploy(); + await gm.deployed(); + + return gm; +}; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/index.ts b/packages/eth-rpc-adapter/src/__tests__/utils/index.ts index 4fc73a37b..f1fd71743 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/index.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/index.ts @@ -1,4 +1,7 @@ -export * from './SubsManager'; +export * from './subs-manager'; export * from './test-utils'; -export * from './evmAccounts'; +export * from './evm-accounts'; export * from './consts'; +export * from './gas-monster'; +export * from './eth-rpc-apis'; +export * from './erc20'; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/SubsManager.ts b/packages/eth-rpc-adapter/src/__tests__/utils/subs-manager.ts similarity index 100% rename from packages/eth-rpc-adapter/src/__tests__/utils/SubsManager.ts rename to packages/eth-rpc-adapter/src/__tests__/utils/subs-manager.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts b/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts index 7fc031e93..6fd01cfc4 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts @@ -1,33 +1,12 @@ -import { BigNumber, ContractFactory, Signer } from 'ethers'; -import { BlockTagish, sleep } from '@acala-network/eth-providers'; -import { Log, Provider, TransactionRequest } from '@ethersproject/abstract-provider'; +import { Log, Provider } from '@ethersproject/abstract-provider'; import { expect } from 'vitest'; import { hexValue } from '@ethersproject/bytes'; -import { parseEther } from 'ethers/lib/utils'; -import axios from 'axios'; -import erc20Abi from '../abis/IERC20.json'; +import { sleep } from '@acala-network/eth-providers'; import { - ERC20_BYTECODE, - ETH_RPC_URL, - GASMONSTER_ABI, - GASMONSTER_BYTECODE, - KARURA_ETH_RPC_URL, LogHexified, } from './consts'; -import { JsonRpcError } from '../../server'; - -export const rpcGet = - (method: string, url: string = ETH_RPC_URL) => - (params: any[] = []) => - axios.get(url, { - data: { - id: 0, - jsonrpc: '2.0', - method, - params, - }, - }); +import { eth_blockNumber, eth_getBlockByNumber, eth_getTransactionCount } from './eth-rpc-apis'; export const hexilifyLog = (log: Log) => ({ ...log, @@ -36,60 +15,6 @@ export const hexilifyLog = (log: Log) => ({ logIndex: hexValue(parseInt(log.logIndex as any)), }); -/* ---------- local rpc methods ---------- */ -export const eth_call = rpcGet('eth_call'); -export const eth_blockNumber = rpcGet('eth_blockNumber'); -export const eth_getBlockByNumber = rpcGet('eth_getBlockByNumber'); -export const eth_getTransactionReceipt = rpcGet('eth_getTransactionReceipt'); -export const eth_getLogs = rpcGet<{ data: { result: LogHexified[]; error?: JsonRpcError } }>('eth_getLogs'); -export const eth_getTransactionByHash = rpcGet('eth_getTransactionByHash'); -export const eth_accounts = rpcGet('eth_accounts'); -export const eth_sendRawTransaction = rpcGet('eth_sendRawTransaction'); -export const eth_getTransactionCount = rpcGet('eth_getTransactionCount'); -export const eth_getBalance = rpcGet('eth_getBalance'); -export const eth_chainId = rpcGet('eth_chainId'); -export const eth_gasPrice = rpcGet('eth_gasPrice'); -export const eth_estimateGas = rpcGet('eth_estimateGas'); -export const eth_getEthGas = rpcGet('eth_getEthGas'); -export const eth_getCode = rpcGet('eth_getCode'); -export const net_runtimeVersion = rpcGet('net_runtimeVersion'); -export const eth_isBlockFinalized = rpcGet('eth_isBlockFinalized'); -export const eth_newFilter = rpcGet('eth_newFilter'); -export const eth_newBlockFilter = rpcGet('eth_newBlockFilter'); -export const eth_getFilterChanges = rpcGet('eth_getFilterChanges'); -export const eth_getFilterLogs = rpcGet<{ - data: { - result: LogHexified[]; - error?: JsonRpcError; - }; -}>('eth_getFilterLogs'); -export const eth_uninstallFilter = rpcGet('eth_uninstallFilter'); -export const net_listening = rpcGet('net_listening'); - -/* ---------- karura mainnet rpc methods ---------- */ -export const eth_blockNumber_karura = rpcGet('eth_blockNumber', KARURA_ETH_RPC_URL); -export const eth_getTransactionReceipt_karura = rpcGet('eth_getTransactionReceipt', KARURA_ETH_RPC_URL); -export const eth_getTransactionByHash_karura = rpcGet('eth_getTransactionByHash', KARURA_ETH_RPC_URL); -export const eth_getBlockByNumber_karura = rpcGet('eth_getBlockByNumber', KARURA_ETH_RPC_URL); -export const eth_getStorageAt_karura = rpcGet('eth_getStorageAt', KARURA_ETH_RPC_URL); - -export const estimateGas = async ( - tx: TransactionRequest, - blockTag?: BlockTagish -) => { - const gasPrice = (await eth_gasPrice([])).data.result; - const res = await eth_estimateGas([{ ...tx, gasPrice }, blockTag]); - if (res.data.error) { - throw new Error(res.data.error.message); - } - const gasLimit = res.data.result; - - return { - gasPrice: BigNumber.from(gasPrice), - gasLimit: BigNumber.from(gasLimit), - }; -}; - export const bigIntDiff = (x: bigint, y: bigint): bigint => { return x > y ? x - y : y - x; }; @@ -112,22 +37,6 @@ export const expectLogsEqual = (a: LogHexified[], b: LogHexified[]): void => { ); }; -export const deployErc20 = async (wallet: Signer) => { - const Token = new ContractFactory(erc20Abi.abi, ERC20_BYTECODE, wallet); - const token = await Token.deploy(parseEther('1000000000'), 'TestToken', 18, 'TT'); - await token.deployed(); - - return token; -}; - -export const deployGasMonster = async (wallet: Signer) => { - const GM = new ContractFactory(GASMONSTER_ABI, GASMONSTER_BYTECODE, wallet); - const gm = await GM.deploy(); - await gm.deployed(); - - return gm; -}; - interface IndeterministicObj { blockHash?: string; transactionHash?: string; diff --git a/packages/eth-rpc-adapter/vitest.config.ts b/packages/eth-rpc-adapter/vitest.config.ts index 1517a6fc1..c9fa64ee6 100644 --- a/packages/eth-rpc-adapter/vitest.config.ts +++ b/packages/eth-rpc-adapter/vitest.config.ts @@ -5,11 +5,11 @@ export default mergeConfig( configShared, { test: { - // include: ['**/*.test.ts'], // TODO: run all tests - include: [ - 'src/__tests__/signer.test.ts', - 'src/__tests__/subscription.test.ts', - ], + include: ['**/*.test.ts'], // TODO: run all tests + // include: [ + // 'src/__tests__/signer.test.ts', + // 'src/__tests__/subscription.test.ts', + // ], }, } ); From 364cc2a52afd12d1b766540a96762222dffc87c7 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 11:02:43 +0800 Subject: [PATCH 04/23] add retry --- .github/workflows/test.yml | 12 ++++++++++-- .../src/__tests__/evm-rpc-provider.test.ts | 8 +++++--- packages/eth-rpc-adapter/vitest.config.ts | 6 +----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3582998a..b8ff19bf0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,7 +47,11 @@ jobs: run: yarn workspace @acala-network/eth-rpc-adapter run typegen - name: run tests - run: yarn workspace @acala-network/${{ matrix.project }} run test:coverage + uses: nick-fields/retry@v2 + with: + timeout_minutes: 30 + max_attempts: 3 + command: yarn workspace @acala-network/${{ matrix.project }} run test:coverage - name: save coverage reports uses: actions/upload-artifact@v4 @@ -100,7 +104,11 @@ jobs: run: cd e2e-tests/${{ matrix.project }} && yarn install --immutable - name: run e2e tests - run: cd e2e-tests/${{ matrix.project }} && yarn test:acalaFork + uses: nick-fields/retry@v2 + with: + timeout_minutes: 30 + max_attempts: 3 + command: cd e2e-tests/${{ matrix.project }} && yarn test:acalaFork - name: stop coverage server and generate coverage report run: yarn workspace @acala-network/eth-rpc-adapter run stop:coverage diff --git a/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts b/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts index 514069622..1cda48877 100644 --- a/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts +++ b/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts @@ -1,5 +1,5 @@ import { EvmRpcProvider } from '../rpc-provider'; -import { afterAll, describe, expect, it } from 'vitest'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { runWithTiming, sleep } from '../utils'; import dotenv from 'dotenv'; @@ -98,10 +98,12 @@ describe.skip('all cache', async () => { describe.concurrent('rpc test', async () => { const provider = EvmRpcProvider.from(endpoint); - await provider.isReady(); + + beforeAll(async () => { + await provider.isReady(); + }); afterAll(async () => { - await sleep(5000); await provider.disconnect(); }); diff --git a/packages/eth-rpc-adapter/vitest.config.ts b/packages/eth-rpc-adapter/vitest.config.ts index c9fa64ee6..65874530d 100644 --- a/packages/eth-rpc-adapter/vitest.config.ts +++ b/packages/eth-rpc-adapter/vitest.config.ts @@ -5,11 +5,7 @@ export default mergeConfig( configShared, { test: { - include: ['**/*.test.ts'], // TODO: run all tests - // include: [ - // 'src/__tests__/signer.test.ts', - // 'src/__tests__/subscription.test.ts', - // ], + include: ['**/*.test.ts'], }, } ); From c41c54c19fa5f6c9cb5cbc29e562787cc7e856bd Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 14:22:19 +0800 Subject: [PATCH 05/23] eth_sendTx tests --- packages/eth-rpc-adapter/package.json | 2 +- .../src/__tests__/endpoint-tests/endpoint.ts | 393 ------------------ .../endpoint-tests/eth_estimateGas.test.ts | 28 +- .../eth_sendRawTransaction.test.ts | 360 ++++++++++++++++ .../src/__tests__/utils/index.ts | 3 +- .../utils/{test-utils.ts => misc.ts} | 24 +- .../src/__tests__/utils/setup.ts | 19 + 7 files changed, 407 insertions(+), 422 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts rename packages/eth-rpc-adapter/src/__tests__/utils/{test-utils.ts => misc.ts} (72%) create mode 100644 packages/eth-rpc-adapter/src/__tests__/utils/setup.ts diff --git a/packages/eth-rpc-adapter/package.json b/packages/eth-rpc-adapter/package.json index 3f3350032..1c67dedf8 100644 --- a/packages/eth-rpc-adapter/package.json +++ b/packages/eth-rpc-adapter/package.json @@ -8,7 +8,7 @@ "build": "tsc", "ncc:pack": "ncc build src/index.ts -t --target es2020", "typegen": "typechain --target=ethers-v5 --out-dir=./src/__tests__/types src/__tests__/abis/*.json", - "dev": "ts-node-dev -T -r tsconfig-paths/register src/index.ts -l | pino-pretty --singleLine --colorize --ignore time,hostname,jsonrpc,dd", + "dev": "ts-node-dev -T -r tsconfig-paths/register src/index.ts | pino-pretty --singleLine --colorize --ignore time,hostname,jsonrpc,dd", "clean": "rm -rf tsconfig.tsbuildinfo .nyc_output coverage/ lib/", "health-check": "./scripts/health-check.sh", "start": "ts-node -r tsconfig-paths/register src/index.ts", diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index 73ef5e6da..8133de885 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -616,399 +616,6 @@ describe('endpoint', () => { }); }); - describe('eth_sendRawTransaction', async () => { - const chainId = BigNumber.from((await eth_chainId()).data.result).toNumber(); - - const endpoint = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; - const wsProvider = new WsProvider(endpoint); - const api = await ApiPromise.create({ provider: wsProvider }); - - const genesisHash = api.genesisHash.toHex(); // TODO: why EIP-712 salt has to be genesis hash? - - const ETH_Digits = 18; - const ACA_Digits = 12; - const TX_FEE_OFF_TOLERANCE = parseEther('0.01').toBigInt(); // 0.01 ACA - - const queryEthBalance = async (addr): Promise => - BigNumber.from((await eth_getBalance([addr, 'latest'])).data.result); - - const queryNativeBalance = async (addr: string) => - (await queryEthBalance(addr)).div(10 ** (ETH_Digits - ACA_Digits)); - - const getTxFeeFromReceipt = async (txHash: string, toNative = false): Promise => { - await sleep(789); // give cache/subquery a little bit time - const { gasUsed, effectiveGasPrice } = (await eth_getTransactionReceipt([txHash])).data.result; - - const calculatedTxFee = BigInt(gasUsed) * BigInt(effectiveGasPrice); - - return toNative - ? calculatedTxFee / BigInt(10 ** (ETH_Digits - ACA_Digits)) - : calculatedTxFee; - }; - - afterAll(async () => { - await api.disconnect(); - }); - - describe('deploy contract (hello world)', () => { - const partialDeployTx = { - chainId, - data: deployHelloWorldData, - type: 0, - }; - - describe('with legacy EIP-155 signature', () => { - it('send tx correctly, gas estimation is accurate, receipt\'s gas info is accurate', async () => { - const prevBalance = await queryEthBalance(wallet1.address); - - const unsignedTx = { - ...partialDeployTx, - nonce: await getNonce(wallet1.address), - }; - - const { gasPrice, gasLimit } = await estimateGas(unsignedTx); - - const rawTx = await wallet1.signTransaction({ - ...unsignedTx, - gasPrice, - gasLimit, - }); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 - - const receiptTxFee = await getTxFeeFromReceipt(res.data.result); - const afterBalance = await queryEthBalance(wallet1.address); - - const realTxFee = prevBalance.sub(afterBalance).toBigInt(); - const estimatedTxFee = gasPrice.mul(gasLimit).toBigInt(); - const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); - const diffEstimateTxFee = bigIntDiff(realTxFee, estimatedTxFee); - - // console.log({ - // estimatedTxFee: formatEther(estimatedTxFee), - // realTxFee: formatEther(realTxFee), - // receiptTxFee: formatEther(receiptTxFee), - // diffReceiptTxFee: formatEther(diffReceiptTxFee), - // diffEstimateTxFee: formatEther(diffEstimateTxFee), - // }); - - expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; - - // estimated tx fee is slightly overestimated now - expect(diffEstimateTxFee < TX_FEE_OFF_TOLERANCE).to.be.false; - }); - }); - - describe('with EIP-1559 signature', () => { - it('throw correct error', async () => { - const unsignedTx = { - ...partialDeployTx, - nonce: await getNonce(wallet1.address), - gasPrice: undefined, - maxPriorityFeePerGas: BigNumber.from(0), - maxFeePerGas: ONE_HUNDRED_GWEI, - type: 2, - }; - - const rawTx = await wallet1.signTransaction(unsignedTx); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.contain('unsupported transaction type: 2, please use legacy or EIP-712 instead'); - }); - }); - - describe('with EIP-712 signature', () => { - it('send tx correctly, receipt\'s gas info is accurate', async () => { - const prevBalance = await queryEthBalance(wallet1.address); - - const gasLimit = BigNumber.from('210000'); - const validUntil = 10000; - const storageLimit = 100000; - - const unsignEip712Tx = { - ...partialDeployTx, - nonce: await getNonce(wallet1.address), - salt: genesisHash, - gasLimit, - validUntil, - storageLimit, - type: 0x60, - }; - - const sig = signTransaction(account1.privateKey, unsignEip712Tx as AcalaEvmTXPayload); - const rawTx = serializeTransaction(unsignEip712Tx as UnsignedAcalaEvmTX, sig); - const parsedTx = parseTransaction(rawTx); - - expect(parsedTx.gasLimit.eq(gasLimit)).equal(true); - expect(BigNumber.from(parsedTx.validUntil).eq(validUntil)).equal(true); - expect(BigNumber.from(parsedTx.storageLimit).eq(storageLimit)).equal(true); - - expect(parsedTx.from).equal(wallet1.address); - expect(parsedTx.data).equal(deployHelloWorldData); - expect(parsedTx.type).equal(96); - expect(parsedTx.maxPriorityFeePerGas).equal(undefined); - expect(parsedTx.maxFeePerGas).equal(undefined); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 - - const receiptTxFee = await getTxFeeFromReceipt(res.data.result); - const afterBalance = await queryEthBalance(wallet1.address); - - const realTxFee = prevBalance.sub(afterBalance).toBigInt(); - const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); - - // console.log({ - // realTxFee: formatEther(realTxFee), - // receiptTxFee: formatEther(receiptTxFee), - // diffReceiptTxFee: formatEther(diffReceiptTxFee), - // }); - - expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; - }); - }); - }); - - describe('call contract (transfer ACA)', () => { - const iface = new Interface(TokenABI.abi); - const transferAmount = parseUnits('123.321', ACA_Digits); - const partialTransferTX = { - chainId, - from: wallet1.address, - to: ADDRESS.ACA, - data: iface.encodeFunctionData('transfer', [account2.evmAddress, transferAmount]), - type: 0, - }; - - describe('with legacy EIP-155 signature', () => { - it('has correct balance after transfer, and receipt\'s gas info is accurate', async () => { - const [balance1, balance2] = await Promise.all([ - queryNativeBalance(account1.evmAddress), - queryNativeBalance(account2.evmAddress), - ]); - - const transferTX = { - ...partialTransferTX, - nonce: await getNonce(wallet1.address), - }; - - const { gasPrice, gasLimit } = await estimateGas(transferTX); - const rawTx = await wallet1.signTransaction({ - ...transferTX, - gasPrice, - gasLimit, - }); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 - - await sleep(1000); - const [_balance1, _balance2] = await Promise.all([ - queryNativeBalance(account1.evmAddress), - queryNativeBalance(account2.evmAddress), - ]); - - const receiptTxFee = await getTxFeeFromReceipt(res.data.result); - const realTxFee = nativeToEthDecimal(balance1.sub(_balance1).sub(transferAmount).toBigInt()).toBigInt(); - const estimatedTxFee = gasPrice.mul(gasLimit).toBigInt(); - const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); - const diffEstimateTxFee = bigIntDiff(realTxFee, estimatedTxFee); - - // console.log({ - // estimatedTxFee: formatEther(estimatedTxFee), - // realTxFee: formatEther(realTxFee), - // receiptTxFee: formatEther(receiptTxFee), - // diffReceiptTxFee: formatEther(diffReceiptTxFee), - // diffEstimateTxFee: formatEther(diffEstimateTxFee), - // }); - - expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; - expect(diffEstimateTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; - expect(formatEther(_balance2.sub(balance2))).to.eq(formatEther(transferAmount)); - }); - }); - - describe('with EIP-1559 signature', () => { - it('throw correct error', async () => { - const priorityFee = BigNumber.from(0); - const transferTX = { - ...partialTransferTX, - nonce: await getNonce(wallet1.address), - gasPrice: undefined, - maxPriorityFeePerGas: priorityFee, - maxFeePerGas: 1000000, - type: 2, - }; - - const rawTx = await wallet1.signTransaction(transferTX); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.contain('unsupported transaction type: 2, please use legacy or EIP-712 instead'); - }); - }); - - describe('with EIP-712 signature', () => { - it('has correct balance after transfer, and receipt\'s gas info is accurate', async () => { - const [balance1, balance2] = await Promise.all([ - queryEthBalance(account1.evmAddress), - queryEthBalance(account2.evmAddress), - ]); - - const gasLimit = BigNumber.from('210000'); - const validUntil = 10000; - const storageLimit = 100000; - - const transferTX = { - ...partialTransferTX, - nonce: await getNonce(wallet1.address), - salt: genesisHash, - gasLimit, - validUntil, - storageLimit, - type: 0x60, - }; - - const sig = signTransaction(account1.privateKey, transferTX as AcalaEvmTXPayload); - const rawTx = serializeTransaction(transferTX as UnsignedAcalaEvmTX, sig); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 - - await sleep(1000); - const [_balance1, _balance2] = await Promise.all([ - queryEthBalance(account1.evmAddress), - queryEthBalance(account2.evmAddress), - ]); - - const receiptTxFee = await getTxFeeFromReceipt(res.data.result); - const realTxFee = balance1.sub(_balance1).sub(nativeToEthDecimal(transferAmount)).toBigInt(); - const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); - - // console.log({ - // realTxFee: formatEther(realTxFee), - // receiptTxFee: formatEther(receiptTxFee), - // diffReceiptTxFee: formatEther(diffReceiptTxFee), - // }); - - expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; - expect(formatEther(_balance2.sub(balance2))).to.eq(formatEther(nativeToEthDecimal(transferAmount))); - }); - }); - }); - - describe('send native ACA token', () => { - const transferAmount = parseEther('16.88'); - const partialNativeTransferTX = { - chainId, - from: wallet1.address, - to: account2.evmAddress, - value: transferAmount, - }; - - describe('with legacy EIP-155 signature', () => { - it('has correct balance after transfer, and receipt\'s gas info is accurate', async () => { - const [balance1, balance2] = await Promise.all([ - queryEthBalance(account1.evmAddress), - queryEthBalance(account2.evmAddress), - ]); - - const unsignedTx = { - ...partialNativeTransferTX, - nonce: await getNonce(wallet1.address), - }; - const { gasPrice, gasLimit } = await estimateGas(unsignedTx); - - const rawTx = await wallet1.signTransaction({ - ...unsignedTx, - gasPrice, - gasLimit, - }); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 - - await sleep(1000); - const [_balance1, _balance2] = await Promise.all([ - queryEthBalance(account1.evmAddress), - queryEthBalance(account2.evmAddress), - ]); - - const receiptTxFee = await getTxFeeFromReceipt(res.data.result); - const realTxFee = balance1.sub(_balance1).sub(transferAmount).toBigInt(); - const estimatedTxFee = gasPrice.mul(gasLimit).toBigInt(); - const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); - const diffEstimateTxFee = bigIntDiff(realTxFee, estimatedTxFee); - - // console.log({ - // estimatedTxFee: formatEther(estimatedTxFee), - // realTxFee: formatEther(realTxFee), - // receiptTxFee: formatEther(receiptTxFee), - // diffReceiptTxFee: formatEther(diffReceiptTxFee), - // diffEstimateTxFee: formatEther(diffEstimateTxFee), - // }); - - expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; - expect(diffEstimateTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; - expect(formatEther(_balance2.sub(balance2))).to.eq(formatEther(transferAmount)); - }); - }); - - describe('with EIP-1559 signature', () => { - it('throw correct error', async () => { - const transferTX = { - ...partialNativeTransferTX, - nonce: await getNonce(wallet1.address), - gasPrice: undefined, - maxPriorityFeePerGas: 0, - maxFeePerGas: 10000000000, - type: 2, - }; - - const rawTx = await wallet1.signTransaction(transferTX); - - const res = await eth_sendRawTransaction([rawTx]); - expect(res.data.error?.message).to.contain('unsupported transaction type: 2, please use legacy or EIP-712 instead'); - }); - }); - - describe('with EIP-712 signature', () => { - // TODO: EIP-712 doesn't use ETH gasLimit and gasPrice, do we need to support it? - it.skip('has correct balance after transfer', async () => { - // const balance1 = await queryEthBalance(account1.evmAddress); - // const balance2 = await queryEthBalance(account2.evmAddress); - // const gasLimit = BigNumber.from('210000'); - // const validUntil = 10000; - // const storageLimit = 100000; - // const transferTX: AcalaEvmTX = { - // ...partialNativeTransferTX, - // ...(await estimateGas()), - // nonce: await getNonce(wallet1.address), - // salt: genesisHash, - // gasLimit, - // validUntil, - // storageLimit, - // type: 0x60 - // }; - // const sig = signTransaction(account1.privateKey, transferTX); - // const rawTx = serializeTransaction(transferTX, sig); - // const parsedTx = parseTransaction(rawTx); - // const res = await eth_sendRawTransaction([rawTx]); - // expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 - // const txHash = res.data.result; - // const { gasUsed, effectiveGasPrice } = (await eth_getTransactionReceipt([txHash])).data.result; - // const calculatedTxFee = BigInt(gasUsed) * BigInt(effectiveGasPrice) / BigInt(10 ** (ETH_Digits - ACA_Digits)); - // const _balance1 = await queryEthBalance(account1.evmAddress); - // const _balance2 = await queryEthBalance(account2.evmAddress); - // const realTxFee = balance1.sub(_balance1).sub(transferAmount).toBigInt(); - // const diff = bigIntDiff(realTxFee, receiptTxFee); - // expect(_balance2.sub(balance2).toBigInt()).equal(transferAmount.toBigInt()); - // expect(Number(diff)).to.lessThan(TX_FEE_OFF_TOLERANCE); - }); - }); - }); - }); - describe('eth_call', () => { const callRequest = (abi: any) => async (address: string, method: string, params?: any[], blockTag?: any) => { const iface = new Interface(abi); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts index 87730bba0..94ffbe7c2 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_estimateGas.test.ts @@ -1,38 +1,18 @@ -import { AcalaJsonRpcProvider, BlockTagish } from '@acala-network/eth-providers'; -import { BigNumber, Contract, Wallet } from 'ethers'; -import { TransactionRequest } from '@ethersproject/abstract-provider'; +import { Contract, Wallet } from 'ethers'; import { beforeAll, describe, expect, it } from 'vitest'; import { parseUnits } from 'ethers/lib/utils'; import { - ETH_RPC_URL, GAS_MONSTER_GAS_REQUIRED, deployErc20, deployGasMonster, + estimateGas, eth_estimateGas, - eth_gasPrice, evmAccounts, + testSetup, } from '../utils'; -export const estimateGas = async ( - tx: TransactionRequest, - blockTag?: BlockTagish -) => { - const gasPrice = (await eth_gasPrice([])).data.result; - const res = await eth_estimateGas([{ ...tx, gasPrice }, blockTag]); - if (res.data.error) { - throw new Error(res.data.error.message); - } - const gasLimit = res.data.result; - - return { - gasPrice: BigNumber.from(gasPrice), - gasLimit: BigNumber.from(gasLimit), - }; -}; - -const provider = new AcalaJsonRpcProvider(ETH_RPC_URL); -const wallet = new Wallet(evmAccounts[0].privateKey, provider); +const { wallet } = testSetup; describe('eth_estimateGas', () => { it('can deal with weird gas contract', async () => { diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts new file mode 100644 index 000000000..4c8b88869 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts @@ -0,0 +1,360 @@ +import { ACA as ACA_ADDR } from '@acala-network/contracts/utils/AcalaAddress'; +import { AcalaEvmTXPayload, UnsignedAcalaEvmTX, parseTransaction, serializeTransaction, signTransaction } from '@acala-network/eth-transactions'; +import { BigNumber } from 'ethers'; +import { Interface, formatEther, parseEther, parseUnits } from 'ethers/lib/utils'; +import { ONE_HUNDRED_GWEI, nativeToEthDecimal, sleep } from '@acala-network/eth-providers'; +import { afterAll, describe, expect, it } from 'vitest'; + +import { + bigIntDiff, + createApi, + deployHelloWorldData, + estimateGas, + eth_chainId, + eth_getBalance, + eth_getTransactionReceipt, + eth_sendRawTransaction, + getNonce, + testSetup, +} from '../utils'; +import Erc20Abi from '../abis/IERC20.json'; + +const ETH_Digits = 18; +const ACA_Digits = 12; +const TX_FEE_OFF_TOLERANCE = parseEther('0.02').toBigInt(); // 0.02 ACA + +const queryEthBalance = async (addr): Promise => + BigNumber.from((await eth_getBalance([addr, 'latest'])).data.result); + +const queryNativeBalance = async (addr: string) => + (await queryEthBalance(addr)).div(10 ** (ETH_Digits - ACA_Digits)); + +const getTxFeeFromReceipt = async (txHash: string, toNative = false): Promise => { + const { gasUsed, effectiveGasPrice } = (await eth_getTransactionReceipt([txHash])).data.result; + + const calculatedTxFee = BigInt(gasUsed) * BigInt(effectiveGasPrice); + + return toNative + ? calculatedTxFee / BigInt(10 ** (ETH_Digits - ACA_Digits)) + : calculatedTxFee; +}; + +const { + provider, + wallets: [wallet, wallet1, wallet2], +} = testSetup; + +describe('eth_sendRawTransaction', async () => { + const api = await createApi(); + const genesisHash = api.genesisHash.toHex(); + const chainId = BigNumber.from((await eth_chainId()).data.result).toNumber(); + + afterAll(async () => { + await api.disconnect(); + }); + + describe('deploy contract (hello world)', () => { + const partialDeployTx = { + chainId, + data: deployHelloWorldData, + }; + + describe('with legacy EIP-155 signature', () => { + it('send tx correctly, gas estimation is accurate, receipt\'s gas info is accurate', async () => { + const prevBalance = await queryEthBalance(wallet.address); + + const unsignedTx = { + ...partialDeployTx, + nonce: await getNonce(wallet.address), + type: 0, + }; + + const { gasPrice, gasLimit } = await estimateGas(unsignedTx); + const rawTx = await wallet.signTransaction({ + ...unsignedTx, + gasPrice, + gasLimit, + }); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 + + const txHash = res.data.result; + await provider.waitForTransaction(txHash); + + const receiptTxFee = await getTxFeeFromReceipt(txHash); + const afterBalance = await queryEthBalance(wallet.address); + + const realTxFee = prevBalance.sub(afterBalance).toBigInt(); + const estimatedTxFee = gasPrice.mul(gasLimit).toBigInt(); + const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); + const diffEstimateTxFee = bigIntDiff(realTxFee, estimatedTxFee); + + expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; + + // estimated tx fee is slightly overestimated now + expect(diffEstimateTxFee < TX_FEE_OFF_TOLERANCE).to.be.false; + }); + }); + + describe('with EIP-1559 signature', () => { + it('throw correct error', async () => { + const unsignedTx = { + ...partialDeployTx, + nonce: await getNonce(wallet.address), + gasPrice: undefined, + maxPriorityFeePerGas: BigNumber.from(0), + maxFeePerGas: ONE_HUNDRED_GWEI, + type: 2, + }; + + const rawTx = await wallet.signTransaction(unsignedTx); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.contain('unsupported transaction type: 2, please use legacy or EIP-712 instead'); + }); + }); + + describe('with EIP-712 signature', () => { + it('send tx correctly, receipt\'s gas info is accurate', async () => { + const prevBalance = await queryEthBalance(wallet.address); + + const gasLimit = BigNumber.from('210000'); + const validUntil = 9999999; + const storageLimit = 100000; + + const unsignEip712Tx = { + ...partialDeployTx, + nonce: await getNonce(wallet.address), + salt: genesisHash, + gasLimit, + validUntil, + storageLimit, + type: 0x60, + }; + + const sig = signTransaction(wallet.privateKey, unsignEip712Tx as AcalaEvmTXPayload); + const rawTx = serializeTransaction(unsignEip712Tx as UnsignedAcalaEvmTX, sig); + const parsedTx = parseTransaction(rawTx); + + expect(parsedTx.gasLimit.eq(gasLimit)).equal(true); + expect(BigNumber.from(parsedTx.validUntil).eq(validUntil)).equal(true); + expect(BigNumber.from(parsedTx.storageLimit).eq(storageLimit)).equal(true); + + expect(parsedTx.from).equal(wallet.address); + expect(parsedTx.data).equal(deployHelloWorldData); + expect(parsedTx.type).equal(96); + expect(parsedTx.maxPriorityFeePerGas).equal(undefined); + expect(parsedTx.maxFeePerGas).equal(undefined); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 + + const txHash = res.data.result; + await provider.waitForTransaction(txHash); + + const receiptTxFee = await getTxFeeFromReceipt(txHash); + const afterBalance = await queryEthBalance(wallet.address); + + const realTxFee = prevBalance.sub(afterBalance).toBigInt(); + const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); + + expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; + }); + }); + }); + + describe('call contract (transfer ACA)', () => { + const iface = new Interface(Erc20Abi.abi); + const transferAmount = parseUnits('12.321', ACA_Digits); + const partialTransferTX = { + chainId, + from: wallet.address, + to: ACA_ADDR, + data: iface.encodeFunctionData('transfer', [wallet1.address, transferAmount]), + }; + + describe('with legacy EIP-155 signature', () => { + it('has correct balance after transfer, and receipt\'s gas info is accurate', async () => { + const [balance0, balance1] = await Promise.all([ + queryNativeBalance(wallet.address), + queryNativeBalance(wallet1.address), + ]); + + const transferTX = { + ...partialTransferTX, + nonce: await getNonce(wallet.address), + type: 0, + }; + + const { gasPrice, gasLimit } = await estimateGas(transferTX); + const rawTx = await wallet.signTransaction({ + ...transferTX, + gasPrice, + gasLimit, + }); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 + + const txHash = res.data.result; + await provider.waitForTransaction(txHash); + + const [_balance0, _balance1] = await Promise.all([ + queryNativeBalance(wallet.address), + queryNativeBalance(wallet1.address), + ]); + + const receiptTxFee = await getTxFeeFromReceipt(res.data.result); + const realTxFee = nativeToEthDecimal(balance0.sub(_balance0).sub(transferAmount).toBigInt()).toBigInt(); + const estimatedTxFee = gasPrice.mul(gasLimit).toBigInt(); + const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); + const diffEstimateTxFee = bigIntDiff(realTxFee, estimatedTxFee); + + expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; + expect(diffEstimateTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; + expect(formatEther(_balance1.sub(balance1))).to.eq(formatEther(transferAmount)); + }); + }); + + describe('with EIP-1559 signature', () => { + it('throw correct error', async () => { + const priorityFee = BigNumber.from(0); + const transferTX = { + ...partialTransferTX, + nonce: await getNonce(wallet.address), + gasPrice: undefined, + maxPriorityFeePerGas: priorityFee, + maxFeePerGas: 1000000, + type: 2, + }; + + const rawTx = await wallet.signTransaction(transferTX); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.contain('unsupported transaction type: 2, please use legacy or EIP-712 instead'); + }); + }); + + describe('with EIP-712 signature', () => { + it('has correct balance after transfer, and receipt\'s gas info is accurate', async () => { + const [balance0, balance1] = await Promise.all([ + queryEthBalance(wallet.address), + queryEthBalance(wallet1.address), + ]); + + const gasLimit = BigNumber.from('210000'); + const validUntil = 9999999; + const storageLimit = 100000; + + const transferTX = { + ...partialTransferTX, + nonce: await getNonce(wallet.address), + salt: genesisHash, + gasLimit, + validUntil, + storageLimit, + type: 0x60, + }; + + const sig = signTransaction(wallet.privateKey, transferTX as AcalaEvmTXPayload); + const rawTx = serializeTransaction(transferTX as UnsignedAcalaEvmTX, sig); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 + + const txHash = res.data.result; + await provider.waitForTransaction(txHash); + + const [_balance0, _balance1] = await Promise.all([ + queryEthBalance(wallet.address), + queryEthBalance(wallet1.address), + ]); + + const receiptTxFee = await getTxFeeFromReceipt(txHash); + const realTxFee = balance0.sub(_balance0).sub(nativeToEthDecimal(transferAmount)).toBigInt(); + const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); + + expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; + expect(formatEther(_balance1.sub(balance1))).to.eq(formatEther(nativeToEthDecimal(transferAmount))); + }); + }); + }); + + describe('send native ACA token', () => { + const transferAmount = parseEther('16.88'); + const partialNativeTransferTX = { + chainId, + from: wallet.address, + to: wallet1.address, + value: transferAmount, + }; + + describe('with legacy EIP-155 signature', () => { + it('has correct balance after transfer, and receipt\'s gas info is accurate', async () => { + const [balance0, balance1] = await Promise.all([ + queryEthBalance(wallet.address), + queryEthBalance(wallet1.address), + ]); + + const unsignedTx = { + ...partialNativeTransferTX, + nonce: await getNonce(wallet.address), + type: 0, + }; + + const { gasPrice, gasLimit } = await estimateGas(unsignedTx); + const rawTx = await wallet.signTransaction({ + ...unsignedTx, + gasPrice, + gasLimit, + }); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200 + + const txHash = res.data.result; + await provider.waitForTransaction(txHash); + + const [_balance0, _balance1] = await Promise.all([ + queryEthBalance(wallet.address), + queryEthBalance(wallet1.address), + ]); + + const receiptTxFee = await getTxFeeFromReceipt(res.data.result); + const realTxFee = balance0.sub(_balance0).sub(transferAmount).toBigInt(); + const estimatedTxFee = gasPrice.mul(gasLimit).toBigInt(); + const diffReceiptTxFee = bigIntDiff(realTxFee, receiptTxFee); + const diffEstimateTxFee = bigIntDiff(realTxFee, estimatedTxFee); + + expect(diffReceiptTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; + expect(diffEstimateTxFee < TX_FEE_OFF_TOLERANCE).to.be.true; + expect(formatEther(_balance1.sub(balance1))).to.eq(formatEther(transferAmount)); + }); + }); + + describe('with EIP-1559 signature', () => { + it('throw correct error', async () => { + const transferTX = { + ...partialNativeTransferTX, + nonce: await getNonce(wallet.address), + gasPrice: undefined, + maxPriorityFeePerGas: 0, + maxFeePerGas: 10000000000, + type: 2, + }; + + const rawTx = await wallet.signTransaction(transferTX); + + const res = await eth_sendRawTransaction([rawTx]); + expect(res.data.error?.message).to.contain('unsupported transaction type: 2, please use legacy or EIP-712 instead'); + }); + }); + + describe('with EIP-712 signature', () => { + // TODO: EIP-712 doesn't use ETH gasLimit and gasPrice, do we need to support it? + it.skip('has correct balance after transfer', async () => { + }); + }); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/index.ts b/packages/eth-rpc-adapter/src/__tests__/utils/index.ts index f1fd71743..d890fb3fc 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/index.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/index.ts @@ -1,7 +1,8 @@ export * from './subs-manager'; -export * from './test-utils'; +export * from './misc'; export * from './evm-accounts'; export * from './consts'; export * from './gas-monster'; export * from './eth-rpc-apis'; export * from './erc20'; +export * from './setup'; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts b/packages/eth-rpc-adapter/src/__tests__/utils/misc.ts similarity index 72% rename from packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts rename to packages/eth-rpc-adapter/src/__tests__/utils/misc.ts index 6fd01cfc4..bf2a55522 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/test-utils.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/misc.ts @@ -1,12 +1,30 @@ -import { Log, Provider } from '@ethersproject/abstract-provider'; +import { BigNumber } from 'ethers'; +import { BlockTagish, sleep } from '@acala-network/eth-providers'; +import { Log, Provider , TransactionRequest } from '@ethersproject/abstract-provider'; import { expect } from 'vitest'; import { hexValue } from '@ethersproject/bytes'; -import { sleep } from '@acala-network/eth-providers'; import { LogHexified, } from './consts'; -import { eth_blockNumber, eth_getBlockByNumber, eth_getTransactionCount } from './eth-rpc-apis'; +import { eth_blockNumber, eth_estimateGas, eth_gasPrice, eth_getBlockByNumber, eth_getTransactionCount } from './eth-rpc-apis'; + +export const estimateGas = async ( + tx: TransactionRequest, + blockTag?: BlockTagish +) => { + const gasPrice = (await eth_gasPrice([])).data.result; + const res = await eth_estimateGas([{ ...tx, gasPrice }, blockTag]); + if (res.data.error) { + throw new Error(res.data.error.message); + } + const gasLimit = res.data.result; + + return { + gasPrice: BigNumber.from(gasPrice), + gasLimit: BigNumber.from(gasLimit), + }; +}; export const hexilifyLog = (log: Log) => ({ ...log, diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/setup.ts b/packages/eth-rpc-adapter/src/__tests__/utils/setup.ts new file mode 100644 index 000000000..845dcb0e7 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/utils/setup.ts @@ -0,0 +1,19 @@ +import { AcalaJsonRpcProvider } from '@acala-network/eth-providers'; +import { ApiPromise, WsProvider } from '@polkadot/api'; +import { Wallet } from 'ethers'; + +import { ETH_RPC_URL, NODE_URL } from './consts'; +import { evmAccounts } from './evm-accounts'; + +const provider = new AcalaJsonRpcProvider(ETH_RPC_URL); +const wallets = evmAccounts.map(account => new Wallet(account.privateKey, provider)); + +export const createApi = () => ApiPromise.create({ + provider: new WsProvider(NODE_URL), +}); + +export const testSetup = { + provider, + wallets, + wallet: wallets[0], +}; From c2b13742d281f47874e551d19fb6cb241b2d0d25 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 14:46:20 +0800 Subject: [PATCH 06/23] misc corner endpoints --- .../src/__tests__/endpoint-tests/endpoint.ts | 82 ----------------- .../eth_sendRawTransaction.test.ts | 4 +- .../src/__tests__/endpoint-tests/misc.test.ts | 91 +++++++++++++++++++ 3 files changed, 93 insertions(+), 84 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index 8133de885..e470dce20 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -609,12 +609,6 @@ describe('endpoint', () => { }); }); - describe('eth_accounts', () => { - it('returns empty array', async () => { - const res = await eth_accounts([]); - expect(res.data.result).to.deep.equal([]); - }); - }); describe('eth_call', () => { const callRequest = (abi: any) => async (address: string, method: string, params?: any[], blockTag?: any) => { @@ -700,75 +694,6 @@ describe('endpoint', () => { }); }); - describe('eth_getEthGas', () => { - it('get correct default contract deployment eth gas params', async () => { - const gasLimit = 21000000; - const storageLimit = 64100; - const validUntil = 1000000; - - // correspond to validUntil = 1000000 - const defaultResults1 = await Promise.all([ - eth_getEthGas([{ gasLimit, storageLimit, validUntil }]), - eth_getEthGas([{ gasLimit, validUntil }]), - eth_getEthGas([{ storageLimit, validUntil }]), - eth_getEthGas([{ validUntil }]), - ]); - - for (const res of defaultResults1) { - const gas = res.data.result; - - expect(parseInt(gas.gasLimit, 16)).to.equal(53064000); - expect(parseInt(gas.gasPrice)).to.equal(202184524778); - } - - // correspond to validUntil = curBlock + 150 - const curBlock = parseInt((await eth_blockNumber()).data.result, 16); - const expectedGasPrice = parseInt( - ( - await eth_getEthGas([ - { - validUntil: curBlock + 150, - }, - ]) - ).data.result.gasPrice, - 16 - ); - - const defaultResults2 = await Promise.all([ - eth_getEthGas([{ gasLimit }]), - eth_getEthGas([{ storageLimit }]), - eth_getEthGas([{ gasLimit, storageLimit }]), - eth_getEthGas([{}]), - eth_getEthGas([]), - ]); - - for (const res of defaultResults2) { - const gas = res.data.result; - - expect(parseInt(gas.gasLimit, 16)).to.equal(53064000); - expect(parseInt(gas.gasPrice)).to.equal(expectedGasPrice); - } - }); - - it('get correct custom eth gas params', async () => { - const gasLimit = 12345678; - const storageLimit = 30000; - const validUntil = 876543; - - const gas = (await eth_getEthGas([{ gasLimit, storageLimit, validUntil }])).data.result; - - expect(parseInt(gas.gasLimit, 16)).to.equal(27353678); - expect(parseInt(gas.gasPrice)).to.equal(201914843605); - }); - - it('throws error when params are not valid', async () => { - const res = await eth_getEthGas([{ anyParam: 12345 }]); - - expect(res.data.error.code).to.equal(-32602); - expect(res.data.error.message).to.contain('parameter can only be \'storageLimit\' | \'gasLimit\' | \'validUntil\''); - }); - }); - describe('eth_getCode', () => { const preCompileAddresses = [ '0x0000000000000000000100000000000000000001', // AUSD @@ -1582,11 +1507,4 @@ describe('endpoint', () => { it.skip('eth_call', async () => {}); it.skip('eth_getStorageAt', async () => {}); }); - - describe('net_listening', () => { - it('returns true', async () => { - const res = (await net_listening([])).data.result; - expect(res).to.deep.equal(true); - }); - }); }); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts index 4c8b88869..48e434e29 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts @@ -2,7 +2,7 @@ import { ACA as ACA_ADDR } from '@acala-network/contracts/utils/AcalaAddress'; import { AcalaEvmTXPayload, UnsignedAcalaEvmTX, parseTransaction, serializeTransaction, signTransaction } from '@acala-network/eth-transactions'; import { BigNumber } from 'ethers'; import { Interface, formatEther, parseEther, parseUnits } from 'ethers/lib/utils'; -import { ONE_HUNDRED_GWEI, nativeToEthDecimal, sleep } from '@acala-network/eth-providers'; +import { ONE_HUNDRED_GWEI, nativeToEthDecimal } from '@acala-network/eth-providers'; import { afterAll, describe, expect, it } from 'vitest'; import { @@ -41,7 +41,7 @@ const getTxFeeFromReceipt = async (txHash: string, toNative = false): Promise { diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts new file mode 100644 index 000000000..acdcd9070 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts @@ -0,0 +1,91 @@ +import { describe, expect, it } from 'vitest'; + +import { + eth_accounts, + eth_blockNumber, + eth_getEthGas, + net_listening, +} from '../utils'; + +describe('eth_accounts', () => { + it('returns empty array', async () => { + const res = await eth_accounts([]); + expect(res.data.result).to.deep.equal([]); + }); +}); + +describe('net_listening', () => { + it('returns true', async () => { + const res = (await net_listening([])).data.result; + expect(res).to.deep.equal(true); + }); +}); + +describe('eth_getEthGas', () => { + it('get correct default contract deployment eth gas params', async () => { + const gasLimit = 21000000; + const storageLimit = 64100; + const validUntil = 1000000; + + // correspond to validUntil = 1000000 + const defaultResults1 = await Promise.all([ + eth_getEthGas([{ gasLimit, storageLimit, validUntil }]), + eth_getEthGas([{ gasLimit, validUntil }]), + eth_getEthGas([{ storageLimit, validUntil }]), + eth_getEthGas([{ validUntil }]), + ]); + + for (const res of defaultResults1) { + const gas = res.data.result; + + expect(parseInt(gas.gasLimit, 16)).to.equal(117192000); + expect(parseInt(gas.gasPrice)).to.equal(202184524778); + } + + // correspond to validUntil = curBlock + 150 + const curBlock = parseInt((await eth_blockNumber([])).data.result, 16); + const expectedGasPrice = parseInt( + ( + await eth_getEthGas([ + { + validUntil: curBlock + 150, + }, + ]) + ).data.result.gasPrice, + 16 + ); + + const defaultResults2 = await Promise.all([ + eth_getEthGas([{ gasLimit }]), + eth_getEthGas([{ storageLimit }]), + eth_getEthGas([{ gasLimit, storageLimit }]), + eth_getEthGas([{}]), + eth_getEthGas([]), + ]); + + for (const res of defaultResults2) { + const gas = res.data.result; + + expect(parseInt(gas.gasLimit, 16)).to.equal(117192000); + expect(parseInt(gas.gasPrice)).to.equal(expectedGasPrice); + } + }); + + it('get correct custom eth gas params', async () => { + const gasLimit = 12345678; + const storageLimit = 30000; + const validUntil = 876543; + + const gas = (await eth_getEthGas([{ gasLimit, storageLimit, validUntil }])).data.result; + + expect(parseInt(gas.gasLimit, 16)).to.equal(57369678); + expect(parseInt(gas.gasPrice)).to.equal(201914843605); + }); + + it('throws error when params are not valid', async () => { + const res = await eth_getEthGas([{ anyParam: 12345 }]); + + expect(res.data.error.code).to.equal(-32602); + expect(res.data.error.message).to.contain('parameter can only be \'storageLimit\' | \'gasLimit\' | \'validUntil\''); + }); +}); From 4419adb9e609b377ee663aad3cbae5ba88308add Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 15:38:47 +0800 Subject: [PATCH 07/23] blocktag tests --- packages/eth-providers/src/base-provider.ts | 1 - .../__tests__/endpoint-tests/blocktag.test.ts | 90 +++++++++++++++++++ .../src/__tests__/endpoint-tests/endpoint.ts | 73 --------------- .../src/__tests__/utils/erc20.ts | 4 +- 4 files changed, 92 insertions(+), 76 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts diff --git a/packages/eth-providers/src/base-provider.ts b/packages/eth-providers/src/base-provider.ts index 838d3eb2c..0238289c8 100644 --- a/packages/eth-providers/src/base-provider.ts +++ b/packages/eth-providers/src/base-provider.ts @@ -1701,7 +1701,6 @@ export abstract class BaseProvider extends AbstractProvider { return sortedReceipts?.[receiptIdx] ? subqlReceiptAdapter(sortedReceipts[receiptIdx]) : null; }; - // TODO: test pending _getPendingTX = async (txHash: string): Promise => { const pendingExtrinsics = await this.api.rpc.author.pendingExtrinsics(); const targetExtrinsic = pendingExtrinsics.find(ex => ex.hash.toHex() === txHash); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts new file mode 100644 index 000000000..20722e2a3 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts @@ -0,0 +1,90 @@ +import { describe, expect, it } from 'vitest'; + +import { + deployErc20, + eth_getBalance, + eth_getBlockByNumber, + eth_getCode, + eth_getTransactionCount, + eth_isBlockFinalized, + testSetup, +} from '../utils'; + +const { wallet } = testSetup; + +describe('finalized/safe/pending blocktag', () => { + /* ---------- + latest block === finalized block in local setup + ---------- */ + + it('eth_getCode', async () => { + const token = await deployErc20(wallet); + + const res = (await eth_getCode([token.address, 'latest'])).data.result; + const resF = (await eth_getCode([token.address, 'finalized'])).data.result; + const resS = (await eth_getCode([token.address, 'safe'])).data.result; + const resP = (await eth_getCode([token.address, 'pending'])).data.result; + + expect(res).not.to.be.undefined; + expect(res).to.equal(resF); + expect(res).to.equal(resS); + expect(res).to.equal(resP); + }); + + it('eth_getTransactionCount', async () => { + const res = (await eth_getTransactionCount([wallet.address, 'latest'])).data.result; + const resF = (await eth_getTransactionCount([wallet.address, 'finalized'])).data.result; + const resS = (await eth_getTransactionCount([wallet.address, 'safe'])).data.result; + + await deployErc20(wallet, false); + const resP = (await eth_getTransactionCount([wallet.address, 'pending'])).data.result; + + expect(res).to.equal(resF); + expect(res).to.equal(resS); + expect(Number(res)).to.equal(Number(resP) - 1); // pending should have +1 nonce + }); + + it('eth_getBalance', async () => { + const res = (await eth_getBalance([wallet.address, 'latest'])).data.result; + const resF = (await eth_getBalance([wallet.address, 'finalized'])).data.result; + const resS = (await eth_getBalance([wallet.address, 'safe'])).data.result; + const resP = (await eth_getBalance([wallet.address, 'pending'])).data.result; + + expect(parseInt(res)).to.greaterThan(0); + expect(res).to.equal(resF); + expect(res).to.equal(resS); + expect(res).to.equal(resP); + }); + + it('eth_getBlockByNumber', async () => { + const res = (await eth_getBlockByNumber(['latest', false])).data.result; + const resF = (await eth_getBlockByNumber(['finalized', false])).data.result; + const resS = (await eth_getBlockByNumber(['safe', false])).data.result; + const resP = (await eth_getBlockByNumber(['pending', false])).data.result; + + expect(res).not.to.be.undefined; + expect(res).to.deep.equal(resF); + expect(res).to.deep.equal(resS); + expect(res).to.deep.equal(resP); + }); + + it('eth_isBlockFinalized', async () => { + const res = (await eth_isBlockFinalized(['latest'])).data.result; + const resF = (await eth_isBlockFinalized(['finalized'])).data.result; + const resS = (await eth_isBlockFinalized(['safe'])).data.result; + + expect(res).to.equal(true); + expect(res).to.deep.equal(resF); + expect(res).to.deep.equal(resS); + }); + + // don't care about these + it.skip('eth_getBlockTransactionCountByNumber', async () => { }); + it.skip('eth_getTransactionByBlockNumberAndIndex', async () => { }); + it.skip('eth_getUncleCountByBlockNumber', async () => { }); + it.skip('eth_getUncleByBlockNumberAndIndex', async () => { }); + + // too lazy to test these + it.skip('eth_call', async () => { }); + it.skip('eth_getStorageAt', async () => { }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index e470dce20..5c10edc09 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -1434,77 +1434,4 @@ describe('endpoint', () => { expect(res.data.error!.message).to.contains('filter not found'); }); }); - - describe('finalized/safe/pending blocktag', () => { - /* ---------- - latest block <=> finalized block in local setup - ---------- */ - it('eth_getTransactionCount', async () => { - const res = (await eth_getTransactionCount([ADDRESS_ALICE, 'latest'])).data.result; - const resF = (await eth_getTransactionCount([ADDRESS_ALICE, 'finalized'])).data.result; - const resS = (await eth_getTransactionCount([ADDRESS_ALICE, 'safe'])).data.result; - const resP = (await eth_getTransactionCount([ADDRESS_ALICE, 'pending'])).data.result; - - expect(parseInt(res)).to.greaterThan(0); - expect(res).to.equal(resF); - expect(res).to.equal(resS); - expect(res).to.equal(resP); // no pending in local setup - }); - - it('eth_getCode', async () => { - const res = (await eth_getCode([DETERMINISTIC_SETUP_DEX_ADDRESS, 'latest'])).data.result; - const resF = (await eth_getCode([DETERMINISTIC_SETUP_DEX_ADDRESS, 'finalized'])).data.result; - const resS = (await eth_getCode([DETERMINISTIC_SETUP_DEX_ADDRESS, 'safe'])).data.result; - const resP = (await eth_getCode([DETERMINISTIC_SETUP_DEX_ADDRESS, 'pending'])).data.result; - - expect(res).not.to.be.undefined; - expect(res).to.equal(resF); - expect(res).to.equal(resS); - expect(res).to.equal(resP); - }); - - it('eth_getBalance', async () => { - const res = (await eth_getBalance([ADDRESS_ALICE, 'latest'])).data.result; - const resF = (await eth_getBalance([ADDRESS_ALICE, 'finalized'])).data.result; - const resS = (await eth_getBalance([ADDRESS_ALICE, 'safe'])).data.result; - const resP = (await eth_getBalance([ADDRESS_ALICE, 'pending'])).data.result; - - expect(parseInt(res)).to.greaterThan(0); - expect(res).to.equal(resF); - expect(res).to.equal(resS); - expect(res).to.equal(resP); - }); - - it('eth_getBlockByNumber', async () => { - const res = (await eth_getBlockByNumber(['latest', false])).data.result; - const resF = (await eth_getBlockByNumber(['finalized', false])).data.result; - const resS = (await eth_getBlockByNumber(['safe', false])).data.result; - const resP = (await eth_getBlockByNumber(['pending', false])).data.result; - - expect(res).not.to.be.undefined; - expect(res).to.deep.equal(resF); - expect(res).to.deep.equal(resS); - expect(res).to.deep.equal(resP); - }); - - it('eth_isBlockFinalized', async () => { - const res = (await eth_isBlockFinalized(['latest'])).data.result; - const resF = (await eth_isBlockFinalized(['finalized'])).data.result; - const resS = (await eth_isBlockFinalized(['safe'])).data.result; - - expect(res).to.equal(true); - expect(res).to.deep.equal(resF); - expect(res).to.deep.equal(resS); - }); - - // don't care about these - it.skip('eth_getBlockTransactionCountByNumber', async () => {}); - it.skip('eth_getTransactionByBlockNumberAndIndex', async () => {}); - it.skip('eth_getUncleCountByBlockNumber', async () => {}); - it.skip('eth_getUncleByBlockNumberAndIndex', async () => {}); - - // too lazy to test these - it.skip('eth_call', async () => {}); - it.skip('eth_getStorageAt', async () => {}); - }); }); diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts b/packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts index 52fb6d652..4c0feacab 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/erc20.ts @@ -286,10 +286,10 @@ export const ERC20_ABI = [ export const ERC20_BYTECODE = '6060604052341561000f57600080fd5b604051610dd1380380610dd18339810160405280805190602001909190805182019190602001805190602001909190805182019190505083600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360008190555082600390805190602001906100a79291906100e3565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906100d99291906100e3565b5050505050610188565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061012457805160ff1916838001178555610152565b82800160010185558215610152579182015b82811115610151578251825591602001919060010190610136565b5b50905061015f9190610163565b5090565b61018591905b80821115610181576000816000905550600101610169565b5090565b90565b610c3a806101976000396000f3006060604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014257806318160ddd1461019c57806323b872dd146101c557806327e235e31461023e578063313ce5671461028b5780635c658165146102ba57806370a082311461032657806395d89b4114610373578063a9059cbb14610401578063dd62ed3e1461045b575b600080fd5b34156100bf57600080fd5b6100c76104c7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101075780820151818401526020810190506100ec565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014d57600080fd5b610182600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610565565b604051808215151515815260200191505060405180910390f35b34156101a757600080fd5b6101af610657565b6040518082815260200191505060405180910390f35b34156101d057600080fd5b610224600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061065d565b604051808215151515815260200191505060405180910390f35b341561024957600080fd5b610275600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108f7565b6040518082815260200191505060405180910390f35b341561029657600080fd5b61029e61090f565b604051808260ff1660ff16815260200191505060405180910390f35b34156102c557600080fd5b610310600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610922565b6040518082815260200191505060405180910390f35b341561033157600080fd5b61035d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610947565b6040518082815260200191505060405180910390f35b341561037e57600080fd5b610386610990565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c65780820151818401526020810190506103ab565b50505050905090810190601f1680156103f35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561040c57600080fd5b610441600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a2e565b604051808215151515815260200191505060405180910390f35b341561046657600080fd5b6104b1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610b87565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561055d5780601f106105325761010080835404028352916020019161055d565b820191906000526020600020905b81548152906001019060200180831161054057829003601f168201915b505050505081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015801561072e5750828110155b151561073957600080fd5b82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555082600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156108865782600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055505b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b60016020528060005260406000206000915090505481565b600460009054906101000a900460ff1681565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a265780601f106109fb57610100808354040283529160200191610a26565b820191906000526020600020905b815481529060010190602001808311610a0957829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610a7e57600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a72305820df254047bc8f2904ad3e966b6db116d703bebd40efadadb5e738c836ffc8f58a0029'; -export const deployErc20 = async (wallet: Signer) => { +export const deployErc20 = async (wallet: Signer, waitForDeployed = true) => { const Token = new ContractFactory(ERC20_ABI, ERC20_BYTECODE, wallet); const token = await Token.deploy(parseEther('1000000000'), 'TestToken', 18, 'TT'); - await token.deployed(); + waitForDeployed && await token.deployed(); return token; }; From 0a81afd6e61a312860b14f64926fa61d850db031 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 16:42:04 +0800 Subject: [PATCH 08/23] eth_call tests --- .../src/__tests__/endpoint-tests/endpoint.ts | 84 -------------- .../__tests__/endpoint-tests/eth_call.test.ts | 103 ++++++++++++++++++ .../eth_sendRawTransaction.test.ts | 4 +- 3 files changed, 105 insertions(+), 86 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_call.test.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index 5c10edc09..738a6c356 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -610,90 +610,6 @@ describe('endpoint', () => { }); - describe('eth_call', () => { - const callRequest = (abi: any) => async (address: string, method: string, params?: any[], blockTag?: any) => { - const iface = new Interface(abi); - - const data = iface.encodeFunctionData(method, params); - const block = blockTag || (await eth_blockNumber()).data.result; - const rawRes = (await eth_call([{ to: address, data }, block])).data.result; - - return iface.decodeFunctionResult(method, rawRes); - }; - - const callToken = callRequest(TokenABI.abi); - const callDex = callRequest(DEXABI.abi); - - it('get correct procompile token info', async () => { - // https://github.com/AcalaNetwork/Acala/blob/a5d9e61c74/node/service/src/chain_spec/mandala.rs#L628-L636 - // Native tokens need to registry in asset_registry module. - const tokenMetaData = [ - { - address: '0x0000000000000000000100000000000000000000', - name: 'Acala', - symbol: 'ACA', - decimals: 12, - }, - { - address: '0x0000000000000000000100000000000000000001', - name: 'Acala Dollar', - symbol: 'AUSD', - decimals: 12, - }, - { - address: '0x0000000000000000000100000000000000000002', - name: 'Polkadot', - symbol: 'DOT', - decimals: 10, - }, - { - address: '0x0000000000000000000100000000000000000003', - name: 'Liquid DOT', - symbol: 'LDOT', - decimals: 10, - }, - ]; - - const tests = tokenMetaData.map(async ({ address, name, symbol, decimals }) => { - const [_name] = await callToken(address, 'name'); - const [_symbol] = await callToken(address, 'symbol'); - const [_decimals] = await callToken(address, 'decimals'); - - expect(_name).to.equal(name); - expect(_symbol).to.equal(symbol); - expect(_decimals).to.equal(decimals); - }); - - await Promise.all(tests); - }); - - it('supports calling historical blocks', async () => { - const dexAddr = '0x0230135fded668a3f7894966b14f42e65da322e4'; // created at block 5 - const before = await callDex(dexAddr, 'getLiquidityPool', [ADDRESS.ACA, ADDRESS.AUSD], { blockNumber: '0x5' }); - // swap happens at block 6 - const block7Hash = (await eth_getBlockByNumber([7, false])).data.result.hash; - const after = await callDex(dexAddr, 'getLiquidityPool', [ADDRESS.ACA, ADDRESS.AUSD], { blockHash: block7Hash }); - - expect(before.map(BigInt)).to.deep.equal([1000000000000000000n, 2000000000000000000n]); - expect(after.map(BigInt)).to.deep.equal([1000002000000000000n, 1999996004007985992n]); - }); - - it('throws correct error for invalid tag', async () => { - const dexAddr = '0x0230135fded668a3f7894966b14f42e65da322e4'; - const data = '0x123123123'; - - expect((await eth_call([{ to: dexAddr, data }, { hahaha: 13542 }])).data.error).to.deep.equal({ - code: -32602, - message: 'invalid argument 1: invalid eip-1898 blocktag, expected to contain blockNumber or blockHash', - }); - - expect((await eth_call([{ to: dexAddr, data }, { blockHash: 123 }])).data.error).to.deep.equal({ - code: -32602, - message: 'invalid argument 1: invalid block hash, expected type String', - }); - }); - }); - describe('eth_getCode', () => { const preCompileAddresses = [ '0x0000000000000000000100000000000000000001', // AUSD diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_call.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_call.test.ts new file mode 100644 index 000000000..68eacb260 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_call.test.ts @@ -0,0 +1,103 @@ +import { + ACA as ACA_ADDR, + AUSD as AUSD_ADDR, + DOT as DOT_ADDR, + LDOT as LDOT_ADDR, +} from '@acala-network/contracts/utils/AcalaAddress'; +import { Interface, parseEther, parseUnits } from 'ethers/lib/utils'; +import { describe, expect, it } from 'vitest'; + +import { BigNumber, Contract, Wallet } from 'ethers'; +import { + deployErc20, + eth_blockNumber, + eth_call, + testSetup, +} from '../utils'; +import erc20Abi from '../abis/IERC20.json'; + +const { wallet } = testSetup; + +describe('eth_call', () => { + const callRequest = (abi: any) => async (address: string, method: string, params?: any[], blockTag?: any) => { + const iface = new Interface(abi); + + const data = iface.encodeFunctionData(method, params); + const block = blockTag || (await eth_blockNumber()).data.result; + const rawRes = (await eth_call([{ to: address, data }, block])).data.result; + + return iface.decodeFunctionResult(method, rawRes); + }; + + const callToken = callRequest(erc20Abi.abi); + + it('get correct procompile token info', async () => { + const tokenMetaData = [ + { + address: ACA_ADDR, + name: 'Acala', + symbol: 'ACA', + decimals: 12, + }, + { + address: AUSD_ADDR, + name: 'aUSD SEED', + symbol: 'aSEED', + decimals: 12, + }, + { + address: DOT_ADDR, + name: 'Polkadot', + symbol: 'DOT', + decimals: 10, + }, + { + address: LDOT_ADDR, + name: 'Liquid DOT', + symbol: 'LDOT', + decimals: 10, + }, + ]; + + const tests = tokenMetaData.map(async ({ address, name, symbol, decimals }) => { + const [_name] = await callToken(address, 'name'); + const [_symbol] = await callToken(address, 'symbol'); + const [_decimals] = await callToken(address, 'decimals'); + + expect(_name).to.equal(name); + expect(_symbol).to.equal(symbol); + expect(_decimals).to.equal(decimals); + }); + + await Promise.all(tests); + }); + + it('supports calling historical blocks', async () => { + const token = await deployErc20(wallet); + + const transferAmount = parseUnits('1', 12); + await (await token.transfer(Wallet.createRandom().address, transferAmount)).wait(); + + const curBlockNumber = Number((await eth_blockNumber()).data.result); + const [beforeBal] = await callToken(token.address, 'balanceOf', [wallet.address], { blockNumber: curBlockNumber - 1 }); + const [afterBal] = await callToken(token.address, 'balanceOf', [wallet.address], { blockNumber: curBlockNumber }); + const [curBal] = await callToken(token.address, 'balanceOf', [wallet.address], 'latest'); + + expect(afterBal.toBigInt()).to.equal(curBal.toBigInt()); + expect(beforeBal.sub(transferAmount).toBigInt()).to.equal(afterBal.toBigInt()); + }); + + it('throws correct error for invalid tag', async () => { + const data = '0x123123123'; + + expect((await eth_call([{ to: ACA_ADDR, data }, { hahaha: 13542 }])).data.error).to.deep.equal({ + code: -32602, + message: 'invalid argument 1: invalid eip-1898 blocktag, expected to contain blockNumber or blockHash', + }); + + expect((await eth_call([{ to: ACA_ADDR, data }, { blockHash: 123 }])).data.error).to.deep.equal({ + code: -32602, + message: 'invalid argument 1: invalid block hash, expected type String', + }); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts index 48e434e29..02ae6a63f 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_sendRawTransaction.test.ts @@ -17,7 +17,7 @@ import { getNonce, testSetup, } from '../utils'; -import Erc20Abi from '../abis/IERC20.json'; +import erc20Abi from '../abis/IERC20.json'; const ETH_Digits = 18; const ACA_Digits = 12; @@ -165,7 +165,7 @@ describe('eth_sendRawTransaction', async () => { }); describe('call contract (transfer ACA)', () => { - const iface = new Interface(Erc20Abi.abi); + const iface = new Interface(erc20Abi.abi); const transferAmount = parseUnits('12.321', ACA_Digits); const partialTransferTX = { chainId, From 73e70e56d17f6b5f401c33476b975909a505818e Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 17:29:12 +0800 Subject: [PATCH 09/23] fix and switch endpoint --- .github/workflows/test.yml | 4 ++-- chopsticks/configs/acala.yml | 2 +- .../src/__tests__/endpoint-tests/blocktag.test.ts | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8ff19bf0..7db9a16ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -50,7 +50,7 @@ jobs: uses: nick-fields/retry@v2 with: timeout_minutes: 30 - max_attempts: 3 + max_attempts: 1 command: yarn workspace @acala-network/${{ matrix.project }} run test:coverage - name: save coverage reports @@ -107,7 +107,7 @@ jobs: uses: nick-fields/retry@v2 with: timeout_minutes: 30 - max_attempts: 3 + max_attempts: 1 command: cd e2e-tests/${{ matrix.project }} && yarn test:acalaFork - name: stop coverage server and generate coverage report diff --git a/chopsticks/configs/acala.yml b/chopsticks/configs/acala.yml index db49e84c4..f4f281789 100644 --- a/chopsticks/configs/acala.yml +++ b/chopsticks/configs/acala.yml @@ -1,4 +1,4 @@ -endpoint: wss://acala-rpc.aca-api.network +endpoint: wss://acala-rpc.dwellir.com mock-signature-host: true runtime-log-level: 5 block: 7000000 diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts index 20722e2a3..5cd070577 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts @@ -36,12 +36,14 @@ describe('finalized/safe/pending blocktag', () => { const resF = (await eth_getTransactionCount([wallet.address, 'finalized'])).data.result; const resS = (await eth_getTransactionCount([wallet.address, 'safe'])).data.result; - await deployErc20(wallet, false); + const token = await deployErc20(wallet, false); const resP = (await eth_getTransactionCount([wallet.address, 'pending'])).data.result; expect(res).to.equal(resF); expect(res).to.equal(resS); expect(Number(res)).to.equal(Number(resP) - 1); // pending should have +1 nonce + + await token.deployed(); // wait for deployment in case it affects next tests }); it('eth_getBalance', async () => { From c9db8a6ec23dcd525dcf7974eee7ce4024cc1d9b Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 20:46:32 +0800 Subject: [PATCH 10/23] eth_getCode tests --- .../src/__tests__/endpoint-tests/endpoint.ts | 258 ------------------ .../endpoint-tests/eth_getCode.test.ts | 68 +++++ .../src/__tests__/endpoint-tests/misc.test.ts | 9 + 3 files changed, 77 insertions(+), 258 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getCode.test.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index 738a6c356..167a7e0e4 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -610,51 +610,6 @@ describe('endpoint', () => { }); - describe('eth_getCode', () => { - const preCompileAddresses = [ - '0x0000000000000000000100000000000000000001', // AUSD - '0x0000000000000000000200000000000000000001', // LP_ACA_AUSD - '0x0000000000000000000000000000000000000803', // DEX - ]; - - const tags = ['latest', 'earliest', 'finalized', 'safe']; - - it('get correct precompile token code', async () => { - for (const addr of preCompileAddresses) { - for (const t of tags) { - const res = (await eth_getCode([addr, t])).data.result; - expect(res.length).to.greaterThan(2); - } - } - }); - - it.skip('get correct user deployed contract code', async () => {}); - - it('returns empty for pending tag or non-exist contract address', async () => { - const randAddr = '0x1ebEc3D7fd088d9eE4B6d8272788f028e5122218'; - for (const t of [...tags, 'pending']) { - const res = (await eth_getCode([randAddr, t])).data.result; - expect(res).to.equal('0x'); - } - }); - - it('supports calling historical blocks', async () => { - const dexAddr = '0x0230135fded668a3f7894966b14f42e65da322e4'; // created at block 5 - expect((await eth_getCode([dexAddr, { blockNumber: 1 }])).data.result).to.equal('0x'); - expect((await eth_getCode([dexAddr, { blockNumber: 5 }])).data.result.length).to.greaterThan(2); - expect((await eth_getCode([dexAddr, { blockNumber: 8 }])).data.result.length).to.greaterThan(2); - expect((await eth_getCode([dexAddr, 7])).data.result.length).to.greaterThan(2); - }); - }); - - describe('net_runtimeVersion', () => { - it('get correct runtime version', async () => { - const version = (await net_runtimeVersion([])).data.result; - - expect(version).to.be.gt(2000); - }); - }); - describe('eth_getBlockByNumber', () => { if (process.env.SKIP_PUBLIC) { console.log('public karura tests are skipped ❗'); @@ -749,219 +704,6 @@ describe('endpoint', () => { }); }); - describe('eth_subscribe', () => { - const provider = new EvmRpcProvider(NODE_RPC_URL); - const aca = new Contract(ADDRESS.ACA, TokenABI.abi, wallet1.connect(provider)); - - const notifications: any[] = []; - let subId0; - let subId1; - let subId2; - let subId3; - let ws: WebSocket; - - beforeAll(() => { - // these has to be in , since everything outside of will be globally executed before any - // also, instantiating ws (next line) has to be inside , otherwise there will be mysterious failure... - ws = new WebSocket(WS_URL); - ws.on('open', () => { - ws.on('message', data => { - const parsedData = JSON.parse(data.toString()); - notifications.push(parsedData); - }); - - ws.send( - JSON.stringify({ - jsonrpc: '2.0', - id: 0, - method: 'eth_subscribe', - params: ['newHeads'], - }) - ); - - ws.send( - JSON.stringify({ - jsonrpc: '2.0', - id: 1, - method: 'eth_subscribe', - params: ['logs', {}], - }) - ); - - ws.send( - JSON.stringify({ - jsonrpc: '2.0', - id: 2, - method: 'eth_subscribe', - params: [ - 'logs', - { - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // transfer - null, - ['0x000000000000000000000000b00cb924ae22b2bbb15e10c17258d6a2af980421'], - ], - }, - ], - }) - ); - - ws.send( - JSON.stringify({ - jsonrpc: '2.0', - id: 3, - method: 'eth_subscribe', - params: [ - 'logs', - { - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55aaaaaaaaaaa', // shouldn't match - ], - }, - ], - }) - ); - }); - }); - - afterAll(async () => { - await provider.disconnect(); - ws.close(); - }); - - it('get correct subscrption notification', async () => { - await provider.isReady(); - await aca.transfer(evmAccounts[1].evmAddress, 111222333444555); - - await sleep(3000); // give ws some time to notify - - subId0 = notifications.find(n => n.id === 0).result; - subId1 = notifications.find(n => n.id === 1).result; - subId2 = notifications.find(n => n.id === 2).result; - subId3 = notifications.find(n => n.id === 3).result; - - const notification0 = notifications.find(n => n.params?.subscription === subId0); // new block - const notification1 = notifications.find(n => n.params?.subscription === subId1); // ACA transfer - const notification2 = notifications.find(n => n.params?.subscription === subId2); // ACA transfer - const notification3 = notifications.find(n => n.params?.subscription === subId3); // no match - - const curBlock = (await eth_blockNumber()).data.result; - const curBlockInfo = (await eth_getBlockByNumber([curBlock, false])).data.result; - - expect(notification0).to.deep.contains({ - jsonrpc: '2.0', - method: 'eth_subscription', - params: { - subscription: subId0, - result: curBlockInfo, - }, - }); - - await sleep(10000); // give subql some time to index - const expectedLog = ( - await eth_getLogs([ - { - blockHash: curBlockInfo.hash, - }, - ]) - ).data.result; - - expect(expectedLog.length).to.equal(1); - delete (expectedLog[0] as any).removed; - - expect(notification1).to.deep.contains({ - jsonrpc: '2.0', - method: 'eth_subscription', - params: { - subscription: subId1, - result: expectedLog[0], - }, - }); - - expect(notification2).to.deep.contains({ - jsonrpc: '2.0', - method: 'eth_subscription', - params: { - subscription: subId2, - result: expectedLog[0], - }, - }); - - expect(notification3).to.equal(undefined); - }); - - it('unsubscribe works', async () => { - notifications.length = 0; - - let reqId = 10; - const unsubscribe = async (id: string) => { - ws.send( - JSON.stringify({ - jsonrpc: '2.0', - id: reqId++, - method: 'eth_unsubscribe', - params: [id], - }) - ); - - await sleep(300); // delay each msg to make sure result order is correct - }; - - await unsubscribe(subId0); - await unsubscribe(subId1); - await unsubscribe(subId3); - await unsubscribe(Wallet.createRandom().address); - - await sleep(3000); // give ws some time to notify - - expect(notifications).to.deep.equal([ - { id: 10, jsonrpc: '2.0', result: true }, - { id: 11, jsonrpc: '2.0', result: true }, - { id: 12, jsonrpc: '2.0', result: true }, - { id: 13, jsonrpc: '2.0', result: false }, - ]); - - // only sub2 is left - notifications.length = 0; - await aca.transfer(evmAccounts[1].evmAddress, 1234567654321); - - await sleep(10000); // give ws some time to notify - - const notification0 = notifications.find(n => n.params?.subscription === subId0); // no match - const notification1 = notifications.find(n => n.params?.subscription === subId1); // no match - const notification2 = notifications.find(n => n.params?.subscription === subId2); // ACA transfer - const notification3 = notifications.find(n => n.params?.subscription === subId3); // no match - - // after unsubscribe they should not be notified anymore - expect(notification0).to.equal(undefined); - expect(notification1).to.equal(undefined); - expect(notification3).to.equal(undefined); - - await sleep(10000); // give subql some time to index - const curBlock = (await eth_blockNumber()).data.result; - const curBlockInfo = (await eth_getBlockByNumber([curBlock, false])).data.result; - const expectedLog = ( - await eth_getLogs([ - { - blockHash: curBlockInfo.hash, - }, - ]) - ).data.result; - - expect(expectedLog.length).to.equal(1); - delete (expectedLog[0] as any).removed; - - expect(notification2).to.deep.contains({ - jsonrpc: '2.0', - method: 'eth_subscription', - params: { - subscription: subId2, - result: expectedLog[0], - }, - }); - }); - }); - describe('eth_newBlockFilter', () => { const provider = new EvmRpcProvider(NODE_RPC_URL); const aca = new Contract(ADDRESS.ACA, TokenABI.abi, wallet1.connect(provider)); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getCode.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getCode.test.ts new file mode 100644 index 000000000..a722218c7 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getCode.test.ts @@ -0,0 +1,68 @@ +import { + ACA as ACA_ADDR, + LP_LCDOT_DOT, +} from '@acala-network/contracts/utils/AcalaAddress'; +import { BlockTagish, Eip1898BlockTag } from '@acala-network/eth-providers'; +import { Contract, Wallet } from 'ethers'; +import { beforeAll, describe, expect, it } from 'vitest'; + +import { + deployErc20, + eth_blockNumber, + eth_getCode, + testSetup, +} from '../utils'; + +const { wallet } = testSetup; + +const PRE_DEPLOYED_ADDRS = [ + ACA_ADDR, + LP_LCDOT_DOT, +]; + +const tags = ['latest', 'earliest', 'finalized', 'safe']; + +describe('eth_getCode', () => { + let token: Contract; + let tokenDeployedBlock: number; + + beforeAll(async () => { + token = await deployErc20(wallet); + tokenDeployedBlock = Number((await eth_blockNumber()).data.result); + }); + + it('can get contract code', async () => { + const allAddrs = PRE_DEPLOYED_ADDRS.concat(token.address as any); + + for (const addr of allAddrs) { + for (const t of tags) { + const res = (await eth_getCode([addr, t])).data.result; + + if (t === 'earliest') { + expect(res).to.equal('0x'); + } else { + expect(res.length).to.greaterThan(2); + } + } + } + }); + + it('returns empty for pending tag or non-exist contract address', async () => { + const randAddr = Wallet.createRandom().address; + for (const t of [...tags, 'pending']) { + const res = (await eth_getCode([randAddr, t])).data.result; + expect(res).to.equal('0x'); + } + }); + + it('supports calling historical blocks', async () => { + const _getTokenCode = async (blockTag: BlockTagish | Eip1898BlockTag) => + (await eth_getCode([token.address, blockTag])).data.result; + + expect((await _getTokenCode('earliest'))).to.equal('0x'); + expect((await _getTokenCode({ blockNumber: tokenDeployedBlock - 1 }))).to.equal('0x'); + + expect((await _getTokenCode('latest')).length).to.greaterThan(2); + expect((await _getTokenCode({ blockNumber: tokenDeployedBlock })).length).to.greaterThan(2); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts index acdcd9070..1cef619b6 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/misc.test.ts @@ -5,6 +5,7 @@ import { eth_blockNumber, eth_getEthGas, net_listening, + net_runtimeVersion, } from '../utils'; describe('eth_accounts', () => { @@ -21,6 +22,14 @@ describe('net_listening', () => { }); }); +describe('net_runtimeVersion', () => { + it('get correct runtime version', async () => { + const version = (await net_runtimeVersion([])).data.result; + + expect(version).to.be.gte(2250); + }); +}); + describe('eth_getEthGas', () => { it('get correct default contract deployment eth gas params', async () => { const gasLimit = 21000000; From 56b9f42d99e38db9ae0dcaf5e2bc854f5f48cf0d Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 21:28:04 +0800 Subject: [PATCH 11/23] eth_getStorageAt tests --- .../src/__tests__/parseBlock.test.ts | 1 - .../__tests__/endpoint-tests/blocktag.test.ts | 3 + .../src/__tests__/endpoint-tests/endpoint.ts | 95 ------------------- .../endpoint-tests/eth_getStorageAt.test.ts | 33 +++++++ .../src/__tests__/utils/eth-rpc-apis.ts | 2 +- 5 files changed, 37 insertions(+), 97 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getStorageAt.test.ts diff --git a/packages/eth-providers/src/__tests__/parseBlock.test.ts b/packages/eth-providers/src/__tests__/parseBlock.test.ts index a56fced30..f9ee0ce9a 100644 --- a/packages/eth-providers/src/__tests__/parseBlock.test.ts +++ b/packages/eth-providers/src/__tests__/parseBlock.test.ts @@ -72,7 +72,6 @@ describe.concurrent('getAllReceiptsAtBlock', () => { }); afterAll(async () => { - await sleep(10_000); await apiK.disconnect(); await apiA.disconnect(); }); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts index 5cd070577..189fc9360 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/blocktag.test.ts @@ -44,6 +44,9 @@ describe('finalized/safe/pending blocktag', () => { expect(Number(res)).to.equal(Number(resP) - 1); // pending should have +1 nonce await token.deployed(); // wait for deployment in case it affects next tests + + const resL = (await eth_getTransactionCount([wallet.address, 'latest'])).data.result; + expect(resL).to.equal(resP); }); it('eth_getBalance', async () => { diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index 167a7e0e4..4db08229e 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -609,101 +609,6 @@ describe('endpoint', () => { }); }); - - describe('eth_getBlockByNumber', () => { - if (process.env.SKIP_PUBLIC) { - console.log('public karura tests are skipped ❗'); - return; - } - - it('when there are 0 EVM transactions', async () => { - const resFull = (await eth_getBlockByNumber_karura([1818188, true])).data.result; - const res = (await eth_getBlockByNumber_karura([1818188, false])).data.result; - - expect(resFull).toMatchSnapshot(); - expect(res).toMatchSnapshot(); - }); - - it('when there are 1 EVM transactions', async () => { - const resFull = (await eth_getBlockByNumber_karura([1818518, true])).data.result; - const res = (await eth_getBlockByNumber_karura([1818518, false])).data.result; - - expect(resFull).toMatchSnapshot(); - expect(res).toMatchSnapshot(); - }); - - it('when there are >= 2 EVM transactions', async () => { - const resFull = (await eth_getBlockByNumber_karura([2449983, true])).data.result; - const res = (await eth_getBlockByNumber_karura([2449983, false])).data.result; - - expect(resFull).toMatchSnapshot(); - expect(res).toMatchSnapshot(); - }); - - it('for very old runtime', async () => { - const resFull = (await eth_getBlockByNumber_karura([372268, true])).data.result; - const res = (await eth_getBlockByNumber_karura([372268, false])).data.result; - - expect(resFull).toMatchSnapshot(); - expect(res).toMatchSnapshot(); - }); - }); - - describe('eth_getBalance', () => { - it('get correct balance', async () => { - const block8Balance = 8999995192165097994000000n; // edit me for different mandala version - expect(BigInt((await eth_getBalance([ADDRESS_ALICE, 8])).data.result)).to.equal(block8Balance); - expect(BigInt((await eth_getBalance([ADDRESS_ALICE, '0x8'])).data.result)).to.equal(block8Balance); - expect(BigInt((await eth_getBalance([ADDRESS_ALICE, { blockNumber: 8 }])).data.result)).to.equal(block8Balance); - - const curBlock = (await eth_blockNumber([])).data.result; - expect(Number((await eth_getBalance([ADDRESS_ALICE, { blockNumber: curBlock }])).data.result)).to.equal( - Number((await eth_getBalance([ADDRESS_ALICE, 'latest'])).data.result) - ); - }); - }); - - describe('eth_getTransactionCount', () => { - it('get correct transaction', async () => { - expect(Number((await eth_getTransactionCount([ADDRESS_ALICE, 1])).data.result)).to.equal(0); - expect(Number((await eth_getTransactionCount([ADDRESS_ALICE, '0x5'])).data.result)).to.equal(1); - expect(Number((await eth_getTransactionCount([ADDRESS_ALICE, { blockNumber: 8 }])).data.result)).to.equal(4); - - const curBlock = (await eth_blockNumber([])).data.result; - expect(Number((await eth_getTransactionCount([ADDRESS_ALICE, { blockNumber: curBlock }])).data.result)).to.equal( - Number((await eth_getTransactionCount([ADDRESS_ALICE, 'latest'])).data.result) - ); - }); - }); - - describe('eth_getStorageAt', () => { - if (process.env.SKIP_PUBLIC) { - console.log('public karura tests are skipped ❗'); - return; - } - - it('get correct storage from public karura', async () => { - const contractAddr = '0x1f3a10587a20114ea25ba1b388ee2dd4a337ce27'; - expect( - ( - await eth_getStorageAt_karura([ - contractAddr, - '0x0000000000000000000000000000000000000000000000000000000000000000', - 2000000, - ]) - ).data.result - ).to.equal('0x55534420436f696e000000000000000000000000000000000000000000000010'); - - expect((await eth_getStorageAt_karura([contractAddr, '0x0', 2000000])).data.result).to.equal( - '0x55534420436f696e000000000000000000000000000000000000000000000010' - ); - - expect((await eth_getStorageAt_karura([contractAddr, '0x3', 2000000])).data.result).to.equal( - '0x000000000000000000000000000000000000000000000000000000070d785f88' - ); - }); - }); - describe('eth_newBlockFilter', () => { const provider = new EvmRpcProvider(NODE_RPC_URL); const aca = new Contract(ADDRESS.ACA, TokenABI.abi, wallet1.connect(provider)); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getStorageAt.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getStorageAt.test.ts new file mode 100644 index 000000000..1af947912 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getStorageAt.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from 'vitest'; + +import { deployErc20, eth_getStorageAt, testSetup } from '../utils'; +import { hexZeroPad, parseEther } from 'ethers/lib/utils'; + +const { wallet } = testSetup; + +describe('eth_getStorageAt', () => { + it('get correct storage', async () => { + const token = await deployErc20(wallet); + + const _getStorageAtForToken = async (slot: string) => { + return (await eth_getStorageAt([token.address, slot, 'latest'])).data.result; + }; + + const totalSupplyStorage = hexZeroPad(parseEther('1000000000').toHexString(), 32); + + expect((await _getStorageAtForToken('0x0000000000000000000000000000000000000000000000000000000000000000'))).to.equal(totalSupplyStorage); + expect((await _getStorageAtForToken('0x0'))).to.equal(totalSupplyStorage); + + expect((await _getStorageAtForToken('0x1'))).to.equal( + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + expect((await _getStorageAtForToken('0x2'))).to.equal( + '0x0000000000000000000000000000000000000000000000000000000000000000' + ); + + expect((await _getStorageAtForToken('0x3'))).to.equal( + '0x54657374546f6b656e0000000000000000000000000000000000000000000012' + ); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts index 24dbaac52..3c3587155 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts @@ -54,4 +54,4 @@ export const eth_blockNumber_karura = rpcGet('eth_blockNumber', KARURA_ETH_RPC_U export const eth_getTransactionReceipt_karura = rpcGet('eth_getTransactionReceipt', KARURA_ETH_RPC_URL); export const eth_getTransactionByHash_karura = rpcGet('eth_getTransactionByHash', KARURA_ETH_RPC_URL); export const eth_getBlockByNumber_karura = rpcGet('eth_getBlockByNumber', KARURA_ETH_RPC_URL); -export const eth_getStorageAt_karura = rpcGet('eth_getStorageAt', KARURA_ETH_RPC_URL); +export const eth_getStorageAt = rpcGet('eth_getStorageAt', ETH_RPC_URL); From 6c5b4988fc19fd52bed305091aeafaf10ca2e0be Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 21:43:11 +0800 Subject: [PATCH 12/23] use retry 2 times --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7db9a16ce..22ec249be 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -50,7 +50,7 @@ jobs: uses: nick-fields/retry@v2 with: timeout_minutes: 30 - max_attempts: 1 + max_attempts: 2 command: yarn workspace @acala-network/${{ matrix.project }} run test:coverage - name: save coverage reports @@ -107,7 +107,7 @@ jobs: uses: nick-fields/retry@v2 with: timeout_minutes: 30 - max_attempts: 1 + max_attempts: 2 command: cd e2e-tests/${{ matrix.project }} && yarn test:acalaFork - name: stop coverage server and generate coverage report From 0fd23c7e7310b80f7660f320df3028119a25cc1a Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Tue, 8 Oct 2024 21:54:05 +0800 Subject: [PATCH 13/23] use dwellir node url --- packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts | 2 +- packages/eth-providers/src/__tests__/parseBlock.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts b/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts index 1cda48877..d63f7203d 100644 --- a/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts +++ b/packages/eth-providers/src/__tests__/evm-rpc-provider.test.ts @@ -5,7 +5,7 @@ import dotenv from 'dotenv'; dotenv.config(); -const ACALA_NODE_URL = 'wss://acala-rpc.aca-api.network'; +const ACALA_NODE_URL = 'wss://acala-rpc.dwellir.com'; const ACALA_SUBQL = 'https://subql-query-acala.aca-api.network'; const endpoint = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; diff --git a/packages/eth-providers/src/__tests__/parseBlock.test.ts b/packages/eth-providers/src/__tests__/parseBlock.test.ts index f9ee0ce9a..3dd2374bb 100644 --- a/packages/eth-providers/src/__tests__/parseBlock.test.ts +++ b/packages/eth-providers/src/__tests__/parseBlock.test.ts @@ -49,7 +49,7 @@ describe.concurrent('getAllReceiptsAtBlock', () => { beforeAll(async () => { console.log('connecting to node...'); const KARURA_NODE_URL = 'wss://karura-rpc.aca-api.network'; - const ACALA_NODE_URL = 'wss://acala-rpc.aca-api.network'; + const ACALA_NODE_URL = 'wss://acala-rpc.dwellir.com'; apiK = new ApiPromise( options({ From 96c42c7bcd1b39d926af149743a59d4be1b2b4ce Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Wed, 9 Oct 2024 10:54:19 +0800 Subject: [PATCH 14/23] moved karura getblockbynumber tests to parseblock test --- .../__snapshots__/parseBlock.test.ts.snap | 105 ++++++++++++++++++ .../src/__tests__/parseBlock.test.ts | 26 +++++ 2 files changed, 131 insertions(+) diff --git a/packages/eth-providers/src/__tests__/__snapshots__/parseBlock.test.ts.snap b/packages/eth-providers/src/__tests__/__snapshots__/parseBlock.test.ts.snap index 0d165b0f2..c9e87133f 100644 --- a/packages/eth-providers/src/__tests__/__snapshots__/parseBlock.test.ts.snap +++ b/packages/eth-providers/src/__tests__/__snapshots__/parseBlock.test.ts.snap @@ -363,6 +363,111 @@ exports[`getAllReceiptsAtBlock > contract creation > with logs + legacy gas 1`] ] `; +exports[`getAllReceiptsAtBlock > different evm tx count > when there are 0 EVM transactions 1`] = `[]`; + +exports[`getAllReceiptsAtBlock > different evm tx count > when there are 1 EVM transactions 1`] = ` +[ + { + "blockHash": "0xab9f0519e9f9885861da35765dad61161c5f939c66b4c4b7091f7e9555e9f92f", + "blockNumber": "0x1bbf96", + "contractAddress": "0x0000000000000000000000000000000000000801", + "cumulativeGasUsed": "0x0", + "effectiveGasPrice": "0x4ced5668c50", + "from": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x3181f", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "0x1", + "to": null, + "transactionHash": "0x79090e3e64da12012839fb40f95ad03703a6d3c999c262b4196796f9753861ca", + "transactionIndex": "0x0", + "type": "0x0", + }, +] +`; + +exports[`getAllReceiptsAtBlock > different evm tx count > when there are 2 EVM transactions 1`] = ` +[ + { + "blockHash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", + "blockNumber": "0x25623f", + "contractAddress": null, + "cumulativeGasUsed": "0x0", + "effectiveGasPrice": "0x15fde28667", + "from": "0x9cb3b68e0c48c53b70f465bda3ba6481a9cb7720", + "gasUsed": "0x2a9f7", + "logs": [ + { + "address": "0x0000000000000000000100000000000000000084", + "blockHash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", + "blockNumber": "0x25623f", + "data": "0x0000000000000000000000000000000000000000000000000001550f7dca7000", + "logIndex": "0x0", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000030385059196602a1498f5f8ef91f3450e3a7b27a", + "0x0000000000000000000000009cb3b68e0c48c53b70f465bda3ba6481a9cb7720", + ], + "transactionHash": "0x7b0361f47dc0be798cb9f7d115d74d68960e685714c515df81dd1a17e3db0cff", + "transactionIndex": "0x0", + }, + { + "address": "0x30385059196602a1498f5f8ef91f3450e3a7b27a", + "blockHash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", + "blockNumber": "0x25623f", + "data": "0x0000000000000000000000009cb3b68e0c48c53b70f465bda3ba6481a9cb77200000000000000000000000000000000000000000000000000001550f7dca70000000000000000000000000000000000000000000000000000000000062f8bc54000000000000000000000000000000000000000000000000000000000025623f0000000000000000000000009cb3b68e0c48c53b70f465bda3ba6481a9cb7720", + "logIndex": "0x1", + "topics": [ + "0xcb3fe4174668d512bcb57104a92bc21df0b8fdeb1cacc3575aa50b74a3e5ad5a", + "0xeac06b4f60edb2a940a2170eea5cef018dc569f5d98b8176f5da7ea640c9bd27", + "0x0000000000000000000000000000000000000000000100000000000000000084", + "0x0000000000000000000000000000000000000000000000000000000000000004", + ], + "transactionHash": "0x7b0361f47dc0be798cb9f7d115d74d68960e685714c515df81dd1a17e3db0cff", + "transactionIndex": "0x0", + }, + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "0x1", + "to": "0x30385059196602a1498f5f8ef91f3450e3a7b27a", + "transactionHash": "0x7b0361f47dc0be798cb9f7d115d74d68960e685714c515df81dd1a17e3db0cff", + "transactionIndex": "0x0", + "type": "0x0", + }, + { + "blockHash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", + "blockNumber": "0x25623f", + "contractAddress": null, + "cumulativeGasUsed": "0x0", + "effectiveGasPrice": "0xb460f6718", + "from": "0xc760da3c525c8511938c35613684c3f6175c01a5", + "gasUsed": "0xc26d", + "logs": [ + { + "address": "0x1f3a10587a20114ea25ba1b388ee2dd4a337ce27", + "blockHash": "0xbdae06c67294bca57bffd390c997d6730a837e1c11252d9bba00cac7384c1f16", + "blockNumber": "0x25623f", + "data": "0x0000000000000000000000000000000000000000000000000000000025342e5d", + "logIndex": "0x0", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000c760da3c525c8511938c35613684c3f6175c01a5", + "0x000000000000000000000000f7abcfa42bf7e7d43d3d53c665ded80fdafb5244", + ], + "transactionHash": "0x9824e1111ba926db7df3091ec45344f224a3086daf5580eaf7ab3e6bf5a6dde6", + "transactionIndex": "0x1", + }, + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "0x1", + "to": "0x1f3a10587a20114ea25ba1b388ee2dd4a337ce27", + "transactionHash": "0x9824e1111ba926db7df3091ec45344f224a3086daf5580eaf7ab3e6bf5a6dde6", + "transactionIndex": "0x1", + "type": "0x0", + }, +] +`; + exports[`getAllReceiptsAtBlock > erc20 XCM > basic xcm 1`] = ` [ { diff --git a/packages/eth-providers/src/__tests__/parseBlock.test.ts b/packages/eth-providers/src/__tests__/parseBlock.test.ts index 3dd2374bb..8f71c41d0 100644 --- a/packages/eth-providers/src/__tests__/parseBlock.test.ts +++ b/packages/eth-providers/src/__tests__/parseBlock.test.ts @@ -198,6 +198,32 @@ describe.concurrent('getAllReceiptsAtBlock', () => { }); }); + describe.concurrent('different evm tx count', () => { + it('when there are 0 EVM transactions', async ({ expect }) => { + const blockNumber = 1818188; + const receipts = await getAllReceiptsAtBlockNumber(apiK, blockNumber); + + expect(receipts.length).to.equal(0); + expect(receipts).toMatchSnapshot(); + }); + + it('when there are 1 EVM transactions', async ({ expect }) => { + const blockNumber = 1818518; + const receipts = await getAllReceiptsAtBlockNumber(apiK, blockNumber); + + expect(receipts.length).to.equal(1); + expect(receipts).toMatchSnapshot(); + }); + + it('when there are 2 EVM transactions', async ({ expect }) => { + const blockNumber = 2449983; + const receipts = await getAllReceiptsAtBlockNumber(apiK, blockNumber); + + expect(receipts.length).to.equal(2); + expect(receipts).toMatchSnapshot(); + }); + }); + describe.concurrent.skip('other types', () => { // it('failed EVM extrinsic - 0 gasLimit', async ({ expect }) => { // // TODO: construct a similar one on karura From 3ed7108b11ca93d148702e4bbf121811ff08f135 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Wed, 9 Oct 2024 11:28:43 +0800 Subject: [PATCH 15/23] eth_getBlockByNumber tests --- .../eth_getBlockByNumber.test.ts | 28 +++++++++++++++++++ .../src/__tests__/utils/eth-rpc-apis.ts | 6 ---- 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getBlockByNumber.test.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getBlockByNumber.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getBlockByNumber.test.ts new file mode 100644 index 000000000..daabb701b --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getBlockByNumber.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest'; + +import { deployErc20, eth_getBlockByNumber, testSetup } from '../utils'; + +const { wallet, provider } = testSetup; + +describe('eth_getBlockByNumber', () => { + it('get correct block info', async () => { + const token = await deployErc20(wallet); + const txHash = token.deployTransaction.hash; + + const curBlockNumber = await provider.getBlockNumber(); + + const res = (await eth_getBlockByNumber([curBlockNumber, false])).data.result; + const resFull = (await eth_getBlockByNumber([curBlockNumber, true])).data.result; + + expect(Number(res.number)).toEqual(curBlockNumber); + expect(res.transactions[0]).to.eq(txHash); + + expect(Number(resFull.number)).toEqual(curBlockNumber); + expect(resFull.transactions[0]).to.contain({ + hash: txHash, + from: wallet.address.toLowerCase(), + to: null, + value: '0x0', + }); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts index 3c3587155..36145afcd 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts @@ -48,10 +48,4 @@ export const eth_getFilterLogs = rpcGet<{ }>('eth_getFilterLogs'); export const eth_uninstallFilter = rpcGet('eth_uninstallFilter'); export const net_listening = rpcGet('net_listening'); - -/* ---------- karura mainnet rpc methods ---------- */ -export const eth_blockNumber_karura = rpcGet('eth_blockNumber', KARURA_ETH_RPC_URL); -export const eth_getTransactionReceipt_karura = rpcGet('eth_getTransactionReceipt', KARURA_ETH_RPC_URL); -export const eth_getTransactionByHash_karura = rpcGet('eth_getTransactionByHash', KARURA_ETH_RPC_URL); -export const eth_getBlockByNumber_karura = rpcGet('eth_getBlockByNumber', KARURA_ETH_RPC_URL); export const eth_getStorageAt = rpcGet('eth_getStorageAt', ETH_RPC_URL); From cf11e33e358573c8eb4e41165090c132557b0130 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Wed, 9 Oct 2024 12:24:29 +0800 Subject: [PATCH 16/23] get tx and receipt tests --- .../endpoint-tests/eth_getTransaction.test.ts | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts new file mode 100644 index 000000000..d4477bdd5 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts @@ -0,0 +1,114 @@ +import { beforeAll, describe, expect, it } from 'vitest'; + +import { BigNumber, Contract, ContractTransaction } from 'ethers'; +import { + deployErc20, + eth_blockNumber, + eth_getTransactionByHash, + eth_getTransactionReceipt, + testSetup, +} from '../utils'; +import { hexZeroPad } from 'ethers/lib/utils'; + +const { wallets: [wallet, wallet1] } = testSetup; + +describe('get tx and receipt', () => { + let token: Contract; + + beforeAll(async () => { + token = await deployErc20(wallet); + }); + + it('can get tx and recipt for contract deployment', async () => { + const tokenDeployedBlock = (await eth_blockNumber()).data.result; + const txHash = token.deployTransaction.hash; + + const tx = (await eth_getTransactionByHash([txHash])).data.result; + const receipt = (await eth_getTransactionReceipt([txHash])).data.result; + + console.log(tx); + console.log(receipt); + + expect(tx).to.contain({ + hash: txHash, + blockNumber: tokenDeployedBlock, + from: wallet.address.toLowerCase(), + to: null, + value: '0x0', + }); + + expect(receipt).to.deep.contain({ + transactionHash: txHash, + blockNumber: tokenDeployedBlock, + from: wallet.address.toLowerCase(), + to: null, + logs: [], + status: '0x1', + type: '0x0', + }); + }); + + it('can get tx and recipt for token transfer', async () => { + const transferAmount = 100; + const pendingTx = await token.transfer(wallet1.address, transferAmount) as ContractTransaction; + + let tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; + let receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; + + console.log(tx); + console.log(receipt); + + expect(tx).to.contain({ + hash: pendingTx.hash, + blockNumber: null, // pending tx + blockHash: null, // pending tx + from: wallet.address.toLowerCase(), + to: token.address.toLowerCase(), + value: '0x0', + }); + + // not mined yet + expect(receipt).to.eq(null); + + /* ------------------------- after tx is mined ------------------------- */ + await pendingTx.wait(); + + tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; + receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; + + console.log(tx); + console.log(receipt); + + const blockNumber = (await eth_blockNumber()).data.result; + expect(tx).to.contain({ + hash: pendingTx.hash, + blockNumber, + from: wallet.address.toLowerCase(), + to: token.address.toLowerCase(), + value: '0x0', + }); + + expect(receipt).toEqual(expect.objectContaining({ + transactionHash: pendingTx.hash, + blockNumber, + from: wallet.address.toLowerCase(), + to: token.address.toLowerCase(), + logs: [ + expect.objectContaining({ + transactionIndex: '0x0', + blockNumber: blockNumber, + transactionHash: pendingTx.hash, + address: token.address.toLowerCase(), + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + hexZeroPad(wallet.address.toLowerCase(), 32), + hexZeroPad(wallet1.address.toLowerCase(), 32), + ], + data: hexZeroPad(BigNumber.from(transferAmount).toHexString(), 32), + logIndex: '0x0', + }), + ], + status: '0x1', + })); + }); +}); From 5cb3063c077fcb2aea8160b7af69d961ca3ac771 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Wed, 9 Oct 2024 15:19:39 +0800 Subject: [PATCH 17/23] eth_newFilter tests --- packages/eth-providers/src/base-provider.ts | 16 +- .../endpoint-tests/eth_getTransaction.test.ts | 3 +- .../endpoint-tests/filter-family.test.ts | 165 ++++++++++++++++++ .../src/__tests__/utils/consts.ts | 10 +- 4 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts diff --git a/packages/eth-providers/src/base-provider.ts b/packages/eth-providers/src/base-provider.ts index 0238289c8..599400f3e 100644 --- a/packages/eth-providers/src/base-provider.ts +++ b/packages/eth-providers/src/base-provider.ts @@ -2070,19 +2070,13 @@ export abstract class BaseProvider extends AbstractProvider { toBlock: effectiveTo, }; - if (!this.subql) { - return logger.throwError( - 'missing subql url to fetch logs, to initialize base provider with subql, please provide a subqlUrl param.' - ); - } - filterInfo.lastPollBlockNumber = curBlockNumber; filterInfo.lastPollTimestamp = Date.now(); - const subqlLogs = await this.subql.getFilteredLogs(effectiveFilter); // FIXME: this misses unfinalized logs - const filteredLogs = subqlLogs.filter(log => filterLogByTopics(log, sanitizedFilter.topics)); + const logs = await this.getLogs(effectiveFilter); + const formattedLogs = logs.map(log => this.formatter.filterLog(log)); - return hexlifyRpcResult(filteredLogs.map(log => this.formatter.filterLog(log))); + return hexlifyRpcResult(formattedLogs); }; _pollBlocks = async (filterInfo: BlockPollFilter): Promise => { @@ -2109,7 +2103,9 @@ export abstract class BaseProvider extends AbstractProvider { } // TODO: TS bug?? why filterInfo type is not BlockPollFilter | LogPollFilter - return filterInfo['logFilter'] ? this._pollLogs(filterInfo as LogPollFilter) : this._pollBlocks(filterInfo); + return filterInfo['logFilter'] + ? this._pollLogs(filterInfo as LogPollFilter) + : this._pollBlocks(filterInfo as BlockPollFilter); }; removePollFilter = (id: string): boolean => { diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts index d4477bdd5..83d924292 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts @@ -2,6 +2,7 @@ import { beforeAll, describe, expect, it } from 'vitest'; import { BigNumber, Contract, ContractTransaction } from 'ethers'; import { + TRANSFER_EVENT_TOPIC, deployErc20, eth_blockNumber, eth_getTransactionByHash, @@ -100,7 +101,7 @@ describe('get tx and receipt', () => { transactionHash: pendingTx.hash, address: token.address.toLowerCase(), topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + TRANSFER_EVENT_TOPIC, hexZeroPad(wallet.address.toLowerCase(), 32), hexZeroPad(wallet1.address.toLowerCase(), 32), ], diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts new file mode 100644 index 000000000..e183100cd --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts @@ -0,0 +1,165 @@ +import { beforeAll, describe, expect, it } from 'vitest'; + +import { Contract } from 'ethers'; +import { + TRANSFER_EVENT_TOPIC, + deployErc20, + eth_blockNumber, + eth_getFilterChanges, + eth_getLogs, + eth_newFilter, + eth_uninstallFilter, + getCurBlockHash, + testSetup, +} from '../utils'; + +const { + wallets: [wallet, wallet1], + provider, +} = testSetup; + +describe('eth_newFilter', () => { + let token: Contract; + const dummyId = '0x12345678906f9c864d9db560d72a247c178ae86b'; + let startBlockNum: number; + let fid0: string; + let fid1: string; + let fid2: string; + let fid3: string; + + const feedTx = async () => token.transfer(wallet1.address, 11122233); + + beforeAll(async () => { + token = await deployErc20(wallet); + + startBlockNum = await provider.getBlockNumber(); + + fid0 = (await eth_newFilter([{}])).data.result; // only pull once at the end + + fid1 = ( + await eth_newFilter([ + { + // normal log poll + address: token.address, + topics: [ + TRANSFER_EVENT_TOPIC, + null, + null, + ], + }, + ]) + ).data.result; + + fid2 = ( + await eth_newFilter([ + { + // normal log poll + address: token.address, + fromBlock: startBlockNum, + toBlock: startBlockNum + 3, + }, + ]) + ).data.result; + + fid3 = ( + await eth_newFilter([ + { + // empty + fromBlock: 3, + toBlock: 100, + }, + ]) + ).data.result; + }); + + it('poll immediately', async () => { + const res1 = (await eth_getFilterChanges([fid1])).data.result; + const res2 = (await eth_getFilterChanges([fid2])).data.result; + const res3 = (await eth_getFilterChanges([fid3])).data.result; + + expect([res1, res2, res3]).to.deep.equal([[], [], []]); + }); + + it('get correct result', async () => { + /* ---------- fire 1 tx ---------- */ + await (await feedTx()).wait(); + + let res1 = (await eth_getFilterChanges([fid1])).data.result; + let res2 = (await eth_getFilterChanges([fid2])).data.result; + let res3 = (await eth_getFilterChanges([fid3])).data.result; + + const curBlockHash = await getCurBlockHash(); + let expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; + + expect(expectedLogs.length).to.equal(1); + expect(res1).to.deep.equal(expectedLogs); + expect(res2).to.deep.equal(expectedLogs); + expect(res3).to.deep.equal([]); + + /* ---------- fire many tx ---------- */ + const txCount = 5; + for (let i = 0; i < txCount; i++) { + await (await feedTx()).wait(); + } + + const res0 = (await eth_getFilterChanges([fid0])).data.result; + res1 = (await eth_getFilterChanges([fid1])).data.result; + res2 = (await eth_getFilterChanges([fid2])).data.result; + res3 = (await eth_getFilterChanges([fid3])).data.result; + + const curHeight = Number((await eth_blockNumber()).data.result); + expectedLogs = ( + await eth_getLogs([ + { + fromBlock: curHeight - txCount, + toBlock: curHeight, + }, + ]) + ).data.result; + + console.log({ + expectedLogs, + curHeight, + }); + + expect(expectedLogs.length).to.equal(txCount + 1); // + 1 because it's all logs, which conains the one in prev test + expect(res0).to.deep.equal(expectedLogs); + expect(res1).to.deep.equal(expectedLogs.slice(1)); + // it's range is [x, x + 3], x is original block, x + 1 is prev test, now only poll for x + 2 and x + 3, so has 2 logs + expect(res2).to.deep.equal(expectedLogs.slice(1, 3)); + expect(res3).to.deep.equal([]); + }); + + it('unsubscribe works', async () => { + const unsub = (await eth_uninstallFilter([fid0])).data.result; + const unsub2 = (await eth_uninstallFilter([fid0])).data.result; + const unsub3 = (await eth_uninstallFilter([dummyId])).data.result; + + expect(unsub).to.equal(true); + expect(unsub2).to.equal(false); + expect(unsub3).to.equal(false); + + await (await feedTx()).wait(); + + const res1 = (await eth_getFilterChanges([fid1])).data.result; + const res2 = (await eth_getFilterChanges([fid2])).data.result; + const res3 = (await eth_getFilterChanges([fid3])).data.result; + + const curBlockHash = await getCurBlockHash(); + const expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; + + // all other filters should still work + expect(expectedLogs.length).to.equal(1); + expect(res1).to.deep.equal(expectedLogs); + expect(res2).to.deep.equal([]); // now block range doesn't match anymore (cannot skip previous test) + expect(res3).to.deep.equal([]); + + // target should be removed + const res0 = await eth_getFilterChanges([fid0]); + expect(res0.data.error.message).to.contains('filter not found'); + }); + + it.skip('throws correct error messege', async () => { + // tested in eth_newBlockFilter + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts index e57229101..1d0009e31 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts @@ -16,13 +16,7 @@ export interface LogHexified { logIndex: string; } -export const ADDRESS_ALICE = '0x82a258cb20e2adb4788153cd5eb5839615ece9a0'; - -export const DETERMINISTIC_SETUP_DEX_ADDRESS = '0x532394de2ca885b7e0306a2e258074cca4e42449'; - -export const KARURA_CONTRACT_CALL_TX_HASH = '0x33661888b04c81858c3603994eeb9a294c57b585bd86b4663ccd5e4fd7f2c325'; -export const KARURA_CONTRACT_DEPLOY_TX_HASH = '0x56a429edfc1c07d7fd4c048e6e868dbaaa632fc329e7bb7ed744a48bca5bb493'; -export const KARURA_SEND_KAR_TX_HASH = '0x69493fd597760d5ad3a81ebbbb48abcc686d33814e097b1db9fc172341c36dae'; - export const deployHelloWorldData = '0x60806040526040518060400160405280600c81526020017f48656c6c6f20576f726c642100000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610166565b82805461006e90610134565b90600052602060002090601f01602090048101928261009057600085556100d7565b82601f106100a957805160ff19168380011785556100d7565b828001600101855582156100d7579182015b828111156100d65782518255916020019190600101906100bb565b5b5090506100e491906100e8565b5090565b5b808211156101015760008160009055506001016100e9565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061014c57607f821691505b602082108114156101605761015f610105565b5b50919050565b61022e806101756000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c605f76c14610030575b600080fd5b61003861004e565b6040516100459190610175565b60405180910390f35b6000805461005b906101c6565b80601f0160208091040260200160405190810160405280929190818152602001828054610087906101c6565b80156100d45780601f106100a9576101008083540402835291602001916100d4565b820191906000526020600020905b8154815290600101906020018083116100b757829003601f168201915b505050505081565b600081519050919050565b600082825260208201905092915050565b60005b838110156101165780820151818401526020810190506100fb565b83811115610125576000848401525b50505050565b6000601f19601f8301169050919050565b6000610147826100dc565b61015181856100e7565b93506101618185602086016100f8565b61016a8161012b565b840191505092915050565b6000602082019050818103600083015261018f818461013c565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806101de57607f821691505b602082108114156101f2576101f1610197565b5b5091905056fea26469706673582212204d363ed34111d1be492d4fd086e9f2df62b3c625e89ade31f30e63201ed1e24f64736f6c63430008090033'; + +export const TRANSFER_EVENT_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; From ebe89a7ebb7474545318fd8b1e6d3e85cf4f4e03 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Wed, 9 Oct 2024 15:53:22 +0800 Subject: [PATCH 18/23] all filter family --- .../src/__tests__/endpoint-tests/endpoint.ts | 1127 +++-------------- .../endpoint-tests/eth_getLogs.test.ts | 114 ++ .../endpoint-tests/eth_newBlockFilter.test.ts | 102 ++ .../endpoint-tests/eth_newFilter.test.ts | 169 +++ .../endpoint-tests/filter-family.test.ts | 165 --- 5 files changed, 589 insertions(+), 1088 deletions(-) create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newBlockFilter.test.ts create mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newFilter.test.ts delete mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts index 4db08229e..cbd215f45 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts @@ -1,1000 +1,281 @@ -/* eslint-disable sort-imports-es6-autofix/sort-imports-es6 */ - -import { - AcalaEvmTXPayload, - UnsignedAcalaEvmTX, - parseTransaction, - serializeTransaction, - signTransaction, -} from '@acala-network/eth-transactions'; -import { ApiPromise, WsProvider } from '@polkadot/api'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Contract } from '@ethersproject/contracts'; -import { AcalaJsonRpcProvider, EvmRpcProvider, ONE_HUNDRED_GWEI, nativeToEthDecimal, sleep } from '@acala-network/eth-providers'; -import { Interface, formatEther, parseEther, parseUnits } from 'ethers/lib/utils'; -import { SubqlProvider } from '@acala-network/eth-providers/utils/subqlProvider'; -import { Wallet } from '@ethersproject/wallet'; -import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -import ADDRESS from '@acala-network/contracts/utils/MandalaAddress'; -import DEXABI from '@acala-network/contracts/build/contracts/DEX.json'; -import TokenABI from '@acala-network/contracts/build/contracts/Token.json'; -import WebSocket from 'ws'; - -import { - deployErc20, - KARURA_ETH_RPC_URL, - NODE_RPC_URL, - SUBQL_URL, - WS_URL, - bigIntDiff, - - /* ---------- local rpc methods ---------- */ - eth_call, - eth_blockNumber, - eth_getBlockByNumber, - eth_getTransactionReceipt, - eth_getLogs, - eth_getTransactionByHash, - eth_accounts, - eth_sendRawTransaction, - eth_getTransactionCount, - eth_getBalance, - eth_chainId, - eth_getEthGas, - eth_getCode, - net_runtimeVersion, - eth_isBlockFinalized, - eth_newFilter, - eth_newBlockFilter, - eth_getFilterChanges, - eth_getFilterLogs, - eth_uninstallFilter, - - /* ---------- karura mainnet rpc methods ---------- */ - eth_blockNumber_karura, - eth_getTransactionReceipt_karura, - eth_getTransactionByHash_karura, - eth_getBlockByNumber_karura, - eth_getStorageAt_karura, - expectLogsEqual, - hexilifyLog, - estimateGas, - getCurBlockHash, - getNonce, - RPC_URL, - net_listening, - deployGasMonster, - toDeterministic, - waitForHeight, - eth_estimateGas, - - ADDRESS_ALICE, - DETERMINISTIC_SETUP_DEX_ADDRESS, - GAS_MONSTER_GAS_REQUIRED, - KARURA_CONTRACT_CALL_TX_HASH, - KARURA_CONTRACT_DEPLOY_TX_HASH, - KARURA_SEND_KAR_TX_HASH, - LogHexified, - allLogs, - deployHelloWorldData, - evmAccounts, - log22_0, - log22_1 } from '../utils'; - - -const subql = new SubqlProvider(SUBQL_URL); - -const account1 = evmAccounts[0]; -const account2 = evmAccounts[1]; -const wallet1 = new Wallet(account1.privateKey); - -describe('endpoint', () => { - // some tests depend on the local deterministic setup or karura mainnet node connection - beforeAll(async () => { - if (process.env.SKIP_CHECK) return; - - try { - const blockNum = (await eth_blockNumber()).data.result; - - const DETERMINISTIC_SETUP_TOTAL_BLOCKS = 22; - if (Number(blockNum) !== DETERMINISTIC_SETUP_TOTAL_BLOCKS) { - throw new Error( - `test env setup failed! expected ${DETERMINISTIC_SETUP_TOTAL_BLOCKS} blocks but got ${Number(blockNum)}` - ); - } - const DETERMINISTIC_SETUP_TOTAL_TXS = 12; - const DETERMINISTIC_SETUP_TOTAL_LOGS = 13; - let tries = 0; - let [allTxReceipts, allLogs] = await Promise.all([ - subql.getAllTxReceipts(), - subql.getAllLogs(), - ]); - while ( - tries++ < 5 && - ( - allTxReceipts.length < DETERMINISTIC_SETUP_TOTAL_TXS || - allLogs.length < DETERMINISTIC_SETUP_TOTAL_LOGS - ) - ) { - console.log(`let's give subql a little bit more time to index, retrying #${tries} in 3s ...`); - await sleep(3000); - - [allTxReceipts, allLogs] = await Promise.all([ - subql.getAllTxReceipts(), - subql.getAllLogs(), - ]); - } - if ( - allTxReceipts.length < DETERMINISTIC_SETUP_TOTAL_TXS || - allLogs.length < DETERMINISTIC_SETUP_TOTAL_LOGS - ) { - throw new Error(` - test env setup failed! - expected ${DETERMINISTIC_SETUP_TOTAL_TXS} Txs in subql but got ${allTxReceipts.length} - expected ${DETERMINISTIC_SETUP_TOTAL_LOGS} logs in subql but got ${allLogs.length} - `); - } +// this should go first since it depends on the deterministic setup +// TODO: refactor tests to seperate self-dependent tests +describe('eth_getLogs', () => { + const ALL_BLOCK_RANGE_FILTER = { fromBlock: 'earliest' }; - if (!process.env.SKIP_PUBLIC) { - const blockNumKarura = (await eth_blockNumber_karura()).data.result; - if (!(Number(blockNumKarura) > 1000000)) { - throw new Error(`test env setup failed! There might be some connection issue with ${KARURA_ETH_RPC_URL}`); - } - } - } catch (e) { - console.log( - ` - ------------------------ - test env setup failed ❌ - ------------------------ - `, - e - ); - throw e; - } - - console.log(` - -------------------------- - test env setup finished ✅ - -------------------------- - `); + describe.concurrent('when no filter', () => { + it('returns all logs from latest block', async () => { + const res = (await eth_getLogs([{}])).data.result; + expect(res.length).to.equal(2); + expect(res[0]).to.deep.contain(log22_0); + expect(res[1]).to.deep.contain(log22_1); + }); }); - // this should go first since it depends on the deterministic setup - // TODO: refactor tests to seperate self-dependent tests - describe('eth_getLogs', () => { - const ALL_BLOCK_RANGE_FILTER = { fromBlock: 'earliest' }; - - describe.concurrent('when no filter', () => { - it('returns all logs from latest block', async () => { - const res = (await eth_getLogs([{}])).data.result; - expect(res.length).to.equal(2); - expect(res[0]).to.deep.contain(log22_0); - expect(res[1]).to.deep.contain(log22_1); - }); - }); + describe.concurrent('filter by address', () => { + it('returns correct logs', async () => { + /* ---------- single address ---------- */ + for (const log of allLogs) { + const res = await eth_getLogs([{ address: log.address, ...ALL_BLOCK_RANGE_FILTER }]); + const expectedLogs = allLogs.filter(l => l.address === log.address); + expectLogsEqual(res.data.result, expectedLogs); + } - describe.concurrent('filter by address', () => { - it('returns correct logs', async () => { - /* ---------- single address ---------- */ - for (const log of allLogs) { - const res = await eth_getLogs([{ address: log.address, ...ALL_BLOCK_RANGE_FILTER }]); - const expectedLogs = allLogs.filter(l => l.address === log.address); - expectLogsEqual(res.data.result, expectedLogs); - } - - // should support different case and array of addresses - for (const log of allLogs) { - const res = await eth_getLogs([ - { address: [log.address.toLocaleUpperCase(), '0x13579'], ...ALL_BLOCK_RANGE_FILTER }, - ]); - const expectedLogs = allLogs.filter(l => l.address === log.address); - expectLogsEqual(res.data.result, expectedLogs); - } - }); + // should support different case and array of addresses + for (const log of allLogs) { + const res = await eth_getLogs([ + { address: [log.address.toLocaleUpperCase(), '0x13579'], ...ALL_BLOCK_RANGE_FILTER }, + ]); + const expectedLogs = allLogs.filter(l => l.address === log.address); + expectLogsEqual(res.data.result, expectedLogs); + } }); + }); - describe.concurrent('filter by block number', () => { - it('returns correct logs', async () => { - const BIG_NUMBER = 88888888; - const BIG_NUMBER_HEX = '0x54C5638'; + describe.concurrent('filter by block number', () => { + it('returns correct logs', async () => { + const BIG_NUMBER = 88888888; + const BIG_NUMBER_HEX = '0x54C5638'; - let res: Awaited>; - let expectedLogs: LogHexified[]; + let res: Awaited>; + let expectedLogs: LogHexified[]; - /* ---------- should return all logs ---------- */ - res = await eth_getLogs([{ ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); + /* ---------- should return all logs ---------- */ + res = await eth_getLogs([{ ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: 0 }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: 0 }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER_HEX }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER_HEX }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: 0, toBlock: 'latest' }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: 0, toBlock: 'latest' }]); + expectLogsEqual(res.data.result, allLogs); - /* ---------- should return no logs ---------- */ - res = await eth_getLogs([{ fromBlock: 99999 }]); - expect(res.data.result).to.deep.equal([]); + /* ---------- should return no logs ---------- */ + res = await eth_getLogs([{ fromBlock: 99999 }]); + expect(res.data.result).to.deep.equal([]); - res = await eth_getLogs([{ toBlock: -1 }]); - expect(res.data.result).to.deep.equal([]); + res = await eth_getLogs([{ toBlock: -1 }]); + expect(res.data.result).to.deep.equal([]); - /* ---------- should return partial logs ---------- */ - const from = 9; - const to = 11; - res = await eth_getLogs([{ fromBlock: from }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); - expectLogsEqual(res.data.result, expectedLogs); + /* ---------- should return partial logs ---------- */ + const from = 9; + const to = 11; + res = await eth_getLogs([{ fromBlock: from }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); + expectLogsEqual(res.data.result, expectedLogs); - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); - res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); - }); + res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); }); + }); - describe.concurrent('filter by block tag', () => { - it('returns correct logs for valid tag', async () => { - let res: Awaited>; - let expectedLogs: LogHexified[]; + describe.concurrent('filter by block tag', () => { + it('returns correct logs for valid tag', async () => { + let res: Awaited>; + let expectedLogs: LogHexified[]; - /* ---------- should return all logs ---------- */ - res = await eth_getLogs([{ fromBlock: 'earliest' }]); - expectLogsEqual(res.data.result, allLogs); + /* ---------- should return all logs ---------- */ + res = await eth_getLogs([{ fromBlock: 'earliest' }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: 0 }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: 0 }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: '0x0' }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: '0x0' }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: '0x00000000' }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: '0x00000000' }]); + expectLogsEqual(res.data.result, allLogs); - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 'latest' }]); - expectLogsEqual(res.data.result, allLogs); + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 'latest' }]); + expectLogsEqual(res.data.result, allLogs); - /* ---------- should return no logs ---------- */ - res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 'earliest' }]); - expect(res.data.result).to.deep.equal([]); + /* ---------- should return no logs ---------- */ + res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 'earliest' }]); + expect(res.data.result).to.deep.equal([]); - res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 5 }]); - expect(res.data.result).to.deep.equal([]); + res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 5 }]); + expect(res.data.result).to.deep.equal([]); - res = await eth_getLogs([{ fromBlock: 'latest', toBlock: '0x5' }]); - expect(res.data.result).to.deep.equal([]); + res = await eth_getLogs([{ fromBlock: 'latest', toBlock: '0x5' }]); + expect(res.data.result).to.deep.equal([]); - res = await eth_getLogs([{ fromBlock: 8, toBlock: 'earliest' }]); - expect(res.data.result).to.deep.equal([]); + res = await eth_getLogs([{ fromBlock: 8, toBlock: 'earliest' }]); + expect(res.data.result).to.deep.equal([]); - /* ---------- should return some logs ---------- */ - const from = 8; - const to = 10; - res = await eth_getLogs([{ fromBlock: from, toBlock: 'latest' }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); - expectLogsEqual(res.data.result, expectedLogs); + /* ---------- should return some logs ---------- */ + const from = 8; + const to = 10; + res = await eth_getLogs([{ fromBlock: from, toBlock: 'latest' }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); + expectLogsEqual(res.data.result, expectedLogs); - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); - res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); - }); + res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); }); + }); - describe.concurrent('filter by topics', () => { - it('returns correct logs', async () => { - let res: Awaited>; - let expectedLogs: LogHexified[]; - - /* ---------- should return all logs ---------- */ - res = await eth_getLogs([{ topics: [], ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ topics: [[]], ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); + describe.concurrent('filter by topics', () => { + it('returns correct logs', async () => { + let res: Awaited>; + let expectedLogs: LogHexified[]; - res = await eth_getLogs([{ topics: [null, [], null, [], 'hahahahaha', 'hohoho'], ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); + /* ---------- should return all logs ---------- */ + res = await eth_getLogs([{ topics: [], ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); - /* ---------- should return no logs ---------- */ - res = await eth_getLogs([{ topics: ['XXX'], ...ALL_BLOCK_RANGE_FILTER }]); - expect(res.data.result).to.deep.equal([]); + res = await eth_getLogs([{ topics: [[]], ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); - /* ---------- should return some logs ---------- */ - for (const log of allLogs) { - res = await eth_getLogs([{ topics: log.topics, ...ALL_BLOCK_RANGE_FILTER }]); - expectedLogs = allLogs.filter( - l => log.topics.length === l.topics.length && log.topics.every((t, i) => l.topics[i] === t) - ); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([{ topics: [log.topics[0]], ...ALL_BLOCK_RANGE_FILTER }]); - expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([ - { topics: [['ooo', log.topics[0], 'xxx', 'yyy'], null, []], ...ALL_BLOCK_RANGE_FILTER }, - ]); - expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([ - { topics: [...new Array(log.topics.length - 1).fill(null), log.topics.at(-1)], ...ALL_BLOCK_RANGE_FILTER }, - ]); - expectedLogs = allLogs.filter(l => l.topics[log.topics.length - 1] === log.topics.at(-1)); - expectLogsEqual(res.data.result, expectedLogs); - } - }); - }); + res = await eth_getLogs([{ topics: [null, [], null, [], 'hahahahaha', 'hohoho'], ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); - describe.concurrent('filter by blockhash', () => { - it('returns correct logs', async () => { - const allLogsFromSubql = await subql.getAllLogs().then(logs => logs.map(hexilifyLog)); - for (const log of allLogsFromSubql) { - const res = await eth_getLogs([{ blockHash: log.blockHash }]); - const expectedLogs = allLogs.filter(l => l.blockNumber === log.blockNumber); - expectLogsEqual(res.data.result, expectedLogs); - } - }); - }); + /* ---------- should return no logs ---------- */ + res = await eth_getLogs([{ topics: ['XXX'], ...ALL_BLOCK_RANGE_FILTER }]); + expect(res.data.result).to.deep.equal([]); - describe.concurrent('filter by multiple params', () => { - it('returns correct logs', async () => { - let res: Awaited>; - let expectedLogs: LogHexified[]; - const allLogsFromSubql = await subql.getAllLogs().then(logs => logs.map(hexilifyLog)); - /* -------------------- match block range -------------------- */ - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 11); - res = await eth_getLogs([{ fromBlock: 8, toBlock: 11, topics: [[], null, []] }]); + /* ---------- should return some logs ---------- */ + for (const log of allLogs) { + res = await eth_getLogs([{ topics: log.topics, ...ALL_BLOCK_RANGE_FILTER }]); + expectedLogs = allLogs.filter( + l => log.topics.length === l.topics.length && log.topics.every((t, i) => l.topics[i] === t) + ); expectLogsEqual(res.data.result, expectedLogs); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= 15); - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 15, topics: [[], null, []] }]); + res = await eth_getLogs([{ topics: [log.topics[0]], ...ALL_BLOCK_RANGE_FILTER }]); + expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); expectLogsEqual(res.data.result, expectedLogs); - for (const log of allLogsFromSubql) { - /* -------------------- match blockhash -------------------- */ - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) === parseInt(log.blockNumber)); - res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[], null, []] }]); - expectLogsEqual(res.data.result, expectedLogs); - - /* -------------------- match first topic -------------------- */ - expectedLogs = allLogs.filter( - l => parseInt(l.blockNumber) === parseInt(log.blockNumber) && l.topics[0] === log.topics[0] - ); - res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[log.topics[0], 'xxx'], null, []] }]); - expectLogsEqual(res.data.result, expectedLogs); - - /* -------------------- match range and topics -------------------- */ - expectedLogs = allLogs.filter( - l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 15 && l.topics[0] === log.topics[0] - ); - res = await eth_getLogs([{ fromBlock: 8, toBlock: 15, topics: [['xxx', log.topics[0]]] }]); - expectLogsEqual(res.data.result, expectedLogs); - - /* -------------------- no match -------------------- */ - res = await eth_getLogs([{ blockHash: log.blockHash, topics: ['0x12345'] }]); - expect(res.data.result).to.deep.equal([]); - - res = await eth_getLogs([{ blockHash: log.blockHash, topics: [log.topics[0], 'xxx'] }]); - expect(res.data.result).to.deep.equal([]); - } - }); - }); - - describe('get latest logs', async () => { - const provider = new AcalaJsonRpcProvider(RPC_URL); - const wallet = new Wallet(evmAccounts[0].privateKey, provider); - let token: Contract; - - beforeAll(async () => { - // need to put in here to prevent interrupte deterministic setup - token = await deployErc20(wallet); - await token.deployed(); - }); - - it('should return latest logs as soon as it\'s finalized, and should not hang if toBlock is large', async () => { - const curHeight = await provider.getBlockNumber(); - await (await token.transfer(ADDRESS_ALICE, 1000)).wait(); - - // should return latest logs as soon as it's finalized - const targetHeight = curHeight + 1; - await waitForHeight(provider, targetHeight); // instant-sealing: best height = finalized height - const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); - - expect(res.data?.result?.length).to.eq(1); - expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); - - // should not hang if toBlock is large - const res2 = await eth_getLogs([{ fromBlock: targetHeight, toBlock: 9999999999 }]); - expect(res2.data.result).to.deep.equal(res.data.result); - }); - - it('should return latest logs before subql is synced', async () => { - const curHeight = await provider.getBlockNumber(); - - for (let i = 0; i < 5; i++) { - const tx = await token.transfer(ADDRESS_ALICE, 1000); - await tx.wait(); - } - - const targetHeight = curHeight + 5; - await waitForHeight(provider, targetHeight); - const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); - - expect(res.data?.result?.length).to.eq(1); - expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); - }); - }); - }); - - describe('eth_getTransactionReceipt', () => { - it('returns correct result when hash exist for local transactions', async () => { - const allTxReceipts = await subql.getAllTxReceipts(); - expect(allTxReceipts.length).to.greaterThan(0); - - const tx1 = allTxReceipts.find(r => r.blockNumber === '10'); - const tx2 = allTxReceipts.find(r => r.blockNumber === '9'); - const tx3 = allTxReceipts.find(r => r.blockNumber === '6'); - const tx4 = allTxReceipts.find(r => r.blockNumber === '20'); - - const [ - res1, - res2, - res3, - res4, // dex.swap with erc20 tokens - ] = await Promise.all([ - eth_getTransactionReceipt([tx1.transactionHash]), - eth_getTransactionReceipt([tx2.transactionHash]), - eth_getTransactionReceipt([tx3.transactionHash]), - eth_getTransactionReceipt([tx4.transactionHash]), - ]); - - expect(toDeterministic(res1.data.result)).toMatchSnapshot(); - expect(toDeterministic(res2.data.result)).toMatchSnapshot(); - expect(toDeterministic(res3.data.result)).toMatchSnapshot(); - expect(toDeterministic(res4.data.result)).toMatchSnapshot(); - }); + res = await eth_getLogs([ + { topics: [['ooo', log.topics[0], 'xxx', 'yyy'], null, []], ...ALL_BLOCK_RANGE_FILTER }, + ]); + expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); + expectLogsEqual(res.data.result, expectedLogs); - it('returns correct result for public karura transactions', async () => { - if (process.env.SKIP_PUBLIC) { - console.log('public karura tests are skipped ❗'); - return; + res = await eth_getLogs([ + { topics: [...new Array(log.topics.length - 1).fill(null), log.topics.at(-1)], ...ALL_BLOCK_RANGE_FILTER }, + ]); + expectedLogs = allLogs.filter(l => l.topics[log.topics.length - 1] === log.topics.at(-1)); + expectLogsEqual(res.data.result, expectedLogs); } - - const [ - contractCallRes, - contractDeployRes, - sendKarRes, - ] = await Promise.all([ - eth_getTransactionReceipt_karura([KARURA_CONTRACT_CALL_TX_HASH]), - eth_getTransactionReceipt_karura([KARURA_CONTRACT_DEPLOY_TX_HASH]), - eth_getTransactionReceipt_karura([KARURA_SEND_KAR_TX_HASH]), - ]); - - expect(contractCallRes.status).to.equal(200); - expect(contractDeployRes.status).to.equal(200); - expect(sendKarRes.status).to.equal(200); - - expect(toDeterministic(contractCallRes.data.result)).toMatchSnapshot(); - expect(toDeterministic(contractDeployRes.data.result)).toMatchSnapshot(); - expect(toDeterministic(sendKarRes.data.result)).toMatchSnapshot(); - }); - - it('return correct error or null', async () => { - let res; - - /* ---------- invalid hex address ---------- */ - res = await eth_getTransactionReceipt(['0x000']); - expect(res.data.error.code).to.equal(-32602); - expect(res.data.error.message).to.contain('invalid argument'); - - /* ---------- hash not found ---------- */ - res = await eth_getTransactionReceipt(['0x7ae069634d1154c0299f7fe1d473cf3d6f06cd9b57182d5319eede35a3a4d776']); - expect(res.data.result).to.equal(null); - - /* ---------- TODO: pending tx ---------- */ - }); - - describe('get latest receipt', async () => { - const provider = new AcalaJsonRpcProvider(RPC_URL); - const wallet = new Wallet(evmAccounts[0].privateKey, provider); - let token: Contract; - - beforeAll(async () => { - // need to put in here to prevent interrupte deterministic setup - token = await deployErc20(wallet); - await token.deployed(); - }); - - it('should be able to get latest receipt as soon as new block is ready', async () => { - const curHeight = await provider.getBlockNumber(); - await (await token.transfer(ADDRESS_ALICE, 1000)).wait(); - - // should return latest receipt as soon as block is ready - const targetHeight = curHeight + 1; - await waitForHeight(provider, targetHeight); - const blockRes = await eth_getBlockByNumber([targetHeight, false]); - const txHashes = blockRes.data?.result.transactions; - expect(txHashes.length).to.eq(1); - const txHash = txHashes[0]; - - const receipt = (await eth_getTransactionReceipt([txHash])).data?.result; - expect(receipt).to.not.be.null; - expect(parseInt(receipt.blockNumber, 16)).to.eq(targetHeight); - }); }); }); - describe('eth_getTransactionByHash', () => { - it('finds correct tx when hash exist for local transactions', async () => { - const allTxReceipts = await subql.getAllTxReceipts(); - const tx1 = allTxReceipts.find(r => r.blockNumber === '10'); - const tx2 = allTxReceipts.find(r => r.blockNumber === '9'); - const tx3 = allTxReceipts.find(r => r.blockNumber === '6'); - const tx4 = allTxReceipts.find(r => r.blockNumber === '20'); - - const [ - res1, - res2, - res3, - res4, // dex.swap with erc20 tokens - ] = await Promise.all([ - eth_getTransactionByHash([tx1.transactionHash]), - eth_getTransactionByHash([tx2.transactionHash]), - eth_getTransactionByHash([tx3.transactionHash]), - eth_getTransactionByHash([tx4.transactionHash]), - ]); - - expect(toDeterministic(res1.data.result)).toMatchSnapshot(); - expect(toDeterministic(res2.data.result)).toMatchSnapshot(); - expect(toDeterministic(res3.data.result)).toMatchSnapshot(); - expect(toDeterministic(res4.data.result)).toMatchSnapshot(); - }); - - it('returns correct result for public karura transactions', async () => { - if (process.env.SKIP_PUBLIC) { - console.log('public karura tests are skipped❗'); - return; + describe.concurrent('filter by blockhash', () => { + it('returns correct logs', async () => { + const allLogsFromSubql = await subql.getAllLogs().then(logs => logs.map(hexilifyLog)); + for (const log of allLogsFromSubql) { + const res = await eth_getLogs([{ blockHash: log.blockHash }]); + const expectedLogs = allLogs.filter(l => l.blockNumber === log.blockNumber); + expectLogsEqual(res.data.result, expectedLogs); } - - const [ - contractCallRes, - contractDeployRes, - sendKarRes, - ] = await Promise.all([ - eth_getTransactionByHash_karura([KARURA_CONTRACT_CALL_TX_HASH]), - eth_getTransactionByHash_karura([KARURA_CONTRACT_DEPLOY_TX_HASH]), - eth_getTransactionByHash_karura([KARURA_SEND_KAR_TX_HASH]), - ]); - - expect(contractCallRes.status).to.equal(200); - expect(contractDeployRes.status).to.equal(200); - expect(sendKarRes.status).to.equal(200); - - expect(toDeterministic(contractCallRes.data.result)).toMatchSnapshot(); - expect(toDeterministic(contractDeployRes.data.result)).toMatchSnapshot(); - expect(toDeterministic(sendKarRes.data.result)).toMatchSnapshot(); - }); - - it.skip('returns correct result when tx is pending', async () => { - // send a 0 tx to mandala - }); - - it('return correct error or null', async () => { - let res; - - /* ---------- invalid hex address ---------- */ - res = await eth_getTransactionByHash(['0x000']); - expect(res.data.error.code).to.equal(-32602); - expect(res.data.error.message).to.contain('invalid argument'); - - /* ---------- hash not found ---------- */ - res = await eth_getTransactionByHash(['0x7ae069634d1154c0299f7fe1d473cf3d6f06cd9b57182d5319eede35a3a4d776']); - expect(res.data.result).to.equal(null); }); }); - describe('eth_newBlockFilter', () => { - const provider = new EvmRpcProvider(NODE_RPC_URL); - const aca = new Contract(ADDRESS.ACA, TokenABI.abi, wallet1.connect(provider)); - - const dummyId = '0x12345678906f9c864d9db560d72a247c178ae86b'; - let blockFilterId0: string; - let blockFilterId1: string; - const expectedBlockHashes: string[] = []; - const allBlockHashes: string[] = []; - - const feedTx = async () => { - await aca.transfer(evmAccounts[1].evmAddress, 111222333444555); - expectedBlockHashes.push(await getCurBlockHash()); - allBlockHashes.push(await getCurBlockHash()); - }; - - beforeAll(async () => { - blockFilterId0 = (await eth_newBlockFilter()).data.result; // only pull once at the end - blockFilterId1 = (await eth_newBlockFilter()).data.result; // normal block poll - - await provider.isReady(); - }); - - afterAll(async () => { - await provider.disconnect(); - }); + describe.concurrent('filter by multiple params', () => { + it('returns correct logs', async () => { + let res: Awaited>; + let expectedLogs: LogHexified[]; + const allLogsFromSubql = await subql.getAllLogs().then(logs => logs.map(hexilifyLog)); + /* -------------------- match block range -------------------- */ + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 11); + res = await eth_getLogs([{ fromBlock: 8, toBlock: 11, topics: [[], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); + + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= 15); + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 15, topics: [[], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); + + for (const log of allLogsFromSubql) { + /* -------------------- match blockhash -------------------- */ + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) === parseInt(log.blockNumber)); + res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); - it('poll immediately', async () => { - const res = (await eth_getFilterChanges([blockFilterId1])).data.result; - expect(res).to.deep.equal([]); - }); + /* -------------------- match first topic -------------------- */ + expectedLogs = allLogs.filter( + l => parseInt(l.blockNumber) === parseInt(log.blockNumber) && l.topics[0] === log.topics[0] + ); + res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[log.topics[0], 'xxx'], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); - it('get correct result', async () => { - /* ---------- fire 1 tx ---------- */ - await feedTx(); - await sleep(10000); // give subql some time to index + /* -------------------- match range and topics -------------------- */ + expectedLogs = allLogs.filter( + l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 15 && l.topics[0] === log.topics[0] + ); + res = await eth_getLogs([{ fromBlock: 8, toBlock: 15, topics: [['xxx', log.topics[0]]] }]); + expectLogsEqual(res.data.result, expectedLogs); - let res = (await eth_getFilterChanges([blockFilterId1])).data.result; - expect(res.length).to.equal(1); - expect(res).to.deep.equal(expectedBlockHashes); - expectedBlockHashes.length = 0; + /* -------------------- no match -------------------- */ + res = await eth_getLogs([{ blockHash: log.blockHash, topics: ['0x12345'] }]); + expect(res.data.result).to.deep.equal([]); - /* ---------- fire many tx ---------- */ - const txCount = 6; - for (let i = 0; i < txCount; i++) { - await feedTx(); + res = await eth_getLogs([{ blockHash: log.blockHash, topics: [log.topics[0], 'xxx'] }]); + expect(res.data.result).to.deep.equal([]); } - await sleep(10000); // give subql some time to index - - res = (await eth_getFilterChanges([blockFilterId1])).data.result; - let resAll = (await eth_getFilterChanges([blockFilterId0])).data.result; - expect(res.length).to.equal(txCount); - expect(resAll.length).to.equal(txCount + 1); - expect(res).to.deep.equal(expectedBlockHashes); - expect(resAll).to.deep.equal(allBlockHashes); - - // query again should return empty - res = (await eth_getFilterChanges([blockFilterId1])).data.result; - resAll = (await eth_getFilterChanges([blockFilterId0])).data.result; - expect(res).to.deep.equal([]); - expect(resAll).to.deep.equal([]); - }); - - it('unsubscribe works', async () => { - expectedBlockHashes.length = 0; - const unsub = (await eth_uninstallFilter([blockFilterId0])).data.result; - const unsub2 = (await eth_uninstallFilter([blockFilterId0])).data.result; - const unsub3 = (await eth_uninstallFilter([dummyId])).data.result; - expect(unsub).to.equal(true); - expect(unsub2).to.equal(false); - expect(unsub3).to.equal(false); - - await feedTx(); - await sleep(10000); // give subql some time to index - - // other filter should still work - let res = (await eth_getFilterChanges([blockFilterId1])).data.result; - expect(res.length).to.equal(1); - expect(res).to.deep.equal(expectedBlockHashes); - - // target filter should be removed - res = await eth_getFilterChanges([blockFilterId0]); - expect(res.data.error.message).to.contains('filter not found'); - }); - - it('throws correct error', async () => { - let res = await eth_getFilterChanges([dummyId]); - expect(res.data.error.message).to.contains('filter not found'); - - // eth_getFilterLogs should not find block filter - res = await eth_getFilterLogs([blockFilterId1]); - expect(res.data.error.message).to.contains('filter not found'); }); }); - describe('eth_newFilter', () => { - const provider = new EvmRpcProvider(NODE_RPC_URL); - const aca = new Contract(ADDRESS.ACA, TokenABI.abi, wallet1.connect(provider)); - - const dummyId = '0x12345678906f9c864d9db560d72a247c178ae86b'; - let startBlockNum: number; - let logFilterId0: string; - let logFilterId1: string; - let logFilterId2: string; - let logFilterId3: string; - - const feedTx = async () => aca.transfer(evmAccounts[1].evmAddress, 111222333444555); + describe('get latest logs', async () => { + const provider = new AcalaJsonRpcProvider(RPC_URL); + const wallet = new Wallet(evmAccounts[0].privateKey, provider); + let token: Contract; beforeAll(async () => { - startBlockNum = Number((await eth_blockNumber()).data.result); - - logFilterId0 = (await eth_newFilter([{}])).data.result; // only pull once at the end - logFilterId1 = ( - await eth_newFilter([ - { - // normal log poll - address: ADDRESS.ACA, - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - null, - ['0x12332', '0x000000000000000000000000b00cb924ae22b2bbb15e10c17258d6a2af980421', '0x78723681eeeee'], - ], - }, - ]) - ).data.result; - logFilterId2 = ( - await eth_newFilter([ - { - // normal log poll - address: ADDRESS.ACA, - fromBlock: startBlockNum, - toBlock: startBlockNum + 3, - }, - ]) - ).data.result; - logFilterId3 = ( - await eth_newFilter([ - { - // empty - fromBlock: 3, - toBlock: 5, - }, - ]) - ).data.result; - - await provider.isReady(); + // need to put in here to prevent interrupte deterministic setup + token = await deployErc20(wallet); + await token.deployed(); }); - afterAll(async () => { - await provider.disconnect(); - }); - - it('poll immediately', async () => { - const res1 = (await eth_getFilterChanges([logFilterId1])).data.result; - const res2 = (await eth_getFilterChanges([logFilterId2])).data.result; - const res3 = (await eth_getFilterChanges([logFilterId3])).data.result; - - expect([res1, res2, res3]).to.deep.equal([[], [], []]); - }); - - it('get correct result', async () => { - /* ---------- fire 1 tx ---------- */ - await feedTx(); - await sleep(10000); // give subql some time to index - - let res1 = (await eth_getFilterChanges([logFilterId1])).data.result; - let res2 = (await eth_getFilterChanges([logFilterId2])).data.result; - let res3 = (await eth_getFilterChanges([logFilterId3])).data.result; - - const curBlockHash = await getCurBlockHash(); - let expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; - - expect(expectedLogs.length).to.equal(1); - expect(res1).to.deep.equal(expectedLogs); - expect(res2).to.deep.equal(expectedLogs); - expect(res3).to.deep.equal([]); - - /* ---------- fire many tx ---------- */ - const txCount = 5; - for (let i = 0; i < txCount; i++) { - await feedTx(); - } - await sleep(10000); // give subql some time to index - - const res0 = (await eth_getFilterChanges([logFilterId0])).data.result; - res1 = (await eth_getFilterChanges([logFilterId1])).data.result; - res2 = (await eth_getFilterChanges([logFilterId2])).data.result; - res3 = (await eth_getFilterChanges([logFilterId3])).data.result; - - const curHeight = Number((await eth_blockNumber()).data.result); - expectedLogs = ( - await eth_getLogs([ - { - fromBlock: curHeight - txCount, - toBlock: curHeight, - }, - ]) - ).data.result; - - expect(expectedLogs.length).to.equal(txCount + 1); // + 1 because it's all logs, which conains the one in prev test - expect(res0).to.deep.equal(expectedLogs); - expect(res1).to.deep.equal(expectedLogs.slice(1)); - // it's range is [x, x + 3], x is original block, x + 1 is prev test, now only poll for x + 2 and x + 3, so has 2 logs - expect(res2).to.deep.equal(expectedLogs.slice(1, 3)); - expect(res3).to.deep.equal([]); - }); - - it('unsubscribe works', async () => { - const unsub = (await eth_uninstallFilter([logFilterId0])).data.result; - const unsub2 = (await eth_uninstallFilter([logFilterId0])).data.result; - const unsub3 = (await eth_uninstallFilter([dummyId])).data.result; - expect(unsub).to.equal(true); - expect(unsub2).to.equal(false); - expect(unsub3).to.equal(false); - - await feedTx(); - await sleep(10000); // give subql some time to index - - const res1 = (await eth_getFilterChanges([logFilterId1])).data.result; - const res2 = (await eth_getFilterChanges([logFilterId2])).data.result; - const res3 = (await eth_getFilterChanges([logFilterId3])).data.result; - - const curBlockHash = await getCurBlockHash(); - const expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; - - // all other filters should still work - expect(expectedLogs.length).to.equal(1); - expect(res1).to.deep.equal(expectedLogs); - expect(res2).to.deep.equal([]); // now block range doesn't match anymore - expect(res3).to.deep.equal([]); - - // target should be removed - const res0 = await eth_getFilterChanges([logFilterId0]); - expect(res0.data.error.message).to.contains('filter not found'); - }); - - it.skip('throws correct error messege', async () => { - // tested in eth_newBlockFilter - }); - }); - - // mostly a copy of eth_newFilter tests, but use eth_getFilterLogs instead of eth_getFilterChanges - describe('eth_getFilterLogs', () => { - const provider = new EvmRpcProvider(NODE_RPC_URL); - const aca = new Contract(ADDRESS.ACA, TokenABI.abi, wallet1.connect(provider)); - - const dummyId = '0x12345678906f9c864d9db560d72a247c178ae86b'; - let startBlockNum: number; - let logFilterId0: string; - let logFilterId1: string; - let logFilterId2: string; - let logFilterId3: string; - - const feedTx = async () => aca.transfer(evmAccounts[1].evmAddress, 111222333444555); - - beforeAll(async () => { - startBlockNum = Number((await eth_blockNumber()).data.result); - - logFilterId0 = (await eth_newFilter([{}])).data.result; // only pull once at the end - logFilterId1 = ( - await eth_newFilter([ - { - // normal log poll - address: ADDRESS.ACA, - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - null, - ['0x12332', '0x000000000000000000000000b00cb924ae22b2bbb15e10c17258d6a2af980421', '0x78723681eeeee'], - ], - }, - ]) - ).data.result; - logFilterId2 = ( - await eth_newFilter([ - { - // normal log poll - address: ADDRESS.ACA, - fromBlock: startBlockNum, - toBlock: startBlockNum + 3, - }, - ]) - ).data.result; - logFilterId3 = ( - await eth_newFilter([ - { - // empty - fromBlock: 3, - toBlock: 5, - }, - ]) - ).data.result; - - await provider.isReady(); - }); + it('should return latest logs as soon as it\'s finalized, and should not hang if toBlock is large', async () => { + const curHeight = await provider.getBlockNumber(); + await (await token.transfer(ADDRESS_ALICE, 1000)).wait(); - afterAll(async () => { - await provider.disconnect(); - }); + // should return latest logs as soon as it's finalized + const targetHeight = curHeight + 1; + await waitForHeight(provider, targetHeight); // instant-sealing: best height = finalized height + const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); - it('poll immediately', async () => { - const res1 = (await eth_getFilterLogs([logFilterId1])).data.result; - const res2 = (await eth_getFilterLogs([logFilterId2])).data.result; - const res3 = (await eth_getFilterLogs([logFilterId3])).data.result; + expect(res.data?.result?.length).to.eq(1); + expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); - expect([res1, res2, res3]).to.deep.equal([[], [], []]); + // should not hang if toBlock is large + const res2 = await eth_getLogs([{ fromBlock: targetHeight, toBlock: 9999999999 }]); + expect(res2.data.result).to.deep.equal(res.data.result); }); - it('get correct result', async () => { - /* ---------- fire 1 tx ---------- */ - await feedTx(); - await sleep(10000); // give subql some time to index - - let res1 = (await eth_getFilterLogs([logFilterId1])).data.result; - let res2 = (await eth_getFilterLogs([logFilterId2])).data.result; - let res3 = (await eth_getFilterLogs([logFilterId3])).data.result; - - const curBlockHash = await getCurBlockHash(); - let expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; + it('should return latest logs before subql is synced', async () => { + const curHeight = await provider.getBlockNumber(); - expect(expectedLogs.length).to.equal(1); - expect(res1).to.deep.equal(expectedLogs); - expect(res2).to.deep.equal(expectedLogs); - expect(res3).to.deep.equal([]); - - /* ---------- fire many tx ---------- */ - const txCount = 5; - for (let i = 0; i < txCount; i++) { - await feedTx(); + for (let i = 0; i < 5; i++) { + const tx = await token.transfer(ADDRESS_ALICE, 1000); + await tx.wait(); } - await sleep(10000); // give subql some time to index - - const res0 = (await eth_getFilterLogs([logFilterId0])).data.result; - res1 = (await eth_getFilterLogs([logFilterId1])).data.result; - res2 = (await eth_getFilterLogs([logFilterId2])).data.result; - res3 = (await eth_getFilterLogs([logFilterId3])).data.result; - - const curHeight = Number((await eth_blockNumber()).data.result); - expectedLogs = ( - await eth_getLogs([ - { - fromBlock: curHeight - txCount, - toBlock: curHeight, - }, - ]) - ).data.result; - - expect(expectedLogs.length).to.equal(txCount + 1); // + 1 because it's all logs, which conains the one in prev test - expect(res0).to.deep.equal(expectedLogs); - expect(res1).to.deep.equal(expectedLogs.slice(1)); - // it's range is [x, x + 3], x is original block, x + 1 is prev test, now only poll for x + 2 and x + 3, so has 2 logs - expect(res2).to.deep.equal(expectedLogs.slice(1, 3)); - expect(res3).to.deep.equal([]); - }); - it('unsubscribe works', async () => { - const unsub = (await eth_uninstallFilter([logFilterId0])).data.result; - const unsub2 = (await eth_uninstallFilter([logFilterId0])).data.result; - const unsub3 = (await eth_uninstallFilter([dummyId])).data.result; - expect(unsub).to.equal(true); - expect(unsub2).to.equal(false); - expect(unsub3).to.equal(false); - - await feedTx(); - await sleep(10000); // give subql some time to index - - const res1 = (await eth_getFilterLogs([logFilterId1])).data.result; - const res2 = (await eth_getFilterLogs([logFilterId2])).data.result; - const res3 = (await eth_getFilterLogs([logFilterId3])).data.result; - - const curBlockHash = await getCurBlockHash(); - const expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; - - // all other filters should still work - expect(expectedLogs.length).to.equal(1); - expect(res1).to.deep.equal(expectedLogs); - expect(res2).to.deep.equal([]); // now block range doesn't match anymore - expect(res3).to.deep.equal([]); - - // target should be removed - const res0 = await eth_getFilterLogs([logFilterId0]); - expect(res0.data.error!.message).to.contains('filter not found'); - }); + const targetHeight = curHeight + 5; + await waitForHeight(provider, targetHeight); + const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); - it('throws correct error messege', async () => { - const res = await eth_getFilterLogs([dummyId]); - expect(res.data.error!.message).to.contains('filter not found'); + expect(res.data?.result?.length).to.eq(1); + expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); }); }); }); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts new file mode 100644 index 000000000..d4477bdd5 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts @@ -0,0 +1,114 @@ +import { beforeAll, describe, expect, it } from 'vitest'; + +import { BigNumber, Contract, ContractTransaction } from 'ethers'; +import { + deployErc20, + eth_blockNumber, + eth_getTransactionByHash, + eth_getTransactionReceipt, + testSetup, +} from '../utils'; +import { hexZeroPad } from 'ethers/lib/utils'; + +const { wallets: [wallet, wallet1] } = testSetup; + +describe('get tx and receipt', () => { + let token: Contract; + + beforeAll(async () => { + token = await deployErc20(wallet); + }); + + it('can get tx and recipt for contract deployment', async () => { + const tokenDeployedBlock = (await eth_blockNumber()).data.result; + const txHash = token.deployTransaction.hash; + + const tx = (await eth_getTransactionByHash([txHash])).data.result; + const receipt = (await eth_getTransactionReceipt([txHash])).data.result; + + console.log(tx); + console.log(receipt); + + expect(tx).to.contain({ + hash: txHash, + blockNumber: tokenDeployedBlock, + from: wallet.address.toLowerCase(), + to: null, + value: '0x0', + }); + + expect(receipt).to.deep.contain({ + transactionHash: txHash, + blockNumber: tokenDeployedBlock, + from: wallet.address.toLowerCase(), + to: null, + logs: [], + status: '0x1', + type: '0x0', + }); + }); + + it('can get tx and recipt for token transfer', async () => { + const transferAmount = 100; + const pendingTx = await token.transfer(wallet1.address, transferAmount) as ContractTransaction; + + let tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; + let receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; + + console.log(tx); + console.log(receipt); + + expect(tx).to.contain({ + hash: pendingTx.hash, + blockNumber: null, // pending tx + blockHash: null, // pending tx + from: wallet.address.toLowerCase(), + to: token.address.toLowerCase(), + value: '0x0', + }); + + // not mined yet + expect(receipt).to.eq(null); + + /* ------------------------- after tx is mined ------------------------- */ + await pendingTx.wait(); + + tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; + receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; + + console.log(tx); + console.log(receipt); + + const blockNumber = (await eth_blockNumber()).data.result; + expect(tx).to.contain({ + hash: pendingTx.hash, + blockNumber, + from: wallet.address.toLowerCase(), + to: token.address.toLowerCase(), + value: '0x0', + }); + + expect(receipt).toEqual(expect.objectContaining({ + transactionHash: pendingTx.hash, + blockNumber, + from: wallet.address.toLowerCase(), + to: token.address.toLowerCase(), + logs: [ + expect.objectContaining({ + transactionIndex: '0x0', + blockNumber: blockNumber, + transactionHash: pendingTx.hash, + address: token.address.toLowerCase(), + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + hexZeroPad(wallet.address.toLowerCase(), 32), + hexZeroPad(wallet1.address.toLowerCase(), 32), + ], + data: hexZeroPad(BigNumber.from(transferAmount).toHexString(), 32), + logIndex: '0x0', + }), + ], + status: '0x1', + })); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newBlockFilter.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newBlockFilter.test.ts new file mode 100644 index 000000000..91ce71b82 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newBlockFilter.test.ts @@ -0,0 +1,102 @@ +import { beforeAll, describe, expect, it } from 'vitest'; + +import { Contract } from 'ethers'; +import { + deployErc20, + eth_getFilterChanges, + eth_getFilterLogs, + eth_newBlockFilter, + eth_uninstallFilter, + getCurBlockHash, + testSetup, +} from '../utils'; + +const { + wallets: [wallet, wallet1], +} = testSetup; + +describe('eth_newBlockFilter', () => { + let token: Contract; + let fid0: string; + let fid1: string; + const dummyId = '0x12345678906f9c864d9db560d72a247c178ae86b'; + const expectedBlockHashes: string[] = []; + const allBlockHashes: string[] = []; + + const feedTx = async () => { + await (await token.transfer(wallet1.address, 1122334455)).wait(); + expectedBlockHashes.push(await getCurBlockHash()); + allBlockHashes.push(await getCurBlockHash()); + }; + + beforeAll(async () => { + token = await deployErc20(wallet); + fid0 = (await eth_newBlockFilter()).data.result; // only pull once at the end + fid1 = (await eth_newBlockFilter()).data.result; // normal block poll + }); + + it('poll immediately', async () => { + const res = (await eth_getFilterChanges([fid1])).data.result; + expect(res).to.deep.equal([]); + }); + + it('get correct result', async () => { + /* ---------- fire 1 tx ---------- */ + await feedTx(); + + let res = (await eth_getFilterChanges([fid1])).data.result; + expect(res.length).to.equal(1); + expect(res).to.deep.equal(expectedBlockHashes); + expectedBlockHashes.length = 0; + + /* ---------- fire many tx ---------- */ + const txCount = 3; + for (let i = 0; i < txCount; i++) { + await feedTx(); + } + + res = (await eth_getFilterChanges([fid1])).data.result; + let resAll = (await eth_getFilterChanges([fid0])).data.result; + expect(res.length).to.equal(txCount); + expect(resAll.length).to.equal(txCount + 1); + expect(res).to.deep.equal(expectedBlockHashes); + expect(resAll).to.deep.equal(allBlockHashes); + + // query again should return empty + res = (await eth_getFilterChanges([fid1])).data.result; + resAll = (await eth_getFilterChanges([fid0])).data.result; + expect(res).to.deep.equal([]); + expect(resAll).to.deep.equal([]); + }); + + it('unsubscribe works', async () => { + expectedBlockHashes.length = 0; + const unsub = (await eth_uninstallFilter([fid0])).data.result; + const unsub2 = (await eth_uninstallFilter([fid0])).data.result; + const unsub3 = (await eth_uninstallFilter([dummyId])).data.result; + + expect(unsub).to.equal(true); + expect(unsub2).to.equal(false); + expect(unsub3).to.equal(false); + + await feedTx(); + + // other filter should still work + let res = (await eth_getFilterChanges([fid1])).data.result; + expect(res.length).to.equal(1); + expect(res).to.deep.equal(expectedBlockHashes); + + // target filter should be removed + res = await eth_getFilterChanges([fid0]); + expect(res.data.error.message).to.contains('filter not found'); + }); + + it('throws correct error', async () => { + let res = await eth_getFilterChanges([dummyId]); + expect(res.data.error.message).to.contains('filter not found'); + + // eth_getFilterLogs should not find block filter + res = await eth_getFilterLogs([fid1]); + expect(res.data.error.message).to.contains('filter not found'); + }); +}); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newFilter.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newFilter.test.ts new file mode 100644 index 000000000..4ac3c2367 --- /dev/null +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_newFilter.test.ts @@ -0,0 +1,169 @@ +import { beforeAll, describe, expect, it } from 'vitest'; + +import { Contract } from 'ethers'; +import { + TRANSFER_EVENT_TOPIC, + deployErc20, + eth_blockNumber, + eth_getFilterChanges, + eth_getFilterLogs, + eth_getLogs, + eth_newFilter, + eth_uninstallFilter, + getCurBlockHash, + testSetup, +} from '../utils'; + +const { + wallets: [wallet, wallet1], + provider, +} = testSetup; + +// using either poll method should has same result +const testEthNewFilter = (pollMethod: 'eth_getFilterChanges' | 'eth_getFilterLogs') => { + describe(`eth_newFilter with ${pollMethod}`, () => { + let token: Contract; + const dummyId = '0x12345678906f9c864d9db560d72a247c178ae86b'; + let startBlockNum: number; + let fid0: string; + let fid1: string; + let fid2: string; + let fid3: string; + + const feedTx = async () => token.transfer(wallet1.address, 11122233); + + const pollFilter = (filterId: string) => ( + pollMethod === 'eth_getFilterChanges' + ? eth_getFilterChanges([filterId]) + : eth_getFilterLogs([filterId]) + ); + + beforeAll(async () => { + token = await deployErc20(wallet); + + startBlockNum = await provider.getBlockNumber(); + + fid0 = (await eth_newFilter([{}])).data.result; // only pull once at the end + + fid1 = ( + await eth_newFilter([ + { + // normal log poll + address: token.address, + topics: [TRANSFER_EVENT_TOPIC, null, null], + }, + ]) + ).data.result; + + fid2 = ( + await eth_newFilter([ + { + // normal log poll + address: token.address, + fromBlock: startBlockNum, + toBlock: startBlockNum + 3, + }, + ]) + ).data.result; + + fid3 = ( + await eth_newFilter([ + { + // empty + fromBlock: 3, + toBlock: 100, + }, + ]) + ).data.result; + }); + + it('poll immediately', async () => { + const res1 = (await pollFilter(fid1)).data.result; + const res2 = (await pollFilter(fid2)).data.result; + const res3 = (await pollFilter(fid3)).data.result; + + expect([res1, res2, res3]).to.deep.equal([[], [], []]); + }); + + it('get correct result', async () => { + /* ---------- fire 1 tx ---------- */ + await (await feedTx()).wait(); + + let res1 = (await pollFilter(fid1)).data.result; + let res2 = (await pollFilter(fid2)).data.result; + let res3 = (await pollFilter(fid3)).data.result; + + const curBlockHash = await getCurBlockHash(); + let expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; + + expect(expectedLogs.length).to.equal(1); + expect(res1).to.deep.equal(expectedLogs); + expect(res2).to.deep.equal(expectedLogs); + expect(res3).to.deep.equal([]); + + /* ---------- fire many tx ---------- */ + const txCount = 5; + for (let i = 0; i < txCount; i++) { + await (await feedTx()).wait(); + } + + const res0 = (await pollFilter(fid0)).data.result; + res1 = (await pollFilter(fid1)).data.result; + res2 = (await pollFilter(fid2)).data.result; + res3 = (await pollFilter(fid3)).data.result; + + const curHeight = Number((await eth_blockNumber()).data.result); + expectedLogs = ( + await eth_getLogs([ + { + fromBlock: curHeight - txCount, + toBlock: curHeight, + }, + ]) + ).data.result; + + expect(expectedLogs.length).to.equal(txCount + 1); // + 1 because it's all logs, which conains the one in prev test + expect(res0).to.deep.equal(expectedLogs); + expect(res1).to.deep.equal(expectedLogs.slice(1)); + // it's range is [x, x + 3], x is original block, x + 1 is prev test, now only poll for x + 2 and x + 3, so has 2 logs + expect(res2).to.deep.equal(expectedLogs.slice(1, 3)); + expect(res3).to.deep.equal([]); + }); + + it('unsubscribe works', async () => { + const unsub = (await eth_uninstallFilter([fid0])).data.result; + const unsub2 = (await eth_uninstallFilter([fid0])).data.result; + const unsub3 = (await eth_uninstallFilter([dummyId])).data.result; + + expect(unsub).to.equal(true); + expect(unsub2).to.equal(false); + expect(unsub3).to.equal(false); + + await (await feedTx()).wait(); + + const res1 = (await pollFilter(fid1)).data.result; + const res2 = (await pollFilter(fid2)).data.result; + const res3 = (await pollFilter(fid3)).data.result; + + const curBlockHash = await getCurBlockHash(); + const expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; + + // all other filters should still work + expect(expectedLogs.length).to.equal(1); + expect(res1).to.deep.equal(expectedLogs); + expect(res2).to.deep.equal([]); // now block range doesn't match anymore (cannot skip previous test) + expect(res3).to.deep.equal([]); + + // target should be removed + const res0 = await pollFilter(fid0); + expect(res0.data.error.message).to.contains('filter not found'); + }); + + it.skip('throws correct error message', async () => { + // tested in eth_newBlockFilter + }); + }); +}; + +testEthNewFilter('eth_getFilterChanges'); +testEthNewFilter('eth_getFilterLogs'); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts deleted file mode 100644 index e183100cd..000000000 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/filter-family.test.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { beforeAll, describe, expect, it } from 'vitest'; - -import { Contract } from 'ethers'; -import { - TRANSFER_EVENT_TOPIC, - deployErc20, - eth_blockNumber, - eth_getFilterChanges, - eth_getLogs, - eth_newFilter, - eth_uninstallFilter, - getCurBlockHash, - testSetup, -} from '../utils'; - -const { - wallets: [wallet, wallet1], - provider, -} = testSetup; - -describe('eth_newFilter', () => { - let token: Contract; - const dummyId = '0x12345678906f9c864d9db560d72a247c178ae86b'; - let startBlockNum: number; - let fid0: string; - let fid1: string; - let fid2: string; - let fid3: string; - - const feedTx = async () => token.transfer(wallet1.address, 11122233); - - beforeAll(async () => { - token = await deployErc20(wallet); - - startBlockNum = await provider.getBlockNumber(); - - fid0 = (await eth_newFilter([{}])).data.result; // only pull once at the end - - fid1 = ( - await eth_newFilter([ - { - // normal log poll - address: token.address, - topics: [ - TRANSFER_EVENT_TOPIC, - null, - null, - ], - }, - ]) - ).data.result; - - fid2 = ( - await eth_newFilter([ - { - // normal log poll - address: token.address, - fromBlock: startBlockNum, - toBlock: startBlockNum + 3, - }, - ]) - ).data.result; - - fid3 = ( - await eth_newFilter([ - { - // empty - fromBlock: 3, - toBlock: 100, - }, - ]) - ).data.result; - }); - - it('poll immediately', async () => { - const res1 = (await eth_getFilterChanges([fid1])).data.result; - const res2 = (await eth_getFilterChanges([fid2])).data.result; - const res3 = (await eth_getFilterChanges([fid3])).data.result; - - expect([res1, res2, res3]).to.deep.equal([[], [], []]); - }); - - it('get correct result', async () => { - /* ---------- fire 1 tx ---------- */ - await (await feedTx()).wait(); - - let res1 = (await eth_getFilterChanges([fid1])).data.result; - let res2 = (await eth_getFilterChanges([fid2])).data.result; - let res3 = (await eth_getFilterChanges([fid3])).data.result; - - const curBlockHash = await getCurBlockHash(); - let expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; - - expect(expectedLogs.length).to.equal(1); - expect(res1).to.deep.equal(expectedLogs); - expect(res2).to.deep.equal(expectedLogs); - expect(res3).to.deep.equal([]); - - /* ---------- fire many tx ---------- */ - const txCount = 5; - for (let i = 0; i < txCount; i++) { - await (await feedTx()).wait(); - } - - const res0 = (await eth_getFilterChanges([fid0])).data.result; - res1 = (await eth_getFilterChanges([fid1])).data.result; - res2 = (await eth_getFilterChanges([fid2])).data.result; - res3 = (await eth_getFilterChanges([fid3])).data.result; - - const curHeight = Number((await eth_blockNumber()).data.result); - expectedLogs = ( - await eth_getLogs([ - { - fromBlock: curHeight - txCount, - toBlock: curHeight, - }, - ]) - ).data.result; - - console.log({ - expectedLogs, - curHeight, - }); - - expect(expectedLogs.length).to.equal(txCount + 1); // + 1 because it's all logs, which conains the one in prev test - expect(res0).to.deep.equal(expectedLogs); - expect(res1).to.deep.equal(expectedLogs.slice(1)); - // it's range is [x, x + 3], x is original block, x + 1 is prev test, now only poll for x + 2 and x + 3, so has 2 logs - expect(res2).to.deep.equal(expectedLogs.slice(1, 3)); - expect(res3).to.deep.equal([]); - }); - - it('unsubscribe works', async () => { - const unsub = (await eth_uninstallFilter([fid0])).data.result; - const unsub2 = (await eth_uninstallFilter([fid0])).data.result; - const unsub3 = (await eth_uninstallFilter([dummyId])).data.result; - - expect(unsub).to.equal(true); - expect(unsub2).to.equal(false); - expect(unsub3).to.equal(false); - - await (await feedTx()).wait(); - - const res1 = (await eth_getFilterChanges([fid1])).data.result; - const res2 = (await eth_getFilterChanges([fid2])).data.result; - const res3 = (await eth_getFilterChanges([fid3])).data.result; - - const curBlockHash = await getCurBlockHash(); - const expectedLogs = (await eth_getLogs([{ blockHash: curBlockHash }])).data.result; - - // all other filters should still work - expect(expectedLogs.length).to.equal(1); - expect(res1).to.deep.equal(expectedLogs); - expect(res2).to.deep.equal([]); // now block range doesn't match anymore (cannot skip previous test) - expect(res3).to.deep.equal([]); - - // target should be removed - const res0 = await eth_getFilterChanges([fid0]); - expect(res0.data.error.message).to.contains('filter not found'); - }); - - it.skip('throws correct error messege', async () => { - // tested in eth_newBlockFilter - }); -}); From a4ff94c70e0e5173318b889ebae4f234f604a8e4 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Wed, 9 Oct 2024 16:32:17 +0800 Subject: [PATCH 19/23] eth_getlogs test --- packages/eth-providers/src/base-provider.ts | 3 +- .../endpoint-tests/eth_getLogs.test.ts | 363 ++++++++++++++---- 2 files changed, 284 insertions(+), 82 deletions(-) diff --git a/packages/eth-providers/src/base-provider.ts b/packages/eth-providers/src/base-provider.ts index 599400f3e..ef4c41965 100644 --- a/packages/eth-providers/src/base-provider.ts +++ b/packages/eth-providers/src/base-provider.ts @@ -1826,7 +1826,8 @@ export abstract class BaseProvider extends AbstractProvider { .map(this.blockCache.getLogsAtBlock.bind(this)) .flat() .filter(log => filterLogByBlockNumber(log, filter.fromBlock, filter.toBlock)) - .filter(log => filterLogByAddress(log, filter.address)); + .filter(log => filterLogByAddress(log, filter.address)) + .filter(log => filterLogByTopics(log, filter.topics)); }; // Bloom-filter Queries diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts index d4477bdd5..6b6a4272e 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts @@ -1,114 +1,315 @@ import { beforeAll, describe, expect, it } from 'vitest'; -import { BigNumber, Contract, ContractTransaction } from 'ethers'; +import { Contract } from 'ethers'; import { + LogHexified, deployErc20, - eth_blockNumber, - eth_getTransactionByHash, - eth_getTransactionReceipt, + eth_getLogs, + expectLogsEqual, testSetup, } from '../utils'; -import { hexZeroPad } from 'ethers/lib/utils'; -const { wallets: [wallet, wallet1] } = testSetup; +const { + provider, + wallets: [wallet, wallet1, wallet2, wallet3], +} = testSetup; -describe('get tx and receipt', () => { - let token: Contract; +describe('eth_getLogs', () => { + let token0: Contract; + let token1: Contract; + let allLogs: LogHexified[]; + // const ALL_BLOCK_RANGE_FILTER = { fromBlock: 'earliest' }; // TODO: use me when subql is ready + let ALL_BLOCK_RANGE_FILTER; beforeAll(async () => { - token = await deployErc20(wallet); + token0 = await deployErc20(wallet); + token1 = await deployErc20(wallet); + + const earliestBlock = await provider.getBlockNumber(); + ALL_BLOCK_RANGE_FILTER = { fromBlock: earliestBlock }; + + await (await token0.transfer(wallet1.address, 1000)).wait(); + await (await token1.transfer(wallet2.address, 2000)).wait(); + await (await token0.transfer(wallet3.address, 3000)).wait(); + + allLogs = (await eth_getLogs([ALL_BLOCK_RANGE_FILTER])).data.result; + console.log(allLogs); + expect(allLogs.length).to.equal(3); + }); + + describe.concurrent('when no filter', () => { + it('returns all logs from latest block', async () => { + const curBlockNum = await provider.getBlockNumber(); + + const res = (await eth_getLogs([{}])).data.result; + expect(res.length).to.equal(1); + expect(Number(res[0].blockNumber)).to.equal(curBlockNum); + }); + }); + + describe.concurrent('filter by address', () => { + it('returns correct logs', async () => { + /* ---------- single address ---------- */ + for (const log of allLogs) { + const res = await eth_getLogs([{ address: log.address, ...ALL_BLOCK_RANGE_FILTER }]); + const expectedLogs = allLogs.filter(l => l.address === log.address); + expectLogsEqual(res.data.result, expectedLogs); + } + + // should support different case and array of addresses + for (const log of allLogs) { + const res = await eth_getLogs([ + { address: [log.address.toLocaleUpperCase(), '0x13579'], ...ALL_BLOCK_RANGE_FILTER }, + ]); + const expectedLogs = allLogs.filter(l => l.address === log.address); + expectLogsEqual(res.data.result, expectedLogs); + } + }); + }); + + describe.concurrent('filter by blockhash', () => { + it('returns correct logs', async () => { + for (const log of allLogs) { + const res = await eth_getLogs([{ blockHash: log.blockHash }]); + const expectedLogs = allLogs.filter(l => l.blockNumber === log.blockNumber); + expectLogsEqual(res.data.result, expectedLogs); + } + }); + }); + + // TODO: enable me when subql is ready + describe.concurrent.skip('filter by block number', () => { + it('returns correct logs', async () => { + const BIG_NUMBER = 88888888; + const BIG_NUMBER_HEX = '0x54C5638'; + + let res: Awaited>; + let expectedLogs: LogHexified[]; + + /* ---------- should return all logs ---------- */ + res = await eth_getLogs([{ ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ fromBlock: 0 }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER_HEX }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ fromBlock: 0, toBlock: 'latest' }]); + expectLogsEqual(res.data.result, allLogs); + + /* ---------- should return no logs ---------- */ + res = await eth_getLogs([{ fromBlock: 99999 }]); + expect(res.data.result).to.deep.equal([]); + + res = await eth_getLogs([{ toBlock: -1 }]); + expect(res.data.result).to.deep.equal([]); + + /* ---------- should return partial logs ---------- */ + const from = 9; + const to = 11; + res = await eth_getLogs([{ fromBlock: from }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); + expectLogsEqual(res.data.result, expectedLogs); + + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); + + res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); + }); }); - it('can get tx and recipt for contract deployment', async () => { - const tokenDeployedBlock = (await eth_blockNumber()).data.result; - const txHash = token.deployTransaction.hash; + // TODO: enable me when subql is ready + describe.concurrent.skip('filter by block tag', () => { + it('returns correct logs for valid tag', async () => { + let res: Awaited>; + let expectedLogs: LogHexified[]; - const tx = (await eth_getTransactionByHash([txHash])).data.result; - const receipt = (await eth_getTransactionReceipt([txHash])).data.result; + /* ---------- should return all logs ---------- */ + res = await eth_getLogs([{ fromBlock: 'earliest' }]); + expectLogsEqual(res.data.result, allLogs); - console.log(tx); - console.log(receipt); + res = await eth_getLogs([{ fromBlock: 0 }]); + expectLogsEqual(res.data.result, allLogs); - expect(tx).to.contain({ - hash: txHash, - blockNumber: tokenDeployedBlock, - from: wallet.address.toLowerCase(), - to: null, - value: '0x0', + res = await eth_getLogs([{ fromBlock: '0x0' }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ fromBlock: '0x00000000' }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 'latest' }]); + expectLogsEqual(res.data.result, allLogs); + + /* ---------- should return no logs ---------- */ + res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 'earliest' }]); + expect(res.data.result).to.deep.equal([]); + + res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 5 }]); + expect(res.data.result).to.deep.equal([]); + + res = await eth_getLogs([{ fromBlock: 'latest', toBlock: '0x5' }]); + expect(res.data.result).to.deep.equal([]); + + res = await eth_getLogs([{ fromBlock: 8, toBlock: 'earliest' }]); + expect(res.data.result).to.deep.equal([]); + + /* ---------- should return some logs ---------- */ + const from = 8; + const to = 10; + res = await eth_getLogs([{ fromBlock: from, toBlock: 'latest' }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); + expectLogsEqual(res.data.result, expectedLogs); + + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); + + res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); + expectLogsEqual(res.data.result, expectedLogs); }); + }); + + describe.concurrent('filter by topics', () => { + it('returns correct logs', async () => { + let res: Awaited>; + let expectedLogs: LogHexified[]; + + /* ---------- should return all logs ---------- */ + res = await eth_getLogs([{ topics: [], ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ topics: [[]], ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); + + res = await eth_getLogs([{ topics: [null, [], null, [], 'hahahahaha', 'hohoho'], ...ALL_BLOCK_RANGE_FILTER }]); + expectLogsEqual(res.data.result, allLogs); - expect(receipt).to.deep.contain({ - transactionHash: txHash, - blockNumber: tokenDeployedBlock, - from: wallet.address.toLowerCase(), - to: null, - logs: [], - status: '0x1', - type: '0x0', + /* ---------- should return no logs ---------- */ + res = await eth_getLogs([{ topics: ['XXX'], ...ALL_BLOCK_RANGE_FILTER }]); + expect(res.data.result).to.deep.equal([]); + + /* ---------- should return some logs ---------- */ + for (const log of allLogs) { + res = await eth_getLogs([{ topics: log.topics, ...ALL_BLOCK_RANGE_FILTER }]); + expectedLogs = allLogs.filter( + l => log.topics.length === l.topics.length && log.topics.every((t, i) => l.topics[i] === t) + ); + expectLogsEqual(res.data.result, expectedLogs); + + res = await eth_getLogs([{ topics: [log.topics[0]], ...ALL_BLOCK_RANGE_FILTER }]); + expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); + expectLogsEqual(res.data.result, expectedLogs); + + res = await eth_getLogs([ + { topics: [['ooo', log.topics[0], 'xxx', 'yyy'], null, []], ...ALL_BLOCK_RANGE_FILTER }, + ]); + expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); + expectLogsEqual(res.data.result, expectedLogs); + + res = await eth_getLogs([ + { topics: [...new Array(log.topics.length - 1).fill(null), log.topics.at(-1)], ...ALL_BLOCK_RANGE_FILTER }, + ]); + expectedLogs = allLogs.filter(l => l.topics[log.topics.length - 1] === log.topics.at(-1)); + expectLogsEqual(res.data.result, expectedLogs); + } }); }); - it('can get tx and recipt for token transfer', async () => { - const transferAmount = 100; - const pendingTx = await token.transfer(wallet1.address, transferAmount) as ContractTransaction; + // TODO: enable me when subql is ready + describe.concurrent.skip('filter by multiple params', () => { + it('returns correct logs', async () => { + let res: Awaited>; + let expectedLogs: LogHexified[]; + const allLogsFromSubql = await subql.getAllLogs().then(logs => logs.map(hexilifyLog)); + /* -------------------- match block range -------------------- */ + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 11); + res = await eth_getLogs([{ fromBlock: 8, toBlock: 11, topics: [[], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); + + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= 15); + res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 15, topics: [[], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); + + for (const log of allLogsFromSubql) { + /* -------------------- match blockhash -------------------- */ + expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) === parseInt(log.blockNumber)); + res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); + + /* -------------------- match first topic -------------------- */ + expectedLogs = allLogs.filter( + l => parseInt(l.blockNumber) === parseInt(log.blockNumber) && l.topics[0] === log.topics[0] + ); + res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[log.topics[0], 'xxx'], null, []] }]); + expectLogsEqual(res.data.result, expectedLogs); - let tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; - let receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; + /* -------------------- match range and topics -------------------- */ + expectedLogs = allLogs.filter( + l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 15 && l.topics[0] === log.topics[0] + ); + res = await eth_getLogs([{ fromBlock: 8, toBlock: 15, topics: [['xxx', log.topics[0]]] }]); + expectLogsEqual(res.data.result, expectedLogs); - console.log(tx); - console.log(receipt); + /* -------------------- no match -------------------- */ + res = await eth_getLogs([{ blockHash: log.blockHash, topics: ['0x12345'] }]); + expect(res.data.result).to.deep.equal([]); - expect(tx).to.contain({ - hash: pendingTx.hash, - blockNumber: null, // pending tx - blockHash: null, // pending tx - from: wallet.address.toLowerCase(), - to: token.address.toLowerCase(), - value: '0x0', + res = await eth_getLogs([{ blockHash: log.blockHash, topics: [log.topics[0], 'xxx'] }]); + expect(res.data.result).to.deep.equal([]); + } }); + }); + + // TODO: enable me when subql is ready + describe.skip('get latest logs', async () => { + let token: Contract; - // not mined yet - expect(receipt).to.eq(null); + beforeAll(async () => { + // need to put in here to prevent interrupte deterministic setup + token = await deployErc20(wallet); + await token.deployed(); + }); - /* ------------------------- after tx is mined ------------------------- */ - await pendingTx.wait(); + it('should return latest logs as soon as it\'s finalized, and should not hang if toBlock is large', async () => { + const curHeight = await provider.getBlockNumber(); + await (await token.transfer(ADDRESS_ALICE, 1000)).wait(); - tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; - receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; + // should return latest logs as soon as it's finalized + const targetHeight = curHeight + 1; + await waitForHeight(provider, targetHeight); // instant-sealing: best height = finalized height + const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); - console.log(tx); - console.log(receipt); + expect(res.data?.result?.length).to.eq(1); + expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); - const blockNumber = (await eth_blockNumber()).data.result; - expect(tx).to.contain({ - hash: pendingTx.hash, - blockNumber, - from: wallet.address.toLowerCase(), - to: token.address.toLowerCase(), - value: '0x0', + // should not hang if toBlock is large + const res2 = await eth_getLogs([{ fromBlock: targetHeight, toBlock: 9999999999 }]); + expect(res2.data.result).to.deep.equal(res.data.result); }); - expect(receipt).toEqual(expect.objectContaining({ - transactionHash: pendingTx.hash, - blockNumber, - from: wallet.address.toLowerCase(), - to: token.address.toLowerCase(), - logs: [ - expect.objectContaining({ - transactionIndex: '0x0', - blockNumber: blockNumber, - transactionHash: pendingTx.hash, - address: token.address.toLowerCase(), - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - hexZeroPad(wallet.address.toLowerCase(), 32), - hexZeroPad(wallet1.address.toLowerCase(), 32), - ], - data: hexZeroPad(BigNumber.from(transferAmount).toHexString(), 32), - logIndex: '0x0', - }), - ], - status: '0x1', - })); + it('should return latest logs before subql is synced', async () => { + const curHeight = await provider.getBlockNumber(); + + for (let i = 0; i < 5; i++) { + const tx = await token.transfer(ADDRESS_ALICE, 1000); + await tx.wait(); + } + + const targetHeight = curHeight + 5; + await waitForHeight(provider, targetHeight); + const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); + + expect(res.data?.result?.length).to.eq(1); + expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); + }); }); }); From 6b4544b997b0cbd8fdd1a61a09bc901b35c6eff6 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Thu, 10 Oct 2024 14:37:36 +0800 Subject: [PATCH 20/23] clean up --- .../src/__tests__/endpoint-tests/endpoint.ts | 281 ------------------ .../endpoint-tests/eth_getLogs.test.ts | 1 - .../endpoint-tests/eth_getTransaction.test.ts | 9 - 3 files changed, 291 deletions(-) delete mode 100644 packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts deleted file mode 100644 index cbd215f45..000000000 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/endpoint.ts +++ /dev/null @@ -1,281 +0,0 @@ - - -// this should go first since it depends on the deterministic setup -// TODO: refactor tests to seperate self-dependent tests -describe('eth_getLogs', () => { - const ALL_BLOCK_RANGE_FILTER = { fromBlock: 'earliest' }; - - describe.concurrent('when no filter', () => { - it('returns all logs from latest block', async () => { - const res = (await eth_getLogs([{}])).data.result; - expect(res.length).to.equal(2); - expect(res[0]).to.deep.contain(log22_0); - expect(res[1]).to.deep.contain(log22_1); - }); - }); - - describe.concurrent('filter by address', () => { - it('returns correct logs', async () => { - /* ---------- single address ---------- */ - for (const log of allLogs) { - const res = await eth_getLogs([{ address: log.address, ...ALL_BLOCK_RANGE_FILTER }]); - const expectedLogs = allLogs.filter(l => l.address === log.address); - expectLogsEqual(res.data.result, expectedLogs); - } - - // should support different case and array of addresses - for (const log of allLogs) { - const res = await eth_getLogs([ - { address: [log.address.toLocaleUpperCase(), '0x13579'], ...ALL_BLOCK_RANGE_FILTER }, - ]); - const expectedLogs = allLogs.filter(l => l.address === log.address); - expectLogsEqual(res.data.result, expectedLogs); - } - }); - }); - - describe.concurrent('filter by block number', () => { - it('returns correct logs', async () => { - const BIG_NUMBER = 88888888; - const BIG_NUMBER_HEX = '0x54C5638'; - - let res: Awaited>; - let expectedLogs: LogHexified[]; - - /* ---------- should return all logs ---------- */ - res = await eth_getLogs([{ ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: 0 }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: -100000, toBlock: BIG_NUMBER_HEX }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: 0, toBlock: 'latest' }]); - expectLogsEqual(res.data.result, allLogs); - - /* ---------- should return no logs ---------- */ - res = await eth_getLogs([{ fromBlock: 99999 }]); - expect(res.data.result).to.deep.equal([]); - - res = await eth_getLogs([{ toBlock: -1 }]); - expect(res.data.result).to.deep.equal([]); - - /* ---------- should return partial logs ---------- */ - const from = 9; - const to = 11; - res = await eth_getLogs([{ fromBlock: from }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); - }); - }); - - describe.concurrent('filter by block tag', () => { - it('returns correct logs for valid tag', async () => { - let res: Awaited>; - let expectedLogs: LogHexified[]; - - /* ---------- should return all logs ---------- */ - res = await eth_getLogs([{ fromBlock: 'earliest' }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: 0 }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: '0x0' }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: '0x00000000' }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 'latest' }]); - expectLogsEqual(res.data.result, allLogs); - - /* ---------- should return no logs ---------- */ - res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 'earliest' }]); - expect(res.data.result).to.deep.equal([]); - - res = await eth_getLogs([{ fromBlock: 'latest', toBlock: 5 }]); - expect(res.data.result).to.deep.equal([]); - - res = await eth_getLogs([{ fromBlock: 'latest', toBlock: '0x5' }]); - expect(res.data.result).to.deep.equal([]); - - res = await eth_getLogs([{ fromBlock: 8, toBlock: 'earliest' }]); - expect(res.data.result).to.deep.equal([]); - - /* ---------- should return some logs ---------- */ - const from = 8; - const to = 10; - res = await eth_getLogs([{ fromBlock: from, toBlock: 'latest' }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([{ fromBlock: from, toBlock: to }]); - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= from && parseInt(l.blockNumber) <= to); - expectLogsEqual(res.data.result, expectedLogs); - }); - }); - - describe.concurrent('filter by topics', () => { - it('returns correct logs', async () => { - let res: Awaited>; - let expectedLogs: LogHexified[]; - - /* ---------- should return all logs ---------- */ - res = await eth_getLogs([{ topics: [], ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ topics: [[]], ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); - - res = await eth_getLogs([{ topics: [null, [], null, [], 'hahahahaha', 'hohoho'], ...ALL_BLOCK_RANGE_FILTER }]); - expectLogsEqual(res.data.result, allLogs); - - /* ---------- should return no logs ---------- */ - res = await eth_getLogs([{ topics: ['XXX'], ...ALL_BLOCK_RANGE_FILTER }]); - expect(res.data.result).to.deep.equal([]); - - /* ---------- should return some logs ---------- */ - for (const log of allLogs) { - res = await eth_getLogs([{ topics: log.topics, ...ALL_BLOCK_RANGE_FILTER }]); - expectedLogs = allLogs.filter( - l => log.topics.length === l.topics.length && log.topics.every((t, i) => l.topics[i] === t) - ); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([{ topics: [log.topics[0]], ...ALL_BLOCK_RANGE_FILTER }]); - expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([ - { topics: [['ooo', log.topics[0], 'xxx', 'yyy'], null, []], ...ALL_BLOCK_RANGE_FILTER }, - ]); - expectedLogs = allLogs.filter(l => l.topics[0] === log.topics[0]); - expectLogsEqual(res.data.result, expectedLogs); - - res = await eth_getLogs([ - { topics: [...new Array(log.topics.length - 1).fill(null), log.topics.at(-1)], ...ALL_BLOCK_RANGE_FILTER }, - ]); - expectedLogs = allLogs.filter(l => l.topics[log.topics.length - 1] === log.topics.at(-1)); - expectLogsEqual(res.data.result, expectedLogs); - } - }); - }); - - describe.concurrent('filter by blockhash', () => { - it('returns correct logs', async () => { - const allLogsFromSubql = await subql.getAllLogs().then(logs => logs.map(hexilifyLog)); - for (const log of allLogsFromSubql) { - const res = await eth_getLogs([{ blockHash: log.blockHash }]); - const expectedLogs = allLogs.filter(l => l.blockNumber === log.blockNumber); - expectLogsEqual(res.data.result, expectedLogs); - } - }); - }); - - describe.concurrent('filter by multiple params', () => { - it('returns correct logs', async () => { - let res: Awaited>; - let expectedLogs: LogHexified[]; - const allLogsFromSubql = await subql.getAllLogs().then(logs => logs.map(hexilifyLog)); - /* -------------------- match block range -------------------- */ - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 11); - res = await eth_getLogs([{ fromBlock: 8, toBlock: 11, topics: [[], null, []] }]); - expectLogsEqual(res.data.result, expectedLogs); - - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) <= 15); - res = await eth_getLogs([{ fromBlock: 'earliest', toBlock: 15, topics: [[], null, []] }]); - expectLogsEqual(res.data.result, expectedLogs); - - for (const log of allLogsFromSubql) { - /* -------------------- match blockhash -------------------- */ - expectedLogs = allLogs.filter(l => parseInt(l.blockNumber) === parseInt(log.blockNumber)); - res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[], null, []] }]); - expectLogsEqual(res.data.result, expectedLogs); - - /* -------------------- match first topic -------------------- */ - expectedLogs = allLogs.filter( - l => parseInt(l.blockNumber) === parseInt(log.blockNumber) && l.topics[0] === log.topics[0] - ); - res = await eth_getLogs([{ blockHash: log.blockHash, topics: [[log.topics[0], 'xxx'], null, []] }]); - expectLogsEqual(res.data.result, expectedLogs); - - /* -------------------- match range and topics -------------------- */ - expectedLogs = allLogs.filter( - l => parseInt(l.blockNumber) >= 8 && parseInt(l.blockNumber) <= 15 && l.topics[0] === log.topics[0] - ); - res = await eth_getLogs([{ fromBlock: 8, toBlock: 15, topics: [['xxx', log.topics[0]]] }]); - expectLogsEqual(res.data.result, expectedLogs); - - /* -------------------- no match -------------------- */ - res = await eth_getLogs([{ blockHash: log.blockHash, topics: ['0x12345'] }]); - expect(res.data.result).to.deep.equal([]); - - res = await eth_getLogs([{ blockHash: log.blockHash, topics: [log.topics[0], 'xxx'] }]); - expect(res.data.result).to.deep.equal([]); - } - }); - }); - - describe('get latest logs', async () => { - const provider = new AcalaJsonRpcProvider(RPC_URL); - const wallet = new Wallet(evmAccounts[0].privateKey, provider); - let token: Contract; - - beforeAll(async () => { - // need to put in here to prevent interrupte deterministic setup - token = await deployErc20(wallet); - await token.deployed(); - }); - - it('should return latest logs as soon as it\'s finalized, and should not hang if toBlock is large', async () => { - const curHeight = await provider.getBlockNumber(); - await (await token.transfer(ADDRESS_ALICE, 1000)).wait(); - - // should return latest logs as soon as it's finalized - const targetHeight = curHeight + 1; - await waitForHeight(provider, targetHeight); // instant-sealing: best height = finalized height - const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); - - expect(res.data?.result?.length).to.eq(1); - expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); - - // should not hang if toBlock is large - const res2 = await eth_getLogs([{ fromBlock: targetHeight, toBlock: 9999999999 }]); - expect(res2.data.result).to.deep.equal(res.data.result); - }); - - it('should return latest logs before subql is synced', async () => { - const curHeight = await provider.getBlockNumber(); - - for (let i = 0; i < 5; i++) { - const tx = await token.transfer(ADDRESS_ALICE, 1000); - await tx.wait(); - } - - const targetHeight = curHeight + 5; - await waitForHeight(provider, targetHeight); - const res = await eth_getLogs([{ fromBlock: targetHeight, toBlock: targetHeight }]); - - expect(res.data?.result?.length).to.eq(1); - expect(parseInt(res.data.result[0].blockNumber, 16)).to.eq(targetHeight); - }); - }); -}); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts index 6b6a4272e..048a9467a 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getLogs.test.ts @@ -33,7 +33,6 @@ describe('eth_getLogs', () => { await (await token0.transfer(wallet3.address, 3000)).wait(); allLogs = (await eth_getLogs([ALL_BLOCK_RANGE_FILTER])).data.result; - console.log(allLogs); expect(allLogs.length).to.equal(3); }); diff --git a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts index 83d924292..4051e6b4c 100644 --- a/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/endpoint-tests/eth_getTransaction.test.ts @@ -27,9 +27,6 @@ describe('get tx and receipt', () => { const tx = (await eth_getTransactionByHash([txHash])).data.result; const receipt = (await eth_getTransactionReceipt([txHash])).data.result; - console.log(tx); - console.log(receipt); - expect(tx).to.contain({ hash: txHash, blockNumber: tokenDeployedBlock, @@ -56,9 +53,6 @@ describe('get tx and receipt', () => { let tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; let receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; - console.log(tx); - console.log(receipt); - expect(tx).to.contain({ hash: pendingTx.hash, blockNumber: null, // pending tx @@ -77,9 +71,6 @@ describe('get tx and receipt', () => { tx = (await eth_getTransactionByHash([pendingTx.hash])).data.result; receipt = (await eth_getTransactionReceipt([pendingTx.hash])).data.result; - console.log(tx); - console.log(receipt); - const blockNumber = (await eth_blockNumber()).data.result; expect(tx).to.contain({ hash: pendingTx.hash, From b095bf4e9a7721ded3a15d23380de8221ae3c212 Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Thu, 10 Oct 2024 15:10:27 +0800 Subject: [PATCH 21/23] add retry to start test infra --- .github/workflows/test.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 22ec249be..4891f6694 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,7 +36,11 @@ jobs: run: yarn install --immutable - name: start test infra - run: docker compose up -d + uses: nick-fields/retry@v2 + with: + timeout_minutes: 5 + max_attempts: 3 + command: docker compose up -d - name: start rpc adapter for eth-providers if: matrix.project == 'eth-providers' @@ -93,7 +97,11 @@ jobs: run: yarn install --immutable - name: start test infra - run: docker compose up -d + uses: nick-fields/retry@v2 + with: + timeout_minutes: 5 + max_attempts: 3 + command: docker compose up -d - name: start coverage server env: From 395a106c684a9fccd393b444b3c985301b7d6e4e Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Thu, 10 Oct 2024 15:21:04 +0800 Subject: [PATCH 22/23] cleanup --- packages/eth-rpc-adapter/src/__tests__/subscription.test.ts | 5 ++--- packages/eth-rpc-adapter/src/__tests__/utils/consts.ts | 1 - packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts b/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts index 0505fe307..d3daeae0a 100644 --- a/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts +++ b/packages/eth-rpc-adapter/src/__tests__/subscription.test.ts @@ -6,11 +6,10 @@ import { afterAll, beforeAll, beforeEach, describe, it } from 'vitest'; import { expect } from 'chai'; import { parseUnits } from 'ethers/lib/utils'; -import { ETH_RPC_URL, ETH_RPC_URL_WS, SubsManager, evmAccounts, getAddrSelector } from './utils'; +import { ETH_RPC_URL, ETH_RPC_URL_WS, SubsManager, TRANSFER_EVENT_TOPIC, evmAccounts, getAddrSelector } from './utils'; import { IERC20, IERC20__factory } from './types'; const oneAcaErc20 = parseUnits('1', 12); -const TRANSFER_SELECTOR = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; describe('eth subscription', () => { let deployer: Wallet; @@ -41,7 +40,7 @@ describe('eth subscription', () => { const sub1 = sm.subscribeLogs({}); const sub2 = sm.subscribeLogs({ topics: [ - TRANSFER_SELECTOR, + TRANSFER_EVENT_TOPIC, null, [userAddrSelector], ], diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts index 1d0009e31..c8a61feeb 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/consts.ts @@ -1,5 +1,4 @@ export const NODE_URL = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944'; -export const KARURA_ETH_RPC_URL = process.env.KARURA_ETH_RPC_URL || 'http://127.0.0.1:8546'; export const ETH_RPC_URL = process.env.ETH_RPC_URL || 'http://127.0.0.1:8545'; export const ETH_RPC_URL_WS = process.env.ETH_RPC_URL_WS || ETH_RPC_URL.replace('http', 'ws'); export const SUBQL_URL = process.env.SUBQL_URL || 'http://127.0.0.1:3001'; diff --git a/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts index 36145afcd..dd89153b2 100644 --- a/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts +++ b/packages/eth-rpc-adapter/src/__tests__/utils/eth-rpc-apis.ts @@ -2,7 +2,6 @@ import axios from 'axios'; import { ETH_RPC_URL, - KARURA_ETH_RPC_URL, LogHexified, } from './consts'; import { JsonRpcError } from '../../server'; @@ -19,7 +18,6 @@ export const rpcGet = }, }); -/* ---------- local rpc methods ---------- */ export const eth_call = rpcGet('eth_call'); export const eth_blockNumber = rpcGet('eth_blockNumber'); export const eth_getBlockByNumber = rpcGet('eth_getBlockByNumber'); From 53fc83d690ca7b279d741953de6a5881a1f9767a Mon Sep 17 00:00:00 2001 From: Shunji Zhan Date: Thu, 10 Oct 2024 15:39:06 +0800 Subject: [PATCH 23/23] decrease test timeout --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4891f6694..f5b3a7285 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,7 +53,7 @@ jobs: - name: run tests uses: nick-fields/retry@v2 with: - timeout_minutes: 30 + timeout_minutes: 15 max_attempts: 2 command: yarn workspace @acala-network/${{ matrix.project }} run test:coverage @@ -114,7 +114,7 @@ jobs: - name: run e2e tests uses: nick-fields/retry@v2 with: - timeout_minutes: 30 + timeout_minutes: 15 max_attempts: 2 command: cd e2e-tests/${{ matrix.project }} && yarn test:acalaFork