Skip to content

Commit

Permalink
Simple Contract Integrations (ethereum-optimism#16)
Browse files Browse the repository at this point in the history
* fix timestamp

* Changing examples package to be more generic (ethereum-optimism#64)

* Changing examples package to be more generic
* Updating default exec manager address

* Add executable fullnode (ethereum-optimism#66)

* Add executable fullnode

* Add better logging with debug mode

* Fix linting bug

* Fixing output bytecode to not have 0x prepended (ethereum-optimism#70)

* Add test for SLOAD and SSTORE shims in the govm (ethereum-optimism#39)

We've forked Geth to intercept calls to the ExecutionManger contract in ethereum-optimism/go-ethereum#1. Add a a test that tests these changes. The test is a copy of the existing simple storage spec with some minor changes. Namely, we don't test that storage events were emitted when ExecutionManager#ovmSSTORE is called because our forked version of Geth doesn't emit events. This also makes a couple changes to test helper file:

We pass in the address of the ExecutionManager to manuallyDeployOvmContract instead of the ExecutionManager itself. This allows us to pass in an address of an ExecutionManager that's already been deployed which we need to do in our new test.

Replace getTransactionReceipt with waitForTransaction. When we were using the Javascript provider transactions would be mined more-or-less immediately. This means that getTransactionReceipt could be called immediately after sendTransaction and the transaction would be ready. When we're talking to a Geth node this may not be the case. Switching to waitForTransaction allows time for the transaction to be mined.

* Truffle ERC-20 Example (ethereum-optimism#69)

Working Truffle Example!
Note: A small hack is required to get this to work -- documented in `packages/examples/truffle-config.js`

Also adds:
* Fix for nonces in ExecutionManager.sol
* Gas limit fix setting it to the required 9_000_000 vs 5_000_000 in the fullnode
* Util for adding padding to strings to make them of a certain length
* Optional `add0x` param on `bufToHexStr(...)`
* Lock around separate txs that are assumed to be run sequentially in DefaultWeb3Handler

Co-authored-by: Mason Fischer <[email protected]>

* Test that nonces are incremented on calls (ethereum-optimism#71)

Before we were only incrementing nonces on CREATE. Wallets expect nonces
to be incremented on CALLs aswell. This test tests that we are in fact
inrementing nonces on CALLs aswell.

Other changes:

* Update the name of the executeCall test

* Configuring OVM in separate truffle config as an easy example of side-by-side standard testing & ovm testing (ethereum-optimism#72)

* pre rebase

* move tests to fullnode pkg;2C

* add txorigin test

* finish dep struggles

* typo

Co-authored-by: Will Meister <[email protected]>
Co-authored-by: Karl Floersch <[email protected]>
Co-authored-by: Mason Fischer <[email protected]>
  • Loading branch information
4 people authored Mar 4, 2020
1 parent a896fce commit 00581e3
Show file tree
Hide file tree
Showing 18 changed files with 223 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const defaultWhitelist: EVMOpcode[] = [
Opcode.EXP,
Opcode.EXTCODECOPY,
Opcode.EXTCODESIZE,
Opcode.EXTCODEHASH,
Opcode.GAS,
Opcode.GT,
Opcode.INVALID,
Expand All @@ -93,6 +94,7 @@ const defaultWhitelist: EVMOpcode[] = [
Opcode.MULMOD,
Opcode.NOT,
Opcode.OR,
Opcode.ORIGIN,
Opcode.PC,
Opcode.POP,
Opcode.PUSH1,
Expand Down
14 changes: 12 additions & 2 deletions packages/rollup-dev-tools/src/tools/transpiler/transpiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,21 @@ export class TranspilerImpl implements Transpiler {
const deployedBytecodeTranspilationResult: TaggedTranspilationResult = this.transpileBytecodePreservingTags(
taggedDeployedEVMBytecode
)
// todo error handle however above

if (!deployedBytecodeTranspilationResult.succeeded) {
errors.push(
...(deployedBytecodeTranspilationResult as ErroredTranspilation).errors
)
return {
succeeded: false,
errors,
}
}
const transpiledDeployedBytecode: EVMBytecode =
deployedBytecodeTranspilationResult.bytecodeWithTags

log.debug(`Fixing constant indices for transpiled deployed bytecode...`)
log.debug(`Fixing the constant indices for transpiled deployed bytecode...`)
log.debug(`errors are: ${JSON.stringify(errors)}`)
// Note that fixTaggedConstantOffsets() scrubs all fixed tags, so we do not re-fix when we use finalTranspiledDeployedBytecode to reconstruct the returned initcode
const finalTranspiledDeployedBytecode: EVMBytecode = this.fixTaggedConstantOffsets(
transpiledDeployedBytecode as EVMBytecode,
Expand Down Expand Up @@ -186,6 +191,10 @@ export class TranspilerImpl implements Transpiler {
...(constructorInitLogicTranspilationResult as ErroredTranspilation)
.errors
)
return {
succeeded: false,
errors,
}
}
const transpiledConstructorInitLogic: EVMBytecode =
constructorInitLogicTranspilationResult.bytecodeWithTags
Expand Down Expand Up @@ -251,6 +260,7 @@ export class TranspilerImpl implements Transpiler {
taggedBytecode: EVMBytecode,
errors
): EVMBytecode {
log.debug(`tagged input: ${formatBytecode(taggedBytecode)}`)
const inputAsBuf: Buffer = bytecodeToBuffer(taggedBytecode)
const bytecodeToReturn: EVMBytecode = []
for (const [index, op] of taggedBytecode.entries()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ describe('Solitity contracts should have constants correctly accessible when usi
const bytesMemoryConstB: Buffer = Buffer.from(
`this should pass but the error message is much longer`
)
it('should work for the first bytes memory constant', async () => {
it('should work for the second bytes memory constant', async () => {
const retrievedBytesMemoryBVal: Buffer = await getGetterReturnedVal(
deployedGetterAddress,
'getBytesMemoryConstantB',
Expand Down
9 changes: 6 additions & 3 deletions packages/rollup-full-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
],
"scripts": {
"all": "yarn clean && yarn build && yarn test && yarn fix && yarn lint",
"build": "waffle waffle-config.json && tsc -p .",
"clean": "rimraf build/ && rimraf test/contracts/build",
"build": "waffle waffle-config-untranspiled.json && waffle waffle-config-transpiled.json && tsc -p .",
"clean": "rimraf build/ && yarn clean-contracts",
"fix": "prettier --config ../../prettier-config.json --write 'index.ts' '{src,test}/**/*.ts'",
"lint": "tslint --format stylish --project .",
"test": "waffle waffle-config.json && mocha --require source-map-support/register --require ts-node/register 'test/**/*.spec.ts' --timeout 8000 --exit",
"test": "yarn build-contracts && mocha --require source-map-support/register --require ts-node/register 'test/**/*.spec.ts' --timeout 8000 --exit",
"clean-contracts": "rimraf ./test/contracts/build && mkdir ./test/contracts/build && mkdir ./test/contracts/build/transpiled && mkdir ./test/contracts/build/untranspiled",
"build-contracts": "yarn clean-contracts && waffle waffle-config-untranspiled.json && waffle waffle-config-transpiled.json",
"server:aggregator": "env DEBUG=\"info:*,error:*\" node ./exec/aggregator.js",
"server:fullnode": "env DEBUG=\"info:*,error:*\" node ./exec/fullnode.js",
"server:fullnode:debug": "env DEBUG=\"info:*,error:*,debug:*\" node ./exec/fullnode.js"
Expand Down Expand Up @@ -45,6 +47,7 @@
"fastpriorityqueue": "^0.6.3"
},
"devDependencies": {
"@eth-optimism/solc-transpiler": "^0.0.1-alpha.12",
"@types/abstract-leveldown": "^5.0.1",
"@types/chai": "^4.1.7",
"@types/mocha": "^5.2.7",
Expand Down
8 changes: 6 additions & 2 deletions packages/rollup-full-node/test/app/handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import '../setup'
import { getLogger } from '@eth-optimism/core-utils'

/* Internal Imports */
import { FullnodeRpcServer, DefaultWeb3Handler } from '../../src/app'
import * as SimpleStorage from '../contracts/build/SimpleStorage.json'
import {
FullnodeRpcServer,
deployOvmContract,
DefaultWeb3Handler,
} from '../../src/app'
import * as SimpleStorage from '../contracts/build/untranspiled/SimpleStorage.json'
import { ethers, ContractFactory } from 'ethers'
import { FullnodeHandler } from '../../src/types'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pragma solidity ^0.5.0;
import "./CallerReturner.sol";

contract CallerGetter {
function getMsgSenderFrom(address _callerReturner) public view returns(address) {
return CallerReturner(_callerReturner).getMsgSender();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity ^0.5.0;

contract CallerReturner {
function getMsgSender() public view returns(address) {
return msg.sender;
}
}
19 changes: 19 additions & 0 deletions packages/rollup-full-node/test/contracts/transpiled/ExtCode.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pragma solidity ^0.5.0;

contract ExtCode {
function getExtCodeSizeOf(address _addr) public returns(uint) {
uint toReturn;
assembly {
toReturn:= extcodesize(_addr)
}
return toReturn;
}

function getExtCodeHashOf(address _addr) public returns(bytes32) {
bytes32 toReturn;
assembly {
toReturn:= extcodehash(_addr)
}
return toReturn;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity ^0.5.0;

contract OriginGetter {
function getTxOrigin() public view returns(address) {
return tx.origin;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity ^0.5.0;

contract SelfAware {
function getMyAddress() public view returns(address) {
return address(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pragma solidity ^0.5.0;
import "./SimpleStorage.sol";

contract SimpleCaller {
function doGetStorageCall(address _target, bytes32 key) public view returns(bytes32) {
return SimpleStorage(_target).getStorage(key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity ^0.5.0;

contract SimpleStorage {
mapping(bytes32 => bytes32) public builtInStorage;
function setStorage(bytes32 key, bytes32 value) public {
builtInStorage[key] = value;
}

function getStorage(bytes32 key) public view returns (bytes32) {
return builtInStorage[key];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity ^0.5.0;

contract TimeGetter {
function getTimestamp() public view returns(uint256) {
return block.timestamp;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import '../../../rollup-dev-tools/test/setup'
/* External Imports */
import {
getLogger,
remove0x,
bufToHexString,
hexStrToBuf,
} from '@eth-optimism/core-utils'
import {
Address,
formatBytecode,
bufferToBytecode,
} from '@eth-optimism/rollup-core'

/* Contract Imports */

import * as SimpleStorage from '../contracts/build/transpiled/SimpleStorage.json'
import * as SimpleCaller from '../contracts/build/transpiled/SimpleCaller.json'
import * as SelfAware from '../contracts/build/transpiled/SelfAware.json'
import * as CallerGetter from '../contracts/build/transpiled/CallerGetter.json'
import * as OriginGetter from '../contracts/build/transpiled/OriginGetter.json'
import * as CallerReturner from '../contracts/build/transpiled/CallerReturner.json'
import * as TimeGetter from '../contracts/build/transpiled/TimeGetter.json'

import { createMockProvider, getWallets, deployContract } from '../../'

describe(`Various opcodes should be usable in combination with transpiler and full node`, () => {
let provider
let wallet

beforeEach(async () => {
provider = await createMockProvider()
const wallets = getWallets(provider)
wallet = wallets[0]
})

afterEach(() => {
provider.closeOVM()
})

// TEST BASIC FUNCTIONALITIES

it('should process cross-ovm-contract calls', async () => {
const simpleStorage = await deployContract(wallet, SimpleStorage, [], [])
const simpleCaller = await deployContract(wallet, SimpleCaller, [], [])

const storageKey = '0x' + '01'.repeat(32)
const storageValue = '0x' + '02'.repeat(32)

await simpleStorage.setStorage(storageKey, storageValue)

const res = await simpleCaller.doGetStorageCall(
simpleStorage.address,
storageKey
)
res.should.equal(storageValue)
})
it('should work for address(this)', async () => {
const selfAware = await deployContract(wallet, SelfAware, [], [])
const deployedAddress: Address = selfAware.address
const returnedAddress: Address = await selfAware.getMyAddress()
deployedAddress.should.equal(returnedAddress)
})
it.skip('should work for block.timestamp', async () => {
// todo, once we handle timestamps, unskip this test
const timeGetter = await deployContract(wallet, TimeGetter, [], [])
const time = await timeGetter.getTimestamp()
time._hex.should.equal('???')
})
it('should work for msg.sender', async () => {
const callerReturner = await deployContract(wallet, CallerReturner, [], [])
const callerGetter = await deployContract(wallet, CallerGetter, [], [])
const result = await callerGetter.getMsgSenderFrom(callerReturner.address)
result.should.equal(callerGetter.address)
})
it('should work for tx.origin', async () => {
const originGetter = await deployContract(wallet, OriginGetter, [], [])
const result = await originGetter.getTxOrigin()
result.should.equal(wallet.address)
})

// SIMPLE STORAGE TEST
it('should set storage & retrieve the value', async () => {
const simpleStorage = await deployContract(wallet, SimpleStorage, [], [])
// Create some constants we will use for storage
const storageKey = '0x' + '01'.repeat(32)
const storageValue = '0x' + '02'.repeat(32)
// Set storage with our new storage elements
await simpleStorage.setStorage(storageKey, storageValue)
// Get the storage
const res = await simpleStorage.getStorage(storageKey)
// Verify we got the value!
res.should.equal(storageValue)
})
})
14 changes: 14 additions & 0 deletions packages/rollup-full-node/waffle-config-transpiled.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"sourcesPath": "./test/contracts/transpiled",
"targetPath": "./test/contracts/build/transpiled",
"npmPath": "../../node_modules",
"solcVersion": "../../node_modules/@eth-optimism/solc-transpiler",
"compilerOptions": {
"outputSelection": {
"*": {
"*": ["*"]
}
},
"executionManagerAddress": "0xA193E42526F1FEA8C99AF609dcEabf30C1c29fAA"
}
}
12 changes: 12 additions & 0 deletions packages/rollup-full-node/waffle-config-untranspiled.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"sourcesPath": "./test/contracts/untranspiled",
"targetPath": "./test/contracts/build/untranspiled",
"npmPath": "../../node_modules",
"compilerOptions": {
"outputSelection": {
"*": {
"*": ["*"]
}
}
}
}
5 changes: 0 additions & 5 deletions packages/rollup-full-node/waffle-config.json

This file was deleted.

0 comments on commit 00581e3

Please sign in to comment.