From 0e4fb48e8c5a9a987da5a67bae262fb9359bf3bd Mon Sep 17 00:00:00 2001 From: ben-chain Date: Fri, 24 Apr 2020 12:30:56 -0400 Subject: [PATCH 01/29] pass RevertErrors up in full node --- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index bf608c471ad3..4398a663a755 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -41,6 +41,7 @@ import { UnsupportedMethodError, Web3Handler, Web3RpcMethods, + RevertError, } from '../types' import { initializeL2Node, getCurrentTime } from './utils' import { NoOpL2ToL1MessageSubmitter } from './message-submitter' @@ -616,14 +617,14 @@ export class DefaultWeb3Handler } catch (e) { logError( log, - `Error executing transaction!\n\nIncrementing nonce for sender (${ovmTx.from} and returning failed tx hash. Ovm tx hash: ${ovmTxHash}, internal hash: ${internalTxHash}.`, + `Error executing internal transaction!\n\nIncrementing nonce for sender (${ovmTx.from} and returning failed tx hash. Ovm tx hash: ${ovmTxHash}, internal hash: ${internalTxHash}.`, e ) await this.context.executionManager.incrementNonce(add0x(ovmTx.from)) log.debug(`Nonce incremented successfully for ${ovmTx.from}.`) - return ovmTxHash + throw new RevertError(e.message as string) } if (remove0x(internalTxHash) !== remove0x(returnedInternalTxHash)) { @@ -898,7 +899,7 @@ export class DefaultWeb3Handler ovmTx.data, ovmFrom, ZERO_ADDRESS, - false + true ) log.debug(`EOA calldata: [${internalCalldata}]`) From 413a98f28bac3c7a0b43bbaffebc914d622455c3 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Fri, 24 Apr 2020 16:36:17 -0400 Subject: [PATCH 02/29] revert messages working, receipts not --- .../test/app/web-rpc-handler.spec.ts | 64 ++++++++++++++++++- .../contracts/transpiled/SimpleReversion.sol | 10 +++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index a5076874c41d..c1b24c3b9856 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -9,7 +9,7 @@ import { ZERO_ADDRESS, hexStrToBuf, } from '@eth-optimism/core-utils' -import { CHAIN_ID } from '@eth-optimism/ovm' +import { CHAIN_ID, convertInternalLogsToOvmLogs } from '@eth-optimism/ovm' import { ethers, ContractFactory, Wallet, Contract, utils } from 'ethers' import { resolve } from 'path' @@ -21,6 +21,7 @@ import assert from 'assert' import { FullnodeRpcServer, DefaultWeb3Handler } from '../../src/app' import * as SimpleStorage from '../contracts/build/untranspiled/SimpleStorage.json' import * as EventEmitter from '../contracts/build/untranspiled/EventEmitter.json' +import * as SimpleReversion from '../contracts/build/transpiled/SimpleReversion.json' import { Web3RpcMethods } from '../../src/types' const log = getLogger('web3-handler', true) @@ -115,6 +116,22 @@ export const getUnsignedTransactionCalldata = ( return contract.interface.functions[functionName].encode(args) } +const assertAsyncThrowsWithMessage = async ( + func: () => Promise, + message: string +): Promise => { + let succeeded = true + try { + await func() + succeeded = false + } catch (e) { + if (e.message !== message) { + succeeded = false + } + } + succeeded.should.equal(true, 'Function didn\'t throw as expected or threw with the wrong error message.' ) +} + /********* * TESTS * *********/ @@ -151,6 +168,51 @@ describe('Web3Handler', () => { }) }) + describe.only('EVM reversion handling', async () => { + let wallet + let simpleReversion + beforeEach(async () => { + wallet = getWallet(httpProvider) + const factory = new ContractFactory( + SimpleReversion.abi, + SimpleReversion.bytecode, + wallet + ) + simpleReversion = await factory.deploy() + }) + it('Should propogate generic internal EVM reverts upwards for sendRawTransaction', async () => { + await assertAsyncThrowsWithMessage( + async () => { + await simpleReversion.doRevert() + }, + 'VM Exception while processing transaction: revert' + ) + }) + it('Should propogate solidity require messages upwards for sendRawTransaction', async () => { + const solidityRevertMessage = 'trolololo' + await assertAsyncThrowsWithMessage( + async () => { + await simpleReversion.doRevertWithMessage(solidityRevertMessage) + }, + 'VM Exception while processing transaction: revert ' + solidityRevertMessage + ) + }) + it('Logs should acknowledge the reversion as well', async () => { + // this will fail, but that's fine, we want it to and then check its logs + try { + await simpleReversion.doRevert() + } catch {} + const receipt = ( + await httpProvider.getTransactionReceipt( + '0xade9e00b889b02e994f9ef2d652f3fdb6f34c5862c4a78e959b2b36c79142dc9' + ) + ) + log.debug(`the receipt is: ${JSON.stringify(receipt)}`) + // .map((x) => simpleReversion.interface.parseLog(x)) + }) + + }) + describe('the getBlockByNumber endpoint', () => { it('should return a block with the correct timestamp', async () => { const block = await httpProvider.getBlock('latest') diff --git a/packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol b/packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol new file mode 100644 index 000000000000..39496a7c55a1 --- /dev/null +++ b/packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol @@ -0,0 +1,10 @@ +pragma solidity ^0.5.0; + +contract SimpleReversion { + function doRevert() public { + revert(); + } + function doRevertWithMessage(string memory _message) public { + require(false, _message); + } +} \ No newline at end of file From 291a4d531be22aecb937e27236c627bc7489a2fd Mon Sep 17 00:00:00 2001 From: ben-chain Date: Fri, 24 Apr 2020 17:54:17 -0400 Subject: [PATCH 03/29] receipts working for failed txs --- packages/ovm/src/app/utils.ts | 24 +++++++----- .../ovm/src/contracts/ExecutionManager.sol | 8 +++- packages/ovm/test/app/utils.spec.ts | 30 ++------------- .../src/app/web3-rpc-handler.ts | 37 +++++++++++++++---- .../test/app/test-web-rpc-handler.spec.ts | 2 +- .../test/app/web-rpc-handler.spec.ts | 30 ++++++--------- 6 files changed, 68 insertions(+), 63 deletions(-) diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 41cc618597ec..210c921c46a8 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -97,7 +97,7 @@ export const convertInternalLogsToOvmLogs = (logs: Log[]): Log[] => { * @param internalTxReceipt the internal transaction receipt * @return ovm transaction metadata */ -export const getOvmTransactionMetadata = ( +export const getSuccessfulOvmTransactionMetadata = ( internalTxReceipt: TransactionReceipt ): OvmTransactionMetadata => { let ovmTo @@ -113,9 +113,6 @@ export const getOvmTransactionMetadata = ( .map((log) => executionManagerInterface.parseLog(log)) .filter((log) => log != null) const callingWithEoaLog = logs.find((log) => log.name === 'CallingWithEOA') - const eoaContractCreatedLog = logs.find( - (log) => log.name === 'EOACreatedContract' - ) const revertEvents: LogDescription[] = logs.filter( (x) => x.name === 'EOACallRevert' @@ -125,9 +122,15 @@ export const getOvmTransactionMetadata = ( if (callingWithEoaLog) { ovmFrom = callingWithEoaLog.values._ovmFromAddress } + + const eoaContractCreatedLog = logs.find( + (log) => log.name === 'EOACreatedContract' + ) if (eoaContractCreatedLog) { ovmCreatedContractAddress = eoaContractCreatedLog.values._ovmContractAddress ovmTo = ovmCreatedContractAddress + } else { + ovmTo = callingWithEoaLog.values._ovmToAddress } const metadata: OvmTransactionMetadata = { @@ -174,20 +177,23 @@ export const internalTxReceiptToOvmTxReceipt = async ( internalTxReceipt: TransactionReceipt, ovmTxHash?: string ): Promise => { - const ovmTransactionMetadata = getOvmTransactionMetadata(internalTxReceipt) + const ovmTransactionMetadata = getSuccessfulOvmTransactionMetadata(internalTxReceipt) // Construct a new receipt // // Start off with the internalTxReceipt const ovmTxReceipt: OvmTransactionReceipt = internalTxReceipt // Add the converted logs ovmTxReceipt.logs = convertInternalLogsToOvmLogs(internalTxReceipt.logs) - // Update the to and from fields - ovmTxReceipt.to = ovmTransactionMetadata.ovmTo + // Update the to and from fields if necessary + if (ovmTransactionMetadata.ovmTo) { + ovmTxReceipt.to = ovmTransactionMetadata.ovmTo + } // TODO: Update this to use some default account abstraction library potentially. ovmTxReceipt.from = ovmTransactionMetadata.ovmFrom // Also update the contractAddress in case we deployed a new contract - ovmTxReceipt.contractAddress = - ovmTransactionMetadata.ovmCreatedContractAddress + ovmTxReceipt.contractAddress = !!ovmTransactionMetadata.ovmCreatedContractAddress + ? ovmTransactionMetadata.ovmCreatedContractAddress + : null ovmTxReceipt.status = ovmTransactionMetadata.ovmTxSucceeded ? 1 : 0 diff --git a/packages/ovm/src/contracts/ExecutionManager.sol b/packages/ovm/src/contracts/ExecutionManager.sol index 0e7d97b35c10..14a92a387b8b 100644 --- a/packages/ovm/src/contracts/ExecutionManager.sol +++ b/packages/ovm/src/contracts/ExecutionManager.sol @@ -47,7 +47,8 @@ contract ExecutionManager is FullStateManager { bytes32 _codeContractHash ); event CallingWithEOA( - address _ovmFromAddress + address _ovmFromAddress, + address _ovmToAddress ); event EOACreatedContract( address _ovmContractAddress @@ -137,7 +138,10 @@ contract ExecutionManager is FullStateManager { require(eoaAddress != ZERO_ADDRESS, "Failed to recover signature"); // Require nonce to be correct require(_nonce == getOvmContractNonce(eoaAddress), "Incorrect nonce!"); - emit CallingWithEOA(eoaAddress); + emit CallingWithEOA( + eoaAddress, + _ovmEntrypoint + ); // Make the EOA call for the account executeTransaction(_timestamp, _queueOrigin, _ovmEntrypoint, _callBytes, eoaAddress, ZERO_ADDRESS, false); } diff --git a/packages/ovm/test/app/utils.spec.ts b/packages/ovm/test/app/utils.spec.ts index 4c55d7ccaa60..95b83878b1d6 100644 --- a/packages/ovm/test/app/utils.spec.ts +++ b/packages/ovm/test/app/utils.spec.ts @@ -10,7 +10,7 @@ import { import { TransactionReceipt } from 'ethers/providers' import { convertInternalLogsToOvmLogs, - getOvmTransactionMetadata, + getSuccessfulOvmTransactionMetadata, OvmTransactionMetadata, revertMessagePrefix, } from '../../src/app' @@ -43,13 +43,13 @@ describe('convertInternalLogsToOvmLogs', () => { }) }) -describe('getOvmTransactionMetadata', () => { +describe('getSuccessfulOvmTransactionMetadata', () => { it('should return transaction metadata from calls from externally owned accounts', async () => { const transactionReceipt: TransactionReceipt = { byzantium: true, logs: [ [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [ALICE]], - [EXECUTION_MANAGER_ADDRESS, 'CallingWithEOA(address)', [ALICE]], + [EXECUTION_MANAGER_ADDRESS, 'CallingWithEOA(address,address)', [ALICE,CONTRACT]], [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [ALICE]], [EXECUTION_MANAGER_ADDRESS, 'EOACreatedContract(address)', [CONTRACT]], [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [CONTRACT]], @@ -61,33 +61,11 @@ describe('getOvmTransactionMetadata', () => { ].map((args) => buildLog.apply(null, args)), } - getOvmTransactionMetadata(transactionReceipt).should.deep.eq({ + getSuccessfulOvmTransactionMetadata(transactionReceipt).should.deep.eq({ ovmCreatedContractAddress: CONTRACT, ovmFrom: ALICE, ovmTo: CONTRACT, ovmTxSucceeded: true, }) }) - - it('should return with ovmTxSucceeded equal to false if the transaction reverted', async () => { - const revertMessage: string = 'The tx reverted!' - const msgHex: string = add0x( - Buffer.from(revertMessage, 'utf8').toString('hex') - ) - const encodedMessage: string = abi.encode(['bytes'], [msgHex]) - // needs 4 bytes of sighash - const eventData: string = add0x('ab'.repeat(4) + remove0x(encodedMessage)) - const transactionReceipt: TransactionReceipt = { - byzantium: true, - logs: [ - [EXECUTION_MANAGER_ADDRESS, 'EOACallRevert(bytes)', [eventData]], - ].map((args) => buildLog.apply(null, args)), - } - - const metadata: OvmTransactionMetadata = getOvmTransactionMetadata( - transactionReceipt - ) - metadata.ovmTxSucceeded.should.eq(false) - metadata.revertMessage.should.eq(revertMessagePrefix + revertMessage) - }) }) diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 4398a663a755..daab028f8db4 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -376,6 +376,9 @@ export class DefaultWeb3Handler ? ovmTx[key].toNumber() : ovmTx[key] } + if (typeof transaction[key] === 'number') { + transaction[key] = numberToHexString(transaction[key]) + } }) return transaction @@ -537,18 +540,38 @@ export class DefaultWeb3Handler return null } - // Now let's parse the internal transaction reciept - const ovmTxReceipt: OvmTransactionReceipt = await internalTxReceiptToOvmTxReceipt( - internalTxReceipt, - ovmTxHash - ) + log.debug(`Converting internal tx receipt to ovm receipt, internal receipt is:`, internalTxReceipt) + + // if there are no logs, the tx must have failed, as the Execution Mgr always logs stuff + const txSucceeded: boolean = internalTxReceipt.logs.length !== 0 + let ovmTxReceipt + if (txSucceeded) { + log.debug(`The internal tx previously succeeded for this OVM tx, converting internal receipt to OVM receipt...`) + ovmTxReceipt = await internalTxReceiptToOvmTxReceipt( + internalTxReceipt, + ovmTxHash + ) + } else { + log.debug(`Internal tx previously failed for this OVM tx, creating receipt from the OVM tx itself.`) + const rawOvmTx = await this.getOvmTransactionByHash(ovmTxHash) + const ovmTx = utils.parseTransaction(rawOvmTx) + // for a failing tx, everything is identical between the internal and external receipts, except to and from + ovmTxReceipt = internalTxReceipt + ovmTxReceipt.from = ovmTx.from + ovmTxReceipt.to = ovmTx.to + } + if (ovmTxReceipt.revertMessage !== undefined && !includeRevertMessage) { delete ovmTxReceipt.revertMessage } + if (typeof ovmTxReceipt.status === 'number') { + ovmTxReceipt.status = numberToHexString(ovmTxReceipt.status) + } + log.debug( `Returning tx receipt for ovm tx hash [${ovmTxHash}]: [${JSON.stringify( - internalTxReceipt + ovmTxReceipt )}]` ) return ovmTxReceipt @@ -705,7 +728,7 @@ export class DefaultWeb3Handler ) throw e } - log.debug(`L1 to L2 Transaction mined. Tx hash: ${receipt.hash}`) + log.debug(`L1 to L2 Transaction applied to L2. Tx hash: ${receipt.hash}`) try { const ovmTxReceipt: OvmTransactionReceipt = await internalTxReceiptToOvmTxReceipt( diff --git a/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts index 459ab7d560b4..a46afb7052ec 100644 --- a/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts @@ -22,7 +22,7 @@ import { import * as SimpleStorage from '../contracts/build/untranspiled/SimpleStorage.json' import * as EmptyContract from '../contracts/build/untranspiled/EmptyContract.json' import * as CallerStorer from '../contracts/build/transpiled/CallerStorer.json' -import { getOvmTransactionMetadata } from '@eth-optimism/ovm' +import { getSuccessfulOvmTransactionMetadata } from '@eth-optimism/ovm' const log = getLogger('test-web3-handler', true) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index c1b24c3b9856..62ef18833114 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -129,7 +129,10 @@ const assertAsyncThrowsWithMessage = async ( succeeded = false } } - succeeded.should.equal(true, 'Function didn\'t throw as expected or threw with the wrong error message.' ) + succeeded.should.equal( + true, + "Function didn't throw as expected or threw with the wrong error message." + ) } /********* @@ -181,36 +184,27 @@ describe('Web3Handler', () => { simpleReversion = await factory.deploy() }) it('Should propogate generic internal EVM reverts upwards for sendRawTransaction', async () => { - await assertAsyncThrowsWithMessage( - async () => { - await simpleReversion.doRevert() - }, - 'VM Exception while processing transaction: revert' - ) + await assertAsyncThrowsWithMessage(async () => { + await simpleReversion.doRevert() + }, 'VM Exception while processing transaction: revert') }) it('Should propogate solidity require messages upwards for sendRawTransaction', async () => { const solidityRevertMessage = 'trolololo' - await assertAsyncThrowsWithMessage( - async () => { - await simpleReversion.doRevertWithMessage(solidityRevertMessage) - }, - 'VM Exception while processing transaction: revert ' + solidityRevertMessage - ) + await assertAsyncThrowsWithMessage(async () => { + await simpleReversion.doRevertWithMessage(solidityRevertMessage) + }, 'VM Exception while processing transaction: revert ' + solidityRevertMessage) }) it('Logs should acknowledge the reversion as well', async () => { // this will fail, but that's fine, we want it to and then check its logs try { await simpleReversion.doRevert() } catch {} - const receipt = ( - await httpProvider.getTransactionReceipt( - '0xade9e00b889b02e994f9ef2d652f3fdb6f34c5862c4a78e959b2b36c79142dc9' - ) + const receipt = await httpProvider.getTransactionReceipt( + '0xade9e00b889b02e994f9ef2d652f3fdb6f34c5862c4a78e959b2b36c79142dc9' ) log.debug(`the receipt is: ${JSON.stringify(receipt)}`) // .map((x) => simpleReversion.interface.parseLog(x)) }) - }) describe('the getBlockByNumber endpoint', () => { From f5cb2a01145257c9683b502f480cf01bf36c6feb Mon Sep 17 00:00:00 2001 From: ben-chain Date: Fri, 24 Apr 2020 18:50:27 -0400 Subject: [PATCH 04/29] test receipt generation for reverting txns' --- .../src/app/web3-rpc-handler.ts | 2 +- .../test/app/test-web-rpc-handler.spec.ts | 1 - .../test/app/web-rpc-handler.spec.ts | 40 ++++++++++++++----- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index daab028f8db4..a7294d64e52d 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -828,7 +828,7 @@ export class DefaultWeb3Handler .waitForTransaction(res.hash) .then((receipt) => { log.debug( - `Got receipt mapping ${ovmTxHash} to ${internalTxHash}: ${JSON.stringify( + `Got receipt mapping ovm tx hash ${ovmTxHash} to internal tx hash ${internalTxHash}: ${JSON.stringify( receipt )}` ) diff --git a/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts index a46afb7052ec..10ae540a9864 100644 --- a/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts @@ -22,7 +22,6 @@ import { import * as SimpleStorage from '../contracts/build/untranspiled/SimpleStorage.json' import * as EmptyContract from '../contracts/build/untranspiled/EmptyContract.json' import * as CallerStorer from '../contracts/build/transpiled/CallerStorer.json' -import { getSuccessfulOvmTransactionMetadata } from '@eth-optimism/ovm' const log = getLogger('test-web3-handler', true) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 62ef18833114..d2e9c3db0a6b 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -11,7 +11,7 @@ import { } from '@eth-optimism/core-utils' import { CHAIN_ID, convertInternalLogsToOvmLogs } from '@eth-optimism/ovm' -import { ethers, ContractFactory, Wallet, Contract, utils } from 'ethers' +import { ethers, ContractFactory, Wallet, Contract, utils, providers } from 'ethers' import { resolve } from 'path' import * as rimraf from 'rimraf' import * as fs from 'fs' @@ -33,6 +33,8 @@ const port = 9999 const storageKey = '0x' + '01'.repeat(32) const storageValue = '0x' + '02'.repeat(32) +const EVM_REVERT_MSG = 'VM Exception while processing transaction: revert' + const tmpFilePath = resolve(__dirname, `./.test_db`) const getWallet = (httpProvider) => { @@ -171,7 +173,7 @@ describe('Web3Handler', () => { }) }) - describe.only('EVM reversion handling', async () => { + describe('EVM reversion handling', async () => { let wallet let simpleReversion beforeEach(async () => { @@ -186,24 +188,40 @@ describe('Web3Handler', () => { it('Should propogate generic internal EVM reverts upwards for sendRawTransaction', async () => { await assertAsyncThrowsWithMessage(async () => { await simpleReversion.doRevert() - }, 'VM Exception while processing transaction: revert') + }, EVM_REVERT_MSG) }) it('Should propogate solidity require messages upwards for sendRawTransaction', async () => { const solidityRevertMessage = 'trolololo' await assertAsyncThrowsWithMessage(async () => { await simpleReversion.doRevertWithMessage(solidityRevertMessage) - }, 'VM Exception while processing transaction: revert ' + solidityRevertMessage) + }, EVM_REVERT_MSG + ' ' + solidityRevertMessage) }) - it('Logs should acknowledge the reversion as well', async () => { - // this will fail, but that's fine, we want it to and then check its logs + it('Should serve receipts for reverting transactions', async () => { + const revertingTx = { + nonce: await wallet.getTransactionCount(), + gasPrice: 0, + gasLimit: 9999999999, + to: simpleReversion.address, + chainId: CHAIN_ID, + data: simpleReversion.interface.functions[ + 'doRevert' + ].encode([]) + } + const signedTx = await wallet.sign(revertingTx) + const txHash = ethers.utils.keccak256(signedTx) try { - await simpleReversion.doRevert() - } catch {} + await httpProvider.send( + 'eth_sendRawTransaction', + [signedTx] + ) + } catch(e) { + e.message.should.equal(EVM_REVERT_MSG, 'expected EVM revert but got some other error!') + } const receipt = await httpProvider.getTransactionReceipt( - '0xade9e00b889b02e994f9ef2d652f3fdb6f34c5862c4a78e959b2b36c79142dc9' + txHash ) - log.debug(`the receipt is: ${JSON.stringify(receipt)}`) - // .map((x) => simpleReversion.interface.parseLog(x)) + receipt.from.should.equal(wallet.address) + receipt.to.should.equal(simpleReversion.address) }) }) From 60afc7489af466078459a9890f67a16295f3fb63 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Fri, 24 Apr 2020 19:15:58 -0400 Subject: [PATCH 05/29] bugfix, linting --- packages/ovm/src/app/utils.ts | 7 ++--- packages/ovm/test/app/utils.spec.ts | 6 ++++- .../src/app/web3-rpc-handler.ts | 15 ++++++++--- .../test/app/web-rpc-handler.spec.ts | 27 ++++++++++--------- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 210c921c46a8..c000794aa409 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -121,6 +121,7 @@ export const getSuccessfulOvmTransactionMetadata = ( if (callingWithEoaLog) { ovmFrom = callingWithEoaLog.values._ovmFromAddress + ovmTo = callingWithEoaLog.values._ovmToAddress } const eoaContractCreatedLog = logs.find( @@ -129,8 +130,6 @@ export const getSuccessfulOvmTransactionMetadata = ( if (eoaContractCreatedLog) { ovmCreatedContractAddress = eoaContractCreatedLog.values._ovmContractAddress ovmTo = ovmCreatedContractAddress - } else { - ovmTo = callingWithEoaLog.values._ovmToAddress } const metadata: OvmTransactionMetadata = { @@ -177,7 +176,9 @@ export const internalTxReceiptToOvmTxReceipt = async ( internalTxReceipt: TransactionReceipt, ovmTxHash?: string ): Promise => { - const ovmTransactionMetadata = getSuccessfulOvmTransactionMetadata(internalTxReceipt) + const ovmTransactionMetadata = getSuccessfulOvmTransactionMetadata( + internalTxReceipt + ) // Construct a new receipt // // Start off with the internalTxReceipt diff --git a/packages/ovm/test/app/utils.spec.ts b/packages/ovm/test/app/utils.spec.ts index 95b83878b1d6..5ca2170e75aa 100644 --- a/packages/ovm/test/app/utils.spec.ts +++ b/packages/ovm/test/app/utils.spec.ts @@ -49,7 +49,11 @@ describe('getSuccessfulOvmTransactionMetadata', () => { byzantium: true, logs: [ [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [ALICE]], - [EXECUTION_MANAGER_ADDRESS, 'CallingWithEOA(address,address)', [ALICE,CONTRACT]], + [ + EXECUTION_MANAGER_ADDRESS, + 'CallingWithEOA(address,address)', + [ALICE, CONTRACT], + ], [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [ALICE]], [EXECUTION_MANAGER_ADDRESS, 'EOACreatedContract(address)', [CONTRACT]], [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [CONTRACT]], diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index a7294d64e52d..cfa178ac15a5 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -540,19 +540,26 @@ export class DefaultWeb3Handler return null } - log.debug(`Converting internal tx receipt to ovm receipt, internal receipt is:`, internalTxReceipt) - + log.debug( + `Converting internal tx receipt to ovm receipt, internal receipt is:`, + internalTxReceipt + ) + // if there are no logs, the tx must have failed, as the Execution Mgr always logs stuff const txSucceeded: boolean = internalTxReceipt.logs.length !== 0 let ovmTxReceipt if (txSucceeded) { - log.debug(`The internal tx previously succeeded for this OVM tx, converting internal receipt to OVM receipt...`) + log.debug( + `The internal tx previously succeeded for this OVM tx, converting internal receipt to OVM receipt...` + ) ovmTxReceipt = await internalTxReceiptToOvmTxReceipt( internalTxReceipt, ovmTxHash ) } else { - log.debug(`Internal tx previously failed for this OVM tx, creating receipt from the OVM tx itself.`) + log.debug( + `Internal tx previously failed for this OVM tx, creating receipt from the OVM tx itself.` + ) const rawOvmTx = await this.getOvmTransactionByHash(ovmTxHash) const ovmTx = utils.parseTransaction(rawOvmTx) // for a failing tx, everything is identical between the internal and external receipts, except to and from diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index d2e9c3db0a6b..6b0f8cd920be 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -11,7 +11,14 @@ import { } from '@eth-optimism/core-utils' import { CHAIN_ID, convertInternalLogsToOvmLogs } from '@eth-optimism/ovm' -import { ethers, ContractFactory, Wallet, Contract, utils, providers } from 'ethers' +import { + ethers, + ContractFactory, + Wallet, + Contract, + utils, + providers, +} from 'ethers' import { resolve } from 'path' import * as rimraf from 'rimraf' import * as fs from 'fs' @@ -203,23 +210,19 @@ describe('Web3Handler', () => { gasLimit: 9999999999, to: simpleReversion.address, chainId: CHAIN_ID, - data: simpleReversion.interface.functions[ - 'doRevert' - ].encode([]) + data: simpleReversion.interface.functions['doRevert'].encode([]), } const signedTx = await wallet.sign(revertingTx) const txHash = ethers.utils.keccak256(signedTx) try { - await httpProvider.send( - 'eth_sendRawTransaction', - [signedTx] + await httpProvider.send('eth_sendRawTransaction', [signedTx]) + } catch (e) { + e.message.should.equal( + EVM_REVERT_MSG, + 'expected EVM revert but got some other error!' ) - } catch(e) { - e.message.should.equal(EVM_REVERT_MSG, 'expected EVM revert but got some other error!') } - const receipt = await httpProvider.getTransactionReceipt( - txHash - ) + const receipt = await httpProvider.getTransactionReceipt(txHash) receipt.from.should.equal(wallet.address) receipt.to.should.equal(simpleReversion.address) }) From 038c2ff80eff5645ebcbf739ea386997d729693f Mon Sep 17 00:00:00 2001 From: ben-chain Date: Sat, 25 Apr 2020 14:59:11 -0400 Subject: [PATCH 06/29] fix eth_call reversion errors --- .../rollup-full-node/src/app/utils/l2-node.ts | 14 ++++++++++ .../src/app/web3-rpc-handler.ts | 27 +++++++++++++------ .../test/app/web-rpc-handler.spec.ts | 16 ++++++++--- .../contracts/transpiled/SimpleReversion.sol | 6 +++++ 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/packages/rollup-full-node/src/app/utils/l2-node.ts b/packages/rollup-full-node/src/app/utils/l2-node.ts index 0e5994cc82d1..40d1849967b0 100644 --- a/packages/rollup-full-node/src/app/utils/l2-node.ts +++ b/packages/rollup-full-node/src/app/utils/l2-node.ts @@ -212,3 +212,17 @@ function getL2ToL1MessagePasserContract(wallet: Wallet): Contract { wallet ) } + +/** + * Detects whether an internal L2 node error is due to an EVM revert or some other error + * + * @param e The error message reterned from either eth_sendRawTransaction or eth_call on the internal L2 node + * @returns Whether the error is an EVM revert error or some other issue. + */ +export function isErrorEVMRevert(e: any): boolean { + return ( + !!e.results && + !!Object.keys(e.results)[0] && + e.results[Object.keys(e.results)[0]].error === 'revert' + ) +} diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index cfa178ac15a5..25e855b4c8e5 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -43,7 +43,7 @@ import { Web3RpcMethods, RevertError, } from '../types' -import { initializeL2Node, getCurrentTime } from './utils' +import { initializeL2Node, getCurrentTime, isErrorEVMRevert } from './utils' import { NoOpL2ToL1MessageSubmitter } from './message-submitter' const log = getLogger('web3-handler') @@ -242,10 +242,17 @@ export class DefaultWeb3Handler ]) } catch (e) { log.debug( - `Error executing call: ${JSON.stringify( + `Internal error executing call: ${JSON.stringify( txObject )}, default block: ${defaultBlock}, error: ${JSON.stringify(e)}` ) + console.log('here') + if (isErrorEVMRevert(e)) { + log.debug( + `Internal error appears to be an EVM revert, surfacing revert message up...` + ) + throw new RevertError(e.message as string) + } throw e } @@ -645,16 +652,20 @@ export class DefaultWeb3Handler [internalTx] ) } catch (e) { + if (isErrorEVMRevert(e)) { + log.debug( + `Internal EVM revert for Ovm tx hash: ${ovmTxHash} and internal hash: ${internalTxHash}. Incrementing nonce Incrementing nonce for sender (${ovmTx.from}) and surfacing revert message up...` + ) + await this.context.executionManager.incrementNonce(add0x(ovmTx.from)) + log.debug(`Nonce incremented successfully for ${ovmTx.from}.`) + throw new RevertError(e.message as string) + } logError( log, - `Error executing internal transaction!\n\nIncrementing nonce for sender (${ovmTx.from} and returning failed tx hash. Ovm tx hash: ${ovmTxHash}, internal hash: ${internalTxHash}.`, + `Non-revert error executing internal transaction! Ovm tx hash: ${ovmTxHash}, internal hash: ${internalTxHash}. Returning generic internal error.`, e ) - - await this.context.executionManager.incrementNonce(add0x(ovmTx.from)) - log.debug(`Nonce incremented successfully for ${ovmTx.from}.`) - - throw new RevertError(e.message as string) + throw e } if (remove0x(internalTxHash) !== remove0x(returnedInternalTxHash)) { diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 6b0f8cd920be..d3454892c20b 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -183,6 +183,7 @@ describe('Web3Handler', () => { describe('EVM reversion handling', async () => { let wallet let simpleReversion + const solidityRevertMessage = 'trolololo' beforeEach(async () => { wallet = getWallet(httpProvider) const factory = new ContractFactory( @@ -192,13 +193,12 @@ describe('Web3Handler', () => { ) simpleReversion = await factory.deploy() }) - it('Should propogate generic internal EVM reverts upwards for sendRawTransaction', async () => { + it('Should propogate generic internal EVM reverts upwards for eth_sendRawTransaction', async () => { await assertAsyncThrowsWithMessage(async () => { await simpleReversion.doRevert() }, EVM_REVERT_MSG) }) - it('Should propogate solidity require messages upwards for sendRawTransaction', async () => { - const solidityRevertMessage = 'trolololo' + it('Should propogate solidity require messages upwards for eth_sendRawTransaction', async () => { await assertAsyncThrowsWithMessage(async () => { await simpleReversion.doRevertWithMessage(solidityRevertMessage) }, EVM_REVERT_MSG + ' ' + solidityRevertMessage) @@ -226,6 +226,16 @@ describe('Web3Handler', () => { receipt.from.should.equal(wallet.address) receipt.to.should.equal(simpleReversion.address) }) + it('Should propogate generic EVM reverts for eth_call', async () => { + await assertAsyncThrowsWithMessage(async () => { + await simpleReversion.doRevertPure() + }, EVM_REVERT_MSG) + }) + it('Should propogate custom message EVM reverts for eth_call', async () => { + await assertAsyncThrowsWithMessage(async () => { + await simpleReversion.doRevertWithMessagePure(solidityRevertMessage) + }, EVM_REVERT_MSG + ' ' + solidityRevertMessage) + }) }) describe('the getBlockByNumber endpoint', () => { diff --git a/packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol b/packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol index 39496a7c55a1..df9d32d556da 100644 --- a/packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol +++ b/packages/rollup-full-node/test/contracts/transpiled/SimpleReversion.sol @@ -7,4 +7,10 @@ contract SimpleReversion { function doRevertWithMessage(string memory _message) public { require(false, _message); } + function doRevertPure() public pure { + revert(); + } + function doRevertWithMessagePure(string memory _message) public pure { + require(false, _message); + } } \ No newline at end of file From 9ce3e33729c257d40ce4e2c880a80a79f62cc3e4 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Sat, 25 Apr 2020 15:04:21 -0400 Subject: [PATCH 07/29] linting --- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 25e855b4c8e5..e325e904a391 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -246,7 +246,6 @@ export class DefaultWeb3Handler txObject )}, default block: ${defaultBlock}, error: ${JSON.stringify(e)}` ) - console.log('here') if (isErrorEVMRevert(e)) { log.debug( `Internal error appears to be an EVM revert, surfacing revert message up...` From 2102ae398fb44cc0d5828c0c9a95c5d9f8928c86 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Sun, 26 Apr 2020 14:59:06 -0400 Subject: [PATCH 08/29] fix test sendTransaction endpoint to match spec --- packages/core-utils/src/app/misc.ts | 19 ------------------- .../src/app/fullnode-rpc-server.ts | 2 +- .../src/app/test-web3-rpc-handler.ts | 15 ++++++++------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/packages/core-utils/src/app/misc.ts b/packages/core-utils/src/app/misc.ts index b22163b78f36..d6828f9f06b3 100644 --- a/packages/core-utils/src/app/misc.ts +++ b/packages/core-utils/src/app/misc.ts @@ -290,22 +290,3 @@ export const runInDomain = async ( export const getCurrentTime = (): number => { return Math.round(Date.now() / 1000) } -/** - * Encodes a transaction in RLP format, using a random signature - * @param {object} Transaction object - */ -export const rlpEncodeTransactionWithRandomSig = ( - transaction: object -): string => { - return RLP.encode([ - hexlify(transaction['nonce']), - hexlify(transaction['gasPrice']), - hexlify(transaction['gasLimit']), - hexlify(transaction['to']), - hexlify(transaction['value']), - hexlify(transaction['data']), - '0x11', // v - '0x' + '11'.repeat(32), // r - '0x' + '11'.repeat(32), // s - ]) -} diff --git a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts index 7d8ff4d079dc..bc5d9204c684 100644 --- a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts +++ b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts @@ -119,7 +119,7 @@ export class FullnodeRpcServer extends ExpressHttpServer { ) return buildJsonRpcError('INVALID_PARAMS', request.id) } - logError(log, `Uncaught exception at endpoint-level`, err) + logError(log, `Uncaught exception at endpoint-level for request [${JSON.stringify(request)}]:`, err) return buildJsonRpcError( 'INTERNAL_ERROR', request && request.id ? request.id : null diff --git a/packages/rollup-full-node/src/app/test-web3-rpc-handler.ts b/packages/rollup-full-node/src/app/test-web3-rpc-handler.ts index 40722c4ecb46..254cdabca864 100644 --- a/packages/rollup-full-node/src/app/test-web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/test-web3-rpc-handler.ts @@ -4,7 +4,6 @@ import { getLogger, numberToHexString, castToNumber, - rlpEncodeTransactionWithRandomSig, ZERO_ADDRESS, } from '@eth-optimism/core-utils' import { GAS_LIMIT } from '@eth-optimism/ovm' @@ -144,16 +143,18 @@ export class TestWeb3Handler extends DefaultWeb3Handler { if (!ovmTx.to) { ovmTx.to = '0x' } - if (!ovmTx.gasPrice) { - ovmTx.gasPrice = 0 - } - if (!ovmTx.gasLimit) { + if (!ovmTx.gas) { ovmTx.gasLimit = GAS_LIMIT + } else { + ovmTx.gasLimit = ovmTx.gas + delete ovmTx.gas } + const ovmTxFrom = ovmTx.from + delete ovmTx.from ovmTx.value = 0 return this.sendRawTransaction( - rlpEncodeTransactionWithRandomSig(ovmTx), - ovmTx.from + await this.getNewWallet().sign(ovmTx), + ovmTxFrom ) } From 6be870f47affb85b545cff72f4a548a4624301f1 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Sun, 26 Apr 2020 15:06:21 -0400 Subject: [PATCH 09/29] lint --- packages/rollup-full-node/src/app/fullnode-rpc-server.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts index bc5d9204c684..89a8378be4a6 100644 --- a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts +++ b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts @@ -119,7 +119,13 @@ export class FullnodeRpcServer extends ExpressHttpServer { ) return buildJsonRpcError('INVALID_PARAMS', request.id) } - logError(log, `Uncaught exception at endpoint-level for request [${JSON.stringify(request)}]:`, err) + logError( + log, + `Uncaught exception at endpoint-level for request [${JSON.stringify( + request + )}]:`, + err + ) return buildJsonRpcError( 'INTERNAL_ERROR', request && request.id ? request.id : null From 571a68a6a50ccc0728173448ec107e8ad73bbc5f Mon Sep 17 00:00:00 2001 From: ben-chain Date: Tue, 28 Apr 2020 16:17:29 -0400 Subject: [PATCH 10/29] everything working --- packages/ovm/src/app/utils.ts | 64 +++++++++++++++---- packages/ovm/test/app/utils.spec.ts | 15 +++-- packages/ovm/test/helpers.ts | 6 +- .../src/app/web3-rpc-handler.ts | 38 +++++++++-- .../test/app/web-rpc-handler.spec.ts | 46 +++++++++++++ .../transpiled/events/MasterEventEmitter.sol | 14 ++++ .../transpiled/events/SubEventEmitter.sol | 9 +++ 7 files changed, 164 insertions(+), 28 deletions(-) create mode 100644 packages/rollup-full-node/test/contracts/transpiled/events/MasterEventEmitter.sol create mode 100644 packages/rollup-full-node/test/contracts/transpiled/events/SubEventEmitter.sol diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 19cbe2b25998..93bf86906886 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -10,6 +10,7 @@ import { remove0x, ZERO_ADDRESS, BloomFilter, + hexStrToNumber, } from '@eth-optimism/core-utils' import { ethers } from 'ethers' import { LogDescription } from 'ethers/utils' @@ -60,33 +61,66 @@ export interface OvmTransactionMetadata { } /** - * Convert internal logs into OVM logs. Or in other words, take the logs which + * Convert internal transaction logs into OVM logs. Or in other words, take the logs which * are emitted by a normal Ganache or Geth node (this will include logs from the ExecutionManager), * parse them, and then convert them into logs which look like they would if you were running this tx * using an OVM backend. * + * NOTE: The input logs MUST NOT be stripped of any Execution Manager events, or this function will break. * - * @param logs an array of internal logs which we will parse and then convert. + * @param logs an array of internal transaction logs which we will parse and then convert. * @return the converted logs */ -export const convertInternalLogsToOvmLogs = (logs: Log[]): Log[] => { +export const convertInternalLogsToOvmLogs = ( + logs: Log[], + executionManagerAddress: string +): Log[] => { let activeContract = logs[0] ? logs[0].address : ZERO_ADDRESS const ovmLogs = [] + let cumulativeTxEMLogIndices = 0 + let prevEMLogIndex = 0 + logger.debug(`using em address of ${executionManagerAddress}`) logs.forEach((log) => { - const executionManagerLog = executionManagerInterface.parseLog(log) - if (executionManagerLog) { - if (executionManagerLog.name === 'ActiveContract') { - activeContract = executionManagerLog.values['_activeContract'] + if (log.address.toUpperCase() === executionManagerAddress.toUpperCase()) { + const EMLogIndex = log.logIndex + if (EMLogIndex < prevEMLogIndex) { + logger.debug( + `Detected raw EM log ${log} with lower logIndex than previously processed, must be from a new transaction. Resetting cumulative EM log indices for tx.` + ) + cumulativeTxEMLogIndices = 0 + } + cumulativeTxEMLogIndices++ + prevEMLogIndex = EMLogIndex + const executionManagerLog = executionManagerInterface.parseLog(log) + if (!executionManagerLog) { + logger.debug( + `execution manager log ${log} was unrecognized by the interface parser--Definitely not an activeContract event, ignoring...` + ) } else { logger.debug( - `${executionManagerLog.name}, values: ${JSON.stringify( + `Parsed execution manager event ${ + executionManagerLog.name + } with values: ${JSON.stringify( executionManagerLog.values - )}` + )} and cumulativeTxEMLogIndices: ${cumulativeTxEMLogIndices}` ) + if (executionManagerLog.name === 'ActiveContract') { + activeContract = executionManagerLog.values['_activeContract'] + logger.debug( + `EM activeContract event detected, setting activeContract to ${activeContract}` + ) + } else { + logger.debug(`EM-but-non-activeContract event detected, ignoring...`) + } } } else { - logger.debug(`Non-EM log: ${JSON.stringify(log)}`) - ovmLogs.push({ ...log, address: activeContract }) + const newIndex = log.logIndex - cumulativeTxEMLogIndices + logger.debug( + `Non-EM log: ${JSON.stringify( + log + )}. Using address of active contract ${activeContract} and log index ${newIndex}` + ) + ovmLogs.push({ ...log, address: activeContract, logIndex: newIndex }) } }) return ovmLogs @@ -175,17 +209,21 @@ export const getSuccessfulOvmTransactionMetadata = ( */ export const internalTxReceiptToOvmTxReceipt = async ( internalTxReceipt: TransactionReceipt, + executionManagerAddress: string, ovmTxHash?: string ): Promise => { const ovmTransactionMetadata = getSuccessfulOvmTransactionMetadata( internalTxReceipt ) // Construct a new receipt - // + // Start off with the internalTxReceipt const ovmTxReceipt: OvmTransactionReceipt = internalTxReceipt // Add the converted logs - ovmTxReceipt.logs = convertInternalLogsToOvmLogs(internalTxReceipt.logs) + ovmTxReceipt.logs = convertInternalLogsToOvmLogs( + internalTxReceipt.logs, + executionManagerAddress + ) // Update the to and from fields if necessary if (ovmTransactionMetadata.ovmTo) { ovmTxReceipt.to = ovmTransactionMetadata.ovmTo diff --git a/packages/ovm/test/app/utils.spec.ts b/packages/ovm/test/app/utils.spec.ts index 5ca2170e75aa..84ab580dd16a 100644 --- a/packages/ovm/test/app/utils.spec.ts +++ b/packages/ovm/test/app/utils.spec.ts @@ -29,15 +29,16 @@ describe('convertInternalLogsToOvmLogs', () => { it('should replace the address of the event with the address of the last active contract event', async () => { convertInternalLogsToOvmLogs( [ - [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [ALICE]], - [EXECUTION_MANAGER_ADDRESS, 'EventFromAlice()', []], - [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [BOB]], - [EXECUTION_MANAGER_ADDRESS, 'EventFromBob()', []], - ].map((args) => buildLog.apply(null, args)) + [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [ALICE], 0], + [CODE_CONTRACT, 'EventFromAlice()', [], 1], + [EXECUTION_MANAGER_ADDRESS, 'ActiveContract(address)', [BOB], 2], + [CODE_CONTRACT, 'EventFromBob()', [], 3], + ].map((args) => buildLog.apply(null, args)), + EXECUTION_MANAGER_ADDRESS ).should.deep.eq( [ - [ALICE, 'EventFromAlice()', []], - [BOB, 'EventFromBob()', []], + [ALICE, 'EventFromAlice()', [], 0], + [BOB, 'EventFromBob()', [], 1], ].map((args) => buildLog.apply(null, args)) ) }) diff --git a/packages/ovm/test/helpers.ts b/packages/ovm/test/helpers.ts index b4b2cabb49a5..ebe388241d01 100644 --- a/packages/ovm/test/helpers.ts +++ b/packages/ovm/test/helpers.ts @@ -80,7 +80,7 @@ export const manuallyDeployOvmContractReturnReceipt = async ( false ) - return internalTxReceiptToOvmTxReceipt(receipt) + return internalTxReceiptToOvmTxReceipt(receipt, executionManager.address) } /** @@ -318,7 +318,8 @@ export const didCreateSucceed = async ( export const buildLog = ( address: string, event: string, - data: string[] + data: string[], + logIndex: number ): Log => { const types = event.match(/\((.+)\)/) const encodedData = types ? abi.encode(types[1].split(','), data) : '0x' @@ -327,6 +328,7 @@ export const buildLog = ( address, topics: [add0x(keccak256(strToHexStr(event)))], data: encodedData, + logIndex, } } diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index a8cd0b4ca1c7..ce1ddb5fbbeb 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -471,20 +471,44 @@ export class DefaultWeb3Handler } public async getLogs(ovmFilter: any): Promise { - log.debug(`Requesting logs with filter [${JSON.stringify(ovmFilter)}].`) + log.debug(`Requesting logs with ovm filter [${JSON.stringify(ovmFilter)}].`) const filter = JSON.parse(JSON.stringify(ovmFilter)) - if (filter['address']) { + if (filter['address'] && Array.isArray(filter['address'])) { + const codeContractAddresses = filter['address'].map(async (address) => { + return await this.context.executionManager.getCodeContractAddress( + address + ) + }) + filter['address'] = [ + ...codeContractAddresses, + this.context.executionManager.address, + ] + } + if (filter['address'] && !Array.isArray(filter['address'])) { const codeContractAddress = await this.context.executionManager.getCodeContractAddress( filter.address ) - filter['address'] = codeContractAddress + filter['address'] = [ + codeContractAddress, + this.context.executionManager.address, + ] } + log.debug(`Converted ovm filter to internal filter ${filter}`) + const res = await this.context.provider.send(Web3RpcMethods.getLogs, [ filter, ]) - let logs = JSON.parse(JSON.stringify(convertInternalLogsToOvmLogs(res))) - log.debug(`Log result: [${logs}], filter: [${JSON.stringify(filter)}].`) + let logs = JSON.parse( + JSON.stringify( + convertInternalLogsToOvmLogs(res, this.context.executionManager.address) + ) + ) + log.debug( + `Log result: [${JSON.stringify(logs)}], filter: [${JSON.stringify( + filter + )}].` + ) logs = await Promise.all( logs.map(async (logItem, index) => { logItem['logIndex'] = numberToHexString(index) @@ -584,6 +608,7 @@ export class DefaultWeb3Handler ) ovmTxReceipt = await internalTxReceiptToOvmTxReceipt( internalTxReceipt, + this.context.executionManager.address, ovmTxHash ) } else { @@ -783,7 +808,8 @@ export class DefaultWeb3Handler try { const ovmTxReceipt: OvmTransactionReceipt = await internalTxReceiptToOvmTxReceipt( - txReceipt + txReceipt, + this.context.executionManager.address ) await this.processTransactionEvents(ovmTxReceipt) } catch (e) { diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 683ac8428530..e277c92acac9 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -29,6 +29,8 @@ import { FullnodeRpcServer, DefaultWeb3Handler } from '../../src/app' import * as SimpleStorage from '../contracts/build/untranspiled/SimpleStorage.json' import * as EventEmitter from '../contracts/build/untranspiled/EventEmitter.json' import * as SimpleReversion from '../contracts/build/transpiled/SimpleReversion.json' +import * as MasterEventEmitter from '../contracts/build/transpiled/MasterEventEmitter.json' +import * as SubEventEmitter from '../contracts/build/transpiled/SubEventEmitter.json' import { Web3RpcMethods } from '../../src/types' const log = getLogger('web3-handler', true) @@ -475,6 +477,50 @@ describe('Web3Handler', () => { parsedLogs.length.should.eq(1) parsedLogs[0].name.should.eq('Event') }) + describe('Nested contract call events', async () => { + let wallet + let sub + let master + beforeEach(async () => { + wallet = getWallet(httpProvider) + const subFactory = new ContractFactory( + SubEventEmitter.abi, + SubEventEmitter.bytecode, + wallet + ) + sub = await subFactory.deploy() + const masterFactory = new ContractFactory( + MasterEventEmitter.abi, + MasterEventEmitter.bytecode, + wallet + ) + master = await masterFactory.deploy(sub.address) + }) + it('should return nested contract call events with the correct addresses for each log', async () => { + await master.callSubEmitter() + const logs = await httpProvider.send(Web3RpcMethods.getLogs, [ + { + fromBlock: 'latest', + toBlock: 'latest', + }, + ]) + logs[0].address.should.eq(master.address) + logs[1].address.should.eq(sub.address) + }) + it('should return logs which are the same as a transaction receipt', async () => { + const tx = await master.callSubEmitter() + const gotLogs = await httpProvider.send(Web3RpcMethods.getLogs, [ + { + fromBlock: 'latest', + toBlock: 'latest', + }, + ]) + const receipt = await httpProvider.send( + Web3RpcMethods.getTransactionReceipt, + [tx.hash] + ) + }) + }) }) describe('SimpleStorage integration test', () => { diff --git a/packages/rollup-full-node/test/contracts/transpiled/events/MasterEventEmitter.sol b/packages/rollup-full-node/test/contracts/transpiled/events/MasterEventEmitter.sol new file mode 100644 index 000000000000..9be7918efc14 --- /dev/null +++ b/packages/rollup-full-node/test/contracts/transpiled/events/MasterEventEmitter.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.5.0; +import "./SubEventEmitter.sol"; + +contract MasterEventEmitter { + event Taco(address); + SubEventEmitter public sub; + constructor (address _sub) public { + sub = SubEventEmitter(_sub); + } + function callSubEmitter() public { + emit Taco(0x0000000000000000000000000000000000000000); + sub.doEmit(); + } +} \ No newline at end of file diff --git a/packages/rollup-full-node/test/contracts/transpiled/events/SubEventEmitter.sol b/packages/rollup-full-node/test/contracts/transpiled/events/SubEventEmitter.sol new file mode 100644 index 000000000000..0f3d5e95fe84 --- /dev/null +++ b/packages/rollup-full-node/test/contracts/transpiled/events/SubEventEmitter.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.5.0; + +contract SubEventEmitter { + event Burger(address); + + function doEmit() public { + emit Burger(0x4206900000000000000000000000000000000000); + } +} \ No newline at end of file From cce86918a16afe4f593a1aa864fd972ca8b5007c Mon Sep 17 00:00:00 2001 From: ben-chain Date: Tue, 28 Apr 2020 16:29:17 -0400 Subject: [PATCH 11/29] linting --- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index ce1ddb5fbbeb..4d6043c82e94 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -475,7 +475,7 @@ export class DefaultWeb3Handler const filter = JSON.parse(JSON.stringify(ovmFilter)) if (filter['address'] && Array.isArray(filter['address'])) { const codeContractAddresses = filter['address'].map(async (address) => { - return await this.context.executionManager.getCodeContractAddress( + return this.context.executionManager.getCodeContractAddress( address ) }) From 9d3fd6384ab265a23c573caa51b5a2f123a3a298 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Tue, 28 Apr 2020 16:44:15 -0400 Subject: [PATCH 12/29] linting --- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 4d6043c82e94..741ecd148296 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -475,9 +475,7 @@ export class DefaultWeb3Handler const filter = JSON.parse(JSON.stringify(ovmFilter)) if (filter['address'] && Array.isArray(filter['address'])) { const codeContractAddresses = filter['address'].map(async (address) => { - return this.context.executionManager.getCodeContractAddress( - address - ) + return this.context.executionManager.getCodeContractAddress(address) }) filter['address'] = [ ...codeContractAddresses, From 7c1b3cc73dc8f5d039a73c12d6e666cad611db42 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Tue, 28 Apr 2020 20:57:49 -0400 Subject: [PATCH 13/29] bad multi level filter --- packages/ovm/src/app/abi.ts | 17 ++++ packages/ovm/src/app/index.ts | 1 + packages/ovm/src/app/utils.ts | 1 - .../src/app/web3-rpc-handler.ts | 15 +++- .../test/app/web-rpc-handler.spec.ts | 78 ++++++++++++------- .../contracts/untranspiled/EventEmitter.sol | 6 +- 6 files changed, 83 insertions(+), 35 deletions(-) create mode 100644 packages/ovm/src/app/abi.ts diff --git a/packages/ovm/src/app/abi.ts b/packages/ovm/src/app/abi.ts new file mode 100644 index 000000000000..55473ccef07e --- /dev/null +++ b/packages/ovm/src/app/abi.ts @@ -0,0 +1,17 @@ +/* External Imports */ +import { utils, ContractFactory } from 'ethers' + +/* Internal Imports */ +import * as ExecutionManager from '../../build/contracts/ExecutionManager.json' + +const EMContract = new ContractFactory( + ExecutionManager.abi, + ExecutionManager.bytecode +) +const EMEvents = EMContract.interface.events +let topics = [] +for (const eventKey of Object.keys(EMEvents)) { + topics.push(EMEvents[eventKey].topic) +} + +export const ALL_EXECUTION_MANAGER_EVENT_TOPICS = topics diff --git a/packages/ovm/src/app/index.ts b/packages/ovm/src/app/index.ts index a93d358c2607..71aa96a9349e 100644 --- a/packages/ovm/src/app/index.ts +++ b/packages/ovm/src/app/index.ts @@ -2,3 +2,4 @@ export * from './constants' export * from './ovm' export * from './serialization' export * from './utils' +export * from './abi' diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 93bf86906886..598d56b3599c 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -79,7 +79,6 @@ export const convertInternalLogsToOvmLogs = ( const ovmLogs = [] let cumulativeTxEMLogIndices = 0 let prevEMLogIndex = 0 - logger.debug(`using em address of ${executionManagerAddress}`) logs.forEach((log) => { if (log.address.toUpperCase() === executionManagerAddress.toUpperCase()) { const EMLogIndex = log.logIndex diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 741ecd148296..5397487dd153 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -24,6 +24,7 @@ import { internalTxReceiptToOvmTxReceipt, l2ToL1MessagePasserInterface, OvmTransactionReceipt, + ALL_EXECUTION_MANAGER_EVENT_TOPICS, } from '@eth-optimism/ovm' import AsyncLock from 'async-lock' @@ -471,8 +472,8 @@ export class DefaultWeb3Handler } public async getLogs(ovmFilter: any): Promise { - log.debug(`Requesting logs with ovm filter [${JSON.stringify(ovmFilter)}].`) const filter = JSON.parse(JSON.stringify(ovmFilter)) + if (filter['address'] && Array.isArray(filter['address'])) { const codeContractAddresses = filter['address'].map(async (address) => { return this.context.executionManager.getCodeContractAddress(address) @@ -482,6 +483,7 @@ export class DefaultWeb3Handler this.context.executionManager.address, ] } + // todo convert singleton to single-element array instead so getCodeContractAddress mapping is sufficient for all cases if (filter['address'] && !Array.isArray(filter['address'])) { const codeContractAddress = await this.context.executionManager.getCodeContractAddress( filter.address @@ -491,7 +493,16 @@ export class DefaultWeb3Handler this.context.executionManager.address, ] } - log.debug(`Converted ovm filter to internal filter ${filter}`) + + if (filter['topics']) { + if (!Array.isArray(filter['topics'][0])) { + filter['topics'][0] = [JSON.parse(JSON.stringify(filter['topics'][0]))] + } + filter['topics'][0].push(...ALL_EXECUTION_MANAGER_EVENT_TOPICS) + } + log.debug( + `Converted ovm filter to internal filter ${JSON.stringify(filter)}` + ) const res = await this.context.provider.send(Web3RpcMethods.getLogs, [ filter, diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index e277c92acac9..72fa6e44750b 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -449,40 +449,59 @@ describe('Web3Handler', () => { }) }) - describe('the getLogs endpoint', () => { - it('should return logs', async () => { - const executionManagerAddress = await httpProvider.send( - 'ovm_getExecutionManagerAddress', - [] - ) - const wallet = getWallet(httpProvider) - const balance = await httpProvider.getBalance(wallet.address) - const factory = new ContractFactory( - EventEmitter.abi, - EventEmitter.bytecode, - wallet - ) - const eventEmitter = await factory.deploy() - const deploymentTxReceipt = await wallet.provider.getTransactionReceipt( - eventEmitter.deployTransaction.hash - ) - const tx = await eventEmitter.emitEvent(executionManagerAddress) - - const logs = await httpProvider.getLogs({ - address: eventEmitter.address, + describe.only('the getLogs endpoint', () => { + let wallet + beforeEach(async () => { + wallet = getWallet(httpProvider) + }) + describe('Non-subcall events', async () => { + let eventEmitter + let eventEmitterFactory + beforeEach(async () => { + eventEmitterFactory = new ContractFactory( + EventEmitter.abi, + EventEmitter.bytecode, + wallet + ) + eventEmitter = await eventEmitterFactory.deploy() + await eventEmitter.emitEvent() + }) + const DUMMY_EVENT_NAME = 'DummyEvent()' + const verifyEventEmitterLogs = (logs: any) => { + logs[0].address.should.eq(eventEmitter.address) + logs[0].logIndex.should.eq(0) + const parsedLogs = logs.map((x) => + eventEmitterFactory.interface.parseLog(x) + ) + parsedLogs.length.should.eq(1) + parsedLogs[0].signature.should.eq(DUMMY_EVENT_NAME) + } + it('should return correct logs with #nofilter', async () => { + const logs = await httpProvider.getLogs({ + fromBlock: 'latest', + toBlock: 'latest', + }) + verifyEventEmitterLogs(logs) + }) + it('should return correct logs with address filter', async () => { + const logs = await httpProvider.getLogs({ + address: eventEmitter.address, + }) + verifyEventEmitterLogs(logs) + }) + it('should return correct logs with a topics filter', async () => { + const dummyTopic = + eventEmitterFactory.interface.events[DUMMY_EVENT_NAME].topic + const logs = await httpProvider.getLogs({ + topics: [dummyTopic], + }) + verifyEventEmitterLogs(logs) }) - logs[0].address.should.eq(eventEmitter.address) - logs[0].logIndex.should.eq(0) - const parsedLogs = logs.map((x) => factory.interface.parseLog(x)) - parsedLogs.length.should.eq(1) - parsedLogs[0].name.should.eq('Event') }) describe('Nested contract call events', async () => { - let wallet let sub let master beforeEach(async () => { - wallet = getWallet(httpProvider) const subFactory = new ContractFactory( SubEventEmitter.abi, SubEventEmitter.bytecode, @@ -507,7 +526,7 @@ describe('Web3Handler', () => { logs[0].address.should.eq(master.address) logs[1].address.should.eq(sub.address) }) - it('should return logs which are the same as a transaction receipt', async () => { + it("should return logs which are the same as a transaction receipt's logs", async () => { const tx = await master.callSubEmitter() const gotLogs = await httpProvider.send(Web3RpcMethods.getLogs, [ { @@ -519,6 +538,7 @@ describe('Web3Handler', () => { Web3RpcMethods.getTransactionReceipt, [tx.hash] ) + gotLogs.should.deep.equal(receipt.logs) }) }) }) diff --git a/packages/rollup-full-node/test/contracts/untranspiled/EventEmitter.sol b/packages/rollup-full-node/test/contracts/untranspiled/EventEmitter.sol index 088bd22b2a41..09824963fc42 100644 --- a/packages/rollup-full-node/test/contracts/untranspiled/EventEmitter.sol +++ b/packages/rollup-full-node/test/contracts/untranspiled/EventEmitter.sol @@ -1,8 +1,8 @@ pragma solidity ^0.5.0; contract EventEmitter { - event Event(); - function emitEvent(address exeMgrAddr) public { - emit Event(); + event DummyEvent(); + function emitEvent() public { + emit DummyEvent(); } } From 021917a49244700a601ecc4fa7e56ac84d613dce Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 16:02:46 -0400 Subject: [PATCH 14/29] handle unsupported filter handler --- .../src/app/fullnode-rpc-server.ts | 9 +++++ .../src/app/web3-rpc-handler.ts | 35 ++++++++++--------- packages/rollup-full-node/src/types/errors.ts | 6 ++++ .../test/app/web-rpc-handler.spec.ts | 13 +++++-- 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts index ca1dc261f826..0741ef267ec7 100644 --- a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts +++ b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts @@ -21,6 +21,7 @@ import { RevertError, TransactionLimitError, UnsupportedMethodError, + UnsupportedFilterError } from '../types' const log: Logger = getLogger('rollup-fullnode-rpc-server') @@ -119,6 +120,14 @@ export class FullnodeRpcServer extends ExpressHttpServer { ) return buildJsonRpcError('METHOD_NOT_FOUND', request.id) } + if (err instanceof UnsupportedFilterError) { + log.debug( + `Received request with unsupported filter parameters: [${JSON.stringify( + request + )}]` + ) + return buildJsonRpcError('UNSUPPORTED_TOPICS_ERROR', request.id) + } if (err instanceof InvalidParametersError) { log.debug( `Received request with valid method but invalid parameters: [${JSON.stringify( diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 5397487dd153..5a7b9a646dd4 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -41,6 +41,7 @@ import { Web3Handler, Web3RpcMethods, RevertError, + UnsupportedFilterError } from '../types' import { initializeL2Node, getCurrentTime, isErrorEVMRevert } from './util' import { NoOpL2ToL1MessageSubmitter } from './message-submitter' @@ -473,35 +474,35 @@ export class DefaultWeb3Handler public async getLogs(ovmFilter: any): Promise { const filter = JSON.parse(JSON.stringify(ovmFilter)) - - if (filter['address'] && Array.isArray(filter['address'])) { - const codeContractAddresses = filter['address'].map(async (address) => { - return this.context.executionManager.getCodeContractAddress(address) - }) + // We cannot filter out execution manager events or else convertInternalLogsToOvmLogs will break. So add EM address to address filter + if (filter['address']) { + if (!Array.isArray(filter['address'])) { + filter['address'] = [filter['address']] + } + let codeContractAddresses = [] + for (let address of filter['address']) { + codeContractAddresses.push(await this.context.executionManager.getCodeContractAddress(address)) + } + console.log(JSON.stringify(codeContractAddresses)) filter['address'] = [ ...codeContractAddresses, this.context.executionManager.address, ] } - // todo convert singleton to single-element array instead so getCodeContractAddress mapping is sufficient for all cases - if (filter['address'] && !Array.isArray(filter['address'])) { - const codeContractAddress = await this.context.executionManager.getCodeContractAddress( - filter.address - ) - filter['address'] = [ - codeContractAddress, - this.context.executionManager.address, - ] - } - + // We cannot filter out execution manager events or else convertInternalLogsToOvmLogs will break. So add EM topics to topics filter if (filter['topics']) { + if (filter['topics'].length > 1) { + // todo make this proper error + const msg = `The provided filter ${filter} has multiple levels of topic filter. Multi-level topic filters are currently unsupported by the OVM.` + throw new UnsupportedFilterError(msg) + } if (!Array.isArray(filter['topics'][0])) { filter['topics'][0] = [JSON.parse(JSON.stringify(filter['topics'][0]))] } filter['topics'][0].push(...ALL_EXECUTION_MANAGER_EVENT_TOPICS) } log.debug( - `Converted ovm filter to internal filter ${JSON.stringify(filter)}` + `Converted ovm filter ${JSON.stringify(ovmFilter)} to internal filter ${JSON.stringify(filter)}` ) const res = await this.context.provider.send(Web3RpcMethods.getLogs, [ diff --git a/packages/rollup-full-node/src/types/errors.ts b/packages/rollup-full-node/src/types/errors.ts index 728ac89a683c..f57f0bfd92e7 100644 --- a/packages/rollup-full-node/src/types/errors.ts +++ b/packages/rollup-full-node/src/types/errors.ts @@ -18,6 +18,12 @@ export class InvalidParametersError extends Error { } } +export class UnsupportedFilterError extends Error { + constructor(message?: string) { + super(message || 'The provided filter is currently unsupported by the OVM') + } +} + export class RevertError extends Error { constructor(message?: string) { super(message || 'Revert: The provided transaction reverted.') diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 72fa6e44750b..ff71f5d31fd2 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -449,7 +449,7 @@ describe('Web3Handler', () => { }) }) - describe.only('the getLogs endpoint', () => { + describe('the getLogs endpoint', () => { let wallet beforeEach(async () => { wallet = getWallet(httpProvider) @@ -494,9 +494,18 @@ describe('Web3Handler', () => { eventEmitterFactory.interface.events[DUMMY_EVENT_NAME].topic const logs = await httpProvider.getLogs({ topics: [dummyTopic], - }) + }) verifyEventEmitterLogs(logs) }) + it('Should throw throw with proper error for unsupported multi-topic filtering', async () => { + const dummyTopic = + eventEmitterFactory.interface.events[DUMMY_EVENT_NAME].topic + assertAsyncThrowsWithMessage(async () => { + await httpProvider.getLogs({ + topics: [dummyTopic, dummyTopic], + }) + }, 'Unsupported filter parameters') + }) }) describe('Nested contract call events', async () => { let sub From ba3f5de00ed372b8a7ddbd765c71f98b2e4c4319 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 16:04:19 -0400 Subject: [PATCH 15/29] merge updated error code --- .../core-utils/src/app/transport/server/json-rpc-errors.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/core-utils/src/app/transport/server/json-rpc-errors.ts b/packages/core-utils/src/app/transport/server/json-rpc-errors.ts index a6bc89093426..912e8e15482f 100644 --- a/packages/core-utils/src/app/transport/server/json-rpc-errors.ts +++ b/packages/core-utils/src/app/transport/server/json-rpc-errors.ts @@ -21,6 +21,10 @@ export const JSONRPC_ERRORS = { code: -32603, message: 'Internal error', }, + UNSUPPORTED_TOPICS_ERROR: { + code: -32604, + message: 'Unsupported filter parameters', + }, REVERT_ERROR: { code: -32015, message: 'revert: requested action reverted', From ebd81f3a0230fb08afcd8b4030dfbbce5e72bfbb Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 16:18:44 -0400 Subject: [PATCH 16/29] linting --- .../src/app/fullnode-rpc-server.ts | 2 +- .../rollup-full-node/src/app/web3-rpc-handler.ts | 15 +++++++++------ packages/rollup-full-node/src/types/errors.ts | 2 +- .../test/app/web-rpc-handler.spec.ts | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts index 0741ef267ec7..fcede771fbbc 100644 --- a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts +++ b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts @@ -21,7 +21,7 @@ import { RevertError, TransactionLimitError, UnsupportedMethodError, - UnsupportedFilterError + UnsupportedFilterError, } from '../types' const log: Logger = getLogger('rollup-fullnode-rpc-server') diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 5a7b9a646dd4..92f47bd085e7 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -41,7 +41,7 @@ import { Web3Handler, Web3RpcMethods, RevertError, - UnsupportedFilterError + UnsupportedFilterError, } from '../types' import { initializeL2Node, getCurrentTime, isErrorEVMRevert } from './util' import { NoOpL2ToL1MessageSubmitter } from './message-submitter' @@ -479,11 +479,12 @@ export class DefaultWeb3Handler if (!Array.isArray(filter['address'])) { filter['address'] = [filter['address']] } - let codeContractAddresses = [] - for (let address of filter['address']) { - codeContractAddresses.push(await this.context.executionManager.getCodeContractAddress(address)) + const codeContractAddresses = [] + for (const address of filter['address']) { + codeContractAddresses.push( + await this.context.executionManager.getCodeContractAddress(address) + ) } - console.log(JSON.stringify(codeContractAddresses)) filter['address'] = [ ...codeContractAddresses, this.context.executionManager.address, @@ -502,7 +503,9 @@ export class DefaultWeb3Handler filter['topics'][0].push(...ALL_EXECUTION_MANAGER_EVENT_TOPICS) } log.debug( - `Converted ovm filter ${JSON.stringify(ovmFilter)} to internal filter ${JSON.stringify(filter)}` + `Converted ovm filter ${JSON.stringify( + ovmFilter + )} to internal filter ${JSON.stringify(filter)}` ) const res = await this.context.provider.send(Web3RpcMethods.getLogs, [ diff --git a/packages/rollup-full-node/src/types/errors.ts b/packages/rollup-full-node/src/types/errors.ts index f57f0bfd92e7..667d58bf98b4 100644 --- a/packages/rollup-full-node/src/types/errors.ts +++ b/packages/rollup-full-node/src/types/errors.ts @@ -21,7 +21,7 @@ export class InvalidParametersError extends Error { export class UnsupportedFilterError extends Error { constructor(message?: string) { super(message || 'The provided filter is currently unsupported by the OVM') - } + } } export class RevertError extends Error { diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index ff71f5d31fd2..1331b2e57909 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -342,7 +342,7 @@ describe('Web3Handler', () => { const deploymentTxReceipt = await wallet.provider.getTransactionReceipt( eventEmitter.deployTransaction.hash ) - const tx = await eventEmitter.emitEvent(executionManagerAddress) + const tx = await eventEmitter.emitEvent() await wallet.provider.getTransactionReceipt(tx.hash) const block = await httpProvider.send('eth_getBlockByNumber', [ 'latest', @@ -494,7 +494,7 @@ describe('Web3Handler', () => { eventEmitterFactory.interface.events[DUMMY_EVENT_NAME].topic const logs = await httpProvider.getLogs({ topics: [dummyTopic], - }) + }) verifyEventEmitterLogs(logs) }) it('Should throw throw with proper error for unsupported multi-topic filtering', async () => { From 36ee32e2c2719cb48ea217ad1f78aa49f52dbf72 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 16:55:18 -0400 Subject: [PATCH 17/29] fix merge accidents --- packages/ovm/src/app/utils.ts | 10 +++++----- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 6 +++--- .../rollup-full-node/test/app/web-rpc-handler.spec.ts | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index ad4f2d9d71ce..795dfa85fbed 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -77,7 +77,7 @@ export const convertInternalLogsToOvmLogs = ( executionManagerAddress: string ): Log[] => { let activeContract = logs[0] ? logs[0].address : ZERO_ADDRESS - const loggerLogs = [`Parsing logs from contract ${activeContract}: `] + const loggerLogs = [`Parsing internal logs ${JSON.stringify(logs)}: `] const ovmLogs = [] let cumulativeTxEMLogIndices = 0 let prevEMLogIndex = 0 @@ -85,7 +85,7 @@ export const convertInternalLogsToOvmLogs = ( if (log.address.toUpperCase() === executionManagerAddress.toUpperCase()) { const EMLogIndex = log.logIndex if (EMLogIndex < prevEMLogIndex) { - logger.debug( + loggerLogs.push( `Detected raw EM log ${log} with lower logIndex than previously processed, must be from a new transaction. Resetting cumulative EM log indices for tx.` ) cumulativeTxEMLogIndices = 0 @@ -94,7 +94,7 @@ export const convertInternalLogsToOvmLogs = ( prevEMLogIndex = EMLogIndex const executionManagerLog = executionManagerInterface.parseLog(log) if (!executionManagerLog) { - logger.debug( + loggerLogs.push( `execution manager log ${log} was unrecognized by the interface parser--Definitely not an activeContract event, ignoring...` ) } else { @@ -105,11 +105,11 @@ export const convertInternalLogsToOvmLogs = ( ) if (executionManagerLog.name === 'ActiveContract') { activeContract = executionManagerLog.values['_activeContract'] - logger.debug( + loggerLogs.push( `EM activeContract event detected, setting activeContract to ${activeContract}` ) } else { - logger.debug(`EM-but-non-activeContract event detected, ignoring...`) + loggerLogs.push(`EM-but-non-activeContract event detected, ignoring...`) } } } else { diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 89ee418fc3d7..93af76a0b65f 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -547,7 +547,6 @@ export class DefaultWeb3Handler ) logs = await Promise.all( logs.map(async (logItem, index) => { - logItem['logIndex'] = numberToHexString(index) logItem['transactionHash'] = await this.getOvmTxHash( logItem['transactionHash'] ) @@ -558,8 +557,9 @@ export class DefaultWeb3Handler const receipt = await this.getTransactionReceipt(transaction.hash) transaction['to'] = receipt.contractAddress } - logItem['address'] = transaction['to'] - + if (typeof logItem['logIndex'] === 'number') { + logItem['logIndex'] = numberToHexString(logItem['logIndex']) + } return logItem }) ) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 89c4f2b922f3..9907f88f961a 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -458,7 +458,7 @@ describe('Web3Handler', () => { }) }) - describe('the getLogs endpoint', () => { + describe.only('the getLogs endpoint', () => { let wallet beforeEach(async () => { wallet = getWallet(httpProvider) @@ -541,6 +541,8 @@ describe('Web3Handler', () => { toBlock: 'latest', }, ]) + console.log(`master addy is ${master.address}, sub addy is ${sub.address}`) + console.log(`logs are ${JSON.stringify(logs)}`) logs[0].address.should.eq(master.address) logs[1].address.should.eq(sub.address) }) From b4bddc139eb02c53db2bf9ff529dd691d894d890 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 16:55:45 -0400 Subject: [PATCH 18/29] linting --- packages/rollup-full-node/test/app/web-rpc-handler.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 9907f88f961a..80c6ca19ef4c 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -458,7 +458,7 @@ describe('Web3Handler', () => { }) }) - describe.only('the getLogs endpoint', () => { + describe('the getLogs endpoint', () => { let wallet beforeEach(async () => { wallet = getWallet(httpProvider) From ee41892e9b4832a605e3c2a1e1a565c52b007358 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 16:56:25 -0400 Subject: [PATCH 19/29] linting --- packages/ovm/src/app/utils.ts | 4 +++- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 2 +- packages/rollup-full-node/test/app/web-rpc-handler.spec.ts | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 795dfa85fbed..335c4e6da6d4 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -109,7 +109,9 @@ export const convertInternalLogsToOvmLogs = ( `EM activeContract event detected, setting activeContract to ${activeContract}` ) } else { - loggerLogs.push(`EM-but-non-activeContract event detected, ignoring...`) + loggerLogs.push( + `EM-but-non-activeContract event detected, ignoring...` + ) } } } else { diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 93af76a0b65f..0ef43da6599f 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -559,7 +559,7 @@ export class DefaultWeb3Handler } if (typeof logItem['logIndex'] === 'number') { logItem['logIndex'] = numberToHexString(logItem['logIndex']) - } + } return logItem }) ) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 80c6ca19ef4c..9c0599533326 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -541,7 +541,9 @@ describe('Web3Handler', () => { toBlock: 'latest', }, ]) - console.log(`master addy is ${master.address}, sub addy is ${sub.address}`) + console.log( + `master addy is ${master.address}, sub addy is ${sub.address}` + ) console.log(`logs are ${JSON.stringify(logs)}`) logs[0].address.should.eq(master.address) logs[1].address.should.eq(sub.address) From 96cb62af5e23b9ffe84079da10840f0fae3db330 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 16:58:02 -0400 Subject: [PATCH 20/29] fix log indexing bug --- packages/ovm/src/app/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 335c4e6da6d4..1427568d3360 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -84,7 +84,7 @@ export const convertInternalLogsToOvmLogs = ( logs.forEach((log) => { if (log.address.toUpperCase() === executionManagerAddress.toUpperCase()) { const EMLogIndex = log.logIndex - if (EMLogIndex < prevEMLogIndex) { + if (EMLogIndex <= prevEMLogIndex) { loggerLogs.push( `Detected raw EM log ${log} with lower logIndex than previously processed, must be from a new transaction. Resetting cumulative EM log indices for tx.` ) From 051bbfde9a4b51636c91ea3021a63e6572d4a26c Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 17:11:17 -0400 Subject: [PATCH 21/29] add filtering multi-event test --- .../test/app/web-rpc-handler.spec.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 9c0599533326..5779befe2fe9 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -519,8 +519,10 @@ describe('Web3Handler', () => { describe('Nested contract call events', async () => { let sub let master + let subFactory + const SUB_EMITTER_EVENT_NAME = 'Burger' beforeEach(async () => { - const subFactory = new ContractFactory( + subFactory = new ContractFactory( SubEventEmitter.abi, SubEventEmitter.bytecode, wallet @@ -541,13 +543,24 @@ describe('Web3Handler', () => { toBlock: 'latest', }, ]) - console.log( - `master addy is ${master.address}, sub addy is ${sub.address}` - ) - console.log(`logs are ${JSON.stringify(logs)}`) logs[0].address.should.eq(master.address) logs[1].address.should.eq(sub.address) }) + it('Should correctly filter by topic for the inner emission', async () => { + await master.callSubEmitter() + const subEventEmitterTopic = subFactory.interface.events[SUB_EMITTER_EVENT_NAME].topic + const gotLogs = await httpProvider.send(Web3RpcMethods.getLogs, [ + { + topics: [ + subEventEmitterTopic + ] + }, + ]) + gotLogs.length.should.equal(1) + gotLogs[0].topics.should.deep.equal([subEventEmitterTopic]) + gotLogs[0].address.should.equal(sub.address) + gotLogs[0].logIndex.should.equal('0x1') + }) it("should return logs which are the same as a transaction receipt's logs", async () => { const tx = await master.callSubEmitter() const gotLogs = await httpProvider.send(Web3RpcMethods.getLogs, [ @@ -561,7 +574,7 @@ describe('Web3Handler', () => { [tx.hash] ) gotLogs.should.deep.equal(receipt.logs) - }) + }) }) }) From 0ffa7194f1991c325621341cdffcc5617a518e55 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 17:27:15 -0400 Subject: [PATCH 22/29] linting --- .../rollup-full-node/test/app/web-rpc-handler.spec.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 2d80cfacd883..2c45d8486cd2 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -548,12 +548,11 @@ describe('Web3Handler', () => { }) it('Should correctly filter by topic for the inner emission', async () => { await master.callSubEmitter() - const subEventEmitterTopic = subFactory.interface.events[SUB_EMITTER_EVENT_NAME].topic + const subEventEmitterTopic = + subFactory.interface.events[SUB_EMITTER_EVENT_NAME].topic const gotLogs = await httpProvider.send(Web3RpcMethods.getLogs, [ { - topics: [ - subEventEmitterTopic - ] + topics: [subEventEmitterTopic], }, ]) gotLogs.length.should.equal(1) @@ -574,7 +573,7 @@ describe('Web3Handler', () => { [tx.hash] ) gotLogs.should.deep.equal(receipt.logs) - }) + }) }) }) From 7baf8d23c8aa3a8beb08bca426af4a34a25e67d6 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 17:29:01 -0400 Subject: [PATCH 23/29] linting --- .../rollup-full-node/test/app/web-rpc-handler.spec.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 5779befe2fe9..055f5290e5e7 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -548,12 +548,11 @@ describe('Web3Handler', () => { }) it('Should correctly filter by topic for the inner emission', async () => { await master.callSubEmitter() - const subEventEmitterTopic = subFactory.interface.events[SUB_EMITTER_EVENT_NAME].topic + const subEventEmitterTopic = + subFactory.interface.events[SUB_EMITTER_EVENT_NAME].topic const gotLogs = await httpProvider.send(Web3RpcMethods.getLogs, [ { - topics: [ - subEventEmitterTopic - ] + topics: [subEventEmitterTopic], }, ]) gotLogs.length.should.equal(1) @@ -574,7 +573,7 @@ describe('Web3Handler', () => { [tx.hash] ) gotLogs.should.deep.equal(receipt.logs) - }) + }) }) }) From 212f700ddb8295ab7b96339434c26209a7e77d6c Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 17:31:42 -0400 Subject: [PATCH 24/29] linting --- packages/ovm/src/app/abi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ovm/src/app/abi.ts b/packages/ovm/src/app/abi.ts index 55473ccef07e..44c18431b74a 100644 --- a/packages/ovm/src/app/abi.ts +++ b/packages/ovm/src/app/abi.ts @@ -9,7 +9,7 @@ const EMContract = new ContractFactory( ExecutionManager.bytecode ) const EMEvents = EMContract.interface.events -let topics = [] +const topics = [] for (const eventKey of Object.keys(EMEvents)) { topics.push(EMEvents[eventKey].topic) } From 9b8180ce139d912df7aeea0e1b08871350664531 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 18:11:16 -0400 Subject: [PATCH 25/29] use already existing EM interface --- packages/ovm/src/app/abi.ts | 17 ----------------- packages/ovm/src/app/index.ts | 1 - packages/ovm/src/app/utils.ts | 5 +++-- .../src/app/web3-rpc-handler.ts | 12 ++++++++++-- 4 files changed, 13 insertions(+), 22 deletions(-) delete mode 100644 packages/ovm/src/app/abi.ts diff --git a/packages/ovm/src/app/abi.ts b/packages/ovm/src/app/abi.ts deleted file mode 100644 index 44c18431b74a..000000000000 --- a/packages/ovm/src/app/abi.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* External Imports */ -import { utils, ContractFactory } from 'ethers' - -/* Internal Imports */ -import * as ExecutionManager from '../../build/contracts/ExecutionManager.json' - -const EMContract = new ContractFactory( - ExecutionManager.abi, - ExecutionManager.bytecode -) -const EMEvents = EMContract.interface.events -const topics = [] -for (const eventKey of Object.keys(EMEvents)) { - topics.push(EMEvents[eventKey].topic) -} - -export const ALL_EXECUTION_MANAGER_EVENT_TOPICS = topics diff --git a/packages/ovm/src/app/index.ts b/packages/ovm/src/app/index.ts index 71aa96a9349e..a93d358c2607 100644 --- a/packages/ovm/src/app/index.ts +++ b/packages/ovm/src/app/index.ts @@ -2,4 +2,3 @@ export * from './constants' export * from './ovm' export * from './serialization' export * from './utils' -export * from './abi' diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 1427568d3360..8b1ac24ed8c2 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -14,7 +14,7 @@ import { hexStrToNumber, } from '@eth-optimism/core-utils' import { ethers } from 'ethers' -import { LogDescription } from 'ethers/utils' +import { LogDescription } from 'ethers/utils' import { Log, TransactionReceipt } from 'ethers/providers' /* Contract Imports */ @@ -44,6 +44,7 @@ export const revertMessagePrefix: string = export const executionManagerInterface = new ethers.utils.Interface( ExecutionManager.interface ) + export const l2ExecutionManagerInterface = new ethers.utils.Interface( L2ExecutionManager.interface ) @@ -95,7 +96,7 @@ export const convertInternalLogsToOvmLogs = ( const executionManagerLog = executionManagerInterface.parseLog(log) if (!executionManagerLog) { loggerLogs.push( - `execution manager log ${log} was unrecognized by the interface parser--Definitely not an activeContract event, ignoring...` + `Execution manager emitted log with topics: ${log.topics}. These were unrecognized by the interface parser-but definitely not an ActiveContract event, ignoring...` ) } else { loggerLogs.push( diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index 0ef43da6599f..afdc30a626c0 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -24,7 +24,7 @@ import { internalTxReceiptToOvmTxReceipt, l2ToL1MessagePasserInterface, OvmTransactionReceipt, - ALL_EXECUTION_MANAGER_EVENT_TOPICS, + executionManagerInterface } from '@eth-optimism/ovm' import AsyncLock from 'async-lock' @@ -53,6 +53,12 @@ const log = getLogger('web3-handler') export const latestBlock: string = 'latest' const lockKey: string = 'LOCK' +const EMEvents = executionManagerInterface.events +const ALL_EXECUTION_MANAGER_EVENT_TOPICS = [] +for (const eventKey of Object.keys(EMEvents)) { + ALL_EXECUTION_MANAGER_EVENT_TOPICS.push(EMEvents[eventKey].topic) +} + export class DefaultWeb3Handler implements Web3Handler, FullnodeHandler, L1ToL2TransactionListener { private readonly ovmHashToOvmTransactionCache: Object = {} @@ -517,7 +523,9 @@ export class DefaultWeb3Handler if (filter['topics']) { if (filter['topics'].length > 1) { // todo make this proper error - const msg = `The provided filter ${filter} has multiple levels of topic filter. Multi-level topic filters are currently unsupported by the OVM.` + const msg = `The provided filter ${JSON.stringify( + filter + )} has multiple levels of topic filter. Multi-level topic filters are currently unsupported by the OVM.` throw new UnsupportedFilterError(msg) } if (!Array.isArray(filter['topics'][0])) { From 04fa273d23ad95c9309b38e8ce2fd48561ad5b2c Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 18:12:10 -0400 Subject: [PATCH 26/29] linting --- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rollup-full-node/src/app/web3-rpc-handler.ts b/packages/rollup-full-node/src/app/web3-rpc-handler.ts index afdc30a626c0..6ddc6de87f23 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -24,7 +24,7 @@ import { internalTxReceiptToOvmTxReceipt, l2ToL1MessagePasserInterface, OvmTransactionReceipt, - executionManagerInterface + executionManagerInterface, } from '@eth-optimism/ovm' import AsyncLock from 'async-lock' From 6c4914d854262b1c77c42e8b9f72e28984055417 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 18:18:02 -0400 Subject: [PATCH 27/29] linting --- packages/ovm/src/app/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 8b1ac24ed8c2..6d589af4ec2d 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -14,7 +14,7 @@ import { hexStrToNumber, } from '@eth-optimism/core-utils' import { ethers } from 'ethers' -import { LogDescription } from 'ethers/utils' +import { LogDescription } from 'ethers/utils' import { Log, TransactionReceipt } from 'ethers/providers' /* Contract Imports */ From 5db1f40df9662d998ca83fdc9ffb0ef1d4513f3f Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 18:37:37 -0400 Subject: [PATCH 28/29] remove unused var --- packages/rollup-full-node/test/app/web-rpc-handler.spec.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 2c45d8486cd2..6ddcee2bbcbb 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -5,12 +5,10 @@ import { add0x, getLogger, keccak256, - numberToHexString, JSONRPC_ERRORS, - ZERO_ADDRESS, hexStrToBuf, } from '@eth-optimism/core-utils' -import { CHAIN_ID, convertInternalLogsToOvmLogs } from '@eth-optimism/ovm' +import { CHAIN_ID } from '@eth-optimism/ovm' import { ethers, @@ -18,7 +16,6 @@ import { Wallet, Contract, utils, - providers, } from 'ethers' import { resolve } from 'path' import * as rimraf from 'rimraf' From e3c3e0a575d27c6668b9a9dad4b0f454670d5147 Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 18:49:26 -0400 Subject: [PATCH 29/29] linting --- .../rollup-full-node/test/app/web-rpc-handler.spec.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts index 6ddcee2bbcbb..3abbe91b9b98 100644 --- a/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts +++ b/packages/rollup-full-node/test/app/web-rpc-handler.spec.ts @@ -10,13 +10,7 @@ import { } from '@eth-optimism/core-utils' import { CHAIN_ID } from '@eth-optimism/ovm' -import { - ethers, - ContractFactory, - Wallet, - Contract, - utils, -} from 'ethers' +import { ethers, ContractFactory, Wallet, Contract, utils } from 'ethers' import { resolve } from 'path' import * as rimraf from 'rimraf' import * as fs from 'fs'