Skip to content

Commit

Permalink
feat: Block cheat codes in anvil (#8277)
Browse files Browse the repository at this point in the history
Adds a second api to the mainnet-fork, located at
`public-PUBLIC_API_KEY`, in which all cheat codes are blocked. We define
a cheat code as a method in the evm, hardhat, or anvil namespaces. We
use njs for parsing the JSON RPC request body and testing the method
namespace.

The PUBLIC_API_KEY is only set for provernet, for other networks, we
load the same API_KEY secret as always.

This PR also enables logging for anvil, including a logrotate config to
ensure we don't fill up the disk just with logs.
  • Loading branch information
spalladino authored Aug 29, 2024
1 parent 2cfe7cd commit 4a82f53
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 36 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/devnet-deploys.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
API_KEY: ${{ secrets.DEVNET_API_KEY }}
PUBLIC_API_KEY: ${{ secrets.DEVNET_API_KEY }}
FORK_MNEMONIC: ${{ secrets.FORK_MNEMONIC }}
CONTRACT_PUBLISHER_PRIVATE_KEY: ${{ secrets.CONTRACT_PUBLISHER_PRIVATE_KEY }}
CONTRACT_S3_BUCKET: s3://static.aztec.network
Expand Down Expand Up @@ -64,6 +65,7 @@ env:
# Anvil
TF_VAR_FORK_MNEMONIC: ${{ secrets.FORK_MNEMONIC }}
TF_VAR_INFURA_API_KEY: ${{ secrets.INFURA_API_KEY }}
TF_VAR_PUBLIC_API_KEY: ${{ secrets.DEVNET_API_KEY }}

# Faucet
TF_VAR_FAUCET_ACCOUNT_INDEX: 9
Expand Down Expand Up @@ -105,6 +107,7 @@ jobs:
deploy_tag: ${{ steps.set_network_vars.outputs.deploy_tag }}
branch_name: ${{ steps.set_network_vars.outputs.branch_name }}
network_api_key: ${{ steps.set_network_vars.outputs.network_api_key }}
network_public_api_key: ${{ steps.set_network_vars.outputs.network_public_api_key }}
agents_per_prover: ${{ steps.set_network_vars.outputs.agents_per_prover }}
bot_interval: ${{ steps.set_network_vars.outputs.bot_interval }}
node_tcp_range_start: ${{ steps.set_network_vars.outputs.node_tcp_range_start }}
Expand All @@ -131,6 +134,7 @@ jobs:
echo "deploy_tag=devnet" >> $GITHUB_OUTPUT
echo "branch_name=devnet" >> $GITHUB_OUTPUT
echo "network_api_key=DEVNET_API_KEY" >> $GITHUB_OUTPUT
echo "network_public_api_key=DEVNET_API_KEY" >> $GITHUB_OUTPUT
echo "agents_per_prover=4" >> $GITHUB_OUTPUT
echo "bot_interval=180" >> $GITHUB_OUTPUT
echo "node_tcp_range_start=40100" >> $GITHUB_OUTPUT
Expand All @@ -151,6 +155,7 @@ jobs:
echo "deploy_tag=provernet" >> $GITHUB_OUTPUT
echo "branch_name=provernet" >> $GITHUB_OUTPUT
echo "network_api_key=PROVERNET_API_KEY" >> $GITHUB_OUTPUT
echo "network_public_api_key=PROVERNET_PUBLIC_API_KEY" >> $GITHUB_OUTPUT
echo "agents_per_prover=4" >> $GITHUB_OUTPUT
echo "bot_interval=300" >> $GITHUB_OUTPUT
echo "node_tcp_range_start=40200" >> $GITHUB_OUTPUT
Expand All @@ -171,6 +176,7 @@ jobs:
echo "deploy_tag=alphanet" >> $GITHUB_OUTPUT
echo "branch_name=alphanet" >> $GITHUB_OUTPUT
echo "network_api_key=ALPHANET_API_KEY" >> $GITHUB_OUTPUT
echo "network_public_api_key=ALPHANET_API_KEY" >> $GITHUB_OUTPUT
echo "agents_per_prover=1" >> $GITHUB_OUTPUT
echo "bot_interval=30" >> $GITHUB_OUTPUT
echo "node_tcp_range_start=40000" >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -200,6 +206,8 @@ jobs:
TF_VAR_DEPLOY_TAG: ${{ needs.set-network.outputs.deploy_tag }}
API_KEY: ${{ secrets[needs.set-network.outputs.network_api_key] }}
TF_VAR_API_KEY: ${{ secrets[needs.set-network.outputs.network_api_key] }}
PUBLIC_API_KEY: ${{ secrets[needs.set-network.outputs.network_public_api_key] }}
TF_VAR_PUBLIC_API_KEY: ${{ secrets[needs.set-network.outputs.network_public_api_key] }}
API_KEY_NAME: ${{ needs.set-network.outputs.network_api_key }}
runs-on: ${{ github.actor }}-x86
steps:
Expand Down Expand Up @@ -443,6 +451,8 @@ jobs:
TF_VAR_DEPLOY_TAG: ${{ needs.set-network.outputs.deploy_tag }}
API_KEY: ${{ secrets[needs.set-network.outputs.network_api_key] }}
TF_VAR_API_KEY: ${{ secrets[needs.set-network.outputs.network_api_key] }}
PUBLIC_API_KEY: ${{ secrets[needs.set-network.outputs.network_public_api_key] }}
TF_VAR_PUBLIC_API_KEY: ${{ secrets[needs.set-network.outputs.network_public_api_key] }}
TF_VAR_AGENTS_PER_PROVER: ${{ needs.set-network.outputs.agents_per_prover }}
TF_VAR_BOT_TX_INTERVAL_SECONDS: ${{ needs.set-network.outputs.bot_interval }}
TF_VAR_NODE_LB_RULE_PRIORITY: ${{ needs.set-network.outputs.node_lb_priority_range_start }}
Expand Down
1 change: 1 addition & 0 deletions build-system/scripts/deploy_terraform
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export TF_VAR_DOCKERHUB_ACCOUNT=$DOCKERHUB_ACCOUNT
export TF_VAR_FORK_MNEMONIC=$FORK_MNEMONIC
export TF_VAR_INFURA_API_KEY=$INFURA_API_KEY
export TF_VAR_API_KEY=$FORK_API_KEY
export TF_VAR_PUBLIC_API_KEY=${PUBLIC_FORK_API_KEY:-$FORK_API_KEY}
export TF_VAR_L1_CHAIN_ID=$CHAIN_ID

# If given a repository name, use it to construct and set/override the backend key.
Expand Down
20 changes: 13 additions & 7 deletions iac/mainnet-fork/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,30 @@ build:
FROM ubuntu:focal

# Install nginx
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
RUN apt-get update && apt install -y git curl nginx

# Copy nginx config
COPY . .
COPY nginx/gateway.conf /etc/nginx/gateway.conf
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY ./scripts/install_nginx.sh ./scripts/install_nginx.sh
RUN ./scripts/install_nginx.sh

# Install foundry
COPY ./scripts/install_foundry.sh ./scripts/install_foundry.sh
RUN ./scripts/install_foundry.sh
ENV PATH="./foundry/bin:${PATH}"

# Copy nginx config
COPY ./scripts ./scripts
COPY ./redeploy ./redeploy
COPY ./nginx/ /etc/nginx/
COPY --chmod 640 ./etc/anvil.logrotate.conf /etc/logrotate.d/anvil

# Expose port 80
EXPOSE 80

# Set entrypoint.
ENTRYPOINT ["sh", "-c", "./scripts/run_nginx_anvil.sh"]

export-local:
FROM +build
SAVE IMAGE aztecprotocol/mainnet-fork

export-mainnet-fork:
FROM +build
ARG DIST_TAG="devnet"
Expand Down
9 changes: 9 additions & 0 deletions iac/mainnet-fork/etc/anvil.logrotate.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/var/log/anvil/*.log {
daily
missingok
rotate 14
size 50M
compress
notifempty
copytruncate
}
22 changes: 19 additions & 3 deletions iac/mainnet-fork/nginx/gateway.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@ server {
listen 80 default_server;
listen 8545;

location = /{{API_KEY}} {
location /{{ADMIN_API_KEY}} {
proxy_pass http://0.0.0.0:8544;
rewrite ^/{{API_KEY}}(.*) /$1 break;
rewrite ^/{{ADMIN_API_KEY}}(.*) /$1 break;
}

location /public-{{PUBLIC_API_KEY}} {
client_body_buffer_size 20M;
client_body_in_single_buffer on;
js_import main from njs/anvil_validation.js;
js_content main.authorize;
}

location @anvil {
proxy_pass http://0.0.0.0:8544;
rewrite ^/({{ADMIN_API_KEY}}|public-{{PUBLIC_API_KEY}})(.*) /$2 break;
}

# Error responses
error_page 404 = @400; # Treat invalid paths as bad requests
error_page 404 = @404;
location @404 {
return 404 '{"error":"Resource not found"}';
}

proxy_intercept_errors on; # Do not send backend errors to client
default_type application/json; # If no content-type, assume JSON
}
1 change: 1 addition & 0 deletions iac/mainnet-fork/nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
load_module modules/ngx_http_js_module.so;

events {
worker_connections 768;
Expand Down
28 changes: 28 additions & 0 deletions iac/mainnet-fork/nginx/njs/anvil_validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Authorizes a request based on the method of the JSON-RPC request body, blocking all cheat codes.
// See https://github.com/nginx/njs-examples?tab=readme-ov-file#authorizing-requests-based-on-request-body-content-http-authorization-request-body
function authorize(r) {
try {
if (r.requestText) {
const body = JSON.parse(r.requestText);
if (body && body.method) {
const method = body.method.replace(/\s+/g).toLowerCase();
if (
method.startsWith("evm_") ||
method.startsWith("hardhat_") ||
method.startsWith("anvil_")
) {
const error = "Restricted method " + method;
r.error(error);
r.return(401, JSON.stringify({ error }));
return;
}
}
}
r.internalRedirect("@anvil");
} catch (e) {
r.error("JSON.parse exception: " + e);
r.return(400, JSON.stringify({ error: "Error parsing request" }));
}
}

export default { authorize };
2 changes: 1 addition & 1 deletion iac/mainnet-fork/redeploy
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3
4
19 changes: 19 additions & 0 deletions iac/mainnet-fork/scripts/install_nginx.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh
set -eu

# See https://nginx.org/en/linux_packages.html#Ubuntu
echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections

apt-get update && apt install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring

curl -sS https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
| tee /etc/apt/sources.list.d/nginx.list

echo "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| tee /etc/apt/preferences.d/99nginx

apt-get update && apt install -y git curl nginx nginx-module-njs
14 changes: 9 additions & 5 deletions iac/mainnet-fork/scripts/run_nginx_anvil.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

set -eum pipefail

# Replace API_KEY in nginx config
echo "Replacing api key with $API_KEY in nginx config..."
sed -i 's/{{API_KEY}}/'$API_KEY'/' /etc/nginx/gateway.conf
# Replace API_KEYs in nginx config
echo "Replacing api keys in nginx config..."
sed -i 's/{{PUBLIC_API_KEY}}/'$PUBLIC_API_KEY'/g' /etc/nginx/gateway.conf
sed -i 's/{{ADMIN_API_KEY}}/'$API_KEY'/g' /etc/nginx/gateway.conf

# Run nginx and anvil alongside each other
trap 'kill $(jobs -p)' SIGTERM
Expand All @@ -21,8 +22,11 @@ echo "result: ${MNEMONIC_STRIPPED:0:10}..."
# Data directory for anvil state
mkdir -p /data

# Run anvil silently
.foundry/bin/anvil --silent --block-time 12 --host $HOST -p $PORT -m "$MNEMONIC_STRIPPED" -f=https://mainnet.infura.io/v3/$INFURA_API_KEY --chain-id=$L1_CHAIN_ID --fork-block-number=15918000 --block-base-fee-per-gas=10 -s=$SNAPSHOT_FREQUENCY --state=./data/state --balance=1000000000000000000 >/dev/null &
# Log directory for anvil
mkdir -p /var/log/anvil/

# Run anvil logging to /var/log/anvil
.foundry/bin/anvil --block-time 12 --host $HOST -p $PORT -m "$MNEMONIC_STRIPPED" -f=https://mainnet.infura.io/v3/$INFURA_API_KEY --chain-id=$L1_CHAIN_ID --fork-block-number=15918000 --block-base-fee-per-gas=10 -s=$SNAPSHOT_FREQUENCY --state=./data/state --balance=1000000000000000000 >>/var/log/anvil/anvil.log &

echo "Waiting for ethereum host at $ETHEREUM_HOST..."
while ! curl -s $ETHEREUM_HOST >/dev/null; do sleep 1; done
Expand Down
26 changes: 6 additions & 20 deletions iac/mainnet-fork/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -119,26 +119,12 @@ resource "aws_ecs_task_definition" "aztec_mainnet_fork" {
image = "${var.DOCKERHUB_ACCOUNT}/mainnet-fork:${var.DEPLOY_TAG}"
essential = true
environment = [
{
name = "API_KEY"
value = "${var.API_KEY}"
},
{
name = "MNEMONIC"
value = "${var.FORK_MNEMONIC}"
},
{
name = "INFURA_API_KEY"
value = "${var.INFURA_API_KEY}"
},
{
name = "L1_CHAIN_ID"
value = "${var.L1_CHAIN_ID}"
},
{
name = "SNAPSHOT_FREQUENCY"
value = "15"
}
{ name = "API_KEY", value = "${var.API_KEY}" },
{ name = "PUBLIC_API_KEY", value = "${var.PUBLIC_API_KEY}" },
{ name = "MNEMONIC", value = "${var.FORK_MNEMONIC}" },
{ name = "INFURA_API_KEY", value = "${var.INFURA_API_KEY}" },
{ name = "L1_CHAIN_ID", value = "${var.L1_CHAIN_ID}" },
{ name = "SNAPSHOT_FREQUENCY", value = "15" }
]
mountPoints = [
{
Expand Down
4 changes: 4 additions & 0 deletions iac/mainnet-fork/terraform/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ variable "API_KEY" {
type = string
}

variable "PUBLIC_API_KEY" {
type = string
}

variable "DOCKERHUB_ACCOUNT" {
type = string
}
Expand Down

0 comments on commit 4a82f53

Please sign in to comment.