From 16a13f3b8029be0f8221ead61f8da63aba96b277 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 19 Dec 2022 15:43:46 +0100 Subject: [PATCH] =?UTF-8?q?fix=20using=20ethereumjs=C3=A8vm=20return=20val?= =?UTF-8?q?ues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/blockchain/providers/worker-vm.ts | 6 +- libs/remix-lib/src/execution/txListener.ts | 2 +- libs/remix-lib/src/execution/txRunnerVM.ts | 4 +- libs/remix-lib/src/index.ts | 1 + libs/remix-simulator/src/VmProxy.ts | 12 ++-- libs/remix-simulator/src/methods/blocks.ts | 32 +++++----- .../src/methods/transactions.ts | 62 ++++++++++++++----- 7 files changed, 78 insertions(+), 41 deletions(-) diff --git a/apps/remix-ide/src/blockchain/providers/worker-vm.ts b/apps/remix-ide/src/blockchain/providers/worker-vm.ts index fddc07f77a..4ba664490c 100644 --- a/apps/remix-ide/src/blockchain/providers/worker-vm.ts +++ b/apps/remix-ide/src/blockchain/providers/worker-vm.ts @@ -1,4 +1,5 @@ import { Provider } from '@remix-project/remix-simulator' +import { bigIntToHex } from '@ethereumjs/util' let provider: Provider = null self.onmessage = (e: MessageEvent) => { @@ -14,7 +15,10 @@ self.onmessage = (e: MessageEvent) => { { if (provider) { provider.sendAsync(data.query, (error, result) => { - result = JSON.parse(JSON.stringify(result)) + result = JSON.parse(JSON.stringify(result, (key, value) => { + if (typeof value === 'bigint') return bigIntToHex(value) + return value + })) self.postMessage({ cmd: 'sendAsyncResult', error, diff --git a/libs/remix-lib/src/execution/txListener.ts b/libs/remix-lib/src/execution/txListener.ts index de94fbf3e6..083f314a0a 100644 --- a/libs/remix-lib/src/execution/txListener.ts +++ b/libs/remix-lib/src/execution/txListener.ts @@ -10,7 +10,7 @@ function addExecutionCosts (txResult, tx, execResult) { if (txResult) { if (execResult) { tx.returnValue = execResult.returnValue - if (execResult.gasUsed) tx.executionCost = execResult.gasUsed.toString(10) + if (execResult.executionGasUsed) tx.executionCost = execResult.executionGasUsed.toString(10) } if (txResult.receipt && txResult.receipt.gasUsed) tx.transactionCost = txResult.receipt.gasUsed.toString(10) } diff --git a/libs/remix-lib/src/execution/txRunnerVM.ts b/libs/remix-lib/src/execution/txRunnerVM.ts index 8dff9f29c3..010f27b31b 100644 --- a/libs/remix-lib/src/execution/txRunnerVM.ts +++ b/libs/remix-lib/src/execution/txRunnerVM.ts @@ -52,7 +52,7 @@ export class TxRunnerVM { this.nextNonceForCall = 0 } - execute (args, confirmationCb, gasEstimationForceSend, promptCb, callback) { + execute (args, confirmationCb, gasEstimationForceSend, promptCb, callback: VMExecutionCallBack) { let data = args.data if (data.slice(0, 2) !== '0x') { data = '0x' + data @@ -136,7 +136,7 @@ export class TxRunnerVM { runBlockInVm (tx, block, callback) { this.getVMObject().vm.runBlock({ block: block, generate: true, skipBlockValidation: true, skipBalance: false, skipNonce: true }).then((results: RunBlockResult) => { - const result = results.results[0] + const result: RunTxResult = results.results[0] /*if (result) { const status = result.execResult.exceptionError ? 0 : 1 result.receipt.status diff --git a/libs/remix-lib/src/index.ts b/libs/remix-lib/src/index.ts index 1f2cdb6676..643df1258e 100644 --- a/libs/remix-lib/src/index.ts +++ b/libs/remix-lib/src/index.ts @@ -18,6 +18,7 @@ import * as txResultHelper from './helpers/txResultHelper' export { ConsoleLogs } from './helpers/hhconsoleSigs' export { ICompilerApi, ConfigurationSettings } from './types/ICompilerApi' export { QueryParams } from './query-params' +export { VMxecutionResult } from './execution/txRunnerVM' const helpers = { ui: uiHelper, diff --git a/libs/remix-simulator/src/VmProxy.ts b/libs/remix-simulator/src/VmProxy.ts index 32e7253b27..5969c106b3 100644 --- a/libs/remix-simulator/src/VmProxy.ts +++ b/libs/remix-simulator/src/VmProxy.ts @@ -8,6 +8,8 @@ import utils from 'web3-utils' import { ethers } from 'ethers' import { VMContext } from './vm-context' import type { InterpreterStep } from '@ethereumjs/evm/dist/interpreter' +import type { AfterTxEvent } from '@ethereumjs/vm' +import type { TypedTransaction } from '@ethereumjs/tx' export class VmProxy { vmContext: VMContext @@ -90,10 +92,10 @@ export class VmProxy { this.vm.evm.events.on('step', async (data: InterpreterStep) => { await this.pushTrace(data) }) - this.vm.events.on('afterTx', async (data: any) => { + this.vm.events.on('afterTx', async (data: AfterTxEvent) => { await this.txProcessed(data) }) - this.vm.events.on('beforeTx', async (data: any) => { + this.vm.events.on('beforeTx', async (data: TypedTransaction) => { await this.txWillProcess(data) }) } @@ -104,7 +106,7 @@ export class VmProxy { return ret } - async txWillProcess (data) { + async txWillProcess (data: TypedTransaction) { this.incr++ this.processingHash = bufferToHex(data.hash()) this.vmTraces[this.processingHash] = { @@ -140,12 +142,12 @@ export class VmProxy { this.processingIndex = 0 } - async txProcessed (data) { + async txProcessed (data: AfterTxEvent) { const lastOp = this.vmTraces[this.processingHash].structLogs[this.processingIndex - 1] if (lastOp) { lastOp.error = lastOp.op !== 'RETURN' && lastOp.op !== 'STOP' && lastOp.op !== 'DESTRUCT' } - const gasUsed = '0x' + data.gasUsed.toString(16) + const gasUsed = '0x' + data.totalGasSpent.toString(16) this.vmTraces[this.processingHash].gas = gasUsed this.txsReceipt[this.processingHash].gasUsed = gasUsed const logs = [] diff --git a/libs/remix-simulator/src/methods/blocks.ts b/libs/remix-simulator/src/methods/blocks.ts index eb82a91d99..93d084c251 100644 --- a/libs/remix-simulator/src/methods/blocks.ts +++ b/libs/remix-simulator/src/methods/blocks.ts @@ -51,22 +51,22 @@ export class Blocks { blockHash: '0x' + block.hash().toString('hex'), blockNumber: bigIntToHex(block.header.number), from: receipt.from, - gas: toHex(receipt.gas), + gas: bigIntToHex(receipt.gas), chainId: '0xd05', gasPrice: '0x4a817c800', // 20000000000 hash: receipt.transactionHash, input: receipt.input, nonce: bigIntToHex(tx.nonce), transactionIndex: this.TX_INDEX, - value: receipt.value === '0x' ? '0x0' : receipt.value, + value: bigIntToHex(tx.value), to: receipt.to ? receipt.to : null } } }) const b = { baseFeePerGas: '0x01', - number: this.toHex(block.header.number), - hash: this.toHex(block.hash()), + number: bigIntToHex(block.header.number), + hash: block.hash(), parentHash: this.toHex(block.header.parentHash), nonce: this.toHex(block.header.nonce), sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', @@ -74,13 +74,13 @@ export class Blocks { transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', stateRoot: this.toHex(block.header.stateRoot), miner: this.coinbase, - difficulty: this.toHex(block.header.difficulty), - totalDifficulty: this.toHex((block.header as any).totalDifficulty), + difficulty: bigIntToHex(block.header.difficulty), + totalDifficulty: bigIntToHex((block.header as any).totalDifficulty || 0), extraData: this.toHex(block.header.extraData), size: '0x027f07', // 163591 - gasLimit: this.toHex(block.header.gasLimit), - gasUsed: this.toHex(block.header.gasUsed), - timestamp: this.toHex(block.header.timestamp), + gasLimit: bigIntToHex(block.header.gasLimit), + gasUsed: bigIntToHex(block.header.gasUsed), + timestamp: bigIntToHex(block.header.timestamp), transactions, uncles: [] } @@ -112,14 +112,14 @@ export class Blocks { input: receipt.input, nonce: bigIntToHex(tx.nonce), transactionIndex: this.TX_INDEX, - value: receipt.value === '0x' ? '0x0' : receipt.value, + value: bigIntToHex(tx.value), to: receipt.to ? receipt.to : null } } }) const b = { baseFeePerGas: '0x01', - number: this.toHex(block.header.number), + number: bigIntToHex(block.header.number), hash: this.toHex(block.hash()), parentHash: this.toHex(block.header.parentHash), nonce: this.toHex(block.header.nonce), @@ -128,13 +128,13 @@ export class Blocks { transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', stateRoot: this.toHex(block.header.stateRoot), miner: this.coinbase, - difficulty: this.toHex(block.header.difficulty), - totalDifficulty: this.toHex((block.header as any).totalDifficulty), + difficulty: bigIntToHex(block.header.difficulty), + totalDifficulty: bigIntToHex((block.header as any).totalDifficulty || 0), extraData: this.toHex(block.header.extraData), size: '0x027f07', // 163591 - gasLimit: this.toHex(block.header.gasLimit), - gasUsed: this.toHex(block.header.gasUsed), - timestamp: this.toHex(block.header.timestamp), + gasLimit: bigIntToHex(block.header.gasLimit), + gasUsed: bigIntToHex(block.header.gasUsed), + timestamp: bigIntToHex(block.header.timestamp), transactions, uncles: [] } diff --git a/libs/remix-simulator/src/methods/transactions.ts b/libs/remix-simulator/src/methods/transactions.ts index 6c60820477..94a8bfc21d 100644 --- a/libs/remix-simulator/src/methods/transactions.ts +++ b/libs/remix-simulator/src/methods/transactions.ts @@ -1,11 +1,24 @@ import { toHex, toDecimal } from 'web3-utils' +import { bigIntToHex } from '@ethereumjs/util' import { toChecksumAddress, BN, Address } from 'ethereumjs-util' import { processTx } from './txProcess' import { execution } from '@remix-project/remix-lib' import { ethers } from 'ethers' +import { VMxecutionResult } from '@remix-project/remix-lib' +import { RunTxResult } from '@ethereumjs/vm' +import { Log, EvmError } from '@ethereumjs/evm' const TxRunnerVM = execution.TxRunnerVM const TxRunner = execution.TxRunner +export type VMExecResult = { + exceptionError: EvmError + executionGasUsed: bigint + gas: bigint + gasRefund: bigint + logs: Log[] + returnValue: Buffer +} + export class Transactions { vmContext accounts @@ -69,12 +82,20 @@ export class Transactions { if (payload.params && payload.params.length > 0 && payload.params[0].from) { payload.params[0].from = toChecksumAddress(payload.params[0].from) } - processTx(this.txRunnerInstance, payload, false, (error, result) => { + processTx(this.txRunnerInstance, payload, false, (error, result: VMxecutionResult) => { if (!error && result) { this.vmContext.addBlock(result.block) const hash = '0x' + result.tx.hash().toString('hex') this.vmContext.trackTx(hash, result.block, result.tx) - this.vmContext.trackExecResult(hash, result.result.execResult) + const execResult: VMExecResult = { + exceptionError: result.result.execResult.exceptionError, + executionGasUsed: result.result.execResult.executionGasUsed, + gas: result.result.execResult.gas, + gasRefund: result.result.execResult.gasRefund, + logs: result.result.execResult.logs, + returnValue: result.result.execResult.returnValue + } + this.vmContext.trackExecResult(hash, execResult) return cb(null, result.transactionHash) } cb(error) @@ -105,7 +126,7 @@ export class Transactions { transactionHash: receipt.hash, transactionIndex: this.TX_INDEX, blockHash: '0x' + txBlock.hash().toString('hex'), - blockNumber: '0x' + txBlock.header.number.toString('hex'), + blockNumber: bigIntToHex(txBlock.header.number), gasUsed: receipt.gasUsed, cumulativeGasUsed: receipt.gasUsed, // only 1 tx per block contractAddress: receipt.contractAddress, @@ -133,9 +154,10 @@ export class Transactions { payload.params[0].gas = 10000000 * 10 - processTx(this.txRunnerInstance, payload, true, (error, { result }) => { + processTx(this.txRunnerInstance, payload, true, (error, value: VMxecutionResult) => { + const result: RunTxResult = value.result if (error) return cb(error) - if (result.status === '0x0') { + if ((result as any).receipt === '0x0') { try { const msg = result.execResult.returnValue const abiCoder = new ethers.utils.AbiCoder() @@ -145,11 +167,11 @@ export class Transactions { return cb(e.message) } } - let gasUsed = result.execResult.gasUsed.toNumber() + let gasUsed = result.execResult.executionGasUsed if (result.execResult.gasRefund) { - gasUsed += result.execResult.gasRefund.toNumber() + gasUsed += result.execResult.gasRefund } - cb(null, Math.ceil(gasUsed + (15 * gasUsed) / 100)) + cb(null, Math.ceil(Number(gasUsed) + (15 * Number(gasUsed)) / 100)) }) } @@ -183,7 +205,15 @@ export class Transactions { this.vmContext.addBlock(result.block) const hash = '0x' + result.tx.hash().toString('hex') this.vmContext.trackTx(hash, result.block, result.tx) - this.vmContext.trackExecResult(hash, result.result.execResult) + const execResult: VMExecResult = { + exceptionError: result.result.execResult.exceptionError, + executionGasUsed: result.result.execResult.executionGasUsed, + gas: result.result.execResult.gas, + gasRefund: result.result.execResult.gasRefund, + logs: result.result.execResult.logs, + returnValue: result.result.execResult.returnValue + } + this.vmContext.trackExecResult(hash, execResult) this.tags[tag] = result.transactionHash // calls are not supposed to return a transaction hash. we do this for keeping track of it and allowing debugging calls. const returnValue = `0x${result.result.execResult.returnValue.toString('hex') || '0'}` @@ -222,7 +252,7 @@ export class Transactions { // TODO: params to add later const r: Record = { blockHash: '0x' + txBlock.hash().toString('hex'), - blockNumber: '0x' + txBlock.header.number.toString('hex'), + blockNumber: bigIntToHex(txBlock.header.number), from: receipt.from, gas: toHex(receipt.gas), chainId: '0xd05', @@ -230,9 +260,9 @@ export class Transactions { gasPrice: '0x4a817c800', // 20000000000 hash: receipt.transactionHash, input: receipt.input, - nonce: '0x' + tx.nonce.toString('hex'), + nonce: bigIntToHex(tx.nonce), transactionIndex: this.TX_INDEX, - value: receipt.value + value: bigIntToHex(tx.value) // "value":"0xf3dbb76162000" // 4290000000000000 // "v": "0x25", // 37 // "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", @@ -271,7 +301,7 @@ export class Transactions { // TODO: params to add later const r: Record = { blockHash: '0x' + txBlock.hash().toString('hex'), - blockNumber: '0x' + txBlock.header.number.toString('hex'), + blockNumber: bigIntToHex(txBlock.header.number), from: receipt.from, gas: toHex(receipt.gas), chainId: '0xd05', @@ -279,7 +309,7 @@ export class Transactions { gasPrice: '0x4a817c800', // 20000000000 hash: receipt.transactionHash, input: receipt.input, - nonce: '0x' + tx.nonce.toString('hex'), + nonce: bigIntToHex(tx.nonce), transactionIndex: this.TX_INDEX, value: receipt.value // "value":"0xf3dbb76162000" // 4290000000000000 @@ -316,7 +346,7 @@ export class Transactions { // TODO: params to add later const r: Record = { blockHash: '0x' + txBlock.hash().toString('hex'), - blockNumber: '0x' + txBlock.header.number.toString('hex'), + blockNumber: bigIntToHex(txBlock.header.number), from: receipt.from, gas: toHex(receipt.gas), // 'gasPrice': '2000000000000', // 0x123 @@ -324,7 +354,7 @@ export class Transactions { gasPrice: '0x4a817c800', // 20000000000 hash: receipt.transactionHash, input: receipt.input, - nonce: '0x' + tx.nonce.toString('hex'), + nonce: bigIntToHex(tx.nonce), transactionIndex: this.TX_INDEX, value: receipt.value // "value":"0xf3dbb76162000" // 4290000000000000