Skip to content

Commit

Permalink
YAS 292: fix test provider's eth_sendTransaction behavior (#103)
Browse files Browse the repository at this point in the history
* remove out of date TODO

* first pass tests passing

* linting

* rename function

* add contract creation test

* linting
  • Loading branch information
ben-chain authored Apr 24, 2020
1 parent f0660f9 commit 2a0155f
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 19 deletions.
11 changes: 8 additions & 3 deletions packages/core-utils/src/app/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,16 +291,21 @@ export const getCurrentTime = (): number => {
return Math.round(Date.now() / 1000)
}
/**
* Encodes a transaction in RLP format
* Encodes a transaction in RLP format, using a random signature
* @param {object} Transaction object
*/
export const rlpEncodeTransaction = (transaction: object): string => {
export const rlpEncodeTransactionWithRandomSig = (
transaction: object
): string => {
return RLP.encode([
hexlify(transaction['nonce']),
hexlify(transaction['gasPrice']),
hexlify(transaction['gasLimit']),
hexlify(transaction['to']),
hexlify(transaction['value']),
transaction['data'],
hexlify(transaction['data']),
'0x11', // v
'0x' + '11'.repeat(32), // r
'0x' + '11'.repeat(32), // s
])
}
26 changes: 22 additions & 4 deletions packages/rollup-full-node/src/app/test-web3-rpc-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import {
getLogger,
numberToHexString,
castToNumber,
rlpEncodeTransaction,
rlpEncodeTransactionWithRandomSig,
ZERO_ADDRESS,
} from '@eth-optimism/core-utils'
import { GAS_LIMIT } from '@eth-optimism/ovm'
import { JsonRpcProvider, Web3Provider } from 'ethers/providers'
import { utils } from 'ethers'

/* Internal Imports */
import { initializeL2Node } from './index'
import { initializeL2Node, latestBlock } from './index'
import { DefaultWeb3Handler } from './web3-rpc-handler'
import {
L2NodeContext,
Expand Down Expand Up @@ -135,8 +137,24 @@ export class TestWeb3Handler extends DefaultWeb3Handler {
*
* @param The transaction to send
*/
public async sendTransaction(ovmTx: object): Promise<string> {
return this.sendRawTransaction(rlpEncodeTransaction(ovmTx))
public async sendTransaction(ovmTx: any): Promise<string> {
if (!ovmTx.nonce) {
ovmTx.nonce = await this.getTransactionCount(ovmTx.from, latestBlock)
}
if (!ovmTx.to) {
ovmTx.to = '0x'
}
if (!ovmTx.gasPrice) {
ovmTx.gasPrice = 0
}
if (!ovmTx.gasLimit) {
ovmTx.gasLimit = GAS_LIMIT
}
ovmTx.value = 0
return this.sendRawTransaction(
rlpEncodeTransactionWithRandomSig(ovmTx),
ovmTx.from
)
}

/**
Expand Down
14 changes: 10 additions & 4 deletions packages/rollup-full-node/src/app/web3-rpc-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import { NoOpL2ToL1MessageSubmitter } from './message-submitter'

const log = getLogger('web3-handler')

const latestBlock: string = 'latest'
export const latestBlock: string = 'latest'

export class DefaultWeb3Handler
implements Web3Handler, FullnodeHandler, L1ToL2TransactionListener {
Expand Down Expand Up @@ -571,15 +571,22 @@ export class DefaultWeb3Handler
return response
}

public async sendRawTransaction(rawOvmTx: string): Promise<string> {
public async sendRawTransaction(
rawOvmTx: string,
fromAddressOverride?: string
): Promise<string> {
const debugTime = new Date().getTime()
const blockTimestamp = this.getTimestamp()
log.debug('Sending raw transaction with params:', rawOvmTx)

// Decode the OVM transaction -- this will be used to construct our internal transaction
const ovmTx = utils.parseTransaction(rawOvmTx)
// override the from address if in testing mode
if (!!fromAddressOverride) {
ovmTx.from = fromAddressOverride
}
log.debug(
`OVM Transaction being parsed ${rawOvmTx}, parsed: ${JSON.stringify(
`OVM Transaction being parsed ${rawOvmTx}, with from address override of [${fromAddressOverride}], parsed: ${JSON.stringify(
ovmTx
)}`
)
Expand Down Expand Up @@ -870,7 +877,6 @@ export class DefaultWeb3Handler
)
throw new Error('Non-EOA transaction detected')
}
// TODO: Make sure we lock this function with this nonce so we don't send to txs with the same nonce
// Generate the calldata which we'll use to call our internal execution manager
// First pull out the `to` field (we just need to check if it's null & if so set ovmTo to the zero address as that's how we deploy contracts)
const ovmTo = ovmTx.to === null ? ZERO_ADDRESS : ovmTx.to
Expand Down
48 changes: 40 additions & 8 deletions packages/rollup-full-node/test/app/test-web-rpc-handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
} from '../../src'
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'

const log = getLogger('test-web3-handler', true)

Expand Down Expand Up @@ -225,7 +227,7 @@ describe('TestHandler', () => {
await testRpcServer.close()
})

it('should run the transaction', async () => {
it('should run the transaction for arbitrary from, to, and data, correctly filling optional fields including nonce', async () => {
const storageKey = add0x('01'.repeat(32))
const storageValue = add0x('02'.repeat(32))
const executionManagerAddress = await httpProvider.send(
Expand All @@ -242,24 +244,54 @@ describe('TestHandler', () => {
'setStorage'
].encode([executionManagerAddress, storageKey, storageValue])
const transaction = {
nonce: 0,
from: wallet.address,
to: simpleStorage.address,
gasPrice: 0,
gasLimit: 0,
value: 0,
data: transactionData,
}

const response = await httpProvider.send('eth_sendTransaction', [
transaction,
])
await httpProvider.send('eth_sendTransaction', [transaction])
const res = await simpleStorage.getStorage(
executionManagerAddress,
storageKey
)
res.should.equal(storageValue)
})

it('the EVM should actually see the arbitrary .from as the sender of the tx', async () => {
const factory = new ContractFactory(
CallerStorer.abi,
CallerStorer.bytecode,
wallet
)
const callerStorer = await factory.deploy()
const setData = await callerStorer.interface.functions[
'storeMsgSender'
].encode([])
const randomFromAddress = add0x('02'.repeat(20))
const transaction = {
from: randomFromAddress,
to: callerStorer.address,
data: setData,
}
await httpProvider.send('eth_sendTransaction', [transaction])
const res = await callerStorer.getLastMsgSender()
res.should.equal(randomFromAddress)
})
it('should allow for contract deployment through the endpoint', async () => {
log.debug(`here is a working log`)
const randomFromAddress = add0x('02'.repeat(20))
const creationInitcode = '0x' + SimpleStorage.bytecode
const transaction = {
from: randomFromAddress,
data: creationInitcode,
}
const txHash = await httpProvider.send('eth_sendTransaction', [
transaction,
])
const txReceipt = await wallet.provider.getTransactionReceipt(txHash)
// make sure the receipt's contractAddress is set
txReceipt.contractAddress.slice(0, 2).should.equal('0x')
})
})

describe('the accounts endpoint', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pragma solidity ^0.5.0;

contract CallerStorer {
address public lastMsgSender;
function storeMsgSender() public {
lastMsgSender = msg.sender;
}
function getLastMsgSender() public view returns(address) {
return lastMsgSender;
}
}

0 comments on commit 2a0155f

Please sign in to comment.