From 2ca62fb41be6ef69b0c07a1bd5502ac425aaf341 Mon Sep 17 00:00:00 2001 From: Kevin Ho Date: Mon, 27 Apr 2020 22:11:55 -0400 Subject: [PATCH 01/10] remove to field override in getLogs (#113) --- 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 558bd8295d293..a8cd0b4ca1c78 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -498,7 +498,6 @@ export class DefaultWeb3Handler const receipt = await this.getTransactionReceipt(transaction.hash) transaction['to'] = receipt.contractAddress } - logItem['address'] = transaction['to'] return logItem }) From 16713101675c815d1ed6ac1243833bb7ce0ee087 Mon Sep 17 00:00:00 2001 From: Will Meister Date: Tue, 28 Apr 2020 11:43:29 -0500 Subject: [PATCH 02/10] Updating environment deploy scripts with new containers (#112) * Updating deployment scripts for The Graph, the router / routed servers, and updating CPU shares --- aws/synthetix/dev/README.md | 37 ++++++ .../dev/full-node/docker-compose.yml | 56 +++++++- aws/synthetix/dev/full-node/ecs-params.yml | 26 ++-- aws/synthetix/prod/geth/ecs-params.yml | 1 + aws/synthetix/prod/web/README.md | 4 + aws/synthetix/prod/web/docker-compose.yml | 120 +++++++++++++++-- aws/synthetix/prod/web/ecs-params.yml | 58 ++++++-- aws/synthetix/uat/geth/ecs-params.yml | 1 + aws/synthetix/uat/web/README.md | 4 + aws/synthetix/uat/web/docker-compose.yml | 124 ++++++++++++++++-- aws/synthetix/uat/web/ecs-params.yml | 60 +++++++-- .../src/app/routing-handler.ts | 2 +- .../src/simple-storage-stress-test.ts | 2 +- 13 files changed, 438 insertions(+), 57 deletions(-) create mode 100644 aws/synthetix/dev/README.md diff --git a/aws/synthetix/dev/README.md b/aws/synthetix/dev/README.md new file mode 100644 index 0000000000000..8e261a4978590 --- /dev/null +++ b/aws/synthetix/dev/README.md @@ -0,0 +1,37 @@ +# Deploying Web RPC Server to Synthetix dev + +## Prerequisites +See prerequisites from parent AWS directory. + +## Steps + +### 1) Configure the Amazon ECS CLI +1. Create a cluster configuration: + ``` + ecs-cli configure --cluster synthetix-dev --default-launch-type EC2 --config-name synthetix-dev-config --region us-east-2 + ``` + +2. Create a profile to use to create the environment + ``` + ecs-cli configure profile --access-key --secret-key --profile-name synthetix-dev-profile + ``` + +### 2) Create the Cluster + ``` + ecs-cli up --keypair optimism-dev --capability-iam --size 1 --instance-type t2.medium --cluster-config synthetix-dev-config --ecs-profile synthetix-dev-profile --port 8545 --security-group --vpc --subnets + ``` + +This may take a few minutes to finish. The result will be a fully provisioned EC2 instance on which your service/task will be deployed. + +### 3) Choose the appropriate `docker-compose.yml` and `ecs-params.yml` +For the rest of the commands, you'll need to be in this directory to use the `docker-compose.yml` and an `ecs-params.yml`. +Make any necessary changes now. + +### 4) Deploy Service & Task to Cluster + ``` + ecs-cli compose --project-name synthetix-dev service up --vpc --cluster-config synthetix-dev-config --ecs-profile synthetix-dev-profile --create-log-groups + ``` + + +# Redeploying after first deploy +Repeat step #4 above diff --git a/aws/synthetix/dev/full-node/docker-compose.yml b/aws/synthetix/dev/full-node/docker-compose.yml index 887d5c7051bd7..99be116442656 100644 --- a/aws/synthetix/dev/full-node/docker-compose.yml +++ b/aws/synthetix/dev/full-node/docker-compose.yml @@ -1,22 +1,47 @@ version: "3" services: - rollup-full-node: + router: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:latest + ports: + - 8545:8545 + environment: + - IS_ROUTING_SERVER=1 + - STARTUP_WAIT_TIMEOUT=30 + - L2_RPC_SERVER_HOST + - L2_RPC_SERVER_PORT=8545 + - TRANSACTION_NODE_URL=http://0.0.0.0:8546 + - READ_ONLY_NODE_URL=http://0.0.0.0:8547 + - REQUEST_LIMIT_PERIOD_MILLIS=1000 + - MAX_NON_TRANSACTION_REQUESTS_PER_UNIT_TIME=10 + - MAX_TRANSACTIONS_PER_UNIT_TIME=5 +# These are just so it waits for the downstream nodes to start up + - L2_NODE_WEB3_URL=http://0.0.0.0:8546 + - L1_NODE_WEB3_URL=http://0.0.0.0:8547 + logging: + driver: awslogs + options: + awslogs-group: synthetix-dev-full-node + awslogs-region: us-east-2 + awslogs-stream-prefix: l2-router + + transaction-node: image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:latest volumes: - full-node-data:/mnt/full-node:rw - l1-node-data:/mnt/l1-node:rw - l2-node-data:/mnt/l2-node:rw ports: - - 8545:8545 + - 8546:8546 environment: + - IS_TRANSACTION_NODE=1 - STARTUP_WAIT_TIMEOUT=30 - CLEAR_DATA_KEY - OPCODE_WHITELIST_MASK - L1_SEQUENCER_MNEMONIC - L2_TO_L1_MESSAGE_RECEIVER_ADDRESS - L2_TO_L1_MESSAGE_FINALITY_DELAY_IN_BLOCKS - - L2_RPC_SERVER_HOST - - L2_RPC_SERVER_PORT + - L2_RPC_SERVER_HOST=0.0.0.0 + - L2_RPC_SERVER_PORT=8546 - L2_RPC_SERVER_PERSISTENT_DB_PATH=/mnt/full-node/level - L2_WALLET_PRIVATE_KEY=0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797 - LOCAL_L1_NODE_PORT @@ -28,9 +53,28 @@ services: options: awslogs-group: synthetix-dev-full-node awslogs-region: us-east-2 - awslogs-stream-prefix: l2-rpc-server + awslogs-stream-prefix: l2-transaction-node + + read-only-node: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:latest + ports: + - 8547:8547 + environment: + - IS_READ_ONLY_NODE=1 + - STARTUP_WAIT_TIMEOUT=30 + - L2_RPC_SERVER_HOST=0.0.0.0 + - L2_RPC_SERVER_PORT=8547 + - L2_EXECUTION_MANAGER_ADDRESS=0xA193E42526F1FEA8C99AF609dcEabf30C1c29fAA + - L2_WALLET_PRIVATE_KEY=0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797 + - L2_NODE_WEB3_URL=http://0.0.0.0:9545/ + logging: + driver: awslogs + options: + awslogs-group: synthetix-dev-full-node + awslogs-region: us-east-2 + awslogs-stream-prefix: l2-read-only-node - geth_l2: + l2-node: image: .dkr.ecr.us-east-2.amazonaws.com/optimism/geth:latest volumes: - l2-node-data:/mnt/l2-node/l2:rw diff --git a/aws/synthetix/dev/full-node/ecs-params.yml b/aws/synthetix/dev/full-node/ecs-params.yml index d09b2d82748af..43976e0aecd59 100644 --- a/aws/synthetix/dev/full-node/ecs-params.yml +++ b/aws/synthetix/dev/full-node/ecs-params.yml @@ -1,21 +1,27 @@ version: 1 task_definition: services: - rollup-full-node: - cpu_shares: 20 + router: + cpu_shares: 204 + mem_limit: 262144000 + transaction-node: + cpu_shares: 408 mem_limit: 524288000 - geth_l2: - cpu_shares: 60 + read-only-node: + cpu_shares: 204 + mem_limit: 262144000 + l2-node: + cpu_shares: 820 mem_limit: 1597847999 graph-node: - cpu_shares: 10 - mem_limit: 524288000 + cpu_shares: 204 + mem_limit: 262144000 ipfs: - cpu_shares: 5 - mem_limit: 524288000 + cpu_shares: 102 + mem_limit: 262144000 postgres: - cpu_shares: 5 - mem_limit: 524288000 + cpu_shares: 102 + mem_limit: 262144000 # This is all local for now -- eventually will change diff --git a/aws/synthetix/prod/geth/ecs-params.yml b/aws/synthetix/prod/geth/ecs-params.yml index 3b5987102a9ab..937c9db37ca36 100644 --- a/aws/synthetix/prod/geth/ecs-params.yml +++ b/aws/synthetix/prod/geth/ecs-params.yml @@ -10,6 +10,7 @@ task_definition: # retries: 3 # start_period: 10s mem_limit: 32653700000 + cpu_shares: 16384 ecs_network_mode: awsvpc diff --git a/aws/synthetix/prod/web/README.md b/aws/synthetix/prod/web/README.md index 56e119b2dc568..bd45f3461b8ac 100644 --- a/aws/synthetix/prod/web/README.md +++ b/aws/synthetix/prod/web/README.md @@ -31,3 +31,7 @@ Make any necessary changes now. ``` ecs-cli compose --project-name synthetix-prod-web service up --vpc --cluster-config synthetix-prod-web-config --ecs-profile synthetix-prod-web-profile --create-log-groups ``` + + +# Redeploying after first deploy +Repeat step #4 above \ No newline at end of file diff --git a/aws/synthetix/prod/web/docker-compose.yml b/aws/synthetix/prod/web/docker-compose.yml index 20251f636c275..3fdd36d034175 100644 --- a/aws/synthetix/prod/web/docker-compose.yml +++ b/aws/synthetix/prod/web/docker-compose.yml @@ -1,29 +1,133 @@ version: "3" services: - rollup-full-node: + router: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:synthetix-prod + ports: + - 8545:8545 + environment: + - IS_ROUTING_SERVER=1 + - STARTUP_WAIT_TIMEOUT=60 + - L2_RPC_SERVER_HOST + - L2_RPC_SERVER_PORT=8545 + - TRANSACTION_NODE_URL=http://0.0.0.0:8546 + - READ_ONLY_NODE_URL=http://0.0.0.0:8547 + - REQUEST_LIMIT_PERIOD_MILLIS=1000 + - MAX_NON_TRANSACTION_REQUESTS_PER_UNIT_TIME=50 + - MAX_TRANSACTIONS_PER_UNIT_TIME=10 +# These are just so it waits for the downstream nodes to start up + - L2_NODE_WEB3_URL=http://0.0.0.0:8546 + - L1_NODE_WEB3_URL=http://0.0.0.0:8547 + + logging: + driver: awslogs + options: + awslogs-group: synthetix-prod-web + awslogs-region: us-east-2 + awslogs-stream-prefix: l2-router + + transaction-node: image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:synthetix-prod volumes: - full-node-data:/mnt/full-node:rw - - l1-node-data:/mnt/l1-node:rw ports: - - 8545:8545 + - 8546:8546 environment: + - IS_TRANSACTION_NODE=1 - CLEAR_DATA_KEY - STARTUP_WAIT_TIMEOUT=60 - - LOCAL_L1_NODE_PERSISTENT_DB_PATH=/mnt/l1-node + - NO_L1_NODE=1 - L2_RPC_SERVER_PERSISTENT_DB_PATH=/mnt/full-node/level - L2_WALLET_PRIVATE_KEY=0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797 - L2_NODE_WEB3_URL=http://synthetix-prod-geth.synthetix-prod:9545 + - L2_RPC_SERVER_HOST=0.0.0.0 + - L2_RPC_SERVER_PORT=8546 logging: driver: awslogs options: awslogs-group: synthetix-prod-web awslogs-region: us-east-2 - awslogs-stream-prefix: web + awslogs-stream-prefix: l2-transaction-node + + read-only-node: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:synthetix-prod + ports: + - 8547:8547 + environment: + - IS_READ_ONLY_NODE=1 + - STARTUP_WAIT_TIMEOUT=30 + - L2_RPC_SERVER_HOST=0.0.0.0 + - L2_RPC_SERVER_PORT=8547 + - L2_EXECUTION_MANAGER_ADDRESS=0xA193E42526F1FEA8C99AF609dcEabf30C1c29fAA + - L2_WALLET_PRIVATE_KEY=0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797 + - L2_NODE_WEB3_URL=http://synthetix-prod-geth.synthetix-prod:9545 + logging: + driver: awslogs + options: + awslogs-group: synthetix-prod-web + awslogs-region: us-east-2 + awslogs-stream-prefix: l2-read-only-node + + graph-node: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/the-graph:latest + ports: + - '8000:8000' + - '8001:8001' + - '8020:8020' + - '8030:8030' + - '8040:8040' + environment: + postgres_host: 0.0.0.0:5432 + postgres_user: graph-node + postgres_pass: let-me-in + postgres_db: graph-node + ipfs: '0.0.0.0:5001' + ethereum: 'ovm:http://0.0.0.0:8545' + RUST_LOG: info + STARTUP_WAIT_TIMEOUT: 30 + OVM_URL_WITH_PORT: 'http://0.0.0.0:8545' + + logging: + driver: awslogs + options: + awslogs-group: synthetix-prod-web + awslogs-region: us-east-2 + awslogs-stream-prefix: the-graph + + ipfs: + image: ipfs/go-ipfs:v0.4.23 + ports: + - '5001:5001' + volumes: + - ipfs-data:/data/ipfs + + logging: + driver: awslogs + options: + awslogs-group: synthetix-prod-web + awslogs-region: us-east-2 + awslogs-stream-prefix: the-graph-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 + + logging: + driver: awslogs + options: + awslogs-group: synthetix-prod-web + awslogs-region: us-east-2 + awslogs-stream-prefix: the-graph-postgres volumes: full-node-data: - l1-node-data: - l2-node-data: - + postgres-data: + ipfs-data: \ No newline at end of file diff --git a/aws/synthetix/prod/web/ecs-params.yml b/aws/synthetix/prod/web/ecs-params.yml index 6063db89d90b1..1513761c445f1 100644 --- a/aws/synthetix/prod/web/ecs-params.yml +++ b/aws/synthetix/prod/web/ecs-params.yml @@ -1,7 +1,7 @@ version: 1 task_definition: services: - rollup-full-node: + router: essential: true healthcheck: test: ["CMD-SHELL", "curl -f -H \"Content-Type: application/json\" -d '{\"jsonrpc\": \"2.0\", \"id\": 9999999, \"method\": \"net_version\"}' http://localhost:8545/ || exit 1"] @@ -9,16 +9,54 @@ task_definition: timeout: 5s retries: 3 start_period: 5s - mem_limit: 7680000000 + # 15% + cpu_shares: 409 + mem_limit: 1.125GB + transaction-node: + essential: true + healthcheck: + test: ["CMD-SHELL", "curl -f -H \"Content-Type: application/json\" -d '{\"jsonrpc\": \"2.0\", \"id\": 9999999, \"method\": \"net_version\"}' http://localhost:8546/ || exit 1"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 5s + # 40% + cpu_shares: 1638 + mem_limit: 2GB # Was 3GB but ECS says not enough memory + read-only-node: + essential: true + healthcheck: + test: ["CMD-SHELL", "curl -f -H \"Content-Type: application/json\" -d '{\"jsonrpc\": \"2.0\", \"id\": 9999999, \"method\": \"net_version\"}' http://localhost:8547/ || exit 1"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 5s + # 15% + cpu_shares: 818 + mem_limit: 1.125GB + graph-node: + # 15% + cpu_shares: 614 + mem_limit: 1.125GB + ipfs: + # 5% + cpu_shares: 204 + mem_limit: 0.375GB + postgres: + # 10% + cpu_shares: 409 + mem_limit: 0.75GB ecs_network_mode: host docker_volumes: - - name: l1-node-data - scope: task - driver: 'local' - - name: full-node-data - scope: shared - autoprovision: true - driver: 'local' - + - name: full-node-data + scope: shared + autoprovision: true + driver: 'local' + - name: postgres-data + scope: task + driver: 'local' + - name: ipfs-data + scope: task + driver: 'local' diff --git a/aws/synthetix/uat/geth/ecs-params.yml b/aws/synthetix/uat/geth/ecs-params.yml index dd779aa04c67e..6bc92d817fbbf 100644 --- a/aws/synthetix/uat/geth/ecs-params.yml +++ b/aws/synthetix/uat/geth/ecs-params.yml @@ -10,6 +10,7 @@ task_definition: # retries: 3 # start_period: 10s mem_limit: 32653700000 + cpu_shares: 16384 ecs_network_mode: awsvpc diff --git a/aws/synthetix/uat/web/README.md b/aws/synthetix/uat/web/README.md index c70a5530ce647..97e22aeaf31b6 100644 --- a/aws/synthetix/uat/web/README.md +++ b/aws/synthetix/uat/web/README.md @@ -31,3 +31,7 @@ Make any necessary changes now. ``` ecs-cli compose --project-name synthetix-uat-web service up --vpc --cluster-config synthetix-uat-web-config --ecs-profile synthetix-uat-web-profile --create-log-groups ``` + + +# Redeploying after first deploy +Repeat step #4 above \ No newline at end of file diff --git a/aws/synthetix/uat/web/docker-compose.yml b/aws/synthetix/uat/web/docker-compose.yml index 3328a6f748c5c..a1d166d749928 100644 --- a/aws/synthetix/uat/web/docker-compose.yml +++ b/aws/synthetix/uat/web/docker-compose.yml @@ -1,29 +1,133 @@ version: "3" services: - rollup-full-node: + router: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:synthetix-uat + ports: + - 8545:8545 + environment: + - IS_ROUTING_SERVER=1 + - STARTUP_WAIT_TIMEOUT=60 + - L2_RPC_SERVER_HOST + - L2_RPC_SERVER_PORT=8545 + - TRANSACTION_NODE_URL=http://0.0.0.0:8546 + - READ_ONLY_NODE_URL=http://0.0.0.0:8547 + - REQUEST_LIMIT_PERIOD_MILLIS=1000 + - MAX_NON_TRANSACTION_REQUESTS_PER_UNIT_TIME=50 + - MAX_TRANSACTIONS_PER_UNIT_TIME=10 + # These are just so it waits for the downstream nodes to start up + - L2_NODE_WEB3_URL=http://0.0.0.0:8546 + - L1_NODE_WEB3_URL=http://0.0.0.0:8547 + + logging: + driver: awslogs + options: + awslogs-group: synthetix-uat-web + awslogs-region: us-east-2 + awslogs-stream-prefix: l2-router + + transaction-node: image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:synthetix-uat volumes: - full-node-data:/mnt/full-node:rw - - l1-node-data:/mnt/l1-node:rw ports: - - 8545:8545 + - 8546:8546 environment: - - CLEAR_DATA_KEY=4 - - STARTUP_WAIT_TIMEOUT=10 - - LOCAL_L1_NODE_PERSISTENT_DB_PATH=/mnt/l1-node + - IS_TRANSACTION_NODE=1 + - CLEAR_DATA_KEY + - STARTUP_WAIT_TIMEOUT=60 + - NO_L1_NODE=1 - L2_RPC_SERVER_PERSISTENT_DB_PATH=/mnt/full-node/level - L2_WALLET_PRIVATE_KEY=0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797 - L2_NODE_WEB3_URL=http://synthetix-uat-geth.synthetix-uat:9545 + - L2_RPC_SERVER_HOST=0.0.0.0 + - L2_RPC_SERVER_PORT=8546 + + logging: + driver: awslogs + options: + awslogs-group: synthetix-uat-web + awslogs-region: us-east-2 + awslogs-stream-prefix: l2-transaction-node + + read-only-node: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/rollup-full-node:synthetix-uat + ports: + - 8547:8547 + environment: + - IS_READ_ONLY_NODE=1 + - STARTUP_WAIT_TIMEOUT=30 + - L2_RPC_SERVER_HOST=0.0.0.0 + - L2_RPC_SERVER_PORT=8547 + - L2_EXECUTION_MANAGER_ADDRESS=0xA193E42526F1FEA8C99AF609dcEabf30C1c29fAA + - L2_WALLET_PRIVATE_KEY=0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797 + - L2_NODE_WEB3_URL=http://synthetix-uat-geth.synthetix-uat:9545 + logging: + driver: awslogs + options: + awslogs-group: synthetix-uat-web + awslogs-region: us-east-2 + awslogs-stream-prefix: l2-read-only-node + + graph-node: + image: .dkr.ecr.us-east-2.amazonaws.com/optimism/the-graph:latest + ports: + - '8000:8000' + - '8001:8001' + - '8020:8020' + - '8030:8030' + - '8040:8040' + environment: + postgres_host: 0.0.0.0:5432 + postgres_user: graph-node + postgres_pass: let-me-in + postgres_db: graph-node + ipfs: '0.0.0.0:5001' + ethereum: 'ovm:http://0.0.0.0:8545' + RUST_LOG: info + STARTUP_WAIT_TIMEOUT: 30 + OVM_URL_WITH_PORT: 'http://0.0.0.0:8545' + + logging: + driver: awslogs + options: + awslogs-group: synthetix-uat-web + awslogs-region: us-east-2 + awslogs-stream-prefix: the-graph + + ipfs: + image: ipfs/go-ipfs:v0.4.23 + ports: + - '5001:5001' + volumes: + - ipfs-data:/data/ipfs logging: driver: awslogs options: awslogs-group: synthetix-uat-web awslogs-region: us-east-2 - awslogs-stream-prefix: web + awslogs-stream-prefix: the-graph-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 + + logging: + driver: awslogs + options: + awslogs-group: synthetix-uat-web + awslogs-region: us-east-2 + awslogs-stream-prefix: the-graph-postgres volumes: full-node-data: - l1-node-data: - l2-node-data: - + postgres-data: + ipfs-data: \ No newline at end of file diff --git a/aws/synthetix/uat/web/ecs-params.yml b/aws/synthetix/uat/web/ecs-params.yml index 913b4c3aff2ef..1513761c445f1 100644 --- a/aws/synthetix/uat/web/ecs-params.yml +++ b/aws/synthetix/uat/web/ecs-params.yml @@ -1,24 +1,62 @@ version: 1 task_definition: services: - rollup-full-node: + router: essential: true healthcheck: - test: ["CMD-SHELL", "curl -f -H \"Content-Type: application/json\" -d '{\"jsonrpc\": \"2.0\", \"id\": 9999999, \"method\": \"eth_blockNumber\"}' http://localhost:8545/ || exit 1"] + test: ["CMD-SHELL", "curl -f -H \"Content-Type: application/json\" -d '{\"jsonrpc\": \"2.0\", \"id\": 9999999, \"method\": \"net_version\"}' http://localhost:8545/ || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 5s - mem_limit: 7680000000 + # 15% + cpu_shares: 409 + mem_limit: 1.125GB + transaction-node: + essential: true + healthcheck: + test: ["CMD-SHELL", "curl -f -H \"Content-Type: application/json\" -d '{\"jsonrpc\": \"2.0\", \"id\": 9999999, \"method\": \"net_version\"}' http://localhost:8546/ || exit 1"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 5s + # 40% + cpu_shares: 1638 + mem_limit: 2GB # Was 3GB but ECS says not enough memory + read-only-node: + essential: true + healthcheck: + test: ["CMD-SHELL", "curl -f -H \"Content-Type: application/json\" -d '{\"jsonrpc\": \"2.0\", \"id\": 9999999, \"method\": \"net_version\"}' http://localhost:8547/ || exit 1"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 5s + # 15% + cpu_shares: 818 + mem_limit: 1.125GB + graph-node: + # 15% + cpu_shares: 614 + mem_limit: 1.125GB + ipfs: + # 5% + cpu_shares: 204 + mem_limit: 0.375GB + postgres: + # 10% + cpu_shares: 409 + mem_limit: 0.75GB ecs_network_mode: host docker_volumes: - - name: l1-node-data - scope: task - driver: 'local' - - name: full-node-data - scope: shared - autoprovision: true - driver: 'local' - + - name: full-node-data + scope: shared + autoprovision: true + driver: 'local' + - name: postgres-data + scope: task + driver: 'local' + - name: ipfs-data + scope: task + driver: 'local' diff --git a/packages/rollup-full-node/src/app/routing-handler.ts b/packages/rollup-full-node/src/app/routing-handler.ts index dab68a153b692..e8390e1f9ce79 100644 --- a/packages/rollup-full-node/src/app/routing-handler.ts +++ b/packages/rollup-full-node/src/app/routing-handler.ts @@ -102,7 +102,7 @@ export class RoutingHandler implements FullnodeHandler { log.debug( `Request for [${method}], params: [${JSON.stringify( params - )}] got result [${result}]` + )}] got result [${JSON.stringify(result)}]` ) return result } catch (e) { diff --git a/packages/test-ovm-full-node/src/simple-storage-stress-test.ts b/packages/test-ovm-full-node/src/simple-storage-stress-test.ts index 3f86d573c5c21..c95302b0a57f4 100644 --- a/packages/test-ovm-full-node/src/simple-storage-stress-test.ts +++ b/packages/test-ovm-full-node/src/simple-storage-stress-test.ts @@ -57,4 +57,4 @@ class SimpleStorageStressTest extends FullNodeStressTest { } } -new SimpleStorageStressTest(10, 'http://0.0.0.0:8545').runBatches(10) +new SimpleStorageStressTest(1, 'http://0.0.0.0:8545').runBatches(10) From 1078fc3bf6d3d7db04297fae63b05f90a52a6f8c Mon Sep 17 00:00:00 2001 From: Karl Floersch Date: Tue, 28 Apr 2020 16:57:52 -0400 Subject: [PATCH 03/10] Revert "remove to field override in getLogs (#113)" (#114) This reverts commit 2ca62fb41be6ef69b0c07a1bd5502ac425aaf341. --- packages/rollup-full-node/src/app/web3-rpc-handler.ts | 1 + 1 file changed, 1 insertion(+) 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 a8cd0b4ca1c78..558bd8295d293 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -498,6 +498,7 @@ export class DefaultWeb3Handler const receipt = await this.getTransactionReceipt(transaction.hash) transaction['to'] = receipt.contractAddress } + logItem['address'] = transaction['to'] return logItem }) From 8677b0ad224e9da12577d923e705134dcf07fcfc Mon Sep 17 00:00:00 2001 From: Mason Fischer Date: Wed, 29 Apr 2020 09:36:01 -0400 Subject: [PATCH 04/10] Clean up logging (#115) --- packages/core-utils/src/app/log.ts | 12 +- packages/ovm/src/app/utils.ts | 7 +- packages/rollup-full-node/package.json | 3 +- .../src/app/test-web3-rpc-handler.ts | 11 +- .../src/app/web3-rpc-handler.ts | 140 +++++---- .../src/types/web3-rpc-handler.ts | 9 + .../test/app/web-rpc-handler.spec.ts | 9 + yarn.lock | 268 ++++++++++++++++++ 8 files changed, 399 insertions(+), 60 deletions(-) diff --git a/packages/core-utils/src/app/log.ts b/packages/core-utils/src/app/log.ts index 53066881f3edd..0aad713a0241e 100644 --- a/packages/core-utils/src/app/log.ts +++ b/packages/core-utils/src/app/log.ts @@ -1,16 +1,20 @@ 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 getLogger = ( identifier: string, isTest: boolean = false ): Logger => { const testString = isTest ? 'test:' : '' return { - debug: debug(`${testString}debug:${identifier}`), - info: debug(`${testString}info:${identifier}`), - warn: debug(`${testString}warn:${identifier}`), - error: debug(`${testString}error:${identifier}`), + debug: joinNewlinesAndDebug(`${testString}debug:${identifier}`), + info: joinNewlinesAndDebug(`${testString}info:${identifier}`), + warn: joinNewlinesAndDebug(`${testString}warn:${identifier}`), + error: joinNewlinesAndDebug(`${testString}error:${identifier}`), } } diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index 19cbe2b259984..c8ee2903fb868 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -9,6 +9,7 @@ import { logError, remove0x, ZERO_ADDRESS, + LOG_NEWLINE_STRING, BloomFilter, } from '@eth-optimism/core-utils' import { ethers } from 'ethers' @@ -71,6 +72,7 @@ export interface OvmTransactionMetadata { */ export const convertInternalLogsToOvmLogs = (logs: Log[]): Log[] => { let activeContract = logs[0] ? logs[0].address : ZERO_ADDRESS + const loggerLogs = [`Parsing logs from contract ${activeContract}: `] const ovmLogs = [] logs.forEach((log) => { const executionManagerLog = executionManagerInterface.parseLog(log) @@ -78,17 +80,18 @@ export const convertInternalLogsToOvmLogs = (logs: Log[]): Log[] => { if (executionManagerLog.name === 'ActiveContract') { activeContract = executionManagerLog.values['_activeContract'] } else { - logger.debug( + loggerLogs.push( `${executionManagerLog.name}, values: ${JSON.stringify( executionManagerLog.values )}` ) } } else { - logger.debug(`Non-EM log: ${JSON.stringify(log)}`) + loggerLogs.push(`Non-EM log: ${JSON.stringify(log)}`) ovmLogs.push({ ...log, address: activeContract }) } }) + logger.debug(loggerLogs.join(LOG_NEWLINE_STRING)) return ovmLogs } diff --git a/packages/rollup-full-node/package.json b/packages/rollup-full-node/package.json index 264c8d30967a8..eef66c7e2c51f 100644 --- a/packages/rollup-full-node/package.json +++ b/packages/rollup-full-node/package.json @@ -49,7 +49,8 @@ "ethers": "^4.0.39", "fastpriorityqueue": "^0.6.3", "level": "^6.0.1", - "rimraf": "^2.6.3" + "rimraf": "^2.6.3", + "web3": "^1.2.7" }, "devDependencies": { "@eth-optimism/solc-transpiler": "^0.0.1-alpha.25", 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 c55db52b22df6..838ffde486764 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 @@ -15,6 +15,7 @@ import { L2ToL1MessageSubmitter, UnsupportedMethodError, Web3RpcMethods, + Web3RpcTypes, } from '../types' import { getCurrentTime, initializeL2Node } from './util' import { NoOpL2ToL1MessageSubmitter } from './message-submitter' @@ -66,24 +67,24 @@ export class TestWeb3Handler extends DefaultWeb3Handler { public async handleRequest(method: string, params: any[]): Promise { switch (method) { case Web3RpcMethods.increaseTimestamp: - this.assertParameters(params, 1) + this.assertParameters(params, [Web3RpcTypes.quantity]) this.increaseTimestamp(params[0]) log.debug(`Set increased timestamp by ${params[0]} seconds.`) return TestWeb3Handler.successString case Web3RpcMethods.mine: return this.context.provider.send(Web3RpcMethods.mine, params) case Web3RpcMethods.sendTransaction: - this.assertParameters(params, 1) + this.assertParameters(params, [Web3RpcTypes.object]) return this.sendTransaction(params[0]) break case Web3RpcMethods.snapshot: - this.assertParameters(params, 0) + this.assertParameters(params, []) return this.snapshot() case Web3RpcMethods.revert: - this.assertParameters(params, 1) + this.assertParameters(params, [Web3RpcTypes.quantity]) return this.revert(params[0]) case Web3RpcMethods.accounts: - this.assertParameters(params, 0) + this.assertParameters(params, []) return this.accounts() default: return super.handleRequest(method, params) 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 558bd8295d293..feadd5c408ea1 100644 --- a/packages/rollup-full-node/src/app/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/app/web3-rpc-handler.ts @@ -27,7 +27,8 @@ import { } from '@eth-optimism/ovm' import AsyncLock from 'async-lock' -import { utils, Wallet } from 'ethers' +import { Contract, utils, Wallet } from 'ethers' +import Web3 from 'web3' import { JsonRpcProvider, TransactionReceipt } from 'ethers/providers' /* Internal Imports */ @@ -38,6 +39,7 @@ import { L2ToL1MessageSubmitter, UnsupportedMethodError, Web3Handler, + Web3RpcTypes, Web3RpcMethods, RevertError, } from '../types' @@ -116,70 +118,91 @@ export class DefaultWeb3Handler // Make sure the method is available let response: any - let args: any[] switch (method) { case Web3RpcMethods.blockNumber: - this.assertParameters(params, 0) + this.assertParameters(params, []) response = await this.blockNumber() break case Web3RpcMethods.call: - args = this.assertParameters(params, 2, latestBlock) - response = await this.call(args[0], args[1]) + this.assertParameters(params, [ + Web3RpcTypes.object, + Web3RpcTypes.quantityOrTag, + ]) + response = await this.call(params[0], params[1] || latestBlock) break case Web3RpcMethods.estimateGas: - args = this.assertParameters(params, 2, latestBlock) - response = await this.estimateGas(args[0], args[1]) + this.assertParameters(params, [ + Web3RpcTypes.object, + Web3RpcTypes.quantityOrTag, + ]) + response = await this.estimateGas(params[0], params[1] || latestBlock) break case Web3RpcMethods.gasPrice: - this.assertParameters(params, 0) + this.assertParameters(params, []) response = await this.gasPrice() break case Web3RpcMethods.getBlockByNumber: - args = this.assertParameters(params, 2) - response = await this.getBlockByNumber(args[0], args[1]) + this.assertParameters(params, [ + Web3RpcTypes.quantityOrTag, + Web3RpcTypes.boolean, + ]) + response = await this.getBlockByNumber(params[0], params[1]) break case Web3RpcMethods.getBlockByHash: - args = this.assertParameters(params, 2) - response = await this.getBlockByHash(args[0], args[1]) + this.assertParameters(params, [Web3RpcTypes.data, Web3RpcTypes.boolean]) + response = await this.getBlockByHash(params[0], params[1]) break case Web3RpcMethods.getBalance: - this.assertParameters(params, 2, latestBlock) + this.assertParameters( + params, + [Web3RpcTypes.address, Web3RpcTypes.quantityOrTag], + latestBlock + ) response = await this.getBalance() break case Web3RpcMethods.getCode: - args = this.assertParameters(params, 2, latestBlock) - response = await this.getCode(args[0], args[1]) + this.assertParameters(params, [ + Web3RpcTypes.data, + Web3RpcTypes.quantityOrTag, + ]) + response = await this.getCode(params[0], params[1] || latestBlock) break case Web3RpcMethods.getExecutionManagerAddress: - this.assertParameters(params, 0) + this.assertParameters(params, []) response = await this.getExecutionManagerAddress() break case Web3RpcMethods.getLogs: - args = this.assertParameters(params, 1) - response = await this.getLogs(args[0]) + this.assertParameters(params, [Web3RpcTypes.object]) + response = await this.getLogs(params[0]) break case Web3RpcMethods.getTransactionByHash: - args = this.assertParameters(params, 1) - response = await this.getTransactionByHash(args[0]) + this.assertParameters(params, [Web3RpcTypes.data]) + response = await this.getTransactionByHash(params[0]) break case Web3RpcMethods.getTransactionCount: - args = this.assertParameters(params, 2, latestBlock) - response = await this.getTransactionCount(args[0], args[1]) + this.assertParameters(params, [ + Web3RpcTypes.data, + Web3RpcTypes.quantityOrTag, + ]) + response = await this.getTransactionCount( + params[0], + params[1] || latestBlock + ) break case Web3RpcMethods.getTransactionReceipt: - args = this.assertParameters(params, 1) - response = await this.getTransactionReceipt(args[0]) + this.assertParameters(params, [Web3RpcTypes.data]) + response = await this.getTransactionReceipt(params[0]) break case Web3RpcMethods.sendRawTransaction: - args = this.assertParameters(params, 1) - response = await this.sendRawTransaction(args[0]) + this.assertParameters(params, [Web3RpcTypes.data]) + response = await this.sendRawTransaction(params[0]) break case Web3RpcMethods.networkVersion: - this.assertParameters(params, 0) + this.assertParameters(params, []) response = await this.networkVersion() break case Web3RpcMethods.chainId: - this.assertParameters(params, 0) + this.assertParameters(params, []) response = await this.chainId() break default: @@ -443,7 +466,7 @@ export class DefaultWeb3Handler defaultBlock )}] curentBlockNumber:[${curentBlockNumber}]` ) - throw new Error( + throw new InvalidParametersError( `Historical code lookups aren't supported. Requested Block: ${hexStrToNumber( defaultBlock )} Current Block: ${curentBlockNumber}` @@ -941,7 +964,7 @@ export class DefaultWeb3Handler private async ovmTxToInternalTx(ovmTx: any): Promise { // Verify that the transaction is not accidentally sending to the ZERO_ADDRESS if (ovmTx.to === ZERO_ADDRESS) { - throw new Error('Sending to Zero Address disallowed') + throw new InvalidParametersError('Sending to Zero Address disallowed') } // Get the nonce of the account that we will use to send everything // Note: + 1 because all transactions will have a tx hash mapping tx sent before them. @@ -951,7 +974,7 @@ export class DefaultWeb3Handler log.error( 'Transaction does not have a valid signature! For now we only support calls from EOAs' ) - throw new Error('Non-EOA transaction detected') + throw new InvalidParametersError('Non-EOA transaction detected') } // 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) @@ -962,7 +985,7 @@ export class DefaultWeb3Handler await this.context.executionManager.getOvmContractNonce(ovmFrom) ).toNumber() if (expectedNonce !== ovmTx.nonce) { - throw new Error( + throw new InvalidParametersError( `Incorrect nonce! Expected nonce: ${expectedNonce} but received nonce: ${ovmTx.nonce}` ) } @@ -1038,23 +1061,44 @@ export class DefaultWeb3Handler protected assertParameters( params: any[], - expected: number, + expected: Web3RpcTypes[], defaultLast?: any - ): any[] { - if (!params) { - if (!expected) { - return [] - } - } else if (params.length === expected - 1 || params.length === expected) { - const nonEmptyParams = params.filter((x) => !!x) - return nonEmptyParams.length === expected - ? nonEmptyParams - : [...nonEmptyParams, defaultLast] + ) { + if ( + !( + !params || + params.length === expected.length - 1 || + params.length === expected.length + ) + ) { + throw new InvalidParametersError( + `Expected ${expected} parameters but received ${params.length}.` + ) } - throw new InvalidParametersError( - `Expected ${expected} parameters but received ${ - !params ? 0 : params.length - }.` - ) + expected.forEach((expectedType, index) => { + const param = params[index] + const typeChecks = { + [Web3RpcTypes.quantityOrTag]: (value) => { + return ( + value === undefined || + !isNaN(value) || + ['latest', 'earliest', 'pending'].includes(value) + ) + }, + [Web3RpcTypes.boolean]: (value) => [true, false].includes(value), + [Web3RpcTypes.quantity]: (value) => !isNaN(value), + [Web3RpcTypes.data]: Web3.utils.isHex, + [Web3RpcTypes.address]: Web3.utils.isAddress, + [Web3RpcTypes.object]: (value) => { + return value instanceof Object + }, + } + + if (!typeChecks[expectedType](param)) { + throw new InvalidParametersError( + `Expected ${expectedType} but got ${param}` + ) + } + }) } } diff --git a/packages/rollup-full-node/src/types/web3-rpc-handler.ts b/packages/rollup-full-node/src/types/web3-rpc-handler.ts index 1476b1f8a6cf7..22ce9cfc9946d 100644 --- a/packages/rollup-full-node/src/types/web3-rpc-handler.ts +++ b/packages/rollup-full-node/src/types/web3-rpc-handler.ts @@ -30,6 +30,15 @@ export interface Web3Handler { chainId(): Promise } +export enum Web3RpcTypes { + quantity = 'quantity', + boolean = 'boolean', + data = 'data', + address = 'address', + object = 'object', + quantityOrTag = 'quantityOrTag', +} + // Enum of supported web3 rpc methods export enum Web3RpcMethods { blockNumber = 'eth_blockNumber', 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 683ac8428530b..0489bd73f4e28 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 @@ -6,6 +6,7 @@ import { getLogger, keccak256, numberToHexString, + JSONRPC_ERRORS, ZERO_ADDRESS, hexStrToBuf, } from '@eth-optimism/core-utils' @@ -178,6 +179,14 @@ describe('Web3Handler', () => { balance.toNumber().should.eq(0) }) + + it('should return a parameter error if an invalid parameter is passed', async () => { + const wallet = getWallet(httpProvider) + + await assertAsyncThrowsWithMessage(async () => { + await httpProvider.send('eth_getBalance', [1]) + }, JSONRPC_ERRORS.INVALID_PARAMS.message) + }) }) describe('EVM reversion handling', async () => { diff --git a/yarn.lock b/yarn.lock index e6a9c7dcda38c..bc30730c49b9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3759,6 +3759,15 @@ eth-lib@^0.1.26: ws "^3.0.0" xhr-request-promise "^0.1.2" +eth-lib@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" @@ -4199,6 +4208,11 @@ eventemitter3@3.1.2, eventemitter3@^3.1.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== +eventemitter3@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" + integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + events@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" @@ -9271,6 +9285,23 @@ swarm-js@0.1.39: tar "^4.0.2" xhr-request-promise "^0.1.2" +swarm-js@^0.1.40: + version "0.1.40" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" + integrity sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA== + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request "^1.0.1" + table@^5.0.2: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -9982,6 +10013,16 @@ web3-bzz@1.2.4: swarm-js "0.1.39" underscore "1.9.1" +web3-bzz@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.7.tgz#aa0f3d162f0777a5f35367dc5b70012dd1e129d0" + integrity sha512-iTIWBR+Z+Bn09WprtKm46LmyNOasg2lUn++AjXkBTB8UNxlUybxtza84yl2ETTZUs0zuFzdSSAEgbjhygG+9oA== + dependencies: + "@types/node" "^10.12.18" + got "9.6.0" + swarm-js "^0.1.40" + underscore "1.9.1" + web3-core-helpers@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.35.tgz#d681d218a0c6e3283ee1f99a078ab9d3eef037f1" @@ -10009,6 +10050,15 @@ web3-core-helpers@1.2.4: web3-eth-iban "1.2.4" web3-utils "1.2.4" +web3-core-helpers@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.7.tgz#522f859775ea0d15e7e40359c46d4efc5da92aee" + integrity sha512-bdU++9QATGeCetVrMp8pV97aQtVkN5oLBf/TWu/qumC6jK/YqrvLlBJLdwbz0QveU8zOSap6GCvJbqKvmmbV2A== + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.7" + web3-utils "1.2.7" + web3-core-method@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.35.tgz#fc10e2d546cf4886038e6130bd5726b0952a4e5f" @@ -10042,6 +10092,17 @@ web3-core-method@1.2.4: web3-core-subscriptions "1.2.4" web3-utils "1.2.4" +web3-core-method@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.7.tgz#73fd80d2bf0765ff6efc454db49ac83d1769a45e" + integrity sha512-e1TI0QUnByDMbQ8QHwnjxfjKw0LIgVRY4TYrlPijET9ebqUJU1HCayn/BHIMpV6LKyR1fQj9EldWyT64wZQXkg== + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.7" + web3-core-promievent "1.2.7" + web3-core-subscriptions "1.2.7" + web3-utils "1.2.7" + web3-core-promievent@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.35.tgz#4f1b24737520fa423fee3afee110fbe82bcb8691" @@ -10066,6 +10127,13 @@ web3-core-promievent@1.2.4: any-promise "1.3.0" eventemitter3 "3.1.2" +web3-core-promievent@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.7.tgz#fc7fa489f4cf76a040800f3dfd4b45c51bd3a39f" + integrity sha512-jNmsM/czCeMGQqKKwM9/HZVTJVIF96hdMVNN/V9TGvp+EEE7vDhB4pUocDnc/QF9Z/5QFBCVmvNWttlRgZmU0A== + dependencies: + eventemitter3 "3.1.2" + web3-core-requestmanager@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.35.tgz#2b77cbf6303720ad68899b39fa7f584dc03dbc8f" @@ -10099,6 +10167,17 @@ web3-core-requestmanager@1.2.4: web3-providers-ipc "1.2.4" web3-providers-ws "1.2.4" +web3-core-requestmanager@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.7.tgz#9da0efce898ead7004d4ac50f748f5131cfe4d79" + integrity sha512-HJb/txjHixu1dxIebiZQKBoJCaNu4gsh7mq/uj6Z/w6tIHbybL90s/7ADyMED353yyJ2tDWtYJqeMVAR+KtdaA== + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.7" + web3-providers-http "1.2.7" + web3-providers-ipc "1.2.7" + web3-providers-ws "1.2.7" + web3-core-subscriptions@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.35.tgz#c1b76a2ad3c6e80f5d40b8ba560f01e0f4628758" @@ -10126,6 +10205,15 @@ web3-core-subscriptions@1.2.4: underscore "1.9.1" web3-core-helpers "1.2.4" +web3-core-subscriptions@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.7.tgz#30c64aede03182832883b17c77e21cbb0933c86e" + integrity sha512-W/CzQYOUawdMDvkgA/fmLsnG5aMpbjrs78LZMbc0MFXLpH3ofqAgO2by4QZrrTShUUTeWS0ZuEkFFL/iFrSObw== + dependencies: + eventemitter3 "3.1.2" + underscore "1.9.1" + web3-core-helpers "1.2.7" + web3-core@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.35.tgz#0c44d3c50d23219b0b1531d145607a9bc7cd4b4f" @@ -10159,6 +10247,19 @@ web3-core@1.2.4: web3-core-requestmanager "1.2.4" web3-utils "1.2.4" +web3-core@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.7.tgz#9248b04331e458c76263d758c51b0cc612953900" + integrity sha512-QA0MTae0gXcr3KHe3cQ4x56+Wh43ZKWfMwg1gfCc3NNxPRM1jJ8qudzyptCAUcxUGXWpDG8syLIn1APDz5J8BQ== + dependencies: + "@types/bn.js" "^4.11.4" + "@types/node" "^12.6.1" + bignumber.js "^9.0.0" + web3-core-helpers "1.2.7" + web3-core-method "1.2.7" + web3-core-requestmanager "1.2.7" + web3-utils "1.2.7" + web3-eth-abi@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.35.tgz#2eb9c1c7c7233db04010defcb192293e0db250e6" @@ -10187,6 +10288,15 @@ web3-eth-abi@1.2.4: underscore "1.9.1" web3-utils "1.2.4" +web3-eth-abi@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.7.tgz#6f3471b578649fddd844a14d397a3dd430fc44a5" + integrity sha512-4FnlT1q+D0XBkxSMXlIb/eG337uQeMaUdtVQ4PZ3XzxqpcoDuMgXm4o+3NRxnWmr4AMm6QKjM+hcC7c0mBKcyg== + dependencies: + ethers "4.0.0-beta.3" + underscore "1.9.1" + web3-utils "1.2.7" + web3-eth-accounts@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.35.tgz#7d0e5a69f510dc93874471599eb7abfa9ddf3e63" @@ -10238,6 +10348,23 @@ web3-eth-accounts@1.2.4: web3-core-method "1.2.4" web3-utils "1.2.4" +web3-eth-accounts@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.7.tgz#087f55d04a01b815b93151aac2fc1677436b9c59" + integrity sha512-AE7QWi/iIQIjXwlAPtlMabm/OPFF0a1PhxT1EiTckpYNP8fYs6jW7lYxEtJPPJIKqfMjoi1xkEqTVR1YZQ88lg== + dependencies: + "@web3-js/scrypt-shim" "^0.1.0" + crypto-browserify "3.12.0" + eth-lib "^0.2.8" + ethereumjs-common "^1.3.2" + ethereumjs-tx "^2.1.1" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.7" + web3-core-helpers "1.2.7" + web3-core-method "1.2.7" + web3-utils "1.2.7" + web3-eth-contract@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.35.tgz#5276242d8a3358d9f1ce92b71575c74f9015935c" @@ -10281,6 +10408,21 @@ web3-eth-contract@1.2.4: web3-eth-abi "1.2.4" web3-utils "1.2.4" +web3-eth-contract@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.7.tgz#13d7f6003d6221f9a5fd61c2d3b5d039477c9674" + integrity sha512-uW23Y0iL7XroRNbf9fWZ1N6OYhEYTJX8gTuYASuRnpYrISN5QGiQML6pq/NCzqypR1bl5E0fuINZQSK/xefIVw== + dependencies: + "@types/bn.js" "^4.11.4" + underscore "1.9.1" + web3-core "1.2.7" + web3-core-helpers "1.2.7" + web3-core-method "1.2.7" + web3-core-promievent "1.2.7" + web3-core-subscriptions "1.2.7" + web3-eth-abi "1.2.7" + web3-utils "1.2.7" + web3-eth-ens@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz#a0e52eee68c42a8b9865ceb04e5fb022c2d971d5" @@ -10309,6 +10451,20 @@ web3-eth-ens@1.2.4: web3-eth-contract "1.2.4" web3-utils "1.2.4" +web3-eth-ens@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.7.tgz#0bfa7d4b6c7753abbb31a2eb01a364b538f4c860" + integrity sha512-SPRnvUNWQ0CnnTDBteGIJkvFWEizJcAHlVsrFLICwcwFZu+appjX1UOaoGu2h3GXWtc/XZlu7B451Gi+Os2cTg== + dependencies: + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.7" + web3-core-helpers "1.2.7" + web3-core-promievent "1.2.7" + web3-eth-abi "1.2.7" + web3-eth-contract "1.2.7" + web3-utils "1.2.7" + web3-eth-iban@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.35.tgz#5aa10327a9abb26bcfc4ba79d7bad18a002b332c" @@ -10333,6 +10489,14 @@ web3-eth-iban@1.2.4: bn.js "4.11.8" web3-utils "1.2.4" +web3-eth-iban@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.7.tgz#832809c28586be3c667a713b77a2bcba11b7970f" + integrity sha512-2NrClz1PoQ3nSJBd+91ylCOVga9qbTxjRofq/oSCoHVAEvz3WZyttx9k5DC+0rWqwJF1h69ufFvdHAAlmN/4lg== + dependencies: + bn.js "4.11.8" + web3-utils "1.2.7" + web3-eth-personal@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.35.tgz#ecac95b7a53d04a567447062d5cae5f49879e89f" @@ -10367,6 +10531,18 @@ web3-eth-personal@1.2.4: web3-net "1.2.4" web3-utils "1.2.4" +web3-eth-personal@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.7.tgz#322cc2b14c37737b21772a53e4185686a04bf9be" + integrity sha512-2OAa1Spz0uB29dwCM8+1y0So7E47A4gKznjBEwXIYEcUIsvwT5X7ofFhC2XxyRpqlIWZSQAxRSSJFyupRRXzyw== + dependencies: + "@types/node" "^12.6.1" + web3-core "1.2.7" + web3-core-helpers "1.2.7" + web3-core-method "1.2.7" + web3-net "1.2.7" + web3-utils "1.2.7" + web3-eth@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.35.tgz#c52c804afb95e6624b6f5e72a9af90fbf5005b68" @@ -10423,6 +10599,25 @@ web3-eth@1.2.4: web3-net "1.2.4" web3-utils "1.2.4" +web3-eth@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.7.tgz#9427daefd3641200679c2946f77fc184dbfb5b4c" + integrity sha512-ljLd0oB4IjWkzFGVan4HkYhJXhSXgn9iaSaxdJixKGntZPgWMJfxeA+uLwTrlxrWzhvy4f+39WnT7wCh5e9TGg== + dependencies: + underscore "1.9.1" + web3-core "1.2.7" + web3-core-helpers "1.2.7" + web3-core-method "1.2.7" + web3-core-subscriptions "1.2.7" + web3-eth-abi "1.2.7" + web3-eth-accounts "1.2.7" + web3-eth-contract "1.2.7" + web3-eth-ens "1.2.7" + web3-eth-iban "1.2.7" + web3-eth-personal "1.2.7" + web3-net "1.2.7" + web3-utils "1.2.7" + web3-net@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.35.tgz#5c6688e0dea71fcd910ee9dc5437b94b7f6b3354" @@ -10450,6 +10645,15 @@ web3-net@1.2.4: web3-core-method "1.2.4" web3-utils "1.2.4" +web3-net@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.7.tgz#c355621a8769c9c1a967c801e7db90c92a0e3808" + integrity sha512-j9qeZrS1FNyCeA0BfdLojkxOZQz3FKa1DJI+Dw9fEVhZS68vLOFANu2RB96gR9BoPHo5+k5D3NsKOoxt1gw3Gg== + dependencies: + web3-core "1.2.7" + web3-core-method "1.2.7" + web3-utils "1.2.7" + web3-provider-engine@14.2.0: version "14.2.0" resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-14.2.0.tgz#2efec157b2c429c5c674c079aea96b0a06de8b3d" @@ -10526,6 +10730,14 @@ web3-providers-http@1.2.4: web3-core-helpers "1.2.4" xhr2-cookies "1.1.0" +web3-providers-http@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.7.tgz#31eb15390c103169b3d7d31bdb1ccae9e3f1629d" + integrity sha512-vazGx5onuH/zogrwkUaLFJwFcJ6CckP65VFSHoiV+GTQdkOqgoDIha7StKkslvDz4XJ2FuY/zOZHbtuOYeltXQ== + dependencies: + web3-core-helpers "1.2.7" + xhr2-cookies "1.1.0" + web3-providers-ipc@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.35.tgz#031afeb10fade2ebb0ef2fb82f5e58c04be842d9" @@ -10553,6 +10765,15 @@ web3-providers-ipc@1.2.4: underscore "1.9.1" web3-core-helpers "1.2.4" +web3-providers-ipc@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.7.tgz#4e6716e8723d431df3d6bfa1acd2f7c04e7071ad" + integrity sha512-/zc0y724H2zbkV4UbGGMhsEiLfafjagIzfrsWZnyTZUlSB0OGRmmFm2EkLJAgtXrLiodaHHyXKM0vB8S24bxdA== + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.7" + web3-providers-ws@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.35.tgz#5d38603fd450243a26aae0ff7f680644e77fa240" @@ -10580,6 +10801,16 @@ web3-providers-ws@1.2.4: underscore "1.9.1" web3-core-helpers "1.2.4" +web3-providers-ws@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.7.tgz#95b1cc5dc25e9b9d6630d6754f9354313b62f532" + integrity sha512-b5XzqDpRkNVe6MFs5K6iqOEyjQikHtg3KuU2/ClCDV37hm0WN4xCRVMC0LwegulbDXZej3zT9+1CYzGaGFREzA== + dependencies: + "@web3-js/websocket" "^1.0.29" + eventemitter3 "^4.0.0" + underscore "1.9.1" + web3-core-helpers "1.2.7" + web3-shh@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.35.tgz#7e4a585f8beee0c1927390937c6537748a5d1a58" @@ -10610,6 +10841,16 @@ web3-shh@1.2.4: web3-core-subscriptions "1.2.4" web3-net "1.2.4" +web3-shh@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.7.tgz#5382c7bc2f39539eb2841c4576d23ade25720461" + integrity sha512-f6PAgcpG0ZAo98KqCmeHoDEx5qzm3d5plet18DkT4U6WIeYowKdec8vZaLPRR7c2XreXFJ2gQf45CB7oqR7U/w== + dependencies: + web3-core "1.2.7" + web3-core-method "1.2.7" + web3-core-subscriptions "1.2.7" + web3-net "1.2.7" + web3-utils@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.35.tgz#ced9e1df47c65581c441c5f2af76b05a37a273d7" @@ -10650,6 +10891,20 @@ web3-utils@1.2.4: underscore "1.9.1" utf8 "3.0.0" +web3-utils@1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.7.tgz#b68e232917e4376f81cf38ef79878e5903d18e93" + integrity sha512-FBh/CPJND+eiPeUF9KVbTyTZtXNWxPWtByBaWS6e2x4ACazPX711EeNaZaChIOGSLGe6se2n7kg6wnawe/MjuQ== + dependencies: + bn.js "4.11.8" + eth-lib "0.2.7" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + underscore "1.9.1" + utf8 "3.0.0" + web3@1.0.0-beta.35: version "1.0.0-beta.35" resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.35.tgz#6475095bd451a96e50a32b997ddee82279292f11" @@ -10690,6 +10945,19 @@ web3@1.2.4: web3-shh "1.2.4" web3-utils "1.2.4" +web3@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.7.tgz#fcb83571036c1c6f475bc984785982a444e8d78e" + integrity sha512-jAAJHMfUlTps+jH2li1ckDFEpPrEEriU/ubegSTGRl3KRdNhEqT93+3kd7FHJTn3NgjcyURo2+f7Da1YcZL8Mw== + dependencies: + web3-bzz "1.2.7" + web3-core "1.2.7" + web3-eth "1.2.7" + web3-eth-personal "1.2.7" + web3-net "1.2.7" + web3-shh "1.2.7" + web3-utils "1.2.7" + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" From df25629d772a0b598324b257f46acf1c5b3f558b Mon Sep 17 00:00:00 2001 From: Will Meister Date: Wed, 29 Apr 2020 10:45:13 -0500 Subject: [PATCH 05/10] Making Router handle JSON RPC Errors (#117) * Making it so the router does not throw on properly-formatted JSON errors and instead passes them through --- packages/core-utils/src/app/test-utils.ts | 5 +- .../app/transport/client/json-rpc-client.ts | 33 ++++- .../src/app/transport/client/simple-client.ts | 20 ++- .../src/app/fullnode-rpc-server.ts | 9 ++ .../src/app/routing-handler.ts | 21 ++- packages/rollup-full-node/src/types/errors.ts | 8 ++ .../test/app/routing-handler.spec.ts | 131 +++++++++++++++--- 7 files changed, 189 insertions(+), 38 deletions(-) diff --git a/packages/core-utils/src/app/test-utils.ts b/packages/core-utils/src/app/test-utils.ts index 330945cf871b8..c71cfb6a52928 100644 --- a/packages/core-utils/src/app/test-utils.ts +++ b/packages/core-utils/src/app/test-utils.ts @@ -22,8 +22,9 @@ export class TestUtils { public static async assertThrowsAsync( func: () => Promise, errorType?: any - ): Promise { + ): Promise { let succeeded = true + let error: Error try { await func() succeeded = false @@ -31,12 +32,14 @@ export class TestUtils { if (!!errorType && !(e instanceof errorType)) { succeeded = false } + error = e } assert( succeeded, "Function didn't throw as expected or threw the wrong error." ) + return error } public static async assertRevertsAsync( diff --git a/packages/core-utils/src/app/transport/client/json-rpc-client.ts b/packages/core-utils/src/app/transport/client/json-rpc-client.ts index ebb3bdad59f3b..47403cdf19865 100644 --- a/packages/core-utils/src/app/transport/client/json-rpc-client.ts +++ b/packages/core-utils/src/app/transport/client/json-rpc-client.ts @@ -8,6 +8,7 @@ import { JsonRpcRequest, Client, isJsonRpcErrorResponse, + JsonRpcResponse, } from '../../../types' /** @@ -23,11 +24,34 @@ export class JsonRpcClient /** * Handles a method call by making a JSON-RPC * request to some server. + * * @param method Name of the method to call. * @param [params] Parameters to send with the method call. - * @returns the result of the method call. + * @returns the `result` field of the response to the method call. + * @throws Error if there is any error, including a properly-formatted JsonRpcResponse error. */ public async handle(method: string, params?: any): Promise { + const response: JsonRpcResponse = await this.makeRpcCall(method, params) + + if (isJsonRpcErrorResponse(response)) { + throw new Error(`${JSON.stringify(response.error)}`) + } + return response.result + } + + /** + * Makes an RPC call and returns the full JsonRpcResponse. + * Notably, this differs from handle(...) because it does not throw on error + * or just return the `result` field on success. + * + * @param method Name of the method to call. + * @param [params] Parameters to send with the method call. + * @returns the result of the method call. + */ + public async makeRpcCall( + method: string, + params?: any + ): Promise { const request: JsonRpcRequest = { jsonrpc: '2.0', method, @@ -37,11 +61,6 @@ export class JsonRpcClient const encodedRequest = this.adapter.encodeRequest(request) const encodedResponse = await this.client.request(encodedRequest) - const response = this.adapter.decodeResponse(encodedResponse) - - if (isJsonRpcErrorResponse(response)) { - throw new Error(`${JSON.stringify(response.error)}`) - } - return response.result + return this.adapter.decodeResponse(encodedResponse) } } diff --git a/packages/core-utils/src/app/transport/client/simple-client.ts b/packages/core-utils/src/app/transport/client/simple-client.ts index 49840a75afa40..baa3abce2d5af 100644 --- a/packages/core-utils/src/app/transport/client/simple-client.ts +++ b/packages/core-utils/src/app/transport/client/simple-client.ts @@ -2,7 +2,7 @@ * Wrapper class around a Http-based JsonRpcClient */ import { JsonRpcClient } from './json-rpc-client' -import { HttpRequest, HttpResponse } from '../../../types' +import { HttpRequest, HttpResponse, JsonRpcResponse } from '../../../types' import { JsonRpcHttpAdapter } from './json-rpc-http-adapter' import { AxiosHttpClient } from './axios-http-client' @@ -25,9 +25,25 @@ export class SimpleClient { * request to some server. * @param method Name of the method to call. * @param [params] Parameters to send with the method call. - * @returns the result of the method call. + * @returns the `result` field of the response to the method call. + * @throws Error if there is any error, including a properly-formatted JsonRpcResponse error. */ public async handle(method: string, params?: any): Promise { return this.jsonRpcClient.handle(method, params) } + + /** + * Makes an RPC call and returns the full JsonRpcResponse. + * Notably, this differs from handle(...) because it does not throw one error + * or just return the `result` field on success. + * @param method Name of the method to call. + * @param [params] Parameters to send with the method call. + * @returns the result of the method call. + */ + public async makeRpcCall( + method: string, + params?: any + ): Promise { + return this.jsonRpcClient.makeRpcCall(method, params) + } } 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 ca1dc261f826a..47bbbaae422a1 100644 --- a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts +++ b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts @@ -14,6 +14,7 @@ import { /* Internal Imports */ import { + FormattedJsonRpcError, FullnodeHandler, InvalidParametersError, InvalidTransactionDesinationError, @@ -102,6 +103,14 @@ export class FullnodeRpcServer extends ExpressHttpServer { result, } } catch (err) { + if (err instanceof FormattedJsonRpcError) { + log.debug( + `Received formatted JSON RPC Error response. Returning it as is: ${JSON.stringify( + err.jsonRpcResponse + )}` + ) + return err.jsonRpcResponse + } if (err instanceof RevertError) { log.debug(`Request reverted. Request: ${JSON.stringify(request)}`) const errorResponse: JsonRpcErrorResponse = buildJsonRpcError( diff --git a/packages/rollup-full-node/src/app/routing-handler.ts b/packages/rollup-full-node/src/app/routing-handler.ts index e8390e1f9ce79..f7368ef122a50 100644 --- a/packages/rollup-full-node/src/app/routing-handler.ts +++ b/packages/rollup-full-node/src/app/routing-handler.ts @@ -1,12 +1,20 @@ /* External Imports */ import { Address } from '@eth-optimism/rollup-core' -import { getLogger, logError, SimpleClient } from '@eth-optimism/core-utils' +import { + getLogger, + isJsonRpcErrorResponse, + JsonRpcErrorResponse, + JsonRpcResponse, + logError, + SimpleClient, +} from '@eth-optimism/core-utils' import { parseTransaction, Transaction } from 'ethers/utils' /* Internal Imports */ import { AccountRateLimiter, + FormattedJsonRpcError, FullnodeHandler, InvalidParametersError, InvalidTransactionDesinationError, @@ -95,16 +103,19 @@ export class RoutingHandler implements FullnodeHandler { this.assertDestinationValid(tx) try { - const result: any = + const result: JsonRpcResponse = methodsToRouteWithTransactionHandler.indexOf(method) >= 0 - ? await this.transactionClient.handle(method, params) - : await this.readOnlyClient.handle(method, params) + ? await this.transactionClient.makeRpcCall(method, params) + : await this.readOnlyClient.makeRpcCall(method, params) log.debug( `Request for [${method}], params: [${JSON.stringify( params )}] got result [${JSON.stringify(result)}]` ) - return result + if (isJsonRpcErrorResponse(result)) { + throw new FormattedJsonRpcError(result as JsonRpcErrorResponse) + } + return result.result } catch (e) { logError( log, diff --git a/packages/rollup-full-node/src/types/errors.ts b/packages/rollup-full-node/src/types/errors.ts index 728ac89a683c1..00dad8750f9f7 100644 --- a/packages/rollup-full-node/src/types/errors.ts +++ b/packages/rollup-full-node/src/types/errors.ts @@ -1,3 +1,5 @@ +import { JsonRpcErrorResponse } from '@eth-optimism/core-utils' + export class TreeUpdateError extends Error { constructor(message?: string) { super(message || 'Error occurred performing a tree update!') @@ -62,3 +64,9 @@ export class InvalidTransactionDesinationError extends Error { ) } } + +export class FormattedJsonRpcError extends Error { + constructor(public readonly jsonRpcResponse: JsonRpcErrorResponse) { + super() + } +} diff --git a/packages/rollup-full-node/test/app/routing-handler.spec.ts b/packages/rollup-full-node/test/app/routing-handler.spec.ts index 1920ee3ae51c2..7403fd27693aa 100644 --- a/packages/rollup-full-node/test/app/routing-handler.spec.ts +++ b/packages/rollup-full-node/test/app/routing-handler.spec.ts @@ -1,10 +1,17 @@ /* External Imports */ -import { SimpleClient, TestUtils } from '@eth-optimism/core-utils' - +import { + JsonRpcError, + JsonRpcErrorResponse, + JsonRpcResponse, + JsonRpcSuccessResponse, + SimpleClient, + TestUtils, +} from '@eth-optimism/core-utils' /* Internal Imports */ import { AccountRateLimiter, allWeb3RpcMethodsIncludingTest, + FormattedJsonRpcError, InvalidTransactionDesinationError, RateLimitError, TransactionLimitError, @@ -19,11 +26,15 @@ import { } from '../../src/app' class DummySimpleClient extends SimpleClient { - constructor(private readonly cannedResponse: any) { + constructor(private readonly cannedResponse: JsonRpcResponse) { super('') } - public async handle(method: string, params?: any): Promise { - return this.cannedResponse as T + + public async makeRpcCall( + method: string, + params?: any + ): Promise { + return this.cannedResponse } } @@ -56,13 +67,24 @@ const getSignedTransaction = async ( }) } +const transactionResponse = 'transaction' +const readOnlyResponse = 'read only' +const transactionResponsePayload: JsonRpcSuccessResponse = { + jsonrpc: '2.0', + id: 123, + result: transactionResponse, +} +const readOnlyPayload: JsonRpcSuccessResponse = { + jsonrpc: '2.0', + id: 1234, + result: readOnlyResponse, +} + describe('Routing Handler', () => { describe('Routing Tests', () => { - const transactionResponse = 'transaction' - const readOnlyResponse = 'read only' const routingHandler = new RoutingHandler( - new DummySimpleClient(transactionResponse), - new DummySimpleClient(readOnlyResponse), + new DummySimpleClient(transactionResponsePayload), + new DummySimpleClient(readOnlyPayload), '', new NoOpAccountRateLimiter(), [], @@ -97,14 +119,11 @@ describe('Routing Handler', () => { let rateLimiter: DummyRateLimiter let routingHandler: RoutingHandler - const transactionResponse = 'transaction' - const readOnlyResponse = 'read only' - beforeEach(() => { rateLimiter = new DummyRateLimiter() routingHandler = new RoutingHandler( - new DummySimpleClient(transactionResponse), - new DummySimpleClient(readOnlyResponse), + new DummySimpleClient(transactionResponsePayload), + new DummySimpleClient(readOnlyPayload), '', rateLimiter, [], @@ -156,15 +175,13 @@ describe('Routing Handler', () => { describe('unsupported destination tests', () => { let routingHandler: RoutingHandler - const transactionResponse = 'transaction' - const readOnlyResponse = 'read only' const deployerWallet: Wallet = Wallet.createRandom() const whitelistedTo: string = Wallet.createRandom().address beforeEach(() => { routingHandler = new RoutingHandler( - new DummySimpleClient(transactionResponse), - new DummySimpleClient(readOnlyResponse), + new DummySimpleClient(transactionResponsePayload), + new DummySimpleClient(readOnlyPayload), deployerWallet.address, new NoOpAccountRateLimiter(), [whitelistedTo], @@ -218,13 +235,10 @@ describe('Routing Handler', () => { describe('unsupported methods tests', () => { let routingHandler: RoutingHandler - const transactionResponse = 'transaction' - const readOnlyResponse = 'read only' - beforeEach(() => { routingHandler = new RoutingHandler( - new DummySimpleClient(transactionResponse), - new DummySimpleClient(readOnlyResponse), + new DummySimpleClient(transactionResponsePayload), + new DummySimpleClient(readOnlyPayload), '', new NoOpAccountRateLimiter(), [], @@ -251,4 +265,75 @@ describe('Routing Handler', () => { }, UnsupportedMethodError) }) }) + + describe('Formatted JSON RPC Responses', () => { + let routingHandler: RoutingHandler + + const txError: JsonRpcError = { + code: -123, + message: 'tx error', + data: 'tx error', + } + + const roError: JsonRpcError = { + code: -1234, + message: 'r/o error', + data: 'r/o error', + } + + const transactionErrorResponsePayload: JsonRpcErrorResponse = { + jsonrpc: '2.0', + id: 123, + error: txError, + } + const readOnlyErrorResponsePayload: JsonRpcErrorResponse = { + jsonrpc: '2.0', + id: 1234, + error: roError, + } + + beforeEach(() => { + routingHandler = new RoutingHandler( + new DummySimpleClient(transactionErrorResponsePayload), + new DummySimpleClient(readOnlyErrorResponsePayload), + '', + new NoOpAccountRateLimiter(), + [] + ) + }) + + it('throws Json error on transaction', async () => { + const error: Error = await TestUtils.assertThrowsAsync(async () => { + await routingHandler.handleRequest( + Web3RpcMethods.sendRawTransaction, + [await getSignedTransaction()], + '' + ) + }) + + error.should.be.instanceOf(FormattedJsonRpcError, 'Invalid error type!') + const formatted: FormattedJsonRpcError = error as FormattedJsonRpcError + formatted.jsonRpcResponse.should.deep.equal( + transactionErrorResponsePayload, + 'Incorrect error returned!' + ) + }) + + it('throws Json error on read only request', async () => { + const error: Error = await TestUtils.assertThrowsAsync(async () => { + await routingHandler.handleRequest( + Web3RpcMethods.networkVersion, + [], + '' + ) + }) + + error.should.be.instanceOf(FormattedJsonRpcError, 'Invalid error type!') + const formatted: FormattedJsonRpcError = error as FormattedJsonRpcError + formatted.jsonRpcResponse.should.deep.equal( + readOnlyErrorResponsePayload, + 'Incorrect error returned!' + ) + }) + }) }) From d62ba3dc6354fa41855967d43a914789f624d3ca Mon Sep 17 00:00:00 2001 From: Will Meister Date: Wed, 29 Apr 2020 11:35:18 -0500 Subject: [PATCH 06/10] Fixing catch of formatted json rpc error (#118) * fixing issue logging FormattedJsonRpcErrorResponse as error --- .../rollup-full-node/src/app/routing-handler.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/rollup-full-node/src/app/routing-handler.ts b/packages/rollup-full-node/src/app/routing-handler.ts index f7368ef122a50..eb4014450fbed 100644 --- a/packages/rollup-full-node/src/app/routing-handler.ts +++ b/packages/rollup-full-node/src/app/routing-handler.ts @@ -64,6 +64,7 @@ export class RoutingHandler implements FullnodeHandler { * @param method The Ethereum JSON RPC method. * @param params The parameters. * @param sourceIpAddress The requesting IP address. + * @throws FormattedJsonRpcError if the proxied response is a JsonRpcErrorResponse */ public async handleRequest( method: string, @@ -102,8 +103,9 @@ export class RoutingHandler implements FullnodeHandler { this.assertDestinationValid(tx) + let result: JsonRpcResponse try { - const result: JsonRpcResponse = + result = methodsToRouteWithTransactionHandler.indexOf(method) >= 0 ? await this.transactionClient.makeRpcCall(method, params) : await this.readOnlyClient.makeRpcCall(method, params) @@ -112,10 +114,6 @@ export class RoutingHandler implements FullnodeHandler { params )}] got result [${JSON.stringify(result)}]` ) - if (isJsonRpcErrorResponse(result)) { - throw new FormattedJsonRpcError(result as JsonRpcErrorResponse) - } - return result.result } catch (e) { logError( log, @@ -126,6 +124,11 @@ export class RoutingHandler implements FullnodeHandler { ) throw e } + + if (isJsonRpcErrorResponse(result)) { + throw new FormattedJsonRpcError(result as JsonRpcErrorResponse) + } + return result.result } /** From 09a49dc308c891fa8c802eda7d28d6bec35f1eae Mon Sep 17 00:00:00 2001 From: Will Meister Date: Wed, 29 Apr 2020 14:12:48 -0500 Subject: [PATCH 07/10] making it so that merge to UAT / PROD does not automatically restart servers. We will likely want to be more intentional with timing (#119) --- .github/workflows/synthetix-prod-ecr-deploy.yml | 6 ------ .github/workflows/synthetix-uat-ecr-deploy.yml | 5 ----- 2 files changed, 11 deletions(-) diff --git a/.github/workflows/synthetix-prod-ecr-deploy.yml b/.github/workflows/synthetix-prod-ecr-deploy.yml index e3470f60a0331..72955d6b2e21c 100644 --- a/.github/workflows/synthetix-prod-ecr-deploy.yml +++ b/.github/workflows/synthetix-prod-ecr-deploy.yml @@ -35,12 +35,6 @@ jobs: AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_CI_AWS_ACCOUNT_ID }} run: ./docker/publish-rollup-fullnode-container.sh synthetix-prod - - name: Stop existing ECS tasks to auto-start task with new image - run: | - ./.github/scripts/stop-ecs-task.sh synthetix-prod-web synthetix-prod-web - ./.github/scripts/stop-ecs-task.sh synthetix-prod-geth synthetix-prod-geth - - - name: Logout of Amazon ECR if: always() run: docker logout ${{ steps.login-ecr.outputs.registry }} diff --git a/.github/workflows/synthetix-uat-ecr-deploy.yml b/.github/workflows/synthetix-uat-ecr-deploy.yml index 98736805c8fdf..e7cbabcb42e55 100644 --- a/.github/workflows/synthetix-uat-ecr-deploy.yml +++ b/.github/workflows/synthetix-uat-ecr-deploy.yml @@ -35,11 +35,6 @@ jobs: AWS_ACCOUNT_NUMBER: ${{ secrets.AWS_CI_AWS_ACCOUNT_ID }} run: ./docker/publish-rollup-fullnode-container.sh synthetix-uat - - name: Stop existing ECS tasks to auto-start task with new image - run: | - ./.github/scripts/stop-ecs-task.sh synthetix-uat-web synthetix-uat-web - ./.github/scripts/stop-ecs-task.sh synthetix-uat-geth synthetix-uat-geth - - name: Logout of Amazon ECR if: always() From 95d9449ce3daf08ca672378d1034dbcc47817e0d Mon Sep 17 00:00:00 2001 From: Will Meister Date: Wed, 29 Apr 2020 15:30:53 -0500 Subject: [PATCH 08/10] Ability to clear The Graph data (#121) * Adding ability to clear The Graph data by setting CLEAR_DATA_KEY environment variable --- aws/synthetix/prod/web/ecs-params.yml | 6 ++++-- aws/synthetix/uat/web/ecs-params.yml | 6 ++++-- docker/the-graph/wait-for-ovm.sh | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/aws/synthetix/prod/web/ecs-params.yml b/aws/synthetix/prod/web/ecs-params.yml index 1513761c445f1..76b05bcd57e73 100644 --- a/aws/synthetix/prod/web/ecs-params.yml +++ b/aws/synthetix/prod/web/ecs-params.yml @@ -55,8 +55,10 @@ task_definition: autoprovision: true driver: 'local' - name: postgres-data - scope: task + scope: shared + autoprovision: true driver: 'local' - name: ipfs-data - scope: task + scope: shared + autoprovision: true driver: 'local' diff --git a/aws/synthetix/uat/web/ecs-params.yml b/aws/synthetix/uat/web/ecs-params.yml index 1513761c445f1..76b05bcd57e73 100644 --- a/aws/synthetix/uat/web/ecs-params.yml +++ b/aws/synthetix/uat/web/ecs-params.yml @@ -55,8 +55,10 @@ task_definition: autoprovision: true driver: 'local' - name: postgres-data - scope: task + scope: shared + autoprovision: true driver: 'local' - name: ipfs-data - scope: task + scope: shared + autoprovision: true driver: 'local' diff --git a/docker/the-graph/wait-for-ovm.sh b/docker/the-graph/wait-for-ovm.sh index 002430d73c75b..9f6adcb4be6bc 100755 --- a/docker/the-graph/wait-for-ovm.sh +++ b/docker/the-graph/wait-for-ovm.sh @@ -1,5 +1,7 @@ #!/bin/sh # wait-for-ovm.sh +# NOTE: set the CLEAR_DATA_KEY environment variable to clear the /data directory on startup. +# Directory will only be cleared if CLEAR_DATA_KEY is set AND different from last start. set -e @@ -29,6 +31,23 @@ wait_for_server_to_be_reachable() } +clear_data_if_necessary() +{ + DATA_DIRECTORY=${DATA_DIRECTORY:-/data} + CLEAR_DATA_FILE_PATH="$DATA_DIRECTORY/.clear_data_key_$CLEAR_DATA_KEY" + + if [[ -n "$CLEAR_DATA_KEY" && ! -f "$CLEAR_DATA_FILE_PATH" ]]; then + echo "Detected change in CLEAR_DATA_KEY. Purging data." + rm -rf ${DATA_DIRECTORY}/* + rm -rf ${DATA_DIRECTORY}/.clear_data_key_* + echo "Local data cleared from '${DATA_DIRECTORY}/*'" + echo "Contents of data dir: $(ls -alh $DATA_DIRECTORY)" + touch $CLEAR_DATA_FILE_PATH + fi +} + +clear_data_if_necessary + wait_for_server_to_be_reachable $OVM_URL_WITH_PORT >&2 echo "OVM is up!" From 4d39875588dca9756db45e974dfef775cfb3fba8 Mon Sep 17 00:00:00 2001 From: Will Meister Date: Wed, 29 Apr 2020 16:37:50 -0500 Subject: [PATCH 09/10] changing sh script because of version of sh on debian (#122) * Changing sh script because of version of sh on debian * Changing the DEV / UAT / PROD scripts to mount the postgres & IPFS volumes on The Graph --- .../dev/full-node/docker-compose.yml | 3 +++ aws/synthetix/prod/web/docker-compose.yml | 3 +++ aws/synthetix/uat/web/docker-compose.yml | 3 +++ docker/the-graph/wait-for-ovm.sh | 23 ++++++++++++------- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/aws/synthetix/dev/full-node/docker-compose.yml b/aws/synthetix/dev/full-node/docker-compose.yml index 99be116442656..1320fa60fef28 100644 --- a/aws/synthetix/dev/full-node/docker-compose.yml +++ b/aws/synthetix/dev/full-node/docker-compose.yml @@ -112,6 +112,9 @@ services: RUST_LOG: info STARTUP_WAIT_TIMEOUT: 30 OVM_URL_WITH_PORT: 'http://0.0.0.0:8545' + volumes: + - postgres-data:/data/postgres + - ipfs-data:/data/ipfs logging: driver: awslogs diff --git a/aws/synthetix/prod/web/docker-compose.yml b/aws/synthetix/prod/web/docker-compose.yml index 3fdd36d034175..46aaf23588244 100644 --- a/aws/synthetix/prod/web/docker-compose.yml +++ b/aws/synthetix/prod/web/docker-compose.yml @@ -86,6 +86,9 @@ services: RUST_LOG: info STARTUP_WAIT_TIMEOUT: 30 OVM_URL_WITH_PORT: 'http://0.0.0.0:8545' + volumes: + - postgres-data:/data/postgres + - ipfs-data:/data/ipfs logging: driver: awslogs diff --git a/aws/synthetix/uat/web/docker-compose.yml b/aws/synthetix/uat/web/docker-compose.yml index a1d166d749928..298853271b159 100644 --- a/aws/synthetix/uat/web/docker-compose.yml +++ b/aws/synthetix/uat/web/docker-compose.yml @@ -86,6 +86,9 @@ services: RUST_LOG: info STARTUP_WAIT_TIMEOUT: 30 OVM_URL_WITH_PORT: 'http://0.0.0.0:8545' + volumes: + - postgres-data:/data/postgres + - ipfs-data:/data/ipfs logging: driver: awslogs diff --git a/docker/the-graph/wait-for-ovm.sh b/docker/the-graph/wait-for-ovm.sh index 9f6adcb4be6bc..836fff2213e54 100755 --- a/docker/the-graph/wait-for-ovm.sh +++ b/docker/the-graph/wait-for-ovm.sh @@ -1,6 +1,6 @@ #!/bin/sh # wait-for-ovm.sh -# NOTE: set the CLEAR_DATA_KEY environment variable to clear the /data directory on startup. +# NOTE: set the CLEAR_DATA_KEY environment variable to clear the $POSTGRES_DIR and $IPFS_DIR on startup. # Directory will only be cleared if CLEAR_DATA_KEY is set AND different from last start. set -e @@ -33,16 +33,23 @@ wait_for_server_to_be_reachable() clear_data_if_necessary() { - DATA_DIRECTORY=${DATA_DIRECTORY:-/data} - CLEAR_DATA_FILE_PATH="$DATA_DIRECTORY/.clear_data_key_$CLEAR_DATA_KEY" + POSTGRES_DIR=${POSTGRES_DIR:-/data/postgres} + IPFS_DIR=${IPFS_DIR:-/data/ipfs} + CLEAR_DATA_FILE_PATH="${IPFS_DIR}/.clear_data_key_${CLEAR_DATA_KEY}" - if [[ -n "$CLEAR_DATA_KEY" && ! -f "$CLEAR_DATA_FILE_PATH" ]]; then + if [ -n "$CLEAR_DATA_KEY" -a ! -f "$CLEAR_DATA_FILE_PATH" ]; then echo "Detected change in CLEAR_DATA_KEY. Purging data." - rm -rf ${DATA_DIRECTORY}/* - rm -rf ${DATA_DIRECTORY}/.clear_data_key_* - echo "Local data cleared from '${DATA_DIRECTORY}/*'" - echo "Contents of data dir: $(ls -alh $DATA_DIRECTORY)" + rm -rf ${IPFS_DIR}/* + rm -rf ${IPFS_DIR}/.clear_data_key_* + echo "Local data cleared from '${IPFS_DIR}/*'" + echo "Contents of ipfs dir: $(ls -alh $IPFS_DIR)" + + rm -rf ${POSTGRES_DIR}/* + echo "Local data cleared from '${POSTGRES_DIR}/*'" + echo "Contents of postgres dir: $(ls -alh $POSTGRES_DIR)" touch $CLEAR_DATA_FILE_PATH + else + echo "No change detected in CLEAR_DATA_KEY not deleting data." fi } From 6a8a7a8dbcd859f03e0856f66e53c827f646d31a Mon Sep 17 00:00:00 2001 From: ben-chain Date: Wed, 29 Apr 2020 18:32:54 -0400 Subject: [PATCH 10/10] YAS-335 Improvements to Ethereum event endpoints (#116) * everything working * linting * linting * bad multi level filter * handle unsupported filter handler * merge updated error code * linting * fix merge accidents * linting * linting * fix log indexing bug * add filtering multi-event test * linting * linting * use already existing EM interface * linting * linting --- .../app/transport/server/json-rpc-errors.ts | 4 + packages/ovm/src/app/utils.ts | 64 ++++++-- packages/ovm/test/app/utils.spec.ts | 15 +- packages/ovm/test/helpers.ts | 6 +- .../src/app/fullnode-rpc-server.ts | 9 ++ .../src/app/web3-rpc-handler.ts | 69 +++++++-- packages/rollup-full-node/src/types/errors.ts | 6 + .../test/app/web-rpc-handler.spec.ts | 143 ++++++++++++++---- .../transpiled/events/MasterEventEmitter.sol | 14 ++ .../transpiled/events/SubEventEmitter.sol | 9 ++ .../contracts/untranspiled/EventEmitter.sol | 6 +- 11 files changed, 283 insertions(+), 62 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/core-utils/src/app/transport/server/json-rpc-errors.ts b/packages/core-utils/src/app/transport/server/json-rpc-errors.ts index a6bc89093426f..912e8e15482f0 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', diff --git a/packages/ovm/src/app/utils.ts b/packages/ovm/src/app/utils.ts index c8ee2903fb868..6d589af4ec2da 100644 --- a/packages/ovm/src/app/utils.ts +++ b/packages/ovm/src/app/utils.ts @@ -11,6 +11,7 @@ import { ZERO_ADDRESS, LOG_NEWLINE_STRING, BloomFilter, + hexStrToNumber, } from '@eth-optimism/core-utils' import { ethers } from 'ethers' import { LogDescription } from 'ethers/utils' @@ -43,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 ) @@ -61,34 +63,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 loggerLogs = [`Parsing logs from contract ${activeContract}: `] + const loggerLogs = [`Parsing internal logs ${JSON.stringify(logs)}: `] const ovmLogs = [] + let cumulativeTxEMLogIndices = 0 + let prevEMLogIndex = 0 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) { + 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 + } + cumulativeTxEMLogIndices++ + prevEMLogIndex = EMLogIndex + const executionManagerLog = executionManagerInterface.parseLog(log) + if (!executionManagerLog) { + loggerLogs.push( + `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( `${executionManagerLog.name}, values: ${JSON.stringify( executionManagerLog.values - )}` + )} and cumulativeTxEMLogIndices: ${cumulativeTxEMLogIndices}` ) + if (executionManagerLog.name === 'ActiveContract') { + activeContract = executionManagerLog.values['_activeContract'] + loggerLogs.push( + `EM activeContract event detected, setting activeContract to ${activeContract}` + ) + } else { + loggerLogs.push( + `EM-but-non-activeContract event detected, ignoring...` + ) + } } } else { - loggerLogs.push(`Non-EM log: ${JSON.stringify(log)}`) - ovmLogs.push({ ...log, address: activeContract }) + const newIndex = log.logIndex - cumulativeTxEMLogIndices + loggerLogs.push( + `Non-EM log: ${JSON.stringify( + log + )}. Using address of active contract ${activeContract} and log index ${newIndex}` + ) + ovmLogs.push({ ...log, address: activeContract, logIndex: newIndex }) } }) logger.debug(loggerLogs.join(LOG_NEWLINE_STRING)) @@ -178,17 +212,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 5ca2170e75aa4..84ab580dd16a5 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 b4b2cabb49a50..ebe388241d01c 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/fullnode-rpc-server.ts b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts index 47bbbaae422a1..15719a4681aad 100644 --- a/packages/rollup-full-node/src/app/fullnode-rpc-server.ts +++ b/packages/rollup-full-node/src/app/fullnode-rpc-server.ts @@ -22,6 +22,7 @@ import { RevertError, TransactionLimitError, UnsupportedMethodError, + UnsupportedFilterError, } from '../types' const log: Logger = getLogger('rollup-fullnode-rpc-server') @@ -128,6 +129,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 feadd5c408ea1..6ddc6de87f235 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, + executionManagerInterface, } from '@eth-optimism/ovm' import AsyncLock from 'async-lock' @@ -42,6 +43,7 @@ import { Web3RpcTypes, Web3RpcMethods, RevertError, + UnsupportedFilterError, } from '../types' import { initializeL2Node, getCurrentTime, isErrorEVMRevert } from './util' import { NoOpL2ToL1MessageSubmitter } from './message-submitter' @@ -51,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 = {} @@ -494,23 +502,59 @@ export class DefaultWeb3Handler } public async getLogs(ovmFilter: any): Promise { - log.debug(`Requesting logs with filter [${JSON.stringify(ovmFilter)}].`) const filter = JSON.parse(JSON.stringify(ovmFilter)) + // We cannot filter out execution manager events or else convertInternalLogsToOvmLogs will break. So add EM address to address filter if (filter['address']) { - const codeContractAddress = await this.context.executionManager.getCodeContractAddress( - filter.address - ) - filter['address'] = codeContractAddress + if (!Array.isArray(filter['address'])) { + filter['address'] = [filter['address']] + } + const codeContractAddresses = [] + for (const address of filter['address']) { + codeContractAddresses.push( + await this.context.executionManager.getCodeContractAddress(address) + ) + } + filter['address'] = [ + ...codeContractAddresses, + 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 ${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])) { + filter['topics'][0] = [JSON.parse(JSON.stringify(filter['topics'][0]))] + } + filter['topics'][0].push(...ALL_EXECUTION_MANAGER_EVENT_TOPICS) } + log.debug( + `Converted ovm filter ${JSON.stringify( + ovmFilter + )} to internal filter ${JSON.stringify(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) logItem['transactionHash'] = await this.getOvmTxHash( logItem['transactionHash'] ) @@ -521,8 +565,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 }) ) @@ -608,6 +653,7 @@ export class DefaultWeb3Handler ) ovmTxReceipt = await internalTxReceiptToOvmTxReceipt( internalTxReceipt, + this.context.executionManager.address, ovmTxHash ) } else { @@ -807,7 +853,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/src/types/errors.ts b/packages/rollup-full-node/src/types/errors.ts index 00dad8750f9f7..4681fad3fcee5 100644 --- a/packages/rollup-full-node/src/types/errors.ts +++ b/packages/rollup-full-node/src/types/errors.ts @@ -20,6 +20,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 0489bd73f4e28..055f5290e5e77 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 @@ -30,6 +30,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) @@ -349,7 +351,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', @@ -457,32 +459,121 @@ 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, + 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) + }) + 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 + let master + let subFactory + const SUB_EMITTER_EVENT_NAME = 'Burger' + beforeEach(async () => { + 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 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, [ + { + fromBlock: 'latest', + toBlock: 'latest', + }, + ]) + const receipt = await httpProvider.send( + Web3RpcMethods.getTransactionReceipt, + [tx.hash] + ) + gotLogs.should.deep.equal(receipt.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') }) }) 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 0000000000000..9be7918efc142 --- /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 0000000000000..0f3d5e95fe843 --- /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 diff --git a/packages/rollup-full-node/test/contracts/untranspiled/EventEmitter.sol b/packages/rollup-full-node/test/contracts/untranspiled/EventEmitter.sol index 088bd22b2a417..09824963fc428 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(); } }