diff --git a/Dockerfile b/Dockerfile
index ac78d3ef6cf7..27a1589fcae9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,6 +4,9 @@ WORKDIR /server
COPY . /server
RUN yarn
+# Copy live env config updates file to /server so that it may be updated while running.
+COPY ./packages/rollup-full-node/config/env_var_updates.config /server
+
WORKDIR /server/packages/rollup-full-node
EXPOSE 8545
diff --git a/Dockerfile.dev b/Dockerfile.dev
new file mode 100644
index 000000000000..67f857340d8d
--- /dev/null
+++ b/Dockerfile.dev
@@ -0,0 +1,5 @@
+FROM node:11
+WORKDIR /mnt/full-node/packages/rollup-full-node
+
+EXPOSE 8545
+CMD [ "bash", "./exec/wait-for-nodes.sh", "yarn", "run", "server:fullnode:debug" ]
diff --git a/README.md b/README.md
index feb4d193ef89..aca47c845ef2 100644
--- a/README.md
+++ b/README.md
@@ -120,5 +120,20 @@ Run tests for a specific package or set of packages:
PKGS=your,packages,here yarn test
```
+### Running the fullnode in Docker
+Running the fullnode in [Docker](https://www.docker.com/) allows us launch our entire stack with a single command.
+
+To run the fullnode in Docker in production run:
+
+`docker-compose up`
+
+To run it in development run:
+
+```sh
+ rm -rf node_modules
+ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run rollup-full-node yarn
+ docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
+```
+
**Contributors: remember to run tests and lint before submitting a pull request!**
Linted code with passing tests makes life easier for everyone and means your contribution can get pulled into this project faster.
diff --git a/aws/synthetix/prod/web/docker-compose.yml b/aws/synthetix/prod/web/docker-compose.yml
index 46aaf2358824..923d83832c55 100644
--- a/aws/synthetix/prod/web/docker-compose.yml
+++ b/aws/synthetix/prod/web/docker-compose.yml
@@ -82,10 +82,10 @@ services:
postgres_pass: let-me-in
postgres_db: graph-node
ipfs: '0.0.0.0:5001'
- ethereum: 'ovm:http://0.0.0.0:8545'
+ ethereum: 'ovm:http://0.0.0.0:8546'
RUST_LOG: info
STARTUP_WAIT_TIMEOUT: 30
- OVM_URL_WITH_PORT: 'http://0.0.0.0:8545'
+ OVM_URL_WITH_PORT: 'http://0.0.0.0:8546'
volumes:
- postgres-data:/data/postgres
- ipfs-data:/data/ipfs
diff --git a/aws/synthetix/uat/web/docker-compose.yml b/aws/synthetix/uat/web/docker-compose.yml
index 298853271b15..4dd1b8100570 100644
--- a/aws/synthetix/uat/web/docker-compose.yml
+++ b/aws/synthetix/uat/web/docker-compose.yml
@@ -82,10 +82,10 @@ services:
postgres_pass: let-me-in
postgres_db: graph-node
ipfs: '0.0.0.0:5001'
- ethereum: 'ovm:http://0.0.0.0:8545'
+ ethereum: 'ovm:http://0.0.0.0:8546'
RUST_LOG: info
STARTUP_WAIT_TIMEOUT: 30
- OVM_URL_WITH_PORT: 'http://0.0.0.0:8545'
+ OVM_URL_WITH_PORT: 'http://0.0.0.0:8546'
volumes:
- postgres-data:/data/postgres
- ipfs-data:/data/ipfs
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
new file mode 100644
index 000000000000..9dc42c4d70a7
--- /dev/null
+++ b/docker-compose.dev.yml
@@ -0,0 +1,9 @@
+version: "3"
+services:
+
+ rollup-full-node:
+ build:
+ context: .
+ dockerfile: Dockerfile.dev
+ volumes:
+ - .:/mnt/full-node:rw
diff --git a/docker-compose.yml b/docker-compose.yml
index c89dd8714a91..19f7f871e471 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -46,6 +46,9 @@ services:
- L2_RPC_SERVER_PORT=8545
- TRANSACTION_NODE_URL=http://rollup-full-node:8546
- READ_ONLY_NODE_URL=http://read-only-node:8547
+ - REQUEST_LIMIT_PERIOD_MILLIS=1000
+ - MAX_NON_TRANSACTION_REQUESTS_PER_UNIT_TIME=10
+ - MAX_TRANSACTIONS_PER_UNIT_TIME=10
read-only-node:
image: optimism-monorepo_rollup-full-node:latest
@@ -77,7 +80,60 @@ services:
ports:
- 9545:9545
+ graph-node:
+ build:
+ context: docker/the-graph
+ dockerfile: Dockerfile
+ ports:
+ - '8000:8000'
+ - '8001:8001'
+ - '8020:8020'
+ - '8030:8030'
+ - '8040:8040'
+ environment:
+ postgres_host: postgres:5432
+ postgres_user: graph-node
+ postgres_pass: let-me-in
+ postgres_db: graph-node
+ ipfs: 'ipfs:5001'
+ ethereum: 'ovm:http://router:8545'
+ RUST_LOG: info
+ STARTUP_WAIT_TIMEOUT: 30
+ OVM_URL_WITH_PORT: 'http://router:8545'
+ volumes:
+ - postgres-data:/data/postgres
+ - ipfs-data:/data/ipfs
+
+ ipfs:
+ image: ipfs/go-ipfs:v0.4.23
+ ports:
+ - '5001:5001'
+ volumes:
+ - ipfs-data:/data/ipfs
+
+ postgres:
+ image: postgres
+ ports:
+ - '5432:5432'
+ command: ["postgres", "-cshared_preload_libraries=pg_stat_statements"]
+ environment:
+ POSTGRES_USER: graph-node
+ POSTGRES_PASSWORD: let-me-in
+ POSTGRES_DB: graph-node
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+
volumes:
full-node-data:
l1-node-data:
l2-node-data:
+ postgres-data:
+ ipfs-data:
+
+
+
+
+
+
+
+
diff --git a/packages/core-utils/src/app/log.ts b/packages/core-utils/src/app/log.ts
index 0aad713a0241..0df49bc0b84f 100644
--- a/packages/core-utils/src/app/log.ts
+++ b/packages/core-utils/src/app/log.ts
@@ -1,9 +1,24 @@
import debug from 'debug'
import { Logger } from '../types'
-export const LOG_NEWLINE_STRING = '<\n>'
-export const joinNewlinesAndDebug = (logs: string) =>
- debug(logs.replace('\n', LOG_NEWLINE_STRING))
+export const LOG_CR_STRING = '<\\r>'
+export const LOG_NEWLINE_STRING = '<\\n>'
+export const joinNewlinesAndDebug = (...logs: any[]) => {
+ const stringifiedLogs = []
+ for (const l of logs) {
+ if (typeof l !== 'string') {
+ stringifiedLogs.push(JSON.stringify(l))
+ } else {
+ stringifiedLogs.push(l)
+ }
+ }
+ return debug(
+ stringifiedLogs
+ .join(' ')
+ .replace(/\n/g, LOG_NEWLINE_STRING)
+ .replace(/\r/g, LOG_CR_STRING)
+ )
+}
export const getLogger = (
identifier: string,
diff --git a/packages/docs/src/core/src/spec/jump-transpilation.rst b/packages/docs/src/core/src/spec/jump-transpilation.rst
index c430c2652fdd..a154c130322d 100644
--- a/packages/docs/src/core/src/spec/jump-transpilation.rst
+++ b/packages/docs/src/core/src/spec/jump-transpilation.rst
@@ -59,4 +59,4 @@ Duplicate above code once for each (compare jumpdest, post-transpile jumpdest) p
**Note on bytecode interpretation**
-Note that properly processing these conditions requires preprocessing the code; a particularly pathological use case is ``PUSH2 JUMPDEST PUSH1 PUSH2 JUMPDEST PUSH1 PUSH2 JUMPDEST PUSH1 ...``, as this code has all ``JUMPDEST``s invalid but an alternative piece of code equivalent to this but only with the leading ``PUSH2`` replaced with another op (eg. ``BALANCE``) will have all ``JUMPDESTS`` valid. We appropriately deal with this, both in our transpiler and purity checker.
\ No newline at end of file
+Note that properly processing these conditions requires preprocessing the code; a particularly pathological use case is ``PUSH2 JUMPDEST PUSH1 PUSH2 JUMPDEST PUSH1 PUSH2 JUMPDEST PUSH1 ...``, as this code has all ``JUMPDEST``s invalid but an alternative piece of code equivalent to this but only with the leading ``PUSH2`` replaced with another op (eg. ``BALANCE``) will have all ``JUMPDESTS`` valid. We appropriately deal with this, both in our transpiler and safety checker.
\ No newline at end of file
diff --git a/packages/docs/src/core/src/spec/overview.rst b/packages/docs/src/core/src/spec/overview.rst
index db8ef8cda70d..63b414b654b6 100644
--- a/packages/docs/src/core/src/spec/overview.rst
+++ b/packages/docs/src/core/src/spec/overview.rst
@@ -4,7 +4,7 @@ OVM Overview and Architecture
The core functionality of the OVM is to run transactions in such a way that they are "pure" or "deterministic"--that is, no matter what time in the future a dispute about them is triggered on layer 1, the output of the computation is the same--*no matter what the state of the L1.
-To accomplish this, there are two critical smart contracts: the Execution Manager, and the Purity Checker.
+To accomplish this, there are two critical smart contracts: the Execution Manager, and the Safety Checker.
*****************
Execution Manager
@@ -19,10 +19,10 @@ The execution manager interfaces with "code contracts," which are contracts comp
**************
-Purity Checker
+Safety Checker
**************
-To ensure that the execution of an OVM transaction is deterministic between L1 and L2, we must enforce that **only** the container interface described above is used. To accomplish this, we have a "purity checker." The purity checker analyzes the low-level assembly bytecode of an EVM contract to tell the execution manager whether the code conforms to the OVM interface. If it does not, then the execution manager does not allow such a contract to be created or used in a fraud proof.
+To ensure that the execution of an OVM transaction is deterministic between L1 and L2, we must enforce that **only** the container interface described above is used. To accomplish this, we have a "safety checker." The safety checker analyzes the low-level assembly bytecode of an EVM contract to tell the execution manager whether the code conforms to the OVM interface. If it does not, then the execution manager does not allow such a contract to be created or used in a fraud proof.
.. raw:: html
diff --git a/packages/docs/src/core/src/spec/transpilation-details.rst b/packages/docs/src/core/src/spec/transpilation-details.rst
index b7c7416edbef..b5d3d70229c3 100644
--- a/packages/docs/src/core/src/spec/transpilation-details.rst
+++ b/packages/docs/src/core/src/spec/transpilation-details.rst
@@ -20,7 +20,7 @@ The following opcodes perform stack operations which are constant in terms of L1
- "Pure" memory modifying operations:
- ``MLOAD, MSTORE, MSTORE8, MSIZE``.
- Permitted execution-context-dependent operations:
- - ``CALLVALUE*, CALLDATALOAD, CALLDATASIZE, CALLDATACOPY, CODESIZE, RETURNDATASIZE, RETURNDATACOPY`` \*Note: ``CALLVALUE`` will always be 0 because we enforce that all ``CALL`` s always pass 0 in our purity checking.
+ - ``CALLVALUE*, CALLDATALOAD, CALLDATASIZE, CALLDATACOPY, CODESIZE, RETURNDATASIZE, RETURNDATACOPY`` \*Note: ``CALLVALUE`` will always be 0 because we enforce that all ``CALL`` s always pass 0 in our safety checking.
Replaced Opcodes
================
@@ -119,7 +119,7 @@ These opcodes are banned simply because we don't want to support them currently.
ETH-native Value
-----------------------------------------
-We have made the decision for now not to use native ETH, and instead do everything with wrapped ETH (WETH). Note: ``CALLVALUE`` is actually able to be whitelisted, because our Purity Checker enforces that all Calls are made with a value of 0. Contracts are welcome to use msg.value, it will just always return 0. This means that the following opcodes are banned, not just transpiled:
+We have made the decision for now not to use native ETH, and instead do everything with wrapped ETH (WETH). Note: ``CALLVALUE`` is actually able to be whitelisted, because our Safety Checker enforces that all Calls are made with a value of 0. Contracts are welcome to use msg.value, it will just always return 0. This means that the following opcodes are banned, not just transpiled:
- ``BALANCE`` -- gets ``address(this).balance``
While not a ban, another note here is that all ``value``-related inputs to other opcodes like ``CREATE`` or ``CALL`` are overridden to ``0`` by their transpiled counterparts. We do have good inline documentation for how a native ``value`` could be added if needed. Another option is we could even transpile the native ETH opcodes to use ``WETH`` instead. TBD.
diff --git a/packages/ovm/config/.env.example b/packages/ovm/config/.env.example
index e1d7d24f2be3..8e44b8c42c8d 100644
--- a/packages/ovm/config/.env.example
+++ b/packages/ovm/config/.env.example
@@ -13,7 +13,7 @@
# Mnemonic for the wallet used to deploy the contracts
DEPLOY_MNEMONIC='response fresh afford leader twice silent table exist aisle pelican focus bird'
-DEPLOY_PURITY_CHECKER_CONTRACT_ADDRESS='0x some address here'
+DEPLOY_SAFETY_CHECKER_CONTRACT_ADDRESS='0x some address here'
# Note: can use any network name. 'local' or leaving it blank will deploy to DEPLOY_LOCAL_URL
DEPLOY_NETWORK='local'
@@ -30,4 +30,4 @@ OPCODE_WHITELIST_MASK='0x600a0000000000000000001fffffffffffffffff0fcf000063f0000
# CREATE, CREATE2, DELEGATECALL, DIFFICULTY, EXTCODECOPY, EXTCODESIZE,
# GASLIMIT, GASPRICE, NUMBER, ORIGIN, SELFDESTRUCT, SLOAD, SSTORE,
# STATICCALL, TIMESTAMP
-# See test/purity-checker/whitelist-mask-generator.spec.ts for more info
+# See test/safety-checker/whitelist-mask-generator.spec.ts for more info
diff --git a/packages/ovm/deploy/execution-manager.ts b/packages/ovm/deploy/execution-manager.ts
index 0f906401f993..21f98c6d2785 100644
--- a/packages/ovm/deploy/execution-manager.ts
+++ b/packages/ovm/deploy/execution-manager.ts
@@ -3,7 +3,7 @@ import { deploy, deployContract } from '@eth-optimism/core-utils'
import { Wallet } from 'ethers'
/* Internal Imports */
-import { deployPurityChecker } from './purity-checker'
+import { deploySafetyChecker } from './safety-checker'
import * as ExecutionManager from '../build/contracts/ExecutionManager.json'
import { resolve } from 'path'
import { GAS_LIMIT, DEFAULT_OPCODE_WHITELIST_MASK } from '../src/app'
@@ -13,13 +13,13 @@ const executionManagerDeploymentFunction = async (
): Promise => {
console.log(`\nDeploying ExecutionManager!\n`)
- const purityCheckerContractAddress = await deployPurityChecker()
+ const safetyCheckerContractAddress = await deploySafetyChecker()
const executionManager = await deployContract(
ExecutionManager,
wallet,
DEFAULT_OPCODE_WHITELIST_MASK,
- purityCheckerContractAddress,
+ safetyCheckerContractAddress,
GAS_LIMIT,
true
)
diff --git a/packages/ovm/deploy/purity-checker.ts b/packages/ovm/deploy/safety-checker.ts
similarity index 61%
rename from packages/ovm/deploy/purity-checker.ts
rename to packages/ovm/deploy/safety-checker.ts
index 2cb18e8f3a95..a8415b9f1dce 100644
--- a/packages/ovm/deploy/purity-checker.ts
+++ b/packages/ovm/deploy/safety-checker.ts
@@ -4,23 +4,23 @@ import { deploy, deployContract, add0x } from '@eth-optimism/core-utils'
import { Wallet } from 'ethers'
/* Internal Imports */
-import * as PurityChecker from '../build/contracts/PurityChecker.json'
+import * as SafetyChecker from '../build/contracts/SafetyChecker.json'
import { resolve } from 'path'
-const purityCheckerDeploymentFunction = async (
+const safetyCheckerDeploymentFunction = async (
wallet: Wallet
): Promise => {
- let purityCheckerContractAddress =
- process.env.DEPLOY_PURITY_CHECKER_CONTRACT_ADDRESS
- if (!purityCheckerContractAddress) {
- console.log(`\nDeploying Purity Checker!\n`)
+ let safetyCheckerContractAddress =
+ process.env.DEPLOY_SAFETY_CHECKER_CONTRACT_ADDRESS
+ if (!safetyCheckerContractAddress) {
+ console.log(`\nDeploying Safety Checker!\n`)
// Default config whitelists all opcodes EXCEPT:
// ADDRESS, BALANCE, BLOCKHASH, CALLCODE, CALLER, COINBASE,
// CREATE, CREATE2, DELEGATECALL, DIFFICULTY, EXTCODECOPY, EXTCODESIZE,
// GASLIMIT, GASPRICE, NUMBER, ORIGIN, SELFDESTRUCT, SLOAD, SSTORE,
// STATICCALL, TIMESTAMP
- // See test/purity-checker/whitelist-mask-generator.spec.ts for more info
+ // See test/contracts/whitelist-mask-generator.spec.ts for more info
const whitelistMask =
process.env.OPCODE_WHITELIST_MASK ||
'0x600a0000000000000000001fffffffffffffffff0fcf000063f000013fff0fff'
@@ -29,41 +29,41 @@ const purityCheckerDeploymentFunction = async (
process.env.EXECUTION_MANAGER_ADDRESS || add0x('12'.repeat(20))
console.log(
- `Deploying Purity Checker using mask '${whitelistMask}' and execution manager '${executionManagerAddress}'...`
+ `Deploying Safety Checker using mask '${whitelistMask}' and execution manager '${executionManagerAddress}'...`
)
whitelistMask
- const purityChecker = await deployContract(
- PurityChecker,
+ const safetyChecker = await deployContract(
+ SafetyChecker,
wallet,
whitelistMask,
executionManagerAddress
)
- purityCheckerContractAddress = purityChecker.address
+ safetyCheckerContractAddress = safetyChecker.address
console.log(
- `Purity Checker deployed to ${purityCheckerContractAddress}!\n\n`
+ `Safety Checker deployed to ${safetyCheckerContractAddress}!\n\n`
)
} else {
console.log(
- `Using Purity Checker contract at ${purityCheckerContractAddress}\n`
+ `Using Safety Checker contract at ${safetyCheckerContractAddress}\n`
)
}
- return purityCheckerContractAddress
+ return safetyCheckerContractAddress
}
/**
- * Deploys the Purity Checker contract.
+ * Deploys the Safety Checker contract.
*
* @param rootContract Whether or not this is the main contract being deployed (as compared to a dependency).
* @returns The deployed contract's address.
*/
-export const deployPurityChecker = async (
+export const deploySafetyChecker = async (
rootContract: boolean = false
): Promise => {
// Note: Path is from 'build/deploy/