diff --git a/.changeset/silent-apples-smile.md b/.changeset/silent-apples-smile.md new file mode 100644 index 00000000..27374802 --- /dev/null +++ b/.changeset/silent-apples-smile.md @@ -0,0 +1,5 @@ +--- +'@fuel-bridge/solidity-contracts': minor +--- + +add manual CI to simulate upgrades with tenderly diff --git a/.changeset/slow-bottles-bathe.md b/.changeset/slow-bottles-bathe.md new file mode 100644 index 00000000..a0fe543e --- /dev/null +++ b/.changeset/slow-bottles-bathe.md @@ -0,0 +1,6 @@ +--- +'@fuel-bridge/solidity-contracts': patch +'@fuel-bridge/test-utils': patch +--- + +upgrade docker setup for fuel core and block committer diff --git a/.github/workflows/manual-simulate-upgrade.yml b/.github/workflows/manual-simulate-upgrade.yml new file mode 100644 index 00000000..7bf4314b --- /dev/null +++ b/.github/workflows/manual-simulate-upgrade.yml @@ -0,0 +1,35 @@ +name: Manual Simulate Upgrade + +on: + workflow_dispatch: + inputs: + vnetId: + description: 'Enter the tenderly virtual testnet id' + required: true + type: string + accessKey: + description: 'Enter the tenderly account access key' + required: true + type: string + rpc: + description: 'Enter tenderly virtual network rpc' + required: true + type: string + +jobs: + simulate-upgrades: + runs-on: ubuntu-latest + env: + RPC_URL: ${{ github.event.inputs.rpc }} + VNET_ID: ${{ github.event.inputs.vnetId }} + ACCESS_KEY: ${{ github.event.inputs.accessKey }} + steps: + - uses: actions/checkout@v3 + - uses: FuelLabs/github-actions/setups/node@master + with: + node-version: 20.16.0 + pnpm-version: 9.0.6 + - name: Simulate Upgrades + run: | + npx hardhat compile && npx hardhat simulate-upgrades --network mainnet + working-directory: ./packages/solidity-contracts diff --git a/docker/block-committer/Dockerfile b/docker/block-committer/Dockerfile index 26419d90..788ce522 100644 --- a/docker/block-committer/Dockerfile +++ b/docker/block-committer/Dockerfile @@ -1,12 +1,7 @@ -FROM ghcr.io/fuellabs/fuel-block-committer:v0.4.0 +FROM ghcr.io/fuellabs/fuel-block-committer:sha-77607e4 -ARG ETHEREUM_WALLET_KEY="" -ARG COMMIT_INTERVAL=1 ARG COMMITER_IP=0.0.0.0 ARG COMMITER_PORT=8888 -ARG ETHEREUM_CHAIN="hardhat" -ARG ETHEREUM_RPC="" -ARG FUEL_GRAPHQL_ENDPOINT="" # dependencies ENV DEBIAN_FRONTEND=noninteractive @@ -16,15 +11,10 @@ RUN apt update && apt install -y curl jq && rm -rf /var/lib/apt/lists/* WORKDIR /block-committer # expose fuel node port -ENV ETHEREUM_WALLET_KEY="${ETHEREUM_WALLET_KEY}" -ENV COMMIT_INTERVAL="${COMMIT_INTERVAL}" ENV HOST="${COMMITER_IP}" ENV PORT="${COMMITER_PORT}" -ENV ETHEREUM_CHAIN="${ETHEREUM_CHAIN}" -ENV ETHEREUM_RPC="${ETHEREUM_RPC}" -ENV FUEL_GRAPHQL_ENDPOINT="${FUEL_GRAPHQL_ENDPOINT}" + EXPOSE ${PORT} # copy over script and run -COPY ./block-commiter.sh . -CMD ["sh", "./block-commiter.sh"] +ENTRYPOINT ["sh", "./block-commiter.sh"] diff --git a/docker/block-committer/block-commiter.sh b/docker/block-committer/block-commiter.sh index 2a3ad815..74caeb01 100644 --- a/docker/block-committer/block-commiter.sh +++ b/docker/block-committer/block-commiter.sh @@ -4,12 +4,13 @@ set -euo RETRIES=${RETRIES:-60} DELAY=${DELAY:-10} JSON='{"jsonrpc":"2.0","id":0,"method":"net_version","params":[]}' +HEALTH_URL=${HEALTH_URL:-"http://fuel_core:4001/v1/health"} -if [ -z "$ETHEREUM_RPC" ]; then +if [ -z "$COMMITTER__ETH__RPC" ]; then echo "Must specify \$ETHEREUM_RPC." exit 1 fi -if [ -z "$FUEL_GRAPHQL_ENDPOINT" ]; then +if [ -z "$COMMITTER__FUEL__GRAPHQL_ENDPOINT" ]; then echo "Must specify \$FUEL_GRAPHQL_ENDPOINT." exit 1 fi @@ -18,7 +19,7 @@ if [ -z "$DEPLOYMENTS_HTTP" ]; then exit 1 fi -echo $FUEL_GRAPHQL_ENDPOINT/health +echo $COMMITTER__FUEL__GRAPHQL_ENDPOINT/health # wait for the base layer to be up echo "Waiting for Fuel Core chain." @@ -29,7 +30,7 @@ curl \ --retry-connrefused \ --retry $RETRIES \ --retry-delay $DELAY \ - $FUEL_GRAPHQL_ENDPOINT/health > /dev/null + $HEALTH_URL > /dev/null echo "Connected to Fuel Core chain." # get the deployments file from the deployer @@ -47,10 +48,10 @@ curl \ echo "Got l1 chain deployment data." # pull data from deployer dump -export STATE_CONTRACT_ADDRESS=$(cat "./addresses.json" | jq -r .FuelChainState) -echo "STATE_CONTRACT_ADDRESS: $STATE_CONTRACT_ADDRESS" -echo "ETHEREUM_RPC: $ETHEREUM_RPC" -echo "FUEL_GRAPHQL_ENDPOINT: $FUEL_GRAPHQL_ENDPOINT" +export COMMITTER__ETH__STATE_CONTRACT_ADDRESS=$(cat "./addresses.json" | jq -r .FuelChainState) +echo "COMMITTER__ETH__STATE_CONTRACT_ADDRESS: $COMMITTER__ETH__STATE_CONTRACT_ADDRESS" +echo "ETHEREUM_RPC: $COMMITTER__ETH__RPC" +echo "FUEL_GRAPHQL_ENDPOINT: $COMMITTER__FUEL__GRAPHQL_ENDPOINT" # start the Block Commiter echo "Starting block commiter" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 949e74bc..d56ba458 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,12 +1,24 @@ version: '3.4' services: + db: + image: postgres:14 + environment: + POSTGRES_USER: username + POSTGRES_PASSWORD: password + POSTGRES_DB: committer_db + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U username -d committer_db'] + interval: 5s + timeout: 5s + retries: 5 + l1_chain: image: fueldev/l1chain:${DOCKER_TAG_L1_CHAIN:-latest} build: dockerfile: ./docker/l1-chain/Dockerfile # Use build context of the root directory - # to allow coping solidity-contracts on Dockerfile + # to allow copying solidity-contracts on Dockerfile context: ../ env_file: - ./envs/l1_chain.env @@ -30,25 +42,55 @@ services: DEPLOYMENTS_HTTP: http://l1_chain:8081/deployments.local.json RUST_LOG: debug DEBUG: true + DB_PATH: /db ports: # expose the service to the host for integration testing - ${FUEL_CORE_HTTP_PORT:-4000}:4001 stop_grace_period: 1s fuel_block_commiter: - depends_on: - - fuel_core - image: fueldev/block-committer:${DOCKER_TAG_FUEL_CORE:-latest} + image: ghcr.io/fuellabs/fuel-block-committer:sha-77607e4 platform: linux/amd64 build: context: ./block-committer/ - env_file: - - ./envs/block_committer.env environment: - ETHEREUM_RPC: ws://l1_chain:9545/ - FUEL_GRAPHQL_ENDPOINT: http://fuel_core:4001/v1 + COMMITTER__ETH__RPC: 'ws://l1_chain:9545/' + COMMITTER__ETH__L1_KEYS__MAIN: 'Private(8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba)' + COMMITTER__ETH__L1_KEYS__BLOB: 'Private(59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d)' + COMMITTER__FUEL__GRAPHQL_ENDPOINT: 'http://fuel_core:4001/graphql' + COMMITTER__FUEL__NUM_BUFFERED_REQUESTS: '5' + COMMITTER__APP__DB__PORT: '5432' + COMMITTER__APP__DB__HOST: 'db' + COMMITTER__APP__DB__USERNAME: 'username' + COMMITTER__APP__DB__PASSWORD: 'password' + COMMITTER__APP__DB__MAX_CONNECTIONS: '10' + COMMITTER__APP__DB__USE_SSL: 'false' + COMMITTER__APP__DB__DATABASE: 'committer_db' + COMMITTER__APP__PORT: '8080' + COMMITTER__APP__HOST: '0.0.0.0' + COMMITTER__APP__BLOCK_CHECK_INTERVAL: '5s' + COMMITTER__APP__TX_FINALIZATION_CHECK_INTERVAL: '5s' + COMMITTER__APP__NUM_BLOCKS_TO_FINALIZE_TX: '3' + COMMITTER__APP__GAS_BUMP_TIMEOUT: '300s' + COMMITTER__APP__TX_MAX_FEE: '4000000000000000' + COMMITTER__APP__SEND_TX_REQUEST_TIMEOUT: '10s' + COMMITTER__APP__BUNDLE__ACCUMULATION_TIMEOUT: '3600s' + COMMITTER__APP__BUNDLE__BLOCKS_TO_ACCUMULATE: '400' + COMMITTER__APP__BUNDLE__OPTIMIZATION_TIMEOUT: '60s' + COMMITTER__APP__BUNDLE__BLOCK_HEIGHT_LOOKBACK: '8500' + COMMITTER__APP__BUNDLE__COMPRESSION_LEVEL: 'level6' + COMMITTER__APP__BUNDLE__OPTIMIZATION_STEP: '100' + COMMITTER__APP__BUNDLE__FRAGMENTS_TO_ACCUMULATE: '3' + COMMITTER__APP__BUNDLE__FRAGMENT_ACCUMULATION_TIMEOUT: '10m' + COMMITTER__APP__BUNDLE__NEW_BUNDLE_CHECK_INTERVAL: '3s' DEPLOYMENTS_HTTP: http://l1_chain:8081/deployments.local.json ports: # expose the service to the host for integration testing - ${COMMITTER_HTTP_PORT:-8888}:8888 - stop_grace_period: 1s + depends_on: + db: + condition: service_healthy + l1_chain: + condition: service_started + fuel_core: + condition: service_started diff --git a/docker/fuel-core/Dockerfile b/docker/fuel-core/Dockerfile index b21cd395..3d8b69db 100644 --- a/docker/fuel-core/Dockerfile +++ b/docker/fuel-core/Dockerfile @@ -3,7 +3,7 @@ # https://github.com/FuelLabs/chain-configuration/tree/master/upgradelog/ignition-testnet # and apply the latest state_transition_function and consensus_parameter # when upgrading fuel-core -FROM ghcr.io/fuellabs/fuel-core:v0.36.0 +FROM ghcr.io/fuellabs/fuel-core:v0.40.0 ARG FUEL_IP=0.0.0.0 ARG FUEL_PORT=4001 @@ -23,15 +23,15 @@ RUN git clone \ /chain-configuration # Anchor the chain configuration to a specific commit to avoid CI breaking -RUN cd /chain-configuration && git checkout c1c4d3bca57f64118a8d157310e0a839ae5c180a +RUN cd /chain-configuration && git checkout 8e4f7b52d7112f929a7cd95b988dfebfd10e87ec # Copy the base local configuration RUN cp -R /chain-configuration/local/* ./ # Copy the devnet consensus parameters and state transition bytecode -RUN cp /chain-configuration/upgradelog/ignition-devnet/consensus_parameters/9.json \ +RUN cp /chain-configuration/upgradelog/ignition-devnet/consensus_parameters/14.json \ ./latest_consensus_parameters.json -RUN cp /chain-configuration/upgradelog/ignition-devnet/state_transition_function/9.wasm \ +RUN cp /chain-configuration/upgradelog/ignition-devnet/state_transition_function/16.wasm \ ./state_transition_bytecode.wasm # update local state_config with custom genesis coins config diff --git a/docker/fuel-core/fuel_core.sh b/docker/fuel-core/fuel_core.sh index 21b694dc..fb5f5264 100644 --- a/docker/fuel-core/fuel_core.sh +++ b/docker/fuel-core/fuel_core.sh @@ -2,8 +2,10 @@ set -euo RETRIES=${RETRIES:-90} +DA_COMPRESSION=${DA_COMPRESSION:-"3600sec"} +GRAPHQL_COMPLEXITY=${GRAPHQL_COMPLEXITY:-500000} JSON='{"jsonrpc":"2.0","id":0,"method":"net_version","params":[]}' -FUEL_DB_PATH=./mnt/db/ +# FUEL_DB_PATH=./mnt/db/ if [ -z "$L1_CHAIN_HTTP" ]; then echo "Must specify \$L1_CHAIN_HTTP." @@ -53,7 +55,6 @@ echo "Starting fuel node." exec /root/fuel-core run \ --ip $FUEL_IP \ --port $FUEL_PORT \ - --db-type in-memory \ --utxo-validation \ --vm-backtrace \ --enable-relayer \ @@ -61,5 +62,7 @@ exec /root/fuel-core run \ --relayer-v2-listening-contracts $FUEL_MESSAGE_PORTAL_CONTRACT_ADDRESS \ --poa-interval-period 1sec \ --debug \ + --da-compression $DA_COMPRESSION \ + --graphql-max-complexity $GRAPHQL_COMPLEXITY \ --min-gas-price 0 \ --snapshot ./ diff --git a/packages/solidity-contracts/contracts/test/PlaceHolder.sol b/packages/solidity-contracts/contracts/test/PlaceHolder.sol new file mode 100644 index 00000000..ae3c2380 --- /dev/null +++ b/packages/solidity-contracts/contracts/test/PlaceHolder.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +/// @dev The only purpose of this contract is to be copied during the Dockerfile build +/// so that hardhat downloads the compiler and it gets cached +contract PlaceHolder {} \ No newline at end of file diff --git a/packages/solidity-contracts/deploy/hardhat/005.register_block_committer.ts b/packages/solidity-contracts/deploy/hardhat/005.register_block_committer.ts index 4231d61d..f0fa19ab 100644 --- a/packages/solidity-contracts/deploy/hardhat/005.register_block_committer.ts +++ b/packages/solidity-contracts/deploy/hardhat/005.register_block_committer.ts @@ -3,7 +3,7 @@ import type { DeployFunction } from 'hardhat-deploy/dist/types'; import { FuelChainState__factory } from '../../typechain'; -const COMMITTER_ADDRESS = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; +const COMMITTER_ADDRESS = '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc'; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { ethers, deployments } = hre; diff --git a/packages/solidity-contracts/docker/block-committer/Dockerfile b/packages/solidity-contracts/docker/block-committer/Dockerfile new file mode 100644 index 00000000..726da51f --- /dev/null +++ b/packages/solidity-contracts/docker/block-committer/Dockerfile @@ -0,0 +1,22 @@ +FROM ghcr.io/fuellabs/fuel-block-committer:sha-77607e4 + +ARG COMMITER_IP=0.0.0.0 +ARG COMMITER_PORT=8888 + +# dependencies +ENV DEBIAN_FRONTEND=noninteractive +RUN apt update && apt install -y curl jq && rm -rf /var/lib/apt/lists/* + +# copy chain config +WORKDIR /block-committer + +# expose fuel node port +ENV HOST="${COMMITER_IP}" +ENV PORT="${COMMITER_PORT}" + +EXPOSE ${PORT} + +# copy over script and run +COPY ./block-committer.sh . +CMD ["sh", "./block-committer.sh"] +# ENTRYPOINT ["sh", "./block-committer.sh"] diff --git a/packages/solidity-contracts/docker/block-committer/block-committer.sh b/packages/solidity-contracts/docker/block-committer/block-committer.sh new file mode 100644 index 00000000..9f733800 --- /dev/null +++ b/packages/solidity-contracts/docker/block-committer/block-committer.sh @@ -0,0 +1,40 @@ +#!/bin/sh +set -euo + +RETRIES=${RETRIES:-60} +DELAY=${DELAY:-10} +JSON='{"jsonrpc":"2.0","id":0,"method":"net_version","params":[]}' +HEALTH_URL=${HEALTH_URL:-"http://fuel_core:4001/v1/health"} + +if [ -z "$COMMITTER__ETH__RPC" ]; then + echo "Must specify \$ETHEREUM_RPC." + exit 1 +fi +if [ -z "$COMMITTER__FUEL__GRAPHQL_ENDPOINT" ]; then + echo "Must specify \$FUEL_GRAPHQL_ENDPOINT." + exit 1 +fi + +echo $COMMITTER__FUEL__GRAPHQL_ENDPOINT/health + +# wait for the base layer to be up +echo "Waiting for Fuel Core chain." +curl \ + --fail \ + --show-error \ + --silent \ + --retry-connrefused \ + --retry $RETRIES \ + --retry-delay $DELAY \ + $HEALTH_URL > /dev/null +echo "Connected to Fuel Core chain." + +# pull data from deployer dump +export COMMITTER__ETH__STATE_CONTRACT_ADDRESS=$(jq -r '.address' /l1chain/fuel-v2-contracts/deployments/localhost/FuelChainState.json) +echo "COMMITTER__ETH__STATE_CONTRACT_ADDRESS: $COMMITTER__ETH__STATE_CONTRACT_ADDRESS" +echo "ETHEREUM_RPC: $COMMITTER__ETH__RPC" +echo "FUEL_GRAPHQL_ENDPOINT: $COMMITTER__FUEL__GRAPHQL_ENDPOINT" + +# start the Block Commiter +echo "Starting block commiter" +exec /root/fuel-block-committer diff --git a/packages/solidity-contracts/docker/docker-compose.yml b/packages/solidity-contracts/docker/docker-compose.yml new file mode 100644 index 00000000..1899a89e --- /dev/null +++ b/packages/solidity-contracts/docker/docker-compose.yml @@ -0,0 +1,100 @@ +version: '3.4' + +services: + db: + image: postgres:14 + environment: + POSTGRES_USER: username + POSTGRES_PASSWORD: password + POSTGRES_DB: committer_db + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U username -d committer_db'] + interval: 5s + timeout: 5s + retries: 5 + + l1_chain: + image: fueldev/l1chain:${DOCKER_TAG_L1_CHAIN:-latest} + build: + dockerfile: ./docker/l1-chain/Dockerfile + # Use build context of the root directory + # to allow copying solidity-contracts on Dockerfile + context: ../ + volumes: + - ../deployments/localhost:/l1chain/fuel-v2-contracts/deployments + ports: + # expose the service to the host for integration testing + - ${L1_CHAIN_HTTP_PORT:-8545}:9545 + stop_grace_period: 1s + + fuel_core: + image: fueldev/fuelcore:${DOCKER_TAG_FUEL_CORE:-latest} + depends_on: + l1_chain: + condition: service_started + volumes: + - ../deployments/localhost:/l1chain/fuel-v2-contracts/deployments + platform: linux/amd64 + build: + context: ./fuel-core/ + env_file: + - ./envs/fuel_core.env + environment: + L1_CHAIN_HTTP: http://l1_chain:8545 + RUST_LOG: debug + DEBUG: true + DB_PATH: /db + ports: + # expose the service to the host for integration testing + - ${FUEL_CORE_HTTP_PORT:-4000}:4001 + stop_grace_period: 1s + restart: always + + fuel_block_commiter: + image: ghcr.io/fuellabs/fuel-block-committer:sha-77607e4 + platform: linux/amd64 + build: + context: ./block-committer/ + volumes: + - ../deployments/localhost:/l1chain/fuel-v2-contracts/deployments + environment: + COMMITTER__ETH__RPC: 'ws://l1_chain:8545/' + COMMITTER__ETH__L1_KEYS__MAIN: 'Private(8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba)' + COMMITTER__ETH__L1_KEYS__BLOB: 'Private(59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d)' + COMMITTER__FUEL__GRAPHQL_ENDPOINT: 'http://fuel_core:4001/graphql' + COMMITTER__FUEL__NUM_BUFFERED_REQUESTS: '5' + COMMITTER__APP__DB__PORT: '5432' + COMMITTER__APP__DB__HOST: 'db' + COMMITTER__APP__DB__USERNAME: 'username' + COMMITTER__APP__DB__PASSWORD: 'password' + COMMITTER__APP__DB__MAX_CONNECTIONS: '10' + COMMITTER__APP__DB__USE_SSL: 'false' + COMMITTER__APP__DB__DATABASE: 'committer_db' + COMMITTER__APP__PORT: '8080' + COMMITTER__APP__HOST: '0.0.0.0' + COMMITTER__APP__BLOCK_CHECK_INTERVAL: '5s' + COMMITTER__APP__TX_FINALIZATION_CHECK_INTERVAL: '5s' + COMMITTER__APP__NUM_BLOCKS_TO_FINALIZE_TX: '3' + COMMITTER__APP__GAS_BUMP_TIMEOUT: '300s' + COMMITTER__APP__TX_MAX_FEE: '4000000000000000' + COMMITTER__APP__SEND_TX_REQUEST_TIMEOUT: '10s' + COMMITTER__APP__BUNDLE__ACCUMULATION_TIMEOUT: '3600s' + COMMITTER__APP__BUNDLE__BLOCKS_TO_ACCUMULATE: '400' + COMMITTER__APP__BUNDLE__OPTIMIZATION_TIMEOUT: '60s' + COMMITTER__APP__BUNDLE__BLOCK_HEIGHT_LOOKBACK: '8500' + COMMITTER__APP__BUNDLE__COMPRESSION_LEVEL: 'level6' + COMMITTER__APP__BUNDLE__OPTIMIZATION_STEP: '100' + COMMITTER__APP__BUNDLE__FRAGMENTS_TO_ACCUMULATE: '3' + COMMITTER__APP__BUNDLE__FRAGMENT_ACCUMULATION_TIMEOUT: '10m' + COMMITTER__APP__BUNDLE__NEW_BUNDLE_CHECK_INTERVAL: '3s' + ports: + # expose the service to the host for integration testing + - ${COMMITTER_HTTP_PORT:-8888}:8888 + depends_on: + db: + condition: service_healthy + l1_chain: + condition: service_started + fuel_core: + condition: service_started + restart: always diff --git a/packages/solidity-contracts/docker/envs/fuel_core.env b/packages/solidity-contracts/docker/envs/fuel_core.env new file mode 100644 index 00000000..7b0bf02d --- /dev/null +++ b/packages/solidity-contracts/docker/envs/fuel_core.env @@ -0,0 +1 @@ +CONSENSUS_KEY_SECRET="0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298" \ No newline at end of file diff --git a/packages/solidity-contracts/docker/fuel-core/Dockerfile b/packages/solidity-contracts/docker/fuel-core/Dockerfile new file mode 100644 index 00000000..3d8b69db --- /dev/null +++ b/packages/solidity-contracts/docker/fuel-core/Dockerfile @@ -0,0 +1,55 @@ +# IMPORTANT! +# Make sure to check: +# https://github.com/FuelLabs/chain-configuration/tree/master/upgradelog/ignition-testnet +# and apply the latest state_transition_function and consensus_parameter +# when upgrading fuel-core +FROM ghcr.io/fuellabs/fuel-core:v0.40.0 + +ARG FUEL_IP=0.0.0.0 +ARG FUEL_PORT=4001 +ARG CONSENSUS_KEY_SECRET="" + +# dependencies +ENV DEBIAN_FRONTEND=noninteractive +RUN apt update && apt install -y git curl jq && rm -rf /var/lib/apt/lists/* + +# copy chain config +WORKDIR /fuel + +COPY ./genesis_coins.json . + +RUN git clone \ + https://github.com/FuelLabs/chain-configuration.git \ + /chain-configuration + +# Anchor the chain configuration to a specific commit to avoid CI breaking +RUN cd /chain-configuration && git checkout 8e4f7b52d7112f929a7cd95b988dfebfd10e87ec + +# Copy the base local configuration +RUN cp -R /chain-configuration/local/* ./ + +# Copy the devnet consensus parameters and state transition bytecode +RUN cp /chain-configuration/upgradelog/ignition-devnet/consensus_parameters/14.json \ + ./latest_consensus_parameters.json +RUN cp /chain-configuration/upgradelog/ignition-devnet/state_transition_function/16.wasm \ + ./state_transition_bytecode.wasm + +# update local state_config with custom genesis coins config +RUN jq '.coins = input' \ + state_config.json genesis_coins.json > tmp.json \ + && mv tmp.json state_config.json + +# update local state_config with testnet consensus parameters +RUN jq '.consensus_parameters = input' \ + state_config.json latest_consensus_parameters.json > tmp.json \ + && mv tmp.json state_config.json + +# expose fuel node port +ENV FUEL_IP="${FUEL_IP}" +ENV FUEL_PORT="${FUEL_PORT}" +ENV CONSENSUS_KEY_SECRET="${CONSENSUS_KEY_SECRET}" +EXPOSE ${FUEL_PORT} + +# copy over script and run +COPY ./fuel_core.sh . +CMD ["sh", "./fuel_core.sh"] \ No newline at end of file diff --git a/packages/solidity-contracts/docker/fuel-core/fuel_core.sh b/packages/solidity-contracts/docker/fuel-core/fuel_core.sh new file mode 100644 index 00000000..fb0eeaf1 --- /dev/null +++ b/packages/solidity-contracts/docker/fuel-core/fuel_core.sh @@ -0,0 +1,53 @@ +#!/bin/sh +set -euo + +#!/bin/sh +set -euo + +RETRIES=${RETRIES:-90} +DA_COMPRESSION=${DA_COMPRESSION:-"3600sec"} +GRAPHQL_COMPLEXITY=${GRAPHQL_COMPLEXITY:-500000} +JSON='{"jsonrpc":"2.0","id":0,"method":"net_version","params":[]}' +# FUEL_DB_PATH=./mnt/db/ + +if [ -z "$L1_CHAIN_HTTP" ]; then + echo "Must specify \$L1_CHAIN_HTTP." + exit 1 +fi + +# wait for the base layer to be up +echo "Waiting for l1 chain." +curl \ + --fail \ + --show-error \ + --silent \ + -H "Content-Type: application/json" \ + --retry-connrefused \ + --retry $RETRIES \ + --retry-delay 1 \ + -d $JSON \ + $L1_CHAIN_HTTP > /dev/null +echo "Connected to l1 chain." + +# pull data from deployer dump +export FUEL_MESSAGE_PORTAL_CONTRACT_ADDRESS=$(jq -r '.address' /l1chain/fuel-v2-contracts/deployments/localhost/FuelMessagePortal.json) +echo "FUEL_MESSAGE_PORTAL_CONTRACT_ADDRESS: $FUEL_MESSAGE_PORTAL_CONTRACT_ADDRESS" +echo "L1_CHAIN_HTTP: $L1_CHAIN_HTTP" + +# start the Fuel client +#--db-path ${FUEL_DB_PATH} +echo "Starting fuel node." +exec /root/fuel-core run \ + --ip $FUEL_IP \ + --port $FUEL_PORT \ + --utxo-validation \ + --vm-backtrace \ + --enable-relayer \ + --relayer $L1_CHAIN_HTTP \ + --relayer-v2-listening-contracts $FUEL_MESSAGE_PORTAL_CONTRACT_ADDRESS \ + --poa-interval-period 1sec \ + --debug \ + --da-compression $DA_COMPRESSION \ + --graphql-max-complexity $GRAPHQL_COMPLEXITY \ + --min-gas-price 0 \ + --snapshot ./ diff --git a/packages/solidity-contracts/docker/fuel-core/genesis_coins.json b/packages/solidity-contracts/docker/fuel-core/genesis_coins.json new file mode 100644 index 00000000..fd78763e --- /dev/null +++ b/packages/solidity-contracts/docker/fuel-core/genesis_coins.json @@ -0,0 +1,299 @@ +[ + { + "owner": "0xc8e615a4089466174459ef19cfd257d2e17adfabff3b8f219dbb5fb4eca87c50", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000001", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x92dffc873b56f219329ed03bb69bebe8c3d8b041088574882f7a6404f02e2f28", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000002", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x456bdaffaf74fe03521754ac445d148033c0c6acf7d593132c43f92fdbc7324c", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000003", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x639880ece7753a32e09164d14dad7436c57737e567f18b98f6ee30fec6b247ec", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000004", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0xfd8c520ef8caff0ad3289aa64acecd4ef86ac8f643fd9b76bf2d163a86a66716", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000005", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x8247104854dd733cb475901d55047f57cb3c8cafe3a9f7233de3325b8bf56a5c", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000006", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x53de37ae51fcfecb17ee3589f68904ac75bf5ec109edeb1065ccb63145287da6", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000007", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x17f4bef51f63f0c28af20d4223a3bf5cf1735a3b7ec52b4fcfbdbb5f30582a6b", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000008", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x95725e9083d8ed1cb52dcf6429d0cfce00cc375eeac5b620b5c36f5b1e734b31", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000009", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x08792a75d5714165aa117fd75450f9efcfb7124d034ef271f2919e4cc287046c", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x000000000000000000000000000000000000000000000000000000000000000a", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x6a16fba49dbdf7689c52b7a22951a54dc164076d27bdc6042b5d8377d68ca10b", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x000000000000000000000000000000000000000000000000000000000000000b", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x6494a55c0e3da212fdd0515507d00ae99151c7966e1448079c76bc447b577254", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x000000000000000000000000000000000000000000000000000000000000000c", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0xe0e1c94a9f9e02454772813ba6a6261b5228db1fabde3a68b23c0e9744ce22fc", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x000000000000000000000000000000000000000000000000000000000000000d", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x425f3e91aedff36e72ae60a8a1d328e625d66d39fcc98d5fcd1ba7df65a9f878", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x000000000000000000000000000000000000000000000000000000000000000e", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0xe2242f2e4971c34bc6fe5e1c0043b1aba717cb6a51f31f0dc0708cca73df905a", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x000000000000000000000000000000000000000000000000000000000000000f", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x6aa67cb316f329111dc708bb766360f5026a614edb11882e14d4cc04f26e0a08", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000010", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0xef5c2b712c4f3a10a37d6371cab2b03a6afd12e4ffcc9567d45d8c4b6e217e5c", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000011", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0xa82f66642de54993b32036eef7914f2dbaa217aa3209707b64d0b90187456a1f", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000012", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x9c9c1f3346b54fe6cb379fa27f338464592515fd865656089c4a23ac34390e6f", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000013", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "owner": "0x8a332bc33f4c10ad36392a9ca958a5ddf56081cc764f61613ea119e42ced6ac5", + "amount": 1000000000000, + "asset_id": "0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", + "tx_id": "0x0000000000000000000000000000000000000000000000000000000000000014", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0 + }, + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000015", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "6b63804cfbf9856e68e5b6e7aef238dc8311ec55bec04df774003a2c96e0418e", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000016", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "54944e5b8189827e470e5a8bacfc6c3667397dc4e1eef7ef3519d16d6d6c6610", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000017", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "e10f526b192593793b7a1559a391445faba82a1d669e3eb2dcd17f9c121b24b1", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000018", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "577e424ee53a16e6a85291feabc8443862495f74ac39a706d2dd0b9fc16955eb", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000019", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "c36be0e14d3eaf5d8d233e0f4a40b3b4e48427d25f84c460d2b03b242a38479e", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "000000000000000000000000000000000000000000000000000000000000002a", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "a1184d77d0d08a064e03b2bd9f50863e88faddea4693a05ca1ee9b1732ea99b7", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "000000000000000000000000000000000000000000000000000000000000002b", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "b5566df884bee4e458151c2fe4082c8af38095cc442c61e0dc83a371d70d88fd", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "000000000000000000000000000000000000000000000000000000000000002c", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "9da7247e1d63d30d69f136f0f8654ee8340362c785b50f0a60513c7edbf5bb7c", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "000000000000000000000000000000000000000000000000000000000000002d", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "4b2ca966aad1a9d66994731db5138933cf61679107c3cde2a10d9594e47c084e", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "000000000000000000000000000000000000000000000000000000000000002e", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "26183fbe7375045250865947695dfc12500dcc43efb9102b4e8c4d3c20009dcb", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "000000000000000000000000000000000000000000000000000000000000002f", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "81f3a10b61828580d06cc4c7b0ed8f59b9fb618be856c55d33decd95489a1e23", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000030", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "587aa0482482efea0234752d1ad9a9c438d1f34d2859b8bef2d56a432cb68e33", + "amount": 1152921504606846976, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + }, + { + "tx_id": "0000000000000000000000000000000000000000000000000000000000000031", + "output_index": 0, + "tx_pointer_block_height": 0, + "tx_pointer_tx_idx": 0, + "owner": "53a9c6a74bee79c5e04115a007984f4bddaafed75f512f68766c6ed59d0aedec", + "amount": 1125899906842624, + "asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07" + } +] diff --git a/packages/solidity-contracts/docker/l1-chain/Dockerfile b/packages/solidity-contracts/docker/l1-chain/Dockerfile new file mode 100644 index 00000000..9463feb3 --- /dev/null +++ b/packages/solidity-contracts/docker/l1-chain/Dockerfile @@ -0,0 +1,42 @@ +FROM node:20-alpine AS BUILD_IMAGE + +# dependencies +RUN apk --no-cache add git curl +RUN npm i -g pnpm + +WORKDIR /l1chain/fuel-v2-contracts + +ARG L1_IP=0.0.0.0 +ARG L1_PORT=8545 + +# clone the contracts repo +COPY package.json /l1chain/fuel-v2-contracts/ + +# copy over the fuel chain and replace consts values + +# build the ethereum contracts and environment +RUN pnpm install +COPY contracts/test/PlaceHolder.sol /l1chain/fuel-v2-contracts/contracts/test/PlaceHolder.sol +COPY .env /l1chain/fuel-v2-contracts/ +COPY hardhat.config.ts /l1chain/fuel-v2-contracts/ +COPY scripts/ /l1chain/fuel-v2-contracts/scripts/ +RUN pnpm compile + +# replace the fuel chain consts values and change contract code +COPY contracts/ /l1chain/fuel-v2-contracts/contracts/ +COPY deploy/ /l1chain/fuel-v2-contracts/deploy/ +COPY protocol/ /l1chain/fuel-v2-contracts/protocol/ + + +# remove build dependencies +# RUN pnpm prune --prod +RUN pnpm compile + +ENV L1_IP="${L1_IP}" +ENV L1_PORT="${L1_PORT}" +EXPOSE ${L1_PORT} +EXPOSE ${SERVE_PORT} + +# copy over script and run +COPY ./docker/l1-chain/l1_chain.sh /l1chain/l1_chain.sh +CMD ["sh", "/l1chain/l1_chain.sh"] diff --git a/packages/solidity-contracts/docker/l1-chain/l1_chain.sh b/packages/solidity-contracts/docker/l1-chain/l1_chain.sh new file mode 100644 index 00000000..fbb41f7e --- /dev/null +++ b/packages/solidity-contracts/docker/l1-chain/l1_chain.sh @@ -0,0 +1,25 @@ +#!/bin/sh +set -euo + +RETRIES=${RETRIES:-120} +JSON='{"jsonrpc":"2.0","id":0,"method":"net_version","params":[]}' + +L1_CHAIN_HTTP="http://127.0.0.1:$L1_PORT" + +pnpm run node +# wait for the base layer to be up +echo "Waiting for l1 chain." +curl \ + --fail \ + --show-error \ + --silent \ + -H "Content-Type: application/json" \ + --retry-connrefused \ + --retry $RETRIES \ + --retry-delay 1 \ + -d $JSON \ + $L1_CHAIN_HTTP > /dev/null + +echo "Connected to l1 chain." + + diff --git a/packages/solidity-contracts/hardhat.config.ts b/packages/solidity-contracts/hardhat.config.ts index 2815dc62..887110fb 100644 --- a/packages/solidity-contracts/hardhat.config.ts +++ b/packages/solidity-contracts/hardhat.config.ts @@ -41,6 +41,10 @@ const config: HardhatUserConfig = { accounts: { count: 128, }, + forking: { + enabled: !!process.env.TENDERLY_RPC_URL, + url: process.env.TENDERLY_RPC_URL ? process.env.TENDERLY_RPC_URL : '', + }, deploy: ['deploy/hardhat'], }, localhost: { diff --git a/packages/solidity-contracts/package.json b/packages/solidity-contracts/package.json index 70087cf7..2bdef0f6 100644 --- a/packages/solidity-contracts/package.json +++ b/packages/solidity-contracts/package.json @@ -20,10 +20,12 @@ "compile": "pnpm hardhat compile --show-stack-traces", "coverage": "pnpm run build && pnpm hardhat coverage --temp artifacts --network hardhat", "check": "pnpm solhint \"contracts/**/*.sol\"", - "node": "pnpm hardhat node --network hardhat", + "node": "pnpm hardhat node --network hardhat --hostname 0.0.0.0", "start-mining": "pnpm hardhat run --no-compile --network localhost scripts/startAutoMining.ts", "serve-deployments": "pnpm ts-node scripts/serveDeployments.ts", "test": "pnpm hardhat test", + "node:up": "sh ./scripts/node:up.sh", + "hardhat:test:integration": "DISABLE_GAS_REPORTER=true pnpm hardhat --network mainnetFork test fork-integration-tests/**/*.ts --bail", "test-no-compile": "pnpm hardhat test --no-compile", "test-parallel": "pnpx mocha 'test/**/*.ts' --recursive --parallel --require hardhat/register", "prettier": "prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'", @@ -52,6 +54,7 @@ "@types/node": "^18.11.9", "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", + "axios": "^1.7.7", "chai": "^4.3.7", "cors": "2.8.5", "dotenv": "^16.0.3", diff --git a/packages/solidity-contracts/scripts/hardhat/index.ts b/packages/solidity-contracts/scripts/hardhat/index.ts index 422b3bfd..b3fff332 100644 --- a/packages/solidity-contracts/scripts/hardhat/index.ts +++ b/packages/solidity-contracts/scripts/hardhat/index.ts @@ -12,4 +12,5 @@ export * from './withdrawalResume'; export * from './withdrawalBlacklist'; export * from './withdrawalWhitelist'; export * from './verifyMainnetDeployment'; +export * from './simulateUpgrades'; export * from './eventFilter'; diff --git a/packages/solidity-contracts/scripts/hardhat/simulateUpgrades.ts b/packages/solidity-contracts/scripts/hardhat/simulateUpgrades.ts new file mode 100644 index 00000000..9b62f531 --- /dev/null +++ b/packages/solidity-contracts/scripts/hardhat/simulateUpgrades.ts @@ -0,0 +1,140 @@ +import { task } from 'hardhat/config'; +import { HardhatRuntimeEnvironment } from 'hardhat/types'; +import { ContractFactory, ethers } from 'ethers'; + +const SECURITY_COUNCIL_MULTISIG = '0x32da601374b38154f05904B16F44A1911Aa6f314'; +const ETH_BALANCE_TO_SET = '0xDE0B6B3A7640000'; // 1 ether +const GAS_AMOUNT = '0x7a1200'; +const GAS_PRICE = '0xF4241'; + +task( + 'simulate-upgrades', + 'Mocks proxy upgrades with tenderly simulation' +).setAction( + async (taskArgs: any, hre: HardhatRuntimeEnvironment): Promise => { + const network = hre.network.name; + + if (network !== 'mainnet') { + return; + } + + const { + upgrades: { prepareUpgrade }, + ethers, + } = hre; + + console.log( + `Mocking proxy upgrades on ${network}:${hre.network.config.chainId}...` + ); + + const signer = await ethers.provider.getSigner(0); + + // fund the signer for deploying the new implementation + const setBalancePayload = { + jsonrpc: '2.0', + method: 'tenderly_setBalance', + params: [[(await signer.getAddress()).toString()], ETH_BALANCE_TO_SET], + }; + + const rpc: string = process.env.RPC_URL!; + + const deployments = await hre.deployments.all(); + + const apiUrl = `https://api.tenderly.co/api/v1/account/fuel-network/project/preprod/vnets/${process.env.VNET_ID}/transactions/simulate`; + const accessKey = process.env.ACCESS_KEY; + + try { + await fetch(rpc, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(setBalancePayload), + }); + + for (const [contractName, deployment] of Object.entries(deployments)) { + if (deployment.abi.length == 0) continue; + + // mocking the deployment for the new implementation too. + // we currently assume that this script will be ran, after the `upgradeVerification` script is executed so we have access to the updated `constructorArgs`, otherwise we can allow the contructor arguments to be entered manually. + const factory = (await ethers.getContractFactory( + deployment.linkedData.factory + )) as ContractFactory; // Typing bug in `getContractFactory` + + const deploymentResponse = (await prepareUpgrade( + deployment.address, + factory, + { + kind: 'uups', + constructorArgs: deployment.linkedData.constructorArgs, + getTxResponse: true, + redeployImplementation: 'always', + } + )) as ethers.TransactionResponse; + + const receipt = await hre.ethers.provider.getTransactionReceipt( + deploymentResponse.hash + ); + + const newImplementationAddress = receipt?.contractAddress!; + + const proxyContractInstance = new ethers.Contract( + deployment.address, + deployment.abi + ); + + // simulating upgrade enables to impersonate the security council multisig, without the need of signatures + const encodedUpgradeData = + proxyContractInstance.interface.encodeFunctionData('upgradeTo', [ + newImplementationAddress, + ]); + + const upgradeImplementationPayload = { + callArgs: { + from: SECURITY_COUNCIL_MULTISIG, + to: deployment.address, + gas: GAS_AMOUNT, + gasPrice: GAS_PRICE, + value: '0x0', + data: encodedUpgradeData, + }, + blockNumber: 'latest', + }; + + const response = await fetch(apiUrl, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + 'X-Access-Key': accessKey, + }, + body: JSON.stringify(upgradeImplementationPayload), + } as any); // typing bug with the request headers + + // simulations don't result in visible state changes so not checking the new implementation here, so instead we check + // the event logs that the `Upgraded` event was emitted + if (response.ok) { + const responsePayload: any = await response.json(); + + if (responsePayload.logs[0].name === 'Upgraded') { + console.log( + `✅ Upgrade simulation successful for ${contractName} (${deployment.address})` + ); + } else { + console.log( + `❌ Upgrade simulation failed for ${contractName} (${deployment.address})` + ); + throw new Error('Upgrade simulation failed'); + } + } else { + console.log( + `❌ Upgrade simulation failed for ${contractName} (${deployment.address})` + ); + throw new Error('Upgrade simulation failed'); + } + } + } catch (error) { + console.log(`❌ Upgrade simulation failed: ${error}`); + } + } +); diff --git a/packages/solidity-contracts/scripts/node:up.sh b/packages/solidity-contracts/scripts/node:up.sh new file mode 100644 index 00000000..71620aaf --- /dev/null +++ b/packages/solidity-contracts/scripts/node:up.sh @@ -0,0 +1 @@ +docker compose -f ./docker/docker-compose.yml up -d --build \ No newline at end of file diff --git a/packages/test-utils/src/scripts/relay-deposit.ts b/packages/test-utils/src/scripts/relay-deposit.ts index dd087dee..61de020a 100644 --- a/packages/test-utils/src/scripts/relay-deposit.ts +++ b/packages/test-utils/src/scripts/relay-deposit.ts @@ -64,9 +64,8 @@ const main = async () => { let endCursor: string | undefined; if (L2_MESSAGE_NONCE) nonce = new BN(L2_MESSAGE_NONCE); - + // eslint-disable-next-line no-constant-condition else - // eslint-disable-next-line no-constant-condition while (true) { const response = await provider.getMessages(predicateRoot, { after: endCursor, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2840c14c..9c5882e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -193,6 +193,9 @@ importers: '@typescript-eslint/parser': specifier: ^5.43.0 version: 5.62.0(eslint@8.57.0)(typescript@4.9.5) + axios: + specifier: ^1.7.7 + version: 1.7.7(debug@4.3.4) chai: specifier: ^4.3.7 version: 4.4.1 @@ -2557,8 +2560,8 @@ packages: resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} engines: {node: '>=4'} - axios@1.7.5: - resolution: {integrity: sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==} + axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} @@ -3298,11 +3301,13 @@ packages: eslint@5.16.0: resolution: {integrity: sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==} engines: {node: ^6.14.0 || ^8.10.0 || >=9.10.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@5.0.1: @@ -7625,7 +7630,7 @@ snapshots: '@openzeppelin/defender-admin-client@1.54.1(bufferutil@4.0.5)(debug@4.3.4)(utf-8-validate@5.0.7)': dependencies: '@openzeppelin/defender-base-client': 1.54.1(debug@4.3.4) - axios: 1.7.5(debug@4.3.4) + axios: 1.7.7(debug@4.3.4) ethers: 5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7) lodash: 4.17.21 node-fetch: 2.7.0 @@ -7639,7 +7644,7 @@ snapshots: dependencies: amazon-cognito-identity-js: 6.3.12 async-retry: 1.3.3 - axios: 1.7.5(debug@4.3.4) + axios: 1.7.7(debug@4.3.4) lodash: 4.17.21 node-fetch: 2.7.0 transitivePeerDependencies: @@ -7656,7 +7661,7 @@ snapshots: '@openzeppelin/defender-sdk-deploy-client@1.12.0(debug@4.3.4)': dependencies: '@openzeppelin/defender-sdk-base-client': 1.12.0 - axios: 1.7.5(debug@4.3.4) + axios: 1.7.7(debug@4.3.4) lodash: 4.17.21 transitivePeerDependencies: - debug @@ -7665,7 +7670,7 @@ snapshots: '@openzeppelin/defender-sdk-network-client@1.12.0(debug@4.3.4)': dependencies: '@openzeppelin/defender-sdk-base-client': 1.12.0 - axios: 1.7.5(debug@4.3.4) + axios: 1.7.7(debug@4.3.4) lodash: 4.17.21 transitivePeerDependencies: - debug @@ -8797,7 +8802,7 @@ snapshots: axe-core@4.7.0: {} - axios@1.7.5(debug@4.3.4): + axios@1.7.7(debug@4.3.4): dependencies: follow-redirects: 1.15.6(debug@4.3.4) form-data: 4.0.0 @@ -10464,7 +10469,7 @@ snapshots: '@ethersproject/transactions': 5.7.0 '@ethersproject/wallet': 5.7.0 '@types/qs': 6.9.15 - axios: 1.7.5(debug@4.3.4) + axios: 1.7.7(debug@4.3.4) chalk: 4.1.2 chokidar: 3.6.0 debug: 4.3.4(supports-color@8.1.1)