Skip to content

Commit

Permalink
Add snapshot and revert endpoints (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
masonforest authored Mar 10, 2020
1 parent ee5559f commit 60dd08c
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 13 deletions.
44 changes: 33 additions & 11 deletions packages/rollup-full-node/src/app/test-web3-rpc-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,24 @@ export class TestWeb3Handler extends DefaultWeb3Handler {
* Override to add some test RPC methods.
*/
public async handleRequest(method: string, params: any[]): Promise<string> {
if (method === Web3RpcMethods.increaseTimestamp) {
this.assertParameters(params, 1)
this.increaseTimestamp(params[0])
log.debug(`Set increased timestamp by ${params[0]} seconds.`)
return TestWeb3Handler.successString
switch (method) {
case Web3RpcMethods.increaseTimestamp:
this.assertParameters(params, 1)
this.increaseTimestamp(params[0])
log.debug(`Set increased timestamp by ${params[0]} seconds.`)
return TestWeb3Handler.successString
case Web3RpcMethods.getTimestamp:
this.assertParameters(params, 0)
return add0x(this.getTimestamp().toString(16))
case Web3RpcMethods.snapshot:
this.assertParameters(params, 0)
return this.snapshot()
case Web3RpcMethods.revert:
this.assertParameters(params, 1)
return this.revert(params[0])
default:
return super.handleRequest(method, params)
}
if (method === Web3RpcMethods.getTimestamp) {
this.assertParameters(params, 0)
return add0x(this.getTimestamp().toString(16))
}

return super.handleRequest(method, params)
}

/**
Expand Down Expand Up @@ -94,4 +100,20 @@ export class TestWeb3Handler extends DefaultWeb3Handler {
throw new UnsupportedMethodError(msg)
}
}

/**
* Takes a snapshot of the current node state.
* @returns The snapshot id that can be used as an parameter of the revert endpoint
*/
private async snapshot(): Promise<string> {
return this.provider.send(Web3RpcMethods.snapshot, [])
}

/**
* Reverts state to the specified snapshot
* @param The snapshot id of the snapshot to restore
*/
private async revert(snapShotId: string): Promise<string> {
return this.provider.send(Web3RpcMethods.revert, [snapShotId])
}
}
2 changes: 1 addition & 1 deletion packages/rollup-full-node/src/app/web3-rpc-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class DefaultWeb3Handler implements Web3Handler, FullnodeHandler {
}

protected constructor(
private readonly provider: Web3Provider,
protected readonly provider: Web3Provider,
private readonly wallet: Wallet,
private readonly executionManager: Contract
) {
Expand Down
2 changes: 2 additions & 0 deletions packages/rollup-full-node/src/types/web3-rpc-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export enum Web3RpcMethods {
getTransactionReceipt = 'eth_getTransactionReceipt',
networkVersion = 'net_version',
sendRawTransaction = 'eth_sendRawTransaction',
snapshot = 'evm_snapshot',
revert = 'evm_revert',

// Test methods:
increaseTimestamp = 'evm_increaseTime',
Expand Down
26 changes: 26 additions & 0 deletions packages/rollup-full-node/test/app/handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,30 @@ describe('Web3Handler', () => {
res.should.equal(storageValue)
})
})

describe('snapshot and revert', () => {
it('should fail (snapshot and revert should only be available in the TestHandler)', async () => {
const httpProvider = new ethers.providers.JsonRpcProvider(baseUrl)
await new Promise((resolve, reject) => {
httpProvider.send('evm_snapshot', []).catch((error) => {
error.message.should.equal('Method not found')
resolve()
})
})

await new Promise((resolve, reject) => {
httpProvider.send('evm_snapshot', []).catch((error) => {
error.message.should.equal('Method not found')
resolve()
})
})

await new Promise((resolve, reject) => {
httpProvider.send('evm_revert', ['0x01']).catch((error) => {
error.message.should.equal('Method not found')
resolve()
})
})
})
})
})
63 changes: 62 additions & 1 deletion packages/rollup-full-node/test/app/test-handler.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import '../setup'
/* External Imports */
import { add0x, getLogger, remove0x } from '@eth-optimism/core-utils'
import { ethers, ContractFactory } from 'ethers'

/* Internal Imports */
import { Web3RpcMethods, TestWeb3Handler } from '../../src'
import {
Web3RpcMethods,
TestWeb3Handler,
FullnodeRpcServer,
DefaultWeb3Handler,
} from '../../src'
import * as SimpleStorage from '../contracts/build/SimpleStorage.json'

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

const secondsSinceEopch = (): number => {
return Math.round(Date.now() / 1000)
}
const host = '0.0.0.0'
const port = 9999
const baseUrl = `http://${host}:${port}`

describe('TestHandler', () => {
let testHandler: TestWeb3Handler
Expand Down Expand Up @@ -60,4 +70,55 @@ describe('TestHandler', () => {
)
})
})

describe('Snapshot and revert', () => {
it('should revert state', async () => {
const testRpcServer = new FullnodeRpcServer(testHandler, host, port)

testRpcServer.listen()
const httpProvider = new ethers.providers.JsonRpcProvider(baseUrl)
const executionManagerAddress = await httpProvider.send(
'ovm_getExecutionManagerAddress',
[]
)
const privateKey = '0x' + '60'.repeat(32)
const wallet = new ethers.Wallet(privateKey, httpProvider)
log.debug('Wallet address:', wallet.address)
const factory = new ContractFactory(
SimpleStorage.abi,
SimpleStorage.bytecode,
wallet
)

const simpleStorage = await factory.deploy()
const deploymentTxReceipt = await wallet.provider.getTransactionReceipt(
simpleStorage.deployTransaction.hash
)

const storageKey = '0x' + '01'.repeat(32)
const storageValue = '0x' + '02'.repeat(32)
const storageValue2 = '0x' + '03'.repeat(32)
// Set storage with our new storage elements
const networkInfo = await httpProvider.getNetwork()
const tx = await simpleStorage.setStorage(
executionManagerAddress,
storageKey,
storageValue
)
const snapShotId = await httpProvider.send('evm_snapshot', [])
const tx2 = await simpleStorage.setStorage(
executionManagerAddress,
storageKey,
storageValue2
)
const receipt = await httpProvider.getTransactionReceipt(tx.hash)
const receipt2 = await httpProvider.getTransactionReceipt(tx2.hash)
const response2 = await httpProvider.send('evm_revert', [snapShotId])
const res = await simpleStorage.getStorage(
executionManagerAddress,
storageKey
)
res.should.equal(storageValue)
})
})
})

0 comments on commit 60dd08c

Please sign in to comment.