diff --git a/.github/actions/setup-k8s-terraform/action.yml b/.github/actions/setup-k8s-terraform/action.yml index 0e6e9833d779..02841bf7c741 100644 --- a/.github/actions/setup-k8s-terraform/action.yml +++ b/.github/actions/setup-k8s-terraform/action.yml @@ -66,14 +66,17 @@ runs: ref: ${{ inputs.ref }} - name: Authenticate to Google Cloud + if: ${{ inputs.cluster != 'kind' }} uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f with: credentials_json: ${{ inputs.gcp_sa_key }} - name: Set up Cloud SDK + if: ${{ inputs.cluster != 'kind' }} uses: google-github-actions/setup-gcloud@6189d56e4096ee891640bb02ac264be376592d6a - name: Install GKE Auth Plugin + if: ${{ inputs.cluster != 'kind' }} shell: bash run: | gcloud components install gke-gcloud-auth-plugin --quiet diff --git a/.github/local_workflow.sh b/.github/local_workflow.sh index 6bfa7e10f50c..ac32b623a4fe 100755 --- a/.github/local_workflow.sh +++ b/.github/local_workflow.sh @@ -30,11 +30,12 @@ fi shift args=("$@") +# Only needed when running against GKE SA_KEY_JSON=$(cat "$GOOGLE_APPLICATION_CREDENTIALS") mkdir -p $REPO_ROOT/.github/.act-tool-cache -act workflow_dispatch -j $workflow_name \ +act -j $workflow_name \ --env RUNNER_TOOL_CACHE=/work/toolcache \ -s GITHUB_TOKEN="$(gh auth token)" \ -s GCP_SA_KEY="$SA_KEY_JSON" \ diff --git a/.github/workflows/ci3.yml b/.github/workflows/ci3.yml index 0ac3fd334ab6..25996fd9b5f8 100644 --- a/.github/workflows/ci3.yml +++ b/.github/workflows/ci3.yml @@ -25,6 +25,8 @@ jobs: # (github.event.pull_request.head.repo.fork resolves to nil if not a pull request) if: github.event.pull_request.head.repo.fork != true && github.event.pull_request.draft == false environment: ${{ startsWith(github.ref, 'refs/tags/v') && 'master' || '' }} + env: + GOOGLE_APPLICATION_CREDENTIALS: /tmp/gcp-key.json steps: ############# # Prepare Env @@ -89,12 +91,9 @@ jobs: chmod 600 ~/.ssh/build_instance_key sudo apt install -y --no-install-recommends redis-tools parallel - - name: Prepare GCP key - env: - GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} + - name: Write GCP key into credentials file run: | - echo "$GCP_SA_KEY" | base64 -w 0 > gcp_sa_key.b64 - echo "GCP_SA_KEY_B64=$(cat gcp_sa_key.b64)" >> $GITHUB_ENV + echo "${{ secrets.GCP_SA_KEY }}" > ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} - name: Get Tree Hash run: echo "TREE_HASH=$(git rev-parse HEAD^{tree})" >> $GITHUB_ENV @@ -122,7 +121,7 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} # Nightly test env vars. - GCP_SA_KEY_B64: ${{ env.GCP_SA_KEY_B64 }} + GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} EXTERNAL_ETHEREUM_HOSTS: "https://json-rpc.${{ secrets.GCP_SEPOLIA_URL }}?key=${{ secrets.GCP_SEPOLIA_API_KEY }},${{ secrets.INFURA_SEPOLIA_URL }}" EXTERNAL_ETHEREUM_CONSENSUS_HOST: "https://beacon.${{ secrets.GCP_SEPOLIA_URL }}" EXTERNAL_ETHEREUM_CONSENSUS_HOST_API_KEY: ${{ secrets.GCP_SEPOLIA_API_KEY }} diff --git a/.github/workflows/deploy-aztec-infra.yml b/.github/workflows/deploy-aztec-infra.yml deleted file mode 100644 index 0d38919bf080..000000000000 --- a/.github/workflows/deploy-aztec-infra.yml +++ /dev/null @@ -1,277 +0,0 @@ -name: Deploy Aztec Infra - -on: - workflow_call: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - namespace: - description: The namespace to deploy to - required: true - type: string - ref: - description: The branch name to deploy from. - required: true - type: string - run_terraform_destroy: - description: Whether to run terraform destroy - required: true - type: boolean - default: false - aztec_docker_image: - description: The Aztec Docker image to deploy - required: true - type: string - l1_rpc_urls: - description: L1 RPC URLs as JSON array - required: true - type: string - l1_consensus_host_urls: - description: L1 consensus host URLs as JSON array - required: true - type: string - l1_consensus_host_api_keys: - description: L1 consensus host API keys as JSON array - required: true - type: string - l1_consensus_host_api_key_headers: - description: L1 consensus host API key headers as JSON array - required: true - type: string - l1_chain_id: - description: L1 chain ID - required: true - type: string - registry_address: - description: Registry contract address - required: true - type: string - slash_factory_address: - description: Slash factory contract address - required: true - type: string - fee_asset_handler_address: - description: Fee asset handler contract address - required: true - type: string - validator_mnemonic: - description: Validator mnemonic phrase - required: true - type: string - validator_mnemonic_start_index: - description: Validator mnemonic start index - required: true - type: number - validators_per_node: - description: Number of validators per node - required: true - type: number - validator_replicas: - description: Number of validator replicas - required: true - type: number - prover_mnemonic: - description: Prover mnemonic phrase - required: true - type: string - prover_mnemonic_start_index: - description: Prover mnemonic start index - required: true - type: number - p2p_bootstrap_resource_profile: - description: P2P bootstrap resource profile - required: true - type: string - validator_resource_profile: - description: Validator resource profile - required: true - type: string - prover_resource_profile: - description: Prover resource profile - required: true - type: string - rpc_resource_profile: - description: RPC resource profile - required: true - type: string - rpc_external_ingress: - description: Whether to use an external ingress for the rpc - required: true - type: boolean - otel_collector_url: - description: The OpenTelemetry collector that will receive metrics from this deployment. Optional - required: false - type: string - secrets: - GCP_SA_KEY: - description: The GCP service account key - required: true - KUBECONFIG_B64: - description: The base64 encoded kubeconfig - required: true - - workflow_dispatch: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - namespace: - description: The namespace to deploy to - required: true - type: string - ref: - description: The branch name to deploy from. - required: true - type: string - run_terraform_destroy: - description: Whether to run terraform destroy - required: true - type: boolean - default: false - aztec_docker_image: - description: The Aztec Docker image to deploy - required: true - type: string - l1_rpc_urls: - description: L1 RPC URLs as JSON array. Format, e.g. ["http://10.96.142.184:8545"] - required: true - type: string - l1_consensus_host_urls: - description: L1 consensus host URLs as JSON array. Format, e.g. ["http://10.96.36.205:5052"] - required: true - type: string - l1_consensus_host_api_keys: - description: L1 consensus host API keys as JSON array. Format, e.g. ["1234567890"] - required: true - type: string - l1_consensus_host_api_key_headers: - description: L1 consensus host API key headers as JSON array. Format, e.g. ["X-API-Key"] - required: true - type: string - l1_chain_id: - description: L1 chain ID - required: true - type: string - registry_address: - description: Registry contract address - required: true - type: string - slash_factory_address: - description: Slash factory contract address - required: true - type: string - fee_asset_handler_address: - description: Fee asset handler contract address - required: true - type: string - validator_mnemonic: - description: Validator mnemonic phrase - required: true - type: string - validator_mnemonic_start_index: - description: Validator mnemonic start index - required: true - type: number - validators_per_node: - description: Number of validators per node - required: true - type: number - validator_replicas: - description: Number of validator replicas - required: true - type: number - prover_mnemonic: - description: Prover mnemonic phrase - required: true - type: string - prover_mnemonic_start_index: - description: Prover mnemonic start index - required: true - type: number - p2p_bootstrap_resource_profile: - description: P2P bootstrap resource profile - required: true - type: string - validator_resource_profile: - description: Validator resource profile - required: true - type: string - prover_resource_profile: - description: Prover resource profile - required: true - type: string - rpc_resource_profile: - description: RPC resource profile - required: true - type: string - rpc_external_ingress: - description: Whether to use an external ingress for the rpc - required: true - type: boolean - otel_collector_url: - description: The OpenTelemetry collector that will receive metrics from this deployment. Optional - required: false - type: string - -jobs: - deploy_aztec_infra: - runs-on: ubuntu-latest - env: - TF_VAR_RELEASE_PREFIX: aztec-infra - TF_VAR_GCP_PROJECT: "testnet-440309" - TF_VAR_GCP_REGION: us-west1 - TF_VAR_K8S_CLUSTER_CONTEXT: ${{ inputs.cluster }} - TF_VAR_NAMESPACE: ${{ inputs.namespace }} - TF_VAR_AZTEC_DOCKER_IMAGE: ${{ inputs.aztec_docker_image }} - TF_VAR_L1_RPC_URLS: ${{ inputs.l1_rpc_urls }} - TF_VAR_L1_CONSENSUS_HOST_URLS: ${{ inputs.l1_consensus_host_urls }} - TF_VAR_L1_CONSENSUS_HOST_API_KEYS: ${{ inputs.l1_consensus_host_api_keys }} - TF_VAR_L1_CONSENSUS_HOST_API_KEY_HEADERS: ${{ inputs.l1_consensus_host_api_key_headers }} - TF_VAR_L1_CHAIN_ID: ${{ inputs.l1_chain_id }} - TF_VAR_REGISTRY_CONTRACT_ADDRESS: ${{ inputs.registry_address }} - TF_VAR_SLASH_FACTORY_CONTRACT_ADDRESS: ${{ inputs.slash_factory_address }} - TF_VAR_FEE_ASSET_HANDLER_CONTRACT_ADDRESS: ${{ inputs.fee_asset_handler_address }} - TF_VAR_VALIDATOR_MNEMONIC: ${{ inputs.validator_mnemonic }} - TF_VAR_VALIDATOR_MNEMONIC_START_INDEX: ${{ inputs.validator_mnemonic_start_index }} - TF_VAR_VALIDATORS_PER_NODE: ${{ inputs.validators_per_node }} - TF_VAR_VALIDATOR_REPLICAS: ${{ inputs.validator_replicas }} - TF_VAR_PROVER_MNEMONIC: ${{ inputs.prover_mnemonic }} - TF_VAR_PROVER_MNEMONIC_START_INDEX: ${{ inputs.prover_mnemonic_start_index }} - TF_VAR_P2P_BOOTSTRAP_RESOURCE_PROFILE: ${{ inputs.p2p_bootstrap_resource_profile }} - TF_VAR_VALIDATOR_RESOURCE_PROFILE: ${{ inputs.validator_resource_profile }} - TF_VAR_PROVER_RESOURCE_PROFILE: ${{ inputs.prover_resource_profile }} - TF_VAR_RPC_RESOURCE_PROFILE: ${{ inputs.rpc_resource_profile }} - TF_VAR_RPC_EXTERNAL_INGRESS: ${{ inputs.rpc_external_ingress }} - TF_VAR_OTEL_COLLECTOR_URL: ${{ inputs.otel_collector_url }} - - steps: - - name: Debug inputs - run: | - echo "cluster: ${{ inputs.cluster }}" - echo "namespace: ${{ inputs.namespace }}" - - - name: Setup K8s and Terraform - uses: ./.github/actions/setup-k8s-terraform - with: - cluster: ${{ inputs.cluster }} - namespace: ${{ inputs.namespace }} - ref: ${{ inputs.ref || github.ref }} - gcp_sa_key: ${{ secrets.GCP_SA_KEY }} - kubeconfig_b64: ${{ secrets.KUBECONFIG_B64 }} - terraform_dir: ./spartan/terraform/deploy-aztec-infra - tf_state_prefix: deploy-aztec-infra - run_terraform_destroy: ${{ inputs.run_terraform_destroy }} - - - name: Terraform Plan - working-directory: ./spartan/terraform/deploy-aztec-infra - run: | - # All variables are now set as TF_VAR_ environment variables - terraform plan -out=tfplan - - - name: Terraform Apply - working-directory: ./spartan/terraform/deploy-aztec-infra - run: | - terraform apply tfplan diff --git a/.github/workflows/deploy-eth-devnet.yml b/.github/workflows/deploy-eth-devnet.yml deleted file mode 100644 index 96fb5d3a8bf2..000000000000 --- a/.github/workflows/deploy-eth-devnet.yml +++ /dev/null @@ -1,239 +0,0 @@ -name: Deploy Eth Devnet - -# This workflow is used to deploy the eth devnet to a cluster. -# It can be used to deploy to kind or a GKE cluster. -# -# Set yourself up to run locally with: -# export GOOGLE_APPLICATION_CREDENTIALS=/your/path/to/testnet-helm-sa.json -# alias lwfl=/your/path/to/aztec-clones/alpha/.github/local_workflow.sh -# -# Then deploy to kind: -# lwfl deploy_eth_devnet --input cluster=kind --input resource_profile=dev --input namespace=mitch-eth-devnet --input create_static_ips=false -# -# Or to a GKE cluster: -# lwfl deploy_eth_devnet --input cluster=aztec-gke-private --input resource_profile=prod --input namespace=mitch-eth-devnet --input create_static_ips=false - -on: - workflow_call: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - namespace: - description: The namespace to deploy to - required: true - type: string - ref: - description: The branch name to deploy from - required: true - type: string - chain_id: - description: Ethereum chain ID for genesis generation - required: false - type: number - default: 1337 - block_time: - description: Block time in seconds for genesis generation - required: false - type: number - default: 12 - gas_limit: - description: Gas limit for blocks in genesis generation - required: false - type: string - default: "32000000" - resource_profile: - description: Resource profile to use (dev or prod) - required: true - type: string - create_static_ips: - description: Whether to create static IPs as part of the eth devnet for the execution and beacon nodes - required: true - type: string - run_terraform_destroy: - description: Whether to run the terraform destroy - required: false - type: string - default: "false" - mnemonic: - description: The mnemonic to use for the eth devnet - required: false - type: string - default: "test test test test test test test test test test test junk" - prefunded_mnemonic_indices: - description: The indices of the prefunded mnemonic to use for the devnet - required: false - type: string - default: "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1000,1001,1002,1003" - secrets: - GCP_SA_KEY: - description: The JSON key for the GCP service account - required: true - KUBECONFIG_B64: - description: The base64 encoded kubeconfig - required: true - outputs: - rpc_url: - description: The RPC URL for the eth devnet - value: ${{ jobs.deploy_eth_devnet.outputs.rpc_url }} - ws_url: - description: The WebSocket URL for the eth devnet - value: ${{ jobs.deploy_eth_devnet.outputs.ws_url }} - beacon_url: - description: The Beacon URL for the eth devnet - value: ${{ jobs.deploy_eth_devnet.outputs.beacon_url }} - chain_id: - description: The chain ID for the eth devnet - value: ${{ jobs.deploy_eth_devnet.outputs.chain_id }} - - workflow_dispatch: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - namespace: - description: The namespace to deploy to - required: true - type: string - ref: - description: The branch name to deploy from. - required: true - type: string - chain_id: - description: Ethereum chain ID for genesis generation - required: false - type: number - default: 1337 - block_time: - description: Block time in seconds for genesis generation - required: false - type: number - default: 12 - gas_limit: - description: Gas limit for blocks in genesis generation - required: false - type: string - default: "32000000" - resource_profile: - description: Resource profile to use (dev or prod) - required: true - type: string - create_static_ips: - description: Whether to create static IPs as part of the eth devnet for the execution and beacon nodes - required: true - type: string - run_terraform_destroy: - description: Whether to run the terraform destroy - required: false - type: string - default: "false" - mnemonic: - description: The mnemonic to use for the eth devnet - required: false - type: string - default: "test test test test test test test test test test test junk" - prefunded_mnemonic_indices: - description: The indices of the prefunded mnemonic to use for the devnet - required: false - type: string - default: "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1000,1001,1002,1003" - -jobs: - deploy_eth_devnet: - runs-on: ubuntu-latest - outputs: - rpc_url: ${{ steps.get-eth-devnet-results.outputs.rpc_url }} - ws_url: ${{ steps.get-eth-devnet-results.outputs.ws_url }} - beacon_url: ${{ steps.get-eth-devnet-results.outputs.beacon_url }} - chain_id: ${{ steps.get-eth-devnet-results.outputs.chain_id }} - env: - TF_STATE_BUCKET: aztec-terraform - REGION: us-west1-a - # Common Terraform variables as environment variables - TF_VAR_NAMESPACE: ${{ inputs.namespace }} - TF_VAR_CHAIN_ID: ${{ inputs.chain_id }} - TF_VAR_BLOCK_TIME: ${{ inputs.block_time }} - TF_VAR_GAS_LIMIT: ${{ inputs.gas_limit }} - TF_VAR_PREFUNDED_MNEMONIC_INDICES: ${{ inputs.prefunded_mnemonic_indices }} - TF_VAR_RESOURCE_PROFILE: ${{ inputs.resource_profile }} - - steps: - - name: Mask the mnemonic - id: mask-mnemonic - run: | - echo "::add-mask::${{ inputs.mnemonic }}" - - - name: Debug inputs - run: | - echo "cluster: ${{ inputs.cluster }}" - echo "namespace: ${{ inputs.namespace }}" - echo "ref: ${{ inputs.ref }}" - echo "chain_id: ${{ inputs.chain_id }}" - echo "block_time: ${{ inputs.block_time }}" - echo "gas_limit: ${{ inputs.gas_limit }}" - echo "resource_profile: ${{ inputs.resource_profile }}" - echo "create_static_ips: ${{ inputs.create_static_ips }}" - echo "run_terraform_destroy: ${{ inputs.run_terraform_destroy }}" - - - name: Setup K8s and Terraform - uses: ./.github/actions/setup-k8s-terraform - with: - cluster: ${{ inputs.cluster }} - namespace: ${{ inputs.namespace }} - ref: ${{ inputs.ref || github.ref }} - gcp_sa_key: ${{ secrets.GCP_SA_KEY }} - kubeconfig_b64: ${{ secrets.KUBECONFIG_B64 }} - terraform_dir: ./spartan/terraform/deploy-eth-devnet - tf_state_prefix: deploy-eth-devnet - run_terraform_destroy: ${{ inputs.run_terraform_destroy }} - - - name: Set up CREATE_STATIC_IPS variable - run: | - # Set CREATE_STATIC_IPS based on cluster type - if [ "${{ inputs.cluster }}" == "kind" ]; then - CREATE_STATIC_IPS=false - else - if [ "${{ inputs.create_static_ips }}" == "true" ]; then - CREATE_STATIC_IPS=true - else - CREATE_STATIC_IPS=false - fi - fi - echo "TF_VAR_CREATE_STATIC_IPS=${CREATE_STATIC_IPS}" >> $GITHUB_ENV - - - name: Terraform Plan - working-directory: ./spartan/terraform/deploy-eth-devnet - run: | - # All variables are now set as TF_VAR_ environment variables - terraform plan -out=tfplan - - - name: Terraform Apply - working-directory: ./spartan/terraform/deploy-eth-devnet - run: | - terraform apply tfplan - - - name: Get eth devnet deployment results - id: get-eth-devnet-results - working-directory: ./spartan/terraform/deploy-eth-devnet - - run: | - echo "=== Eth Devnet Deployment Results ===" - - # Get outputs from the eth-devnet deployment - RPC_URL=$(terraform output -raw eth_execution_rpc_url) - WS_URL=$(terraform output -raw eth_execution_ws_url) - BEACON_URL=$(terraform output -raw eth_beacon_api_url) - CHAIN_ID=$(terraform output -raw chain_id) - - echo "RPC_URL: $RPC_URL" - echo "WS_URL: $WS_URL" - echo "BEACON_URL: $BEACON_URL" - echo "CHAIN_ID: $CHAIN_ID" - - # Export as outputs for other steps - echo "rpc_url=$RPC_URL" >> $GITHUB_OUTPUT - echo "ws_url=$WS_URL" >> $GITHUB_OUTPUT - echo "beacon_url=$BEACON_URL" >> $GITHUB_OUTPUT - echo "chain_id=$CHAIN_ID" >> $GITHUB_OUTPUT diff --git a/.github/workflows/deploy-rollup-contracts.yml b/.github/workflows/deploy-rollup-contracts.yml deleted file mode 100644 index 5ae3246dba29..000000000000 --- a/.github/workflows/deploy-rollup-contracts.yml +++ /dev/null @@ -1,409 +0,0 @@ -name: Deploy Rollup Contracts - -# This workflow is used to deploy rollup contracts to a cluster. -# It can be used to deploy to kind or a GKE cluster. -# -# Note that you can provide your own docker image. This helps to deploy into GKE. -# But if you're running against KIND, you can just load your aztecprotocol/aztec image with -# kind load docker-image aztecprotocol/aztec:yourtag -# -# example: -# export GOOGLE_APPLICATION_CREDENTIALS=/your/path/to/testnet-helm-sa.json -# alias lwfl=/your/path/to/aztec-clones/alpha/.github/local_workflow.sh -# -# lwfl deploy_rollup_contracts --input cluster=aztec-gke-private --input namespace=mitch-eth-devnet --input aztec_docker_image="iamjustmitch/aztec:8ebe8d7c45190b002c77e29358f2b307a23b5336" --input l1_rpc_urls="http://34.83.173.208:8545" --input mnemonic="test test test test test test test test test test test junk" --input l1_chain_id="1337" --input salt="456" --input sponsored_fpc=true --input real_verifier=true --input aztec_target_commitee_size=48 - -on: - workflow_call: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - namespace: - description: The namespace to deploy to - required: true - type: string - ref: - description: The branch name to deploy from - required: true - type: string - aztec_docker_image: - description: Aztec Docker image with tag - required: true - type: string - l1_rpc_urls: - description: Comma-separated list of L1 RPC URLs - required: true - type: string - mnemonic: - description: Mnemonic for deployment - required: true - type: string - l1_chain_id: - description: L1 chain ID - required: true - type: string - salt: - description: Salt for deployment - required: true - type: string - validators: - description: Comma-separated list of validators - required: true - type: string - sponsored_fpc: - description: Enable sponsored FPC - required: true - type: boolean - real_verifier: - description: Deploy real verifier - required: true - type: boolean - # Aztec environment variables - aztec_slot_duration: - description: Aztec slot duration - required: true - type: string - aztec_epoch_duration: - description: Aztec epoch duration - required: true - type: string - aztec_target_committee_size: - description: Aztec target committee size - required: true - type: string - aztec_proof_submission_epochs: - description: Aztec proof submission epochs - required: true - type: string - aztec_activation_threshold: - description: Aztec activation threshold - required: true - type: string - aztec_ejection_threshold: - description: Aztec ejection threshold - required: true - type: string - aztec_slashing_quorum: - description: Aztec slashing quorum - required: true - type: string - aztec_slashing_round_size: - description: Aztec slashing round size - required: true - type: string - aztec_governance_proposer_quorum: - description: Aztec governance proposer quorum - required: true - type: string - aztec_governance_proposer_round_size: - description: Aztec governance proposer round size - required: true - type: string - aztec_mana_target: - description: Aztec mana target - required: true - type: string - aztec_proving_cost_per_mana: - description: Aztec proving cost per mana - required: true - type: string - secrets: - GCP_SA_KEY: - description: The JSON key for the GCP service account - required: true - KUBECONFIG_B64: - description: The base64 encoded kubeconfig - required: true - outputs: - registry_address: - description: The address of the registry contract - value: ${{ jobs.deploy_rollup_contracts.outputs.registry_address }} - slash_factory_address: - description: The address of the slash factory contract - value: ${{ jobs.deploy_rollup_contracts.outputs.slash_factory_address }} - fee_asset_handler_address: - description: The address of the fee asset handler contract - value: ${{ jobs.deploy_rollup_contracts.outputs.fee_asset_handler_address }} - governance_address: - description: The address of the governance contract - value: ${{ jobs.deploy_rollup_contracts.outputs.governance_address }} - governance_proposer_address: - description: The address of the governance proposer contract - value: ${{ jobs.deploy_rollup_contracts.outputs.governance_proposer_address }} - rollup_address: - description: The address of the rollup contract - value: ${{ jobs.deploy_rollup_contracts.outputs.rollup_address }} - inbox_address: - description: The address of the inbox contract - value: ${{ jobs.deploy_rollup_contracts.outputs.inbox_address }} - outbox_address: - description: The address of the outbox contract - value: ${{ jobs.deploy_rollup_contracts.outputs.outbox_address }} - fee_juice_portal_address: - description: The address of the fee juice portal contract - value: ${{ jobs.deploy_rollup_contracts.outputs.fee_juice_portal_address }} - zk_passport_verifier_address: - description: The address of the zk passport verifier contract - value: ${{ jobs.deploy_rollup_contracts.outputs.zk_passport_verifier_address }} - staking_asset_handler_address: - description: The address of the staking asset handler contract - value: ${{ jobs.deploy_rollup_contracts.outputs.staking_asset_handler_address }} - staking_asset_address: - description: The address of the staking asset contract - value: ${{ jobs.deploy_rollup_contracts.outputs.staking_asset_address }} - reward_distributor_address: - description: The address of the reward distributor contract - value: ${{ jobs.deploy_rollup_contracts.outputs.reward_distributor_address }} - gse_address: - description: The address of the gse contract - value: ${{ jobs.deploy_rollup_contracts.outputs.gse_address }} - coin_issuer_address: - description: The address of the coin issuer contract - value: ${{ jobs.deploy_rollup_contracts.outputs.coin_issuer_address }} - - workflow_dispatch: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - namespace: - description: The namespace to deploy to - required: true - type: string - ref: - description: The branch name to deploy from - required: true - type: string - aztec_docker_image: - description: Aztec Docker image with tag that will actually run deploy-l1-contracts - required: true - type: string - l1_rpc_urls: - description: Comma-separated list of L1 RPC URLs - required: true - type: string - mnemonic: - description: Mnemonic for deployment - required: true - type: string - l1_chain_id: - description: L1 chain ID - required: true - type: string - salt: - description: Salt for deployment - required: true - type: string - validators: - description: Comma-separated list of validators - required: true - type: string - default: "" - sponsored_fpc: - description: Enable sponsored FPC - required: true - type: boolean - real_verifier: - description: Deploy real verifier - required: true - type: boolean - # Aztec environment variables - aztec_slot_duration: - description: Aztec slot duration - required: true - type: string - aztec_epoch_duration: - description: Aztec epoch duration - required: true - type: string - aztec_target_committee_size: - description: Aztec target committee size - required: true - type: string - aztec_proof_submission_epochs: - description: Aztec proof submission epochs - required: true - type: string - aztec_activation_threshold: - description: Aztec activation threshold - required: true - type: string - aztec_ejection_threshold: - description: Aztec ejection threshold - required: true - type: string - aztec_slashing_quorum: - description: Aztec slashing quorum - required: true - type: string - aztec_slashing_round_size: - description: Aztec slashing round size - required: true - type: string - aztec_governance_proposer_quorum: - description: Aztec governance proposer quorum - required: true - type: string - aztec_governance_proposer_round_size: - description: Aztec governance proposer round size - required: true - type: string - aztec_mana_target: - description: Aztec mana target - required: true - type: string - aztec_proving_cost_per_mana: - description: Aztec proving cost per mana - required: true - type: string - -jobs: - deploy_rollup_contracts: - runs-on: ubuntu-latest - outputs: - registry_address: ${{ steps.get-rollup-contracts-results.outputs.registry_address }} - slash_factory_address: ${{ steps.get-rollup-contracts-results.outputs.slash_factory_address }} - fee_asset_handler_address: ${{ steps.get-rollup-contracts-results.outputs.fee_asset_handler_address }} - governance_address: ${{ steps.get-rollup-contracts-results.outputs.governance_address }} - governance_proposer_address: ${{ steps.get-rollup-contracts-results.outputs.governance_proposer_address }} - rollup_address: ${{ steps.get-rollup-contracts-results.outputs.rollup_address }} - inbox_address: ${{ steps.get-rollup-contracts-results.outputs.inbox_address }} - outbox_address: ${{ steps.get-rollup-contracts-results.outputs.outbox_address }} - fee_juice_portal_address: ${{ steps.get-rollup-contracts-results.outputs.fee_juice_portal_address }} - zk_passport_verifier_address: ${{ steps.get-rollup-contracts-results.outputs.zk_passport_verifier_address }} - staking_asset_handler_address: ${{ steps.get-rollup-contracts-results.outputs.staking_asset_handler_address }} - staking_asset_address: ${{ steps.get-rollup-contracts-results.outputs.staking_asset_address }} - reward_distributor_address: ${{ steps.get-rollup-contracts-results.outputs.reward_distributor_address }} - gse_address: ${{ steps.get-rollup-contracts-results.outputs.gse_address }} - coin_issuer_address: ${{ steps.get-rollup-contracts-results.outputs.coin_issuer_address }} - env: - TF_STATE_BUCKET: aztec-terraform - REGION: us-west1-a - # Common Terraform variables as environment variables - TF_VAR_NAMESPACE: ${{ inputs.namespace }} - TF_VAR_AZTEC_DOCKER_IMAGE: ${{ inputs.aztec_docker_image }} - TF_VAR_L1_RPC_URLS: ${{ inputs.l1_rpc_urls }} - TF_VAR_MNEMONIC: ${{ inputs.mnemonic }} - TF_VAR_L1_CHAIN_ID: ${{ inputs.l1_chain_id }} - TF_VAR_SALT: ${{ inputs.salt }} - TF_VAR_VALIDATORS: ${{ inputs.validators }} - TF_VAR_SPONSORED_FPC: ${{ inputs.sponsored_fpc }} - TF_VAR_REAL_VERIFIER: ${{ inputs.real_verifier }} - TF_VAR_AZTEC_SLOT_DURATION: ${{ inputs.aztec_slot_duration }} - TF_VAR_AZTEC_EPOCH_DURATION: ${{ inputs.aztec_epoch_duration }} - TF_VAR_AZTEC_TARGET_COMMITTEE_SIZE: ${{ inputs.aztec_target_committee_size }} - TF_VAR_AZTEC_PROOF_SUBMISSION_EPOCHS: ${{ inputs.aztec_proof_submission_epochs }} - TF_VAR_AZTEC_ACTIVATION_THRESHOLD: ${{ inputs.aztec_activation_threshold }} - TF_VAR_AZTEC_EJECTION_THRESHOLD: ${{ inputs.aztec_ejection_threshold }} - TF_VAR_AZTEC_SLASHING_QUORUM: ${{ inputs.aztec_slashing_quorum }} - TF_VAR_AZTEC_SLASHING_ROUND_SIZE: ${{ inputs.aztec_slashing_round_size }} - TF_VAR_AZTEC_GOVERNANCE_PROPOSER_QUORUM: ${{ inputs.aztec_governance_proposer_quorum }} - TF_VAR_AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE: ${{ inputs.aztec_governance_proposer_round_size }} - TF_VAR_AZTEC_MANA_TARGET: ${{ inputs.aztec_mana_target }} - TF_VAR_AZTEC_PROVING_COST_PER_MANA: ${{ inputs.aztec_proving_cost_per_mana }} - - steps: - - name: debug inputs - run: | - echo "cluster: ${{ inputs.cluster }}" - echo "namespace: ${{ inputs.namespace }}" - echo "ref: ${{ inputs.ref }}" - echo "aztec_docker_image: ${{ inputs.aztec_docker_image }}" - echo "l1_rpc_urls: ${{ inputs.l1_rpc_urls }}" - echo "l1_chain_id: ${{ inputs.l1_chain_id }}" - echo "validators: ${{ inputs.validators }}" - echo "sponsored_fpc: ${{ inputs.sponsored_fpc }}" - echo "real_verifier: ${{ inputs.real_verifier }}" - - - name: Setup K8s and Terraform - uses: ./.github/actions/setup-k8s-terraform - with: - cluster: ${{ inputs.cluster }} - namespace: ${{ inputs.namespace }} - ref: ${{ inputs.ref || github.ref }} - gcp_sa_key: ${{ secrets.GCP_SA_KEY }} - kubeconfig_b64: ${{ secrets.KUBECONFIG_B64 }} - terraform_dir: spartan/terraform/deploy-rollup-contracts - tf_state_prefix: deploy-rollup-contracts - additional_state_path: ${{ inputs.salt }} - - - name: Terraform Plan - working-directory: spartan/terraform/deploy-rollup-contracts - run: | - # All variables are now set as TF_VAR_ environment variables - terraform plan -out=tfplan - - - name: Terraform Apply - working-directory: spartan/terraform/deploy-rollup-contracts - run: | - terraform apply tfplan - - - name: Get deployment results - id: get-rollup-contracts-results - working-directory: spartan/terraform/deploy-rollup-contracts - run: | - echo "=== Deployment Results ===" - echo "Job Name: $(terraform output -raw job_name)" - - if [ "$(terraform output -raw deployment_successful)" = "true" ]; then - REGISTRY_ADDRESS=$(terraform output -raw registry_address) - SLASH_FACTORY_ADDRESS=$(terraform output -raw slash_factory_address) - FEE_ASSET_HANDLER_ADDRESS=$(terraform output -raw fee_asset_handler_address) - GOVERNANCE_ADDRESS=$(terraform output -raw governance_address) - GOVERNANCE_PROPOSER_ADDRESS=$(terraform output -raw governance_proposer_address) - ROLLUP_ADDRESS=$(terraform output -raw rollup_address) - INBOX_ADDRESS=$(terraform output -raw inbox_address) - OUTBOX_ADDRESS=$(terraform output -raw outbox_address) - FEE_JUICE_PORTAL_ADDRESS=$(terraform output -raw fee_juice_portal_address) - ZK_PASSPORT_VERIFIER_ADDRESS=$(terraform output -raw zk_passport_verifier_address) - STAKING_ASSET_HANDLER_ADDRESS=$(terraform output -raw staking_asset_handler_address) - STAKING_ASSET_ADDRESS=$(terraform output -raw staking_asset_address) - REWARD_DISTRIBUTOR_ADDRESS=$(terraform output -raw reward_distributor_address) - GSE_ADDRESS=$(terraform output -raw gse_address) - COIN_ISSUER_ADDRESS=$(terraform output -raw coin_issuer_address) - - echo "registry_address=$REGISTRY_ADDRESS" >> $GITHUB_OUTPUT - echo "slash_factory_address=$SLASH_FACTORY_ADDRESS" >> $GITHUB_OUTPUT - echo "fee_asset_handler_address=$FEE_ASSET_HANDLER_ADDRESS" >> $GITHUB_OUTPUT - echo "governance_address=$GOVERNANCE_ADDRESS" >> $GITHUB_OUTPUT - echo "governance_proposer_address=$GOVERNANCE_PROPOSER_ADDRESS" >> $GITHUB_OUTPUT - echo "rollup_address=$ROLLUP_ADDRESS" >> $GITHUB_OUTPUT - echo "inbox_address=$INBOX_ADDRESS" >> $GITHUB_OUTPUT - echo "outbox_address=$OUTBOX_ADDRESS" >> $GITHUB_OUTPUT - echo "fee_juice_portal_address=$FEE_JUICE_PORTAL_ADDRESS" >> $GITHUB_OUTPUT - echo "zk_passport_verifier_address=$ZK_PASSPORT_VERIFIER_ADDRESS" >> $GITHUB_OUTPUT - echo "staking_asset_handler_address=$STAKING_ASSET_HANDLER_ADDRESS" >> $GITHUB_OUTPUT - echo "staking_asset_address=$STAKING_ASSET_ADDRESS" >> $GITHUB_OUTPUT - echo "reward_distributor_address=$REWARD_DISTRIBUTOR_ADDRESS" >> $GITHUB_OUTPUT - echo "gse_address=$GSE_ADDRESS" >> $GITHUB_OUTPUT - echo "coin_issuer_address=$COIN_ISSUER_ADDRESS" >> $GITHUB_OUTPUT - - echo "✅ Rollup contracts deployed successfully!" - echo "" - - echo "Contract Addresses:" - echo " Registry Address: $REGISTRY_ADDRESS" - echo " Slash Factory Address: $SLASH_FACTORY_ADDRESS" - echo " Fee Asset Handler Address: $FEE_ASSET_HANDLER_ADDRESS" - echo " Governance Address: $GOVERNANCE_ADDRESS" - echo " Governance Proposer Address: $GOVERNANCE_PROPOSER_ADDRESS" - echo " Rollup Address: $ROLLUP_ADDRESS" - echo " Inbox Address: $INBOX_ADDRESS" - echo " Outbox Address: $OUTBOX_ADDRESS" - echo " Fee Juice Portal Address: $FEE_JUICE_PORTAL_ADDRESS" - echo " ZK Passport Verifier Address: $ZK_PASSPORT_VERIFIER_ADDRESS" - echo " Staking Asset Handler Address: $STAKING_ASSET_HANDLER_ADDRESS" - echo " Staking Asset Address: $STAKING_ASSET_ADDRESS" - echo " Reward Distributor Address: $REWARD_DISTRIBUTOR_ADDRESS" - echo " GSE Address: $GSE_ADDRESS" - echo " Coin Issuer Address: $COIN_ISSUER_ADDRESS" - echo "" - else - echo "⚠️ JSON output not found in logs, but job completed." - echo "Raw output:" - terraform output -json contract_addresses_json - exit 1 - fi diff --git a/.github/workflows/deploy-scenario-network.yml b/.github/workflows/deploy-scenario-network.yml deleted file mode 100644 index 2ef2e7e23611..000000000000 --- a/.github/workflows/deploy-scenario-network.yml +++ /dev/null @@ -1,177 +0,0 @@ -name: Deploy Scenario Network - -on: - workflow_call: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - namespace: - description: The namespace to deploy to - required: true - type: string - ref: - description: The branch name to deploy from - required: true - type: string - default: "next" - aztec_docker_image: - description: The Docker image to use for the Aztec contracts - required: true - type: string - default: "aztecprotocol/aztec:2.0.0-nightly.20250821" - devnet_mnemonic: - description: The mnemonic to use for the devnet - required: true - type: string - default: "test test test test test test test test test test test junk" - - rollup_deployment_mnemonic: - description: The mnemonic to use for the rollup deployment - required: true - type: string - default: "test test test test test test test test test test test junk" - secrets: - GCP_SA_KEY: - description: The JSON key for the GCP service account - required: true - KUBECONFIG_B64: - description: The base64 encoded kubeconfig - required: false - - workflow_dispatch: - inputs: - cluster: - description: The cluster to deploy to, e.g. aztec-gke-private or kind - required: true - type: string - default: "kind" - namespace: - description: The namespace to deploy to - required: true - type: string - default: "eth-devnet" - ref: - description: The branch name to deploy from. - required: true - type: string - default: "next" - aztec_docker_image: - description: The Docker image to use for the Aztec contracts - required: true - type: string - default: "aztecprotocol/aztec:2.0.0-nightly.20250821" - devnet_mnemonic: - description: The mnemonic to use for the devnet - required: true - type: string - default: "test test test test test test test test test test test junk" - - rollup_deployment_mnemonic: - description: The mnemonic to use for the rollup deployment - required: true - type: string - default: "test test test test test test test test test test test junk" - -jobs: - # First job: Deploy the Eth Devnet - scenario_dispatch_deploy_eth_devnet: - uses: ./.github/workflows/deploy-eth-devnet.yml - with: - cluster: ${{ inputs.cluster }} - namespace: ${{ inputs.namespace }} - ref: ${{ inputs.ref }} - # Prefilled values for scenario network - chain_id: 1337 - block_time: 12 - gas_limit: "32000000" - resource_profile: ${{ inputs.cluster == 'kind' && 'dev' || 'prod' }} - create_static_ips: false - run_terraform_destroy: false - mnemonic: ${{ inputs.devnet_mnemonic }} - prefunded_mnemonic_indices: "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1000,1001,1002,1003" - secrets: - GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} - KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} - - scenario_dispatch_deploy_rollup_contracts: - needs: scenario_dispatch_deploy_eth_devnet - uses: ./.github/workflows/deploy-rollup-contracts.yml - with: - cluster: ${{ inputs.cluster }} - namespace: ${{ inputs.namespace }} - ref: ${{ inputs.ref }} - l1_rpc_urls: ${{ needs.scenario_dispatch_deploy_eth_devnet.outputs.rpc_url }} - l1_chain_id: ${{ needs.scenario_dispatch_deploy_eth_devnet.outputs.chain_id }} - aztec_docker_image: ${{ inputs.aztec_docker_image }} - mnemonic: ${{ inputs.rollup_deployment_mnemonic }} - salt: "456" - # indices 1,2,3,4 on the junk mnemonic - validators: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8,0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC,0x90F79bf6EB2c4f870365E785982E1f101E93b906,0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" - sponsored_fpc: true - real_verifier: true - # Aztec environment variables - aztec_slot_duration: 36 - aztec_epoch_duration: 32 - aztec_target_committee_size: 4 - aztec_proof_submission_epochs: 1 - aztec_activation_threshold: 100 - aztec_ejection_threshold: 50 - aztec_slashing_quorum: 6 - aztec_slashing_round_size: 10 - aztec_governance_proposer_quorum: 6 - aztec_governance_proposer_round_size: 10 - aztec_mana_target: 1000000000 - aztec_proving_cost_per_mana: 100 - secrets: - GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} - KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} - - scenario_dispatch_deploy_aztec_infra: - needs: - - scenario_dispatch_deploy_rollup_contracts - - scenario_dispatch_deploy_eth_devnet - uses: ./.github/workflows/deploy-aztec-infra.yml - with: - cluster: ${{ inputs.cluster }} - namespace: ${{ inputs.namespace }} - ref: ${{ inputs.ref }} - aztec_docker_image: ${{ inputs.aztec_docker_image }} - l1_rpc_urls: '["${{ needs.scenario_dispatch_deploy_eth_devnet.outputs.rpc_url }}"]' - l1_consensus_host_urls: '["${{ needs.scenario_dispatch_deploy_eth_devnet.outputs.beacon_url }}"]' - l1_consensus_host_api_keys: '[""]' - l1_consensus_host_api_key_headers: '[""]' - l1_chain_id: ${{ needs.scenario_dispatch_deploy_eth_devnet.outputs.chain_id }} - registry_address: ${{ needs.scenario_dispatch_deploy_rollup_contracts.outputs.registry_address }} - slash_factory_address: ${{ needs.scenario_dispatch_deploy_rollup_contracts.outputs.slash_factory_address }} - fee_asset_handler_address: ${{ needs.scenario_dispatch_deploy_rollup_contracts.outputs.fee_asset_handler_address }} - validator_mnemonic: ${{ inputs.rollup_deployment_mnemonic }} - validator_mnemonic_start_index: 1 - validators_per_node: 1 - validator_replicas: 4 - prover_mnemonic: ${{ inputs.rollup_deployment_mnemonic }} - prover_mnemonic_start_index: 1000 - p2p_bootstrap_resource_profile: ${{ inputs.cluster == 'kind' && 'dev' || 'prod' }} - validator_resource_profile: ${{ inputs.cluster == 'kind' && 'dev' || 'prod' }} - prover_resource_profile: ${{ inputs.cluster == 'kind' && 'dev' || 'prod' }} - rpc_resource_profile: ${{ inputs.cluster == 'kind' && 'dev' || 'prod' }} - rpc_external_ingress: false - run_terraform_destroy: false - secrets: - GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} - KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} - - deploy_scenario_network: - needs: scenario_dispatch_deploy_aztec_infra - runs-on: ubuntu-latest - env: - TF_STATE_BUCKET: aztec-terraform - REGION: us-west1-a - # Common Terraform variables as environment variables - TF_VAR_NAMESPACE: ${{ inputs.namespace || 'eth-devnet' }} - - steps: - - name: Deploy scenario network - run: | - echo "Deployed scenario network!" diff --git a/.github/workflows/deploy-staging-networks.yml b/.github/workflows/deploy-staging-networks.yml new file mode 100644 index 000000000000..f0ece392b92f --- /dev/null +++ b/.github/workflows/deploy-staging-networks.yml @@ -0,0 +1,83 @@ +# CI for Aztec Network Scenarios. +# Triggered by network-deployments event, which is emitted by ci3.yml when a tagged release passes "normal" CI. +# Only runs on v2 releases. +name: Deploy Staging Networks + +on: + repository_dispatch: + types: + - network-deployments + +concurrency: + group: deploy-staging-networks-${{ github.event.client_payload.major_version }} + cancel-in-progress: true + +jobs: + deploy-staging-networks: + if: ${{ github.event.client_payload.major_version == '2' }} + runs-on: ubuntu-latest + env: + NETWORK_ENV_FILE: /tmp/network.env + GOOGLE_APPLICATION_CREDENTIALS: /tmp/gcp-key.json + steps: + ############# + # Prepare Env + ############# + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + ref: ${{ github.event.client_payload.sha }} + persist-credentials: false + - name: Setup + run: | + # Ensure we can SSH into the spot instances we request. + mkdir -p ~/.ssh + echo ${{ secrets.BUILD_INSTANCE_SSH_KEY }} | base64 --decode > ~/.ssh/build_instance_key + chmod 600 ~/.ssh/build_instance_key + sudo apt install -y --no-install-recommends redis-tools parallel + + - name: Write GCP key into credentials file + run: | + echo "${{ secrets.GCP_SA_KEY }}" > ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} + + # note: it is fine to log the mnemonic here. this is an internal, + # throwaway test network. + - name: Write staging-public network env file + run: | + SEMVER_SALT = $(echo ${{ github.event.client_payload.major_version }} | md5sum | cut -d' ' -f1) + cat > ${{ env.NETWORK_ENV_FILE }} <> $GITHUB_ENV - - - name: Compute Target Branch - id: target_branch - run: | - if [ "${{ github.event_name }}" == "merge_group" ]; then - target_branch=${{ github.event.merge_group.base_ref }} - elif [ "${{ github.event_name }}" == "pull_request" ]; then - target_branch=${{ github.event.pull_request.base.ref }} - else - target_branch=${{ github.ref_name }} - fi - target_branch=${target_branch#refs/heads/} - echo "target_branch=$target_branch" >> $GITHUB_OUTPUT - echo "TARGET_BRANCH=${target_branch}" >> $GITHUB_ENV - - name: Setup run: | # Ensure we can SSH into the spot instances we request. @@ -63,12 +35,29 @@ jobs: chmod 600 ~/.ssh/build_instance_key sudo apt install -y --no-install-recommends redis-tools parallel - - name: Prepare GCP key - env: - GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }} + - name: Write GCP key into credentials file + run: | + echo "${{ secrets.GCP_SA_KEY }}" > ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} + + # note: it is fine to log the mnemonic here. this is an internal, + # throwaway test network, which you can see gets destroyed before it is created each time. + - name: Write network env file run: | - echo "$GCP_SA_KEY" | base64 -w 0 > gcp_sa_key.b64 - echo "GCP_SA_KEY_B64=$(cat gcp_sa_key.b64)" >> $GITHUB_ENV + SEMVER_SALT = $(echo ${{ github.event.client_payload.major_version }} | md5sum | cut -d' ' -f1) + cat > ${{ env.NETWORK_ENV_FILE }} <> $GITHUB_ENV @@ -91,12 +80,13 @@ jobs: GITHUB_TOKEN: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} RUN_ID: ${{ github.run_id }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} - # Nightly test env vars. - GCP_SA_KEY_B64: ${{ env.GCP_SA_KEY_B64 }} - GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} - NAMESPACE: "v${{ github.event.client_payload.major_version }}-scenario" + NETWORK_ENV_FILE: ${{ env.NETWORK_ENV_FILE }} + GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }} run: | - exec ./ci.sh network-scenario + # the network env file and gcp credentials file are mounted into the ec2 instance + # see ci3/bootstrap_ec2 + exec ./ci.sh network-deploy + exec ./ci.sh network-tests - name: Save CI Success if: steps.ci_cache.outputs.cache-hit != 'true' diff --git a/bootstrap.sh b/bootstrap.sh index d2e6113c2384..c5dd61901514 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -444,12 +444,14 @@ case "$cmd" in test release ;; - "ci-network-scenario") + "ci-network-deploy") + export CI=1 + spartan/bootstrap.sh network_deploy $NETWORK_ENV_FILE + ;; + "ci-network-tests") export CI=1 - export USE_TEST_CACHE=1 - export CI_SCENARIO_TEST=1 build - spartan/bootstrap.sh test + spartan/bootstrap.sh network_tests $NETWORK_ENV_FILE ;; "ci-release") export CI=1 diff --git a/ci.sh b/ci.sh index 56956f2d9b43..2a641eae521c 100755 --- a/ci.sh +++ b/ci.sh @@ -23,6 +23,8 @@ function print_usage { echo_cmd "docs" "Spin up an EC2 instance and run docs-only CI." echo_cmd "barretenberg" "Spin up an EC2 instance and run barretenberg-only CI." echo_cmd "merge-queue" "Spin up several EC2 instances to run the merge-queue jobs." + echo_cmd "network-deploy" "Spin up an EC2 instance to deploy a network." + echo_cmd "network-tests" "Spin up an EC2 instance to run tests on a network." echo_cmd "nightly" "Spin up an EC2 instance and run bootstrap nightly." echo_cmd "release" "Spin up an EC2 instance and run bootstrap release." echo_cmd "shell-new" "Spin up an EC2 instance, clone the repo, and drop into a shell." @@ -141,16 +143,13 @@ case "$cmd" in 'run x4-full amd64 ci-full' \ 'run a1-fast arm64 ci-fast' | DUP=1 cache_log "Merge queue CI run" $RUN_ID ;; - "network-scenario") - prep_vars - # Spin up ec2 instance and run the network scenario flow. - run() { - JOB_ID=$1 INSTANCE_POSTFIX=$1 ARCH=$2 exec denoise "bootstrap_ec2 './bootstrap.sh ci-network-scenario'" - } - export -f run - # We need to run the network scenario flow on both x86 and arm64. - parallel --termseq 'TERM,10000' --tagstring '{= $_=~s/run (\w+).*/$1/; =}' --line-buffered --halt now,fail=1 ::: \ - 'run x-network-scenario amd64' | DUP=1 cache_log "Network scenario CI run" $RUN_ID + "network-deploy") + export JOB_ID="x-${NAMESPACE}-network-deploy" + bootstrap_ec2 "./bootstrap.sh ci-network-deploy" + ;; + "network-tests") + export JOB_ID="x-${NAMESPACE}-network-tests" + bootstrap_ec2 "./bootstrap.sh ci-network-tests" ;; "nightly") prep_vars diff --git a/ci3/bootstrap_ec2 b/ci3/bootstrap_ec2 index 9adde433367b..7ec6d799b777 100755 --- a/ci3/bootstrap_ec2 +++ b/ci3/bootstrap_ec2 @@ -194,6 +194,9 @@ EOF # We provide the host user and group ids to the entrypoint script to ensure alignment. # We raise the default pid limit to 32k. function run { + export GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS:-/tmp/gcp-key.json} + export NETWORK_ENV_FILE=${NETWORK_ENV_FILE:-/tmp/network.env} + ssh ${ssh_args:-} -F $ci3/aws/build_instance_ssh_config ubuntu@$ip " # TODO: This should *not* be needed in a CI run. Remove watching code, e.g. in boxes. sudo sysctl fs.inotify.max_user_watches=1048576 &>/dev/null @@ -207,12 +210,6 @@ function run { aws_token=\$(curl -sX PUT http://169.254.169.254/latest/api/token -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600') - # Save GCP_SA_KEY to a file if set (using base64 for safety) - if [ -n '${GCP_SA_KEY_B64:-}' ]; then - echo '${GCP_SA_KEY_B64:-}' | base64 -d > /tmp/gcp-key.json - echo 'GCP_SA_KEY decoded and saved to /tmp/gcp-key.json' - fi - start_build() { echo Starting devbox... docker run --privileged --rm \${docker_args:-} \ @@ -222,8 +219,12 @@ function run { -v bootstrap_ci_repo:/home/aztec-dev/aztec-packages \ -v \$HOME/.aws:/home/aztec-dev/.aws:ro \ -v /mnt/bb-crs:/home/aztec-dev/.bb-crs \ - -v /tmp:/tmp \ -v /dev/kmsg:/dev/kmsg \ + -v /tmp:/tmp \ + -v ${GOOGLE_APPLICATION_CREDENTIALS}:${GOOGLE_APPLICATION_CREDENTIALS}:ro \ + -v ${NETWORK_ENV_FILE}:${NETWORK_ENV_FILE}:ro \ + -e GOOGLE_APPLICATION_CREDENTIALS="${GOOGLE_APPLICATION_CREDENTIALS}" \ + -e NETWORK_ENV_FILE="${NETWORK_ENV_FILE}" \ -e CI=1 \ -e RUN_ID=${RUN_ID:-} \ -e JOB_ID=${JOB_ID:-} \ @@ -253,7 +254,6 @@ function run { -e SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN:-} \ -e AWS_TOKEN=\$aws_token \ -e NAMESPACE=${NAMESPACE:-} \ - -v /tmp/gcp-key.json:/tmp/gcp-key.json:ro \ --pids-limit=32768 \ aztecprotocol/devbox:3.0 bash -c $(printf '%q' "$container_script") } diff --git a/spartan/.gitignore b/spartan/.gitignore index 6eaeea275203..7fb792b30b68 100644 --- a/spartan/.gitignore +++ b/spartan/.gitignore @@ -3,3 +3,8 @@ scripts/logs scripts/LICENSE tfplan *_override.tf +mnemonic.tmp +environments/* +!environments/scenario.local.env +!environments/staging.local.env +*.tfvars diff --git a/spartan/aztec-chaos-scenarios/templates/boot-node-failure.yaml b/spartan/aztec-chaos-scenarios/templates/boot-node-failure.yaml index b31fbf99dbc1..423194253c0c 100644 --- a/spartan/aztec-chaos-scenarios/templates/boot-node-failure.yaml +++ b/spartan/aztec-chaos-scenarios/templates/boot-node-failure.yaml @@ -16,6 +16,6 @@ spec: namespaces: - {{ .Values.global.targetNamespace }} labelSelectors: - app: boot-node + app.kubernetes.io/component: boot-node duration: {{ .Values.bootNodeFailure.duration }} {{- end }} diff --git a/spartan/aztec-chaos-scenarios/templates/prover-broker-kill.yaml b/spartan/aztec-chaos-scenarios/templates/prover-broker-kill.yaml index 5f46d51ae6cd..a169eb5fbedf 100644 --- a/spartan/aztec-chaos-scenarios/templates/prover-broker-kill.yaml +++ b/spartan/aztec-chaos-scenarios/templates/prover-broker-kill.yaml @@ -17,5 +17,5 @@ spec: namespaces: - {{ .Values.global.targetNamespace }} labelSelectors: - app: prover-broker + app.kubernetes.io/component: prover-broker {{- end }} diff --git a/spartan/aztec-chaos-scenarios/templates/prover-failure.yaml b/spartan/aztec-chaos-scenarios/templates/prover-failure.yaml index ad02d2383501..fad3c9b34dce 100644 --- a/spartan/aztec-chaos-scenarios/templates/prover-failure.yaml +++ b/spartan/aztec-chaos-scenarios/templates/prover-failure.yaml @@ -16,6 +16,6 @@ spec: namespaces: - {{ .Values.global.targetNamespace }} labelSelectors: - app: prover-node + app.kubernetes.io/component: prover-node duration: {{ .Values.proverFailure.duration }} {{- end }} diff --git a/spartan/aztec-chaos-scenarios/templates/prover-kill.yaml b/spartan/aztec-chaos-scenarios/templates/prover-kill.yaml index 322b52d9884b..0d431cb9b42a 100644 --- a/spartan/aztec-chaos-scenarios/templates/prover-kill.yaml +++ b/spartan/aztec-chaos-scenarios/templates/prover-kill.yaml @@ -17,5 +17,5 @@ spec: namespaces: - {{ .Values.global.targetNamespace }} labelSelectors: - app: prover-node + app.kubernetes.io/component: prover-node {{- end }} diff --git a/spartan/aztec-chaos-scenarios/templates/validator-kill.yaml b/spartan/aztec-chaos-scenarios/templates/validator-kill.yaml index 11177c404f79..577b55132bf7 100644 --- a/spartan/aztec-chaos-scenarios/templates/validator-kill.yaml +++ b/spartan/aztec-chaos-scenarios/templates/validator-kill.yaml @@ -17,5 +17,5 @@ spec: namespaces: - {{ .Values.global.targetNamespace }} labelSelectors: - app: validator + app.kubernetes.io/component: validator {{- end }} diff --git a/spartan/aztec-node/templates/_helpers.tpl b/spartan/aztec-node/templates/_helpers.tpl index 524e8c5d8fca..25ad07f825ae 100644 --- a/spartan/aztec-node/templates/_helpers.tpl +++ b/spartan/aztec-node/templates/_helpers.tpl @@ -48,6 +48,7 @@ Selector labels {{- define "chart.selectorLabels" -}} app.kubernetes.io/name: {{ include "chart.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/component: {{ .Values.nodeType }} {{- end }} diff --git a/spartan/aztec-node/templates/_pod-template.yaml b/spartan/aztec-node/templates/_pod-template.yaml index e49ba7268167..b6279d482b15 100644 --- a/spartan/aztec-node/templates/_pod-template.yaml +++ b/spartan/aztec-node/templates/_pod-template.yaml @@ -179,6 +179,70 @@ spec: value: "{{ .Values.service.p2p.enabled }}" - name: P2P_PORT value: "{{ .Values.service.p2p.port }}" + - name: PROVER_REAL_PROOFS + value: "{{ .Values.node.proverRealProofs }}" + - name: SENTINEL_ENABLED + value: "{{ .Values.node.sentinel.enabled }}" + {{- if .Values.node.slash.minPenaltyPercentage }} + - name: SLASH_MIN_PENALTY_PERCENTAGE + value: {{ .Values.node.slash.minPenaltyPercentage | quote }} + {{- end }} + {{- if .Values.node.slash.maxPenaltyPercentage }} + - name: SLASH_MAX_PENALTY_PERCENTAGE + value: {{ .Values.node.slash.maxPenaltyPercentage | quote }} + {{- end }} + {{- if .Values.node.slash.validatorsAlways }} + - name: SLASH_VALIDATORS_ALWAYS + value: {{ join "," .Values.node.slash.validatorsAlways | quote }} + {{- end }} + {{- if .Values.node.slash.validatorsNever }} + - name: SLASH_VALIDATORS_NEVER + value: {{ join "," .Values.node.slash.validatorsNever | quote }} + {{- end }} + {{- if .Values.node.slash.prunePenalty }} + - name: SLASH_PRUNE_PENALTY + value: {{ .Values.node.slash.prunePenalty | quote }} + {{- end }} + {{- if .Values.node.slash.dataWithholdingPenalty }} + - name: SLASH_DATA_WITHHOLDING_PENALTY + value: {{ .Values.node.slash.dataWithholdingPenalty | quote }} + {{- end }} + {{- if .Values.node.slash.inactivityPenalty }} + - name: SLASH_INACTIVITY_PENALTY + value: {{ .Values.node.slash.inactivityPenalty | quote }} + {{- end }} + {{- if .Values.node.slash.inactivityTargetPercentage }} + - name: SLASH_INACTIVITY_TARGET_PERCENTAGE + value: {{ .Values.node.slash.inactivityTargetPercentage | quote }} + {{- end }} + {{- if .Values.node.slash.invalidBlockPenalty }} + - name: SLASH_INVALID_BLOCK_PENALTY + value: {{ .Values.node.slash.invalidBlockPenalty | quote }} + {{- end }} + {{- if .Values.node.slash.proposeInvalidAttestationsPenalty }} + - name: SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY + value: {{ .Values.node.slash.proposeInvalidAttestationsPenalty | quote }} + {{- end }} + {{- if .Values.node.slash.attestDescendantOfInvalidPenalty }} + - name: SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY + value: {{ .Values.node.slash.attestDescendantOfInvalidPenalty | quote }} + {{- end }} + {{- if .Values.node.slash.unknownPenalty }} + - name: SLASH_UNKNOWN_PENALTY + value: {{ .Values.node.slash.unknownPenalty | quote }} + {{- end }} + {{- if .Values.node.slash.gracePeriodL2Slots }} + - name: SLASH_GRACE_PERIOD_L2_SLOTS + value: {{ .Values.node.slash.gracePeriodL2Slots | quote }} + {{- end }} + {{- if .Values.node.slash.offenseExpirationRounds }} + - name: SLASH_OFFENSE_EXPIRATION_ROUNDS + value: {{ .Values.node.slash.offenseExpirationRounds | quote }} + {{- end }} + {{- if .Values.node.slash.maxPayloadSize }} + - name: SLASH_MAX_PAYLOAD_SIZE + value: {{ .Values.node.slash.maxPayloadSize | quote }} + {{- end }} {{- if gt (len .Values.global.l1ExecutionUrls) 0 }} - name: ETHEREUM_HOSTS value: {{ join "," .Values.global.l1ExecutionUrls | quote }} diff --git a/spartan/aztec-node/values.yaml b/spartan/aztec-node/values.yaml index dfae8aca1cc7..dd9e1e4548f4 100644 --- a/spartan/aztec-node/values.yaml +++ b/spartan/aztec-node/values.yaml @@ -3,6 +3,9 @@ nameOverride: "" # -- Overrides the chart computed fullname fullnameOverride: "" +# -- Node type - node, validator, prover, bot, etc label on the pod +nodeType: "node" + # -- Pod management policy podManagementPolicy: Parallel @@ -114,6 +117,31 @@ node: failureThreshold: 3 resources: {} + proverRealProofs: true + + sentinel: + enabled: true + slash: + # Penalty percentages for slashing offenses + minPenaltyPercentage: "" + maxPenaltyPercentage: "" + # Validator allowlists/denylists + validatorsAlways: [] + validatorsNever: [] + # Penalty amounts for different offense types + prunePenalty: "" + dataWithholdingPenalty: "" + inactivityPenalty: "" + inactivityTargetPercentage: "" + invalidBlockPenalty: "" + proposeInvalidAttestationsPenalty: "" + attestDescendantOfInvalidPenalty: "" + unknownPenalty: "" + # Slasher behavior configuration + gracePeriodL2Slots: "" + offenseExpirationRounds: "" + maxPayloadSize: "" + persistence: # -- Uses an emptyDir when not enabled enabled: false @@ -170,25 +198,25 @@ rbac: # -- Required ClusterRole rules # @default -- See `values.yaml` clusterRules: - # Required to obtain the nodes external IP + # Required to obtain the nodes external IP - apiGroups: [""] resources: - - "nodes" + - "nodes" verbs: - - "get" - - "list" - - "watch" + - "get" + - "list" + - "watch" # -- Required ClusterRole rules # @default -- See `values.yaml` rules: # Required to get information about the services nodePort. - apiGroups: [""] resources: - - "services" + - "services" verbs: - - "get" - - "list" - - "watch" + - "get" + - "list" + - "watch" serviceAccount: # -- Create a service account diff --git a/spartan/aztec-prover-stack/values.yaml b/spartan/aztec-prover-stack/values.yaml index c57c9fcf44f6..15d12a60e71f 100644 --- a/spartan/aztec-prover-stack/values.yaml +++ b/spartan/aztec-prover-stack/values.yaml @@ -10,6 +10,7 @@ global: l1ConsensusHostApiKeyHeaders: [] node: + nodeType: "prover-node" mnemonic: "test test test test test test test test test test test junk" mnemonicStartIndex: 1000 privateKey: @@ -51,6 +52,7 @@ node: enabled: false broker: + nodeType: "prover-broker" replicaCount: 1 persistence: enabled: false @@ -75,6 +77,7 @@ broker: create: false agent: + nodeType: "prover-agent" replicaCount: 1 persistence: diff --git a/spartan/aztec-validator/values.yaml b/spartan/aztec-validator/values.yaml index 7c4773926439..95b3278e6246 100644 --- a/spartan/aztec-validator/values.yaml +++ b/spartan/aztec-validator/values.yaml @@ -10,6 +10,7 @@ global: l1ConsensusHostApiKeyHeaders: [] validator: + nodeType: "validator" mnemonic: "test test test test test test test test test test test junk" mnemonicStartIndex: 2000 validatorsPerNode: 1 @@ -48,4 +49,3 @@ validator: enabled: true headless: enabled: true - diff --git a/spartan/bootstrap.sh b/spartan/bootstrap.sh index dbc106f49cc4..fd6a929a5a60 100755 --- a/spartan/bootstrap.sh +++ b/spartan/bootstrap.sh @@ -12,6 +12,22 @@ function build { denoise ./spartan/scripts/check_env_vars.sh } +function source_network_env { + local env_file="environments/$1" + # Optionally source an env file passed as first argument + if [[ -n "${env_file:-}" ]]; then + if [[ -f "$env_file" ]]; then + set -a + # shellcheck disable=SC1090 + source "$env_file" + set +a + else + echo "Env file not found: $env_file" >&2 + exit 1 + fi + fi +} + function network_shaping { namespace="$1" chaos_values="$2" @@ -54,44 +70,20 @@ function gke { } function test_cmds { - if [ "$(arch)" == "arm64" ]; then - # Currently maddiaa/eth2-testnet-genesis is not published for arm64. Skip KIND tests. - return - fi - # Note: commands that start with 'timeout ...' override the default timeout. - # TODO figure out why these take long sometimes. - # echo "$hash ./spartan/bootstrap.sh test-kind-smoke" - - # if [ "$CI_NIGHTLY" -eq 1 ]; then - # NIGHTLY_NS=nightly-$(date -u +%Y%m%d) - # echo "$hash:TIMEOUT=20m FRESH_INSTALL=no-deploy NAMESPACE=$NIGHTLY_NS ./spartan/bootstrap.sh test-gke-transfer reth" - # echo "$hash:TIMEOUT=20m FRESH_INSTALL=no-deploy NAMESPACE=$NIGHTLY_NS ./spartan/bootstrap.sh test-gke-transfer geth" - - # Nethermind test can be enabled once https://github.com/NethermindEth/nethermind/pull/8897 is released - # echo "$hash:TIMEOUT=20m FRESH_INSTALL=no-deploy NAMESPACE=$NIGHTLY_NS ./spartan/bootstrap.sh test-gke-transfer nethermind" - - #echo "$hash:TIMEOUT=30m FRESH_INSTALL=no-deploy NAMESPACE=$NIGHTLY_NS ./spartan/bootstrap.sh test-gke-1tps" - #echo "$hash:TIMEOUT=30m FRESH_INSTALL=no-deploy NAMESPACE=$NIGHTLY_NS ./spartan/bootstrap.sh test-gke-4epochs" + # the existing test flow is deprecated. + # we are moving things to use the same deployment flow as the scenario/staging networks. + : +} - # These tests get their own namespaces otherwise they'd interfere with the other tests - #echo "$hash:TIMEOUT=30m MONITOR_DEPLOYMENT=false NAME_POSTFIX='-$NIGHTLY_NS' ./spartan/bootstrap.sh test-gke-upgrade-rollup-version" - #echo "$hash:TIMEOUT=30m MONITOR_DEPLOYMENT=false NAME_POSTFIX='-$NIGHTLY_NS' ./spartan/bootstrap.sh test-gke-cli-upgrade" +function network_test_cmds { + local run_test_script="yarn-project/end-to-end/scripts/run_test.sh" + echo $run_test_script simple src/spartan/smoke.test.ts + echo $run_test_script simple src/spartan/transfer.test.ts +} - # TODO(#12791) re-enable - # echo "$hash:TIMEOUT=50m ./spartan/bootstrap.sh test-kind-4epochs-sepolia" - # echo "$hash:TIMEOUT=30m ./spartan/bootstrap.sh test-prod-deployment" - # fi - if [ "$CI_SCENARIO_TEST" -eq 1 ]; then - local run_test_script="yarn-project/end-to-end/scripts/run_test.sh" - DEFAULT_NAMESPACE="scenario-$(git rev-parse --short HEAD)" - NAMESPACE=${NAMESPACE:-$DEFAULT_NAMESPACE} - K8S_CLUSTER=${K8S_CLUSTER:-"aztec-gke-private"} - PROJECT_ID=${PROJECT_ID:-"testnet-440309"} - REGION=${REGION:-"us-west1-a"} - local env_vars="NAMESPACE=$NAMESPACE K8S_CLUSTER=$K8S_CLUSTER PROJECT_ID=$PROJECT_ID REGION=$REGION" - echo "$hash:TIMEOUT=20m $env_vars $run_test_script simple src/spartan/smoke.test.ts" - echo "$hash:TIMEOUT=20m $env_vars $run_test_script simple src/spartan/transfer.test.ts" - fi +function single_test { + local test_file="$1" + $root/yarn-project/end-to-end/scripts/run_test.sh simple $test_file } function start_env { @@ -115,27 +107,84 @@ function stop_env { fi } -function test { - echo_header "spartan test" - if [ "$CI" -eq 1 ]; then +function gcp_auth { + # if the GCP_PROJECT_ID is set, activate the service account + if [[ -n "${GCP_PROJECT_ID:-}" && "${CLUSTER}" != "kind" ]]; then echo "Activating service account" - gcloud auth activate-service-account --key-file=/tmp/gcp-key.json + if [ "$CI" -eq 1 ]; then + gcloud auth activate-service-account --key-file=$GOOGLE_APPLICATION_CREDENTIALS + fi gcloud config set project "$GCP_PROJECT_ID" + gcloud container clusters get-credentials ${CLUSTER} --region=${GCP_REGION} --project=${GCP_PROJECT_ID} fi +} + +function test { + echo_header "spartan test (deprecated)" + # the existing test flow is deprecated. + # we are moving things to use the same deployment flow as the scenario/staging networks. + : +} - if [ "$CI_SCENARIO_TEST" -eq 1 ]; then - echo "Running network scenario tests sequentially" - test_cmds | filter_test_cmds - else - echo "Running spartan test" - test_cmds | filter_test_cmds | parallelize +function network_tests { + echo_header "spartan scenario test" + + # no parallelize here as we want to run the tests sequentially + network_test_cmds | filter_test_cmds | parallelize 1 +} + +function ensure_eth_balances { + amount="$1" + # if ETHEREUM_HOST is not set, use the first RPC URL + if [ -z "${ETHEREUM_HOST:-}" ]; then + # if using kind, prefer localhost RPC. Requires user to port-forward 8545. + if [[ "${CLUSTER:-kind}" == "kind" ]]; then + export ETHEREUM_HOST="http://localhost:8545" + else + export ETHEREUM_HOST=$(echo "${ETHEREUM_RPC_URLS}" | jq -r '.[0]') + fi fi + ./scripts/ensure_eth_balances.sh "$ETHEREUM_HOST" "$FUNDING_PRIVATE_KEY" "$LABS_INFRA_MNEMONIC" "$LABS_INFRA_INDICES" "$amount" } case "$cmd" in "") # do nothing but the install_deps.sh above ;; + "ensure_eth_balances") + shift + env_file="$1" + amount="$2" + + source_network_env $env_file + ensure_eth_balances "$amount" + ;; + "network_deploy") + shift + env_file="$1" + source_network_env $env_file + + gcp_auth + ./scripts/deploy_network.sh + ;; + "single_test") + shift + env_file="$1" + test_file="$2" + source_network_env $env_file + + gcp_auth + single_test $test_file + ;; + + "network_tests") + shift + env_file="$1" + source_network_env $env_file + + gcp_auth + network_tests + ;; "kind") if ! kubectl config get-clusters | grep -q "^kind-kind$" || ! docker ps | grep -q "kind-control-plane"; then # Sometimes, kubectl does not have our kind context yet kind registers it as existing @@ -175,7 +224,7 @@ case "$cmd" in "hash") echo $hash ;; - test|test_cmds|gke|build|start_env|stop_env) + test|test_cmds|gke|build|start_env|stop_env|gcp_auth) $cmd ;; "test-kind-smoke") diff --git a/spartan/environments/scenario.local.env b/spartan/environments/scenario.local.env new file mode 100644 index 000000000000..c422d7609168 --- /dev/null +++ b/spartan/environments/scenario.local.env @@ -0,0 +1,12 @@ +NAMESPACE=scenario +CLUSTER=kind +CREATE_ETH_DEVNET=true +SALT=123 +LABS_INFRA_MNEMONIC="test test test test test test test test test test test junk" +FUNDING_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +REAL_VERIFIER=false +AZTEC_EPOCH_DURATION=8 +AZTEC_SLOT_DURATION=24 + +# The following need to be set manually +# AZTEC_DOCKER_IMAGE=aztecprotocol/aztec:whatever diff --git a/spartan/environments/staging.local.env b/spartan/environments/staging.local.env new file mode 100644 index 000000000000..97cc68aa4c03 --- /dev/null +++ b/spartan/environments/staging.local.env @@ -0,0 +1,14 @@ +NAMESPACE=staging +CLUSTER=kind +CREATE_ETH_DEVNET=false +SALT=456 +ETHEREUM_CHAIN_ID=1337 +LABS_INFRA_MNEMONIC="test test test test test test test test test test test junk" +FUNDING_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + +# The following need to be set manually +# AZTEC_DOCKER_IMAGE=aztecprotocol/aztec:whatever +# ETHEREUM_RPC_URLS='[""]' +# ETHEREUM_CONSENSUS_HOST_URLS='[""]' +# ETHEREUM_CONSENSUS_HOST_API_KEYS='[""]' +# ETHEREUM_CONSENSUS_HOST_API_KEY_HEADERS='[""]' diff --git a/spartan/scripts/deploy_network.sh b/spartan/scripts/deploy_network.sh new file mode 100755 index 000000000000..3dec535f68bc --- /dev/null +++ b/spartan/scripts/deploy_network.sh @@ -0,0 +1,284 @@ +#!/bin/bash + +set -euo pipefail + +# Resolve repo root and script directory for reliable relative paths +REPO_ROOT="$(git rev-parse --show-toplevel)" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source "${REPO_ROOT}/ci3/source" + +# Basic logging helpers +log() { echo "[INFO] $(date -Is) - $*"; } +err() { echo "[ERROR] $(date -Is) - $*" >&2; } +die() { err "$*"; exit 1; } + +######################## +# GLOBAL VARIABLES +######################## +NAMESPACE=${NAMESPACE} # required +CLUSTER=${CLUSTER:-kind} +SALT=${SALT:-$(date +%s)} +RESOURCE_PROFILE=$([[ "${CLUSTER}" == "kind" ]] && echo "dev" || echo "prod") +BASE_STATE_PATH="${CLUSTER}/${NAMESPACE}" + +# GCP variables, unused if running on kind +GCP_PROJECT_ID=${GCP_PROJECT_ID:-testnet-440309} +GCP_REGION=${GCP_REGION:-us-west1-a} + +######################## +# ETHEREUM / DEVNET VARIABLES +######################## +DESTROY_ETH_DEVNET=${DESTROY_ETH_DEVNET:-false} +CREATE_ETH_DEVNET=${CREATE_ETH_DEVNET:-false} +ETHEREUM_CHAIN_ID=${ETHEREUM_CHAIN_ID:-1337} +ETHEREUM_BLOCK_TIME=${ETHEREUM_BLOCK_TIME:-12} +ETHEREUM_GAS_LIMIT=${ETHEREUM_GAS_LIMIT:-45000000} +LABS_INFRA_MNEMONIC=${LABS_INFRA_MNEMONIC:-test test test test test test test test test test test junk} +LABS_INFRA_INDICES=${LABS_INFRA_INDICES:-0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,1000} + +######################## +# ROLLUP VARIABLES +######################## +DESTROY_ROLLUP_CONTRACTS=${DESTROY_ROLLUP_CONTRACTS:-false} +CREATE_ROLLUP_CONTRACTS=${CREATE_ROLLUP_CONTRACTS:-true} +SPONSORED_FPC=${SPONSORED_FPC:-true} +REAL_VERIFIER=${REAL_VERIFIER:-true} + + +######################## +# AZTEC INFRA VARIABLES +######################## +DESTROY_AZTEC_INFRA=${DESTROY_AZTEC_INFRA:-false} +CREATE_AZTEC_INFRA=${CREATE_AZTEC_INFRA:-true} + + +LABS_INFRA_MNEMONIC=${LABS_INFRA_MNEMONIC:-test test test test test test test test test test test junk} +VALIDATOR_INDICES=${VALIDATOR_INDICES:-1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48} +VALIDATOR_MNEMONIC_START_INDEX=${VALIDATOR_MNEMONIC_START_INDEX:-1} +VALIDATORS_PER_NODE=${VALIDATORS_PER_NODE:-12} +VALIDATOR_REPLICAS=${VALIDATOR_REPLICAS:-4} +PROVER_MNEMONIC_START_INDEX=${PROVER_MNEMONIC_START_INDEX:-1000} +PROVER_REAL_PROOFS=${REAL_VERIFIER:-true} + +OTEL_COLLECTOR_ENDPOINT=${OTEL_COLLECTOR_ENDPOINT:-} + +######################## +# CHAOS MESH VARIABLES +######################## +DESTROY_CHAOS_MESH=${DESTROY_CHAOS_MESH:-false} +CREATE_CHAOS_MESH=${CREATE_CHAOS_MESH:-false} + + +# Compute validator addresses +VALIDATOR_ADDRESSES=$(echo "$VALIDATOR_INDICES" | tr ',' '\n' | xargs -I{} cast wallet address --mnemonic "$LABS_INFRA_MNEMONIC" --mnemonic-index {} | tr '\n' ',' | sed 's/,$//') +log "VALIDATOR_ADDRESSES: ${VALIDATOR_ADDRESSES}" + +# Ensure docker image provided +if [[ -z "${AZTEC_DOCKER_IMAGE:-}" ]]; then + die "AZTEC_DOCKER_IMAGE is not set" +fi + +K8S_CLUSTER_CONTEXT=$(kubectl config current-context) + +# Create the namespace if it doesn't exist +kubectl get namespace "${NAMESPACE}" >/dev/null 2>&1 || kubectl create namespace "${NAMESPACE}" + +# DRY helper to init/plan/apply/destroy a terraform module +tf_run() { + local dir="$1" + local destroy_flag="$2" + local create_flag="$3" + + terraform -chdir="${dir}" init -reconfigure + if [[ "${destroy_flag}" == "true" ]]; then + terraform -chdir="${dir}" destroy -auto-approve + fi + if [[ "${create_flag}" == "true" ]]; then + terraform -chdir="${dir}" plan -out=tfplan + terraform -chdir="${dir}" apply tfplan + fi +} + +# ------------------------------------------------------- +# Optionally deploy Ethereum devnet; otherwise use env URLs +# ------------------------------------------------------- +CSV_RPC_URLS="" +L1_RPC_URLS_JSON="[]" +L1_CONSENSUS_HOST_URLS_JSON="[]" +L1_CONSENSUS_HOST_API_KEYS_JSON="[]" +L1_CONSENSUS_HOST_API_KEY_HEADERS_JSON="[]" + +if [[ "${CREATE_ETH_DEVNET}" == "true" ]]; then + log "CREATE_ETH_DEVNET=true - deploying Ethereum devnet" + + DEPLOY_ETH_DEVNET_DIR="${SCRIPT_DIR}/../terraform/deploy-eth-devnet" + cat > "${DEPLOY_ETH_DEVNET_DIR}/terraform.tfvars" << EOF +project = "${GCP_PROJECT_ID}" +region = "${GCP_REGION}" +K8S_CLUSTER_CONTEXT = "${K8S_CLUSTER_CONTEXT}" +RELEASE_PREFIX = "${NAMESPACE}" +NAMESPACE = "${NAMESPACE}" +ETH_DEVNET_VALUES = "eth-devnet.yaml" +MNEMONIC = "${LABS_INFRA_MNEMONIC}" +CHAIN_ID = "${ETHEREUM_CHAIN_ID}" +BLOCK_TIME = ${ETHEREUM_BLOCK_TIME} +GAS_LIMIT = ${ETHEREUM_GAS_LIMIT} +PREFUNDED_MNEMONIC_INDICES = "${LABS_INFRA_INDICES}" +RESOURCE_PROFILE = "${RESOURCE_PROFILE}" +EOF + + "${SCRIPT_DIR}/override_terraform_backend.sh" "${DEPLOY_ETH_DEVNET_DIR}" "${CLUSTER}" "${BASE_STATE_PATH}/deploy-eth-devnet" + tf_run "${DEPLOY_ETH_DEVNET_DIR}" "${DESTROY_ETH_DEVNET}" "${CREATE_ETH_DEVNET}" + + L1_RPC_URL=$(terraform -chdir="${DEPLOY_ETH_DEVNET_DIR}" output -raw eth_execution_rpc_url) + L1_CONSENSUS_HOST_URL=$(terraform -chdir="${DEPLOY_ETH_DEVNET_DIR}" output -raw eth_beacon_api_url) + [[ -n "${L1_RPC_URL}" ]] || die "Failed to fetch eth_execution_rpc_url" + [[ -n "${L1_CONSENSUS_HOST_URL}" ]] || die "Failed to fetch eth_beacon_api_url" + + # For downstream modules + CSV_RPC_URLS="${L1_RPC_URL}" + L1_RPC_URLS_JSON="[\"${L1_RPC_URL}\"]" + L1_CONSENSUS_HOST_URLS_JSON="[\"${L1_CONSENSUS_HOST_URL}\"]" + L1_CONSENSUS_HOST_API_KEYS_JSON='[""]' + L1_CONSENSUS_HOST_API_KEY_HEADERS_JSON='[""]' +else + log "CREATE_ETH_DEVNET=false - using environment-provided Ethereum endpoints" + + # Expect ETHEREUM_RPC_URLS (JSON array), and consensus host arrays and keys + if [[ -z "${ETHEREUM_RPC_URLS:-}" ]]; then + die "ETHEREUM_RPC_URLS is not set (expected JSON array, e.g. [\"https://...\"])" + fi + CSV_RPC_URLS=$(echo "${ETHEREUM_RPC_URLS}" | jq -r 'join(",")') + + L1_RPC_URLS_JSON="${ETHEREUM_RPC_URLS}" + L1_CONSENSUS_HOST_URLS_JSON="${ETHEREUM_CONSENSUS_HOST_URLS:-[]}" + L1_CONSENSUS_HOST_API_KEYS_JSON="${ETHEREUM_CONSENSUS_HOST_API_KEYS:-[]}" + L1_CONSENSUS_HOST_API_KEY_HEADERS_JSON="${ETHEREUM_CONSENSUS_HOST_API_KEY_HEADERS:-[]}" +fi + +# ------------------------------- +# Deploy rollup contracts +# ------------------------------- +DEPLOY_ROLLUP_CONTRACTS_DIR="${SCRIPT_DIR}/../terraform/deploy-rollup-contracts" +"${SCRIPT_DIR}/override_terraform_backend.sh" "${DEPLOY_ROLLUP_CONTRACTS_DIR}" "${CLUSTER}" "${BASE_STATE_PATH}/deploy-rollup-contracts/${SALT}" + +cat > "${DEPLOY_ROLLUP_CONTRACTS_DIR}/terraform.tfvars" << EOF +K8S_CLUSTER_CONTEXT = "${K8S_CLUSTER_CONTEXT}" +NAMESPACE = "${NAMESPACE}" +AZTEC_DOCKER_IMAGE = "${AZTEC_DOCKER_IMAGE}" +L1_RPC_URLS = "${CSV_RPC_URLS}" +MNEMONIC = "${LABS_INFRA_MNEMONIC}" +L1_CHAIN_ID = "${ETHEREUM_CHAIN_ID}" +SALT = "${SALT}" +VALIDATORS = "${VALIDATOR_ADDRESSES}" +SPONSORED_FPC = ${SPONSORED_FPC} +REAL_VERIFIER = ${REAL_VERIFIER} +AZTEC_SLOT_DURATION = ${AZTEC_SLOT_DURATION:-null} +AZTEC_EPOCH_DURATION = ${AZTEC_EPOCH_DURATION:-null} +AZTEC_TARGET_COMMITTEE_SIZE = ${AZTEC_TARGET_COMMITTEE_SIZE:-null} +AZTEC_PROOF_SUBMISSION_EPOCHS = ${AZTEC_PROOF_SUBMISSION_EPOCHS:-null} +AZTEC_ACTIVATION_THRESHOLD = ${AZTEC_ACTIVATION_THRESHOLD:-null} +AZTEC_EJECTION_THRESHOLD = ${AZTEC_EJECTION_THRESHOLD:-null} +AZTEC_SLASHING_QUORUM = ${AZTEC_SLASHING_QUORUM:-null} +AZTEC_SLASHING_ROUND_SIZE = ${AZTEC_SLASHING_ROUND_SIZE:-null} +AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS = ${AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS:-null} +AZTEC_SLASHING_LIFETIME_IN_ROUNDS = ${AZTEC_SLASHING_LIFETIME_IN_ROUNDS:-null} +AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS = ${AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS:-null} +AZTEC_SLASHING_VETOER = ${AZTEC_SLASHING_VETOER:-null} +AZTEC_SLASHING_OFFSET_IN_ROUNDS = ${AZTEC_SLASHING_OFFSET_IN_ROUNDS:-null} +AZTEC_SLASH_AMOUNT_SMALL = ${AZTEC_SLASH_AMOUNT_SMALL:-null} +AZTEC_SLASH_AMOUNT_MEDIUM = ${AZTEC_SLASH_AMOUNT_MEDIUM:-null} +AZTEC_SLASH_AMOUNT_LARGE = ${AZTEC_SLASH_AMOUNT_LARGE:-null} +AZTEC_SLASHER_FLAVOR = ${AZTEC_SLASHER_FLAVOR:-null} +AZTEC_GOVERNANCE_PROPOSER_QUORUM = ${AZTEC_GOVERNANCE_PROPOSER_QUORUM:-null} +AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE = ${AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE:-null} +AZTEC_MANA_TARGET = ${AZTEC_MANA_TARGET:-null} +AZTEC_PROVING_COST_PER_MANA = ${AZTEC_PROVING_COST_PER_MANA:-null} +JOB_NAME = "deploy-rollup-contracts" +JOB_BACKOFF_LIMIT = 3 +JOB_TTL_SECONDS_AFTER_FINISHED = 3600 +EOF + +tf_run "${DEPLOY_ROLLUP_CONTRACTS_DIR}" "${DESTROY_ROLLUP_CONTRACTS}" "${CREATE_ROLLUP_CONTRACTS}" +log "Deployed rollup contracts" + +REGISTRY_ADDRESS=$(terraform -chdir="${DEPLOY_ROLLUP_CONTRACTS_DIR}" output -raw registry_address) +SLASH_FACTORY_ADDRESS=$(terraform -chdir="${DEPLOY_ROLLUP_CONTRACTS_DIR}" output -raw slash_factory_address) +FEE_ASSET_HANDLER_ADDRESS=$(terraform -chdir="${DEPLOY_ROLLUP_CONTRACTS_DIR}" output -raw fee_asset_handler_address) +[[ -n "${REGISTRY_ADDRESS}" ]] || die "Failed to fetch registry_address" +[[ -n "${SLASH_FACTORY_ADDRESS}" ]] || die "Failed to fetch slash_factory_address" +[[ -n "${FEE_ASSET_HANDLER_ADDRESS}" ]] || die "Failed to fetch fee_asset_handler_address" +log "Got rollup contract addresses" + +# ------------------------------- +# Deploy Aztec infra +# ------------------------------- +DEPLOY_AZTEC_INFRA_DIR="${SCRIPT_DIR}/../terraform/deploy-aztec-infra" +"${SCRIPT_DIR}/override_terraform_backend.sh" "${DEPLOY_AZTEC_INFRA_DIR}" "${CLUSTER}" "${BASE_STATE_PATH}/deploy-aztec-infra/${SALT}" + +cat > "${DEPLOY_AZTEC_INFRA_DIR}/terraform.tfvars" << EOF +K8S_CLUSTER_CONTEXT = "${K8S_CLUSTER_CONTEXT}" +RELEASE_PREFIX = "${NAMESPACE}" +NAMESPACE = "${NAMESPACE}" +GCP_PROJECT_ID = "${GCP_PROJECT_ID}" +GCP_REGION = "${GCP_REGION}" +P2P_BOOTSTRAP_RESOURCE_PROFILE = "${RESOURCE_PROFILE}" +VALIDATOR_RESOURCE_PROFILE = "${RESOURCE_PROFILE}" +PROVER_RESOURCE_PROFILE = "${RESOURCE_PROFILE}" +RPC_RESOURCE_PROFILE = "${RESOURCE_PROFILE}" +AZTEC_DOCKER_IMAGE = "${AZTEC_DOCKER_IMAGE}" +L1_CHAIN_ID = "${ETHEREUM_CHAIN_ID}" +L1_RPC_URLS = ${L1_RPC_URLS_JSON} +L1_CONSENSUS_HOST_URLS = ${L1_CONSENSUS_HOST_URLS_JSON} +L1_CONSENSUS_HOST_API_KEYS = ${L1_CONSENSUS_HOST_API_KEYS_JSON} +L1_CONSENSUS_HOST_API_KEY_HEADERS = ${L1_CONSENSUS_HOST_API_KEY_HEADERS_JSON} +REGISTRY_CONTRACT_ADDRESS = "${REGISTRY_ADDRESS}" +SLASH_FACTORY_CONTRACT_ADDRESS = "${SLASH_FACTORY_ADDRESS}" +FEE_ASSET_HANDLER_CONTRACT_ADDRESS = "${FEE_ASSET_HANDLER_ADDRESS}" +VALIDATOR_MNEMONIC = "${LABS_INFRA_MNEMONIC}" +VALIDATOR_MNEMONIC_START_INDEX = ${VALIDATOR_MNEMONIC_START_INDEX} +VALIDATORS_PER_NODE = ${VALIDATORS_PER_NODE} +VALIDATOR_REPLICAS = ${VALIDATOR_REPLICAS} +PROVER_MNEMONIC = "${LABS_INFRA_MNEMONIC}" +PROVER_MNEMONIC_START_INDEX = ${PROVER_MNEMONIC_START_INDEX} +SENTINEL_ENABLED = ${SENTINEL_ENABLED:-null} +SLASH_MIN_PENALTY_PERCENTAGE = ${SLASH_MIN_PENALTY_PERCENTAGE:-null} +SLASH_MAX_PENALTY_PERCENTAGE = ${SLASH_MAX_PENALTY_PERCENTAGE:-null} +SLASH_INACTIVITY_TARGET_PERCENTAGE = ${SLASH_INACTIVITY_TARGET_PERCENTAGE:-null} +SLASH_INACTIVITY_PENALTY = ${SLASH_INACTIVITY_PENALTY:-null} +SLASH_PRUNE_PENALTY = ${SLASH_PRUNE_PENALTY:-null} +SLASH_DATA_WITHHOLDING_PENALTY = ${SLASH_DATA_WITHHOLDING_PENALTY:-null} +SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY = ${SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY:-null} +SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY = ${SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY:-null} +SLASH_UNKNOWN_PENALTY = ${SLASH_UNKNOWN_PENALTY:-null} +SLASH_INVALID_BLOCK_PENALTY = ${SLASH_INVALID_BLOCK_PENALTY:-null} +SLASH_OFFENSE_EXPIRATION_ROUNDS = ${SLASH_OFFENSE_EXPIRATION_ROUNDS:-null} +SLASH_MAX_PAYLOAD_SIZE = ${SLASH_MAX_PAYLOAD_SIZE:-null} +OTEL_COLLECTOR_ENDPOINT = "${OTEL_COLLECTOR_ENDPOINT}" +PROVER_REAL_PROOFS = ${PROVER_REAL_PROOFS} +EOF + +tf_run "${DEPLOY_AZTEC_INFRA_DIR}" "${DESTROY_AZTEC_INFRA}" "${CREATE_AZTEC_INFRA}" +log "Deployed aztec infra" + + + +######################################## +# Optionally deploy Chaos Mesh via Helm +######################################## +if [[ "${CREATE_CHAOS_MESH}" == "true" ]]; then + log "CREATE_CHAOS_MESH=true - deploying Chaos Mesh" + DEPLOY_CHAOS_MESH_DIR="${SCRIPT_DIR}/../terraform/deploy-chaos-mesh" + cat > "${DEPLOY_CHAOS_MESH_DIR}/terraform.tfvars" << EOF +K8S_CLUSTER_CONTEXT = "${K8S_CLUSTER_CONTEXT}" +RELEASE_NAME = "chaos" +CHAOS_MESH_NAMESPACE = "chaos-mesh" +EOF + + "${SCRIPT_DIR}/override_terraform_backend.sh" "${DEPLOY_CHAOS_MESH_DIR}" "${CLUSTER}" "${BASE_STATE_PATH}/deploy-chaos-mesh/${SALT}" + tf_run "${DEPLOY_CHAOS_MESH_DIR}" "${DESTROY_CHAOS_MESH}" "${CREATE_CHAOS_MESH}" + log "Chaos Mesh installed" +else + log "CREATE_CHAOS_MESH=false - skipping Chaos Mesh installation" +fi diff --git a/spartan/scripts/ensure_eth_balances.sh b/spartan/scripts/ensure_eth_balances.sh new file mode 100755 index 000000000000..ba16e979c361 --- /dev/null +++ b/spartan/scripts/ensure_eth_balances.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash + +set -euo pipefail + +export FOUNDRY_DISABLE_NIGHTLY_WARNING=1 + +# --- Argument Parsing --- +if [ "$#" -lt 2 ]; then + echo "Usage: $0 ETHEREUM_HOST FUNDING_PRIVATE_KEY MNEMONIC_TO_FUND MNEMONIC_INDICES MIN_ETH_BALANCE [output_file]" + echo "Example: $0 \"http://localhost:8545\" \"0x...\" \"test test ...\" \"0,1,2,100,101\" \"1.5\"" + exit 1 +fi + +ETHEREUM_HOST="$1" +FUNDING_PRIVATE_KEY="$2" +MNEMONIC_TO_FUND="$3" +MNEMONIC_INDICES="$4" +MIN_ETH_BALANCE="$5" +output_file="${6:-"mnemonic.tmp"}" + +# ensure necessary environment variables are set +if [ -z "${ETHEREUM_HOST:-}" ]; then + echo "ETHEREUM_HOST environment variable is not set" + exit 1 +fi +if [ -z "${FUNDING_PRIVATE_KEY:-}" ]; then + echo "FUNDING_PRIVATE_KEY environment variable is not set" + exit 1 +fi + +# --- Initial Setup --- +reset_x=false +# Set +x if it's currently enabled to avoid noisy output during setup +if [ -o xtrace ]; then + set +x + reset_x=true +fi + +# Create a temporary file for the new mnemonic if one needs to be created +tmp_filename=$(mktemp) + +# Cleanup function to handle the temp file and restore xtrace +cleanup() { + rm -f "$tmp_filename" + if [ "$reset_x" = true ]; then + set -x + fi +} +trap cleanup EXIT + +# --- Dependency Checks --- +# Function to check for and install a command if it's missing +install_if_missing() { + if ! command -v "$1" &>/dev/null; then + echo "Command '$1' not found. Installing..." + case "$1" in + bc) + (apt-get update && apt-get install -y bc) || (yum install -y bc) || (brew install bc) || echo "Please install 'bc' manually." + ;; + cast) + # Adjust path for standard installations + FOUNDRY_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/foundry" + if [ ! -d "$FOUNDRY_DIR" ]; then + FOUNDRY_DIR="$HOME/.foundry" + fi + export PATH="$PATH:$FOUNDRY_DIR/bin" + curl -L https://foundry.paradigm.xyz | bash + "$FOUNDRY_DIR/bin/foundryup" + ;; + *) + echo "Error: Don't know how to install '$1'." + exit 1 + ;; + esac + fi +} + +install_if_missing "bc" +install_if_missing "cast" + +# --- Main Logic --- + +# Validate and convert the target ETH amount to wei +if [[ ! "$MIN_ETH_BALANCE" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then + echo "Error: Invalid ETH amount provided: $MIN_ETH_BALANCE" + exit 1 +fi +target_wei_amount=$(cast to-wei "$MIN_ETH_BALANCE" ether) +echo "Ensuring each specified address has a minimum balance of $MIN_ETH_BALANCE ETH ($target_wei_amount wei)..." + +# Check if a mnemonic is provided via environment variable, otherwise create one +# Initialize variables for the multicall transaction +calls="[" +total_value_to_send=0 +accounts_to_fund_count=0 +accounts_already_funded_count=0 + +# Convert the comma-separated string of indices into a bash array +IFS=',' read -r -a indices_array <<< "$MNEMONIC_INDICES" + +echo "Processing ${#indices_array[@]} mnemonic indices..." + +for index in "${indices_array[@]}"; do + # Trim whitespace from index + index=$(echo "$index" | tr -d '[:space:]') + if [ -z "$index" ]; then continue; fi + + echo -n " -> Index $index: " + address=$(cast wallet address --mnemonic "$MNEMONIC_TO_FUND" --mnemonic-index "$index") + current_balance=$(cast balance --rpc-url "$ETHEREUM_HOST" "$address") + + # Check if the current balance is less than the target + if (($(echo "$current_balance < $target_wei_amount" | bc -l))); then + top_up_amount=$(echo "$target_wei_amount - $current_balance" | bc) + echo "Balance is ${current_balance}. Topping up with ${top_up_amount} wei. Address: $address" + + # Add this funding operation to the multicall array + calls+="(${address},false,${top_up_amount},0x)," + + # Add the top-up amount to the total value for the transaction + total_value_to_send=$(echo "$total_value_to_send + $top_up_amount" | bc) + accounts_to_fund_count=$((accounts_to_fund_count + 1)) + else + echo "Balance is ${current_balance}. Sufficient funds. Address: $address" + accounts_already_funded_count=$((accounts_already_funded_count + 1)) + fi +done + +# --- Transaction Execution --- + +# Only proceed if there are accounts that need funding +if [ "$accounts_to_fund_count" -eq 0 ]; then + echo "All ${accounts_already_funded_count} specified accounts already have sufficient balance. No transaction needed." + exit 0 +fi + +# Finalize the multicall array string +calls=${calls%,} # Remove trailing comma +calls+="]" + +# Sanity check: ensure the total funding amount isn't excessive +funding_address=$(cast wallet address --private-key "$FUNDING_PRIVATE_KEY") +funding_balance=$(cast balance --rpc-url "$ETHEREUM_HOST" "$funding_address") +if (($(echo "$total_value_to_send > $funding_balance" | bc -l))); then + echo "Error: Total value of this transaction ($total_value_to_send wei) exceeds funding account balance ($funding_balance wei)." + exit 1 +fi + +multicall_address="0xcA11bde05977b3631167028862bE2a173976CA11" # Multicall3 contract on most chains + +echo "Sending transaction to top up $accounts_to_fund_count accounts..." +tx_hash=$(cast send "$multicall_address" \ + "aggregate3Value((address,bool,uint256,bytes)[])" \ + "$calls" \ + --value "$total_value_to_send" \ + --private-key "$FUNDING_PRIVATE_KEY" \ + --rpc-url "$ETHEREUM_HOST" \ + --json) + +tx_hash_val=$(echo "$tx_hash" | jq -r '.transactionHash') + +echo "--------------------------------------------------" +echo "✅ Funding complete!" +echo "Summary:" +echo " - Topped up: $accounts_to_fund_count accounts" +echo " - Already funded: $accounts_already_funded_count accounts" +echo " - Total ETH sent: $(cast from-wei "$total_value_to_send")" +echo " - Transaction Hash: $tx_hash_val" +echo "--------------------------------------------------" + diff --git a/spartan/scripts/install_deps.sh b/spartan/scripts/install_deps.sh index b0b40dfa53da..94829314f5e8 100755 --- a/spartan/scripts/install_deps.sh +++ b/spartan/scripts/install_deps.sh @@ -1,10 +1,13 @@ #!/usr/bin/env bash +echo "Installing dependencies..." source $(git rev-parse --show-toplevel)/ci3/source +echo "Source loaded" os=$(uname | awk '{print tolower($0)}') # if kubectl is not installed, install it if ! command -v kubectl &> /dev/null; then + echo "Installing kubectl..." curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/${os}/$(arch)/kubectl" chmod +x kubectl sudo mv kubectl /usr/local/bin/kubectl @@ -12,6 +15,7 @@ fi # Install kind if it is not installed if ! command -v kind &> /dev/null; then + echo "Installing kind..." curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.23.0/kind-${os}-$(arch) chmod +x ./kind sudo mv ./kind /usr/local/bin/kind @@ -19,6 +23,7 @@ fi # Install helm if it is not installed if ! command -v helm &> /dev/null; then + echo "Installing helm..." curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod +x get_helm.sh sudo ./get_helm.sh @@ -26,6 +31,7 @@ if ! command -v helm &> /dev/null; then fi if ! command -v stern &> /dev/null; then + echo "Installing stern..." # Download Stern curl -Lo stern.tar.gz https://github.com/stern/stern/releases/download/v1.31.0/stern_1.31.0_${os}_$(arch).tar.gz @@ -44,6 +50,7 @@ if ! command -v stern &> /dev/null; then fi if ! command -v gcloud &> /dev/null; then + echo "Installing gcloud..." curl -Lo google-cloud-cli.tar.gz https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-$os-$(arch).tar.gz tar -xzf google-cloud-cli.tar.gz rm google-cloud-cli.tar.gz @@ -57,10 +64,35 @@ fi # Install GKE auth plugin for kubectl if command -v gcloud &> /dev/null; then - if dpkg -l google-cloud-cli 2>/dev/null | grep -q "^ii"; then - sudo apt-get update - sudo apt-get install -y google-cloud-cli-gke-gcloud-auth-plugin + # Check if GKE auth plugin is already installed + if command -v gke-gcloud-auth-plugin &> /dev/null || + gcloud components list --filter="id:gke-gcloud-auth-plugin" --format="value(state.name)" 2>/dev/null | grep -q "Installed"; then + : # do nothing + elif dpkg -l google-cloud-cli 2>/dev/null | grep -q "^ii"; then + # Check if apt package is already installed + if dpkg -l google-cloud-cli-gke-gcloud-auth-plugin 2>/dev/null | grep -q "^ii"; then + : # do nothing + else + echo "Installing GKE auth plugin for kubectl via apt..." + sudo apt-get update + sudo apt-get install -y google-cloud-cli-gke-gcloud-auth-plugin + fi else + echo "Installing GKE auth plugin for kubectl via gcloud components..." gcloud components install gke-gcloud-auth-plugin fi fi + + +# Sanity check commands +require_cmd() { command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"; } + +require_cmd git +require_cmd kubectl +require_cmd terraform +require_cmd sed +require_cmd xargs +require_cmd tr +require_cmd cast +require_cmd jq +require_cmd gcloud diff --git a/spartan/scripts/override_terraform_backend.sh b/spartan/scripts/override_terraform_backend.sh new file mode 100755 index 000000000000..04e4445a11ea --- /dev/null +++ b/spartan/scripts/override_terraform_backend.sh @@ -0,0 +1,28 @@ +TERRAFORM_DIR=$1 +CLUSTER=$2 +STATE_PATH=$3 + +rm -f $TERRAFORM_DIR/backend_override.tf + + + +if [ "${CLUSTER}" == "kind" ]; then + # For kind, use local backend + cat > $TERRAFORM_DIR/backend_override.tf << EOF +terraform { + backend "local" { + path = "state/${STATE_PATH}/terraform.tfstate" + } +} +EOF +else + # For GKE, use GCS backend + cat > $TERRAFORM_DIR/backend_override.tf << EOF +terraform { + backend "gcs" { + bucket = "aztec-terraform" + prefix = "${STATE_PATH}/terraform.tfstate" + } +} +EOF +fi diff --git a/spartan/terraform/deploy-aztec-infra/main.tf b/spartan/terraform/deploy-aztec-infra/main.tf index c9e8cd09fcc9..ca2e6a217f00 100644 --- a/spartan/terraform/deploy-aztec-infra/main.tf +++ b/spartan/terraform/deploy-aztec-infra/main.tf @@ -16,17 +16,11 @@ terraform { } kubernetes = { source = "hashicorp/kubernetes" - version = "~> 2.24.0" + version = "~> 2.38.0" } } } -# Only used if deploying an RPC with an external ingress -provider "google" { - project = var.GCP_PROJECT - region = var.GCP_REGION -} - provider "kubernetes" { alias = "gke-cluster" config_path = "~/.kube/config" @@ -58,7 +52,7 @@ locals { "global.customAztecNetwork.slashFactoryContractAddress" = var.SLASH_FACTORY_CONTRACT_ADDRESS "global.customAztecNetwork.feeAssetHandlerContractAddress" = var.FEE_ASSET_HANDLER_CONTRACT_ADDRESS "global.customAztecNetwork.l1ChainId" = var.L1_CHAIN_ID - "global.otelCollectorEndpoint" = var.OTEL_COLLECTOR_URL + "global.otelCollectorEndpoint" = var.OTEL_COLLECTOR_ENDPOINT } common_list_settings = { @@ -78,8 +72,10 @@ locals { "p2p-bootstrap.yaml", "p2p-bootstrap-resources-${var.P2P_BOOTSTRAP_RESOURCE_PROFILE}.yaml" ] - custom_settings = {} - boot_node_path = "" + custom_settings = { + "nodeType" = "p2p-bootstrap" + } + boot_node_path = "" } validators = { @@ -91,11 +87,24 @@ locals { "validator-resources-${var.VALIDATOR_RESOURCE_PROFILE}.yaml" ] custom_settings = { - "global.customAztecNetwork.enabled" = true - "validator.mnemonic" = var.VALIDATOR_MNEMONIC - "validator.mnemonicStartIndex" = var.VALIDATOR_MNEMONIC_START_INDEX - "validator.validatorsPerNode" = var.VALIDATORS_PER_NODE - "validator.replicaCount" = var.VALIDATOR_REPLICAS + "global.customAztecNetwork.enabled" = true + "validator.mnemonic" = var.VALIDATOR_MNEMONIC + "validator.mnemonicStartIndex" = var.VALIDATOR_MNEMONIC_START_INDEX + "validator.validatorsPerNode" = var.VALIDATORS_PER_NODE + "validator.replicaCount" = var.VALIDATOR_REPLICAS + "validator.sentinel.enabled" = var.SENTINEL_ENABLED + "validator.slash.minPenaltyPercentage" = var.SLASH_MIN_PENALTY_PERCENTAGE + "validator.slash.maxPenaltyPercentage" = var.SLASH_MAX_PENALTY_PERCENTAGE + "validator.slash.inactivityTargetPercentage" = var.SLASH_INACTIVITY_TARGET_PERCENTAGE + "validator.slash.inactivityPenalty" = var.SLASH_INACTIVITY_PENALTY + "validator.slash.prunePenalty" = var.SLASH_PRUNE_PENALTY + "validator.slash.dataWithholdingPenalty" = var.SLASH_DATA_WITHHOLDING_PENALTY + "validator.slash.proposeInvalidAttestationsPenalty" = var.SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY + "validator.slash.attestDescendantOfInvalidPenalty" = var.SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY + "validator.slash.unknownPenalty" = var.SLASH_UNKNOWN_PENALTY + "validator.slash.invalidBlockPenalty" = var.SLASH_INVALID_BLOCK_PENALTY + "validator.slash.offenseExpirationRounds" = var.SLASH_OFFENSE_EXPIRATION_ROUNDS + "validator.slash.maxPayloadSize" = var.SLASH_MAX_PAYLOAD_SIZE } boot_node_path = "validator.node.env.BOOT_NODE_HOST" } @@ -109,8 +118,11 @@ locals { "prover-resources-${var.PROVER_RESOURCE_PROFILE}.yaml" ] custom_settings = { - "node.mnemonic" = var.PROVER_MNEMONIC - "node.mnemonicStartIndex" = var.PROVER_MNEMONIC_START_INDEX + "node.mnemonic" = var.PROVER_MNEMONIC + "node.mnemonicStartIndex" = var.PROVER_MNEMONIC_START_INDEX + "node.node.proverRealProofs" = var.PROVER_REAL_PROOFS + "broker.node.proverRealProofs" = var.PROVER_REAL_PROOFS + "agent.node.proverRealProofs" = var.PROVER_REAL_PROOFS } boot_node_path = "node.node.env.BOOT_NODE_HOST" } @@ -123,8 +135,10 @@ locals { "rpc.yaml", "rpc-resources-${var.RPC_RESOURCE_PROFILE}.yaml" ] - custom_settings = {} - boot_node_path = "node.env.BOOT_NODE_HOST" + custom_settings = { + "nodeType" = "rpc" + } + boot_node_path = "node.env.BOOT_NODE_HOST" } } } @@ -143,30 +157,22 @@ resource "helm_release" "releases" { force_update = true recreate_pods = true reuse_values = true - timeout = 300 - wait = false - wait_for_jobs = false + timeout = 600 + wait = true + wait_for_jobs = true values = [for v in each.value.values : file("./values/${v}")] # Common settings dynamic "set" { - for_each = merge( + for_each = { for k, v in merge( local.common_settings, each.value.custom_settings, # Add boot node if needed each.value.boot_node_path != "" ? { (each.value.boot_node_path) = local.boot_node_url - } : {}, - # Add OTEL endpoint if configured and not p2p_bootstrap - (var.OTEL_COLLECTOR_ENDPOINT != "" && each.key != "p2p_bootstrap") ? { - "global.otelCollectorEndpoint" = var.OTEL_COLLECTOR_ENDPOINT - } : {}, - # Add RPC ingress annotation if needed - (each.key == "rpc" && var.RPC_EXTERNAL_INGRESS && length(google_compute_address.rpc_ingress) > 0) ? { - "service.ingress.annotations.networking\\.gke\\.io\\/load-balancer-ip-addresses" = google_compute_address.rpc_ingress[0].name } : {} - ) + ) : k => v if v != null } content { name = set.key value = set.value @@ -175,7 +181,7 @@ resource "helm_release" "releases" { # Common list settings dynamic "set_list" { - for_each = local.common_list_settings + for_each = { for k, v in local.common_list_settings : k => v if v != null } content { name = set_list.key value = set_list.value @@ -183,10 +189,3 @@ resource "helm_release" "releases" { } } -# Keep the Google Compute Address as separate resource -resource "google_compute_address" "rpc_ingress" { - count = var.RPC_EXTERNAL_INGRESS ? 1 : 0 - provider = google - name = "${var.NAMESPACE}-${var.RELEASE_PREFIX}-rpc-ingress" - address_type = "EXTERNAL" -} diff --git a/spartan/terraform/deploy-aztec-infra/values/prover.yaml b/spartan/terraform/deploy-aztec-infra/values/prover.yaml index 9a17d1e955d1..4e5bef1c53bc 100644 --- a/spartan/terraform/deploy-aztec-infra/values/prover.yaml +++ b/spartan/terraform/deploy-aztec-infra/values/prover.yaml @@ -13,4 +13,4 @@ node: done echo "Boot node is ready!" - export BOOTSTRAP_NODES=$(curl -X POST --data '{"method": "bootstrap_getEncodedEnr"}' $BOOT_NODE_HOST | jq -r .result) + export BOOTSTRAP_NODES=$(curl -X POST -H "content-type: application/json" --data '{"method": "bootstrap_getEncodedEnr"}' $BOOT_NODE_HOST | jq -r .result) diff --git a/spartan/terraform/deploy-aztec-infra/values/rpc.yaml b/spartan/terraform/deploy-aztec-infra/values/rpc.yaml index 0a3ab05e68c6..4d23993dfff0 100644 --- a/spartan/terraform/deploy-aztec-infra/values/rpc.yaml +++ b/spartan/terraform/deploy-aztec-infra/values/rpc.yaml @@ -10,7 +10,7 @@ node: done echo "Boot node is ready!" - export BOOTSTRAP_NODES=$(curl -X POST --data '{"method": "bootstrap_getEncodedEnr"}' $BOOT_NODE_HOST | jq -r .result) + export BOOTSTRAP_NODES=$(curl -X POST -H "content-type: application/json" --data '{"method": "bootstrap_getEncodedEnr"}' $BOOT_NODE_HOST | jq -r .result) startCmd: - --node diff --git a/spartan/terraform/deploy-aztec-infra/values/validator.yaml b/spartan/terraform/deploy-aztec-infra/values/validator.yaml index 8852c9662fa0..ccd3d1120c25 100644 --- a/spartan/terraform/deploy-aztec-infra/values/validator.yaml +++ b/spartan/terraform/deploy-aztec-infra/values/validator.yaml @@ -10,7 +10,7 @@ validator: done echo "Boot node is ready!" - export BOOTSTRAP_NODES=$(curl -X POST --data '{"method": "bootstrap_getEncodedEnr"}' $BOOT_NODE_HOST | jq -r .result) + export BOOTSTRAP_NODES=$(curl -X POST -H "content-type: application/json" --data '{"method": "bootstrap_getEncodedEnr"}' $BOOT_NODE_HOST | jq -r .result) env: SPONSORED_FPC: true diff --git a/spartan/terraform/deploy-aztec-infra/variables.tf b/spartan/terraform/deploy-aztec-infra/variables.tf index 24a9b9353ebf..d848b3534e62 100644 --- a/spartan/terraform/deploy-aztec-infra/variables.tf +++ b/spartan/terraform/deploy-aztec-infra/variables.tf @@ -1,4 +1,4 @@ -variable "GCP_PROJECT" { +variable "GCP_PROJECT_ID" { description = "GCP project id" type = string default = "testnet-440309" @@ -49,12 +49,6 @@ variable "RPC_RESOURCE_PROFILE" { } } -variable "RPC_EXTERNAL_INGRESS" { - description = "Whether to use an external ingress for the rpc" - type = bool - default = false -} - variable "K8S_CLUSTER_CONTEXT" { description = "GKE cluster context" type = string @@ -79,12 +73,6 @@ variable "AZTEC_DOCKER_IMAGE" { default = "aztecprotocol/aztec:staging" } -variable "OTEL_COLLECTOR_URL" { - description = "The URL of an OpenTelemtry collector to send metrics to" - type = string - nullable = true -} - variable "VALIDATOR_VALUES" { description = "The values file to apply" type = string @@ -162,7 +150,7 @@ variable "VALIDATOR_MNEMONIC_START_INDEX" { variable "VALIDATORS_PER_NODE" { description = "The number of validators per node" type = string - default = 1 + default = 12 } variable "VALIDATOR_REPLICAS" { @@ -186,5 +174,89 @@ variable "PROVER_MNEMONIC_START_INDEX" { variable "OTEL_COLLECTOR_ENDPOINT" { description = "Optional OpenTelemetry collector endpoint URL (e.g., http://otel-collector:4318)" type = string - default = "" + default = null + nullable = true +} + +variable "SENTINEL_ENABLED" { + description = "Whether to enable sentinel" + type = string + default = true +} + +variable "SLASH_MIN_PENALTY_PERCENTAGE" { + description = "The slash min penalty percentage" + type = string + nullable = true +} + +variable "SLASH_MAX_PENALTY_PERCENTAGE" { + description = "The slash max penalty percentage" + type = string + nullable = true +} + +variable "SLASH_INACTIVITY_TARGET_PERCENTAGE" { + description = "The slash inactivity target percentage" + type = string + nullable = true +} + +variable "SLASH_INACTIVITY_PENALTY" { + description = "The slash inactivity penalty" + type = string + nullable = true +} + +variable "SLASH_PRUNE_PENALTY" { + description = "The slash prune penalty" + type = string + nullable = true +} + +variable "SLASH_DATA_WITHHOLDING_PENALTY" { + description = "The slash data withholding penalty" + type = string + nullable = true +} + +variable "SLASH_PROPOSE_INVALID_ATTESTATIONS_PENALTY" { + description = "The slash propose invalid attestations penalty" + type = string + default = 0.0 +} + +variable "SLASH_ATTEST_DESCENDANT_OF_INVALID_PENALTY" { + description = "The slash attest descendant of invalid penalty" + type = string + nullable = true +} + +variable "SLASH_UNKNOWN_PENALTY" { + description = "The slash unknown penalty" + type = string + nullable = true +} + +variable "SLASH_INVALID_BLOCK_PENALTY" { + description = "The slash invalid block penalty" + type = string + nullable = true +} + +variable "SLASH_OFFENSE_EXPIRATION_ROUNDS" { + description = "The slash offense expiration rounds" + type = string + nullable = true +} + +variable "SLASH_MAX_PAYLOAD_SIZE" { + description = "The slash max payload size" + type = string + nullable = true +} + +variable "PROVER_REAL_PROOFS" { + description = "Whether to enable prover real proofs" + type = string } diff --git a/spartan/terraform/deploy-chaos-mesh/main.tf b/spartan/terraform/deploy-chaos-mesh/main.tf new file mode 100644 index 000000000000..11fedfd52013 --- /dev/null +++ b/spartan/terraform/deploy-chaos-mesh/main.tf @@ -0,0 +1,47 @@ +terraform { + backend "local" {} + required_providers { + helm = { + source = "hashicorp/helm" + version = "~> 2.16.1" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.38.0" + } + } +} + +provider "kubernetes" { + alias = "gke-cluster" + config_path = "~/.kube/config" + config_context = var.K8S_CLUSTER_CONTEXT +} + +provider "helm" { + alias = "gke-cluster" + kubernetes { + config_path = "~/.kube/config" + config_context = var.K8S_CLUSTER_CONTEXT + } +} + +# Install Chaos Mesh via the local helm chart wrapper in spartan/chaos-mesh +resource "helm_release" "chaos_mesh" { + provider = helm.gke-cluster + name = var.RELEASE_NAME + namespace = var.CHAOS_MESH_NAMESPACE + create_namespace = true + repository = "../../" + chart = "chaos-mesh" + dependency_update = true + upgrade_install = true + force_update = true + recreate_pods = true + reuse_values = true + wait = true + wait_for_jobs = true + timeout = 600 +} + + diff --git a/spartan/terraform/deploy-chaos-mesh/variables.tf b/spartan/terraform/deploy-chaos-mesh/variables.tf new file mode 100644 index 000000000000..75255cb1f54e --- /dev/null +++ b/spartan/terraform/deploy-chaos-mesh/variables.tf @@ -0,0 +1,18 @@ +variable "K8S_CLUSTER_CONTEXT" { + description = "Kubernetes context to install into" + type = string +} + +variable "RELEASE_NAME" { + description = "Helm release name for Chaos Mesh" + type = string + default = "chaos" +} + +variable "CHAOS_MESH_NAMESPACE" { + description = "Namespace to install Chaos Mesh into" + type = string + default = "chaos-mesh" +} + + diff --git a/spartan/terraform/deploy-eth-devnet/main.tf b/spartan/terraform/deploy-eth-devnet/main.tf index 2bdc6bc77603..8471984bb539 100644 --- a/spartan/terraform/deploy-eth-devnet/main.tf +++ b/spartan/terraform/deploy-eth-devnet/main.tf @@ -10,10 +10,6 @@ terraform { source = "hashicorp/kubernetes" version = "~> 2.24.0" } - google = { - source = "hashicorp/google" - version = "~> 5.0" - } null = { source = "hashicorp/null" version = "~> 3.2" @@ -21,11 +17,6 @@ terraform { } } -provider "google" { - project = var.project - region = var.region -} - provider "kubernetes" { alias = "gke-cluster" config_path = "~/.kube/config" @@ -40,29 +31,6 @@ provider "helm" { } } - - -# Static IP addresses for eth-devnet services -resource "google_compute_address" "eth_execution_ip" { - count = var.CREATE_STATIC_IPS ? 1 : 0 - provider = google - name = "${var.NAMESPACE}-${var.RELEASE_PREFIX}-execution-ip" - address_type = "EXTERNAL" - region = var.region - - -} - -resource "google_compute_address" "eth_beacon_ip" { - count = var.CREATE_STATIC_IPS ? 1 : 0 - provider = google - name = "${var.NAMESPACE}-${var.RELEASE_PREFIX}-beacon-ip" - address_type = "EXTERNAL" - region = var.region - - -} - # Generate genesis files before deploying resource "null_resource" "generate_genesis" { triggers = { @@ -123,21 +91,9 @@ resource "helm_release" "eth_devnet" { value = var.MNEMONIC } - - dynamic "set" { - for_each = var.CREATE_STATIC_IPS ? [1] : [] - content { - name = "ethereum.execution.service.loadBalancerIP" - value = google_compute_address.eth_execution_ip[0].address - } - } - - dynamic "set" { - for_each = var.CREATE_STATIC_IPS ? [1] : [] - content { - name = "ethereum.beacon.service.loadBalancerIP" - value = google_compute_address.eth_beacon_ip[0].address - } + set { + name = "fullnameOverride" + value = var.RELEASE_PREFIX } timeout = 300 @@ -146,7 +102,6 @@ resource "helm_release" "eth_devnet" { } data "kubernetes_service" "eth_execution" { - count = var.CREATE_STATIC_IPS ? 0 : 1 provider = kubernetes.gke-cluster metadata { @@ -158,7 +113,6 @@ data "kubernetes_service" "eth_execution" { } data "kubernetes_service" "eth_beacon" { - count = var.CREATE_STATIC_IPS ? 0 : 1 provider = kubernetes.gke-cluster metadata { diff --git a/spartan/terraform/deploy-eth-devnet/outputs.tf b/spartan/terraform/deploy-eth-devnet/outputs.tf index f8fe04fe0e00..d520fc183dee 100644 --- a/spartan/terraform/deploy-eth-devnet/outputs.tf +++ b/spartan/terraform/deploy-eth-devnet/outputs.tf @@ -1,26 +1,26 @@ output "eth_execution_ip" { description = "IP address for Ethereum execution client (Static IP or Cluster IP)" - value = var.CREATE_STATIC_IPS ? google_compute_address.eth_execution_ip[0].address : data.kubernetes_service.eth_execution[0].spec[0].cluster_ip + value = data.kubernetes_service.eth_execution.spec[0].cluster_ip } output "eth_beacon_ip" { description = "IP address for Ethereum beacon client (Static IP or Cluster IP)" - value = var.CREATE_STATIC_IPS ? google_compute_address.eth_beacon_ip[0].address : data.kubernetes_service.eth_beacon[0].spec[0].cluster_ip + value = data.kubernetes_service.eth_beacon.spec[0].cluster_ip } output "eth_execution_rpc_url" { description = "Ethereum execution RPC URL" - value = var.CREATE_STATIC_IPS ? "http://${google_compute_address.eth_execution_ip[0].address}:8545" : "http://${data.kubernetes_service.eth_execution[0].spec[0].cluster_ip}:8545" + value = "http://${data.kubernetes_service.eth_execution.spec[0].cluster_ip}:8545" } output "eth_execution_ws_url" { description = "Ethereum execution WebSocket URL" - value = var.CREATE_STATIC_IPS ? "ws://${google_compute_address.eth_execution_ip[0].address}:8546" : "ws://${data.kubernetes_service.eth_execution[0].spec[0].cluster_ip}:8546" + value = "ws://${data.kubernetes_service.eth_execution.spec[0].cluster_ip}:8546" } output "eth_beacon_api_url" { description = "Ethereum beacon API URL" - value = var.CREATE_STATIC_IPS ? "http://${google_compute_address.eth_beacon_ip[0].address}:5052" : "http://${data.kubernetes_service.eth_beacon[0].spec[0].cluster_ip}:5052" + value = "http://${data.kubernetes_service.eth_beacon.spec[0].cluster_ip}:5052" } output "chain_id" { diff --git a/spartan/terraform/deploy-eth-devnet/variables.tf b/spartan/terraform/deploy-eth-devnet/variables.tf index bb774cf00a44..c4bbb887d26e 100644 --- a/spartan/terraform/deploy-eth-devnet/variables.tf +++ b/spartan/terraform/deploy-eth-devnet/variables.tf @@ -41,13 +41,6 @@ variable "MNEMONIC" { sensitive = true } - -variable "CREATE_STATIC_IPS" { - description = "Whether to create static IP addresses for eth-devnet services" - type = bool - default = true -} - variable "CHAIN_ID" { description = "Ethereum chain ID" type = number @@ -66,11 +59,6 @@ variable "GAS_LIMIT" { default = "1000000000" } -variable "MNEMONIC_SECRET_NAME" { - description = "Name of the Google Secret Manager secret containing the mnemonic" - type = string - default = "eth-devnet-genesis-mnemonic" -} variable "PREFUNDED_MNEMONIC_INDICES" { description = "Comma-separated list of mnemonic indices to prefund with ETH" diff --git a/spartan/terraform/deploy-rollup-contracts/main.tf b/spartan/terraform/deploy-rollup-contracts/main.tf index 4c2ebf07c616..65798243a573 100644 --- a/spartan/terraform/deploy-rollup-contracts/main.tf +++ b/spartan/terraform/deploy-rollup-contracts/main.tf @@ -4,7 +4,7 @@ terraform { required_providers { kubernetes = { source = "hashicorp/kubernetes" - version = "~> 2.24.0" + version = "~> 2.38.0" } } @@ -31,30 +31,31 @@ locals { var.REAL_VERIFIER ? ["--real-verifier"] : [] ) - # Environment variables for the container - env_vars = { - AZTEC_SLOT_DURATION = var.AZTEC_SLOT_DURATION - AZTEC_EPOCH_DURATION = var.AZTEC_EPOCH_DURATION - AZTEC_TARGET_COMMITTEE_SIZE = var.AZTEC_TARGET_COMMITTEE_SIZE - AZTEC_PROOF_SUBMISSION_EPOCHS = var.AZTEC_PROOF_SUBMISSION_EPOCHS - AZTEC_ACTIVATION_THRESHOLD = var.AZTEC_ACTIVATION_THRESHOLD - AZTEC_EJECTION_THRESHOLD = var.AZTEC_EJECTION_THRESHOLD - AZTEC_SLASHING_QUORUM = var.AZTEC_SLASHING_QUORUM - AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS = var.AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS - AZTEC_SLASHING_LIFETIME_IN_ROUNDS = var.AZTEC_SLASHING_LIFETIME_IN_ROUNDS - AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS = var.AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS - AZTEC_SLASHING_VETOER = var.AZTEC_SLASHING_VETOER - AZTEC_SLASHING_OFFSET_IN_ROUNDS = var.AZTEC_SLASHING_OFFSET_IN_ROUNDS - AZTEC_SLASH_AMOUNT_SMALL = var.AZTEC_SLASH_AMOUNT_SMALL - AZTEC_SLASH_AMOUNT_MEDIUM = var.AZTEC_SLASH_AMOUNT_MEDIUM - AZTEC_SLASH_AMOUNT_LARGE = var.AZTEC_SLASH_AMOUNT_LARGE - AZTEC_SLASHER_FLAVOR = var.AZTEC_SLASHER_FLAVOR - AZTEC_GOVERNANCE_PROPOSER_QUORUM = var.AZTEC_GOVERNANCE_PROPOSER_QUORUM - AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE = var.AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE - AZTEC_MANA_TARGET = var.AZTEC_MANA_TARGET - AZTEC_PROVING_COST_PER_MANA = var.AZTEC_PROVING_COST_PER_MANA - LOG_LEVEL = "debug" - } + # Environment variables for the container (omit keys with null values) + env_vars = { for k, v in { + AZTEC_SLOT_DURATION = var.AZTEC_SLOT_DURATION + AZTEC_EPOCH_DURATION = var.AZTEC_EPOCH_DURATION + AZTEC_TARGET_COMMITTEE_SIZE = var.AZTEC_TARGET_COMMITTEE_SIZE + AZTEC_PROOF_SUBMISSION_EPOCHS = var.AZTEC_PROOF_SUBMISSION_EPOCHS + AZTEC_ACTIVATION_THRESHOLD = var.AZTEC_ACTIVATION_THRESHOLD + AZTEC_EJECTION_THRESHOLD = var.AZTEC_EJECTION_THRESHOLD + AZTEC_SLASHING_QUORUM = var.AZTEC_SLASHING_QUORUM + AZTEC_SLASHING_ROUND_SIZE = var.AZTEC_SLASHING_ROUND_SIZE + AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS = var.AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS + AZTEC_SLASHING_LIFETIME_IN_ROUNDS = var.AZTEC_SLASHING_LIFETIME_IN_ROUNDS + AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS = var.AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS + AZTEC_SLASHING_VETOER = var.AZTEC_SLASHING_VETOER + AZTEC_SLASHING_OFFSET_IN_ROUNDS = var.AZTEC_SLASHING_OFFSET_IN_ROUNDS + AZTEC_SLASH_AMOUNT_SMALL = var.AZTEC_SLASH_AMOUNT_SMALL + AZTEC_SLASH_AMOUNT_MEDIUM = var.AZTEC_SLASH_AMOUNT_MEDIUM + AZTEC_SLASH_AMOUNT_LARGE = var.AZTEC_SLASH_AMOUNT_LARGE + AZTEC_SLASHER_FLAVOR = var.AZTEC_SLASHER_FLAVOR + AZTEC_GOVERNANCE_PROPOSER_QUORUM = var.AZTEC_GOVERNANCE_PROPOSER_QUORUM + AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE = var.AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE + AZTEC_MANA_TARGET = var.AZTEC_MANA_TARGET + AZTEC_PROVING_COST_PER_MANA = var.AZTEC_PROVING_COST_PER_MANA + LOG_LEVEL = "debug" + } : k => v if v != null } # Generate a unique job name with timestamp to avoid conflicts job_name = "${var.JOB_NAME}-${formatdate("YYYY-MM-DD-hhmm", timestamp())}" diff --git a/spartan/terraform/deploy-rollup-contracts/variables.tf b/spartan/terraform/deploy-rollup-contracts/variables.tf index 9ec9f4cc34ed..907f429ae2ad 100644 --- a/spartan/terraform/deploy-rollup-contracts/variables.tf +++ b/spartan/terraform/deploy-rollup-contracts/variables.tf @@ -47,114 +47,138 @@ variable "VALIDATORS" { variable "SPONSORED_FPC" { description = "Enable sponsored FPC" type = bool - default = false } variable "REAL_VERIFIER" { description = "Deploy real verifier" type = bool - default = false } # Environment variables for the deployment variable "AZTEC_SLOT_DURATION" { description = "Aztec slot duration" type = string + nullable = true } variable "AZTEC_EPOCH_DURATION" { description = "Aztec epoch duration" type = string + nullable = true } variable "AZTEC_TARGET_COMMITTEE_SIZE" { description = "Aztec target committee size" type = string + nullable = true } variable "AZTEC_PROOF_SUBMISSION_EPOCHS" { description = "Aztec proof submission epochs" type = string + nullable = true } variable "AZTEC_ACTIVATION_THRESHOLD" { description = "Aztec activation threshold" type = string + nullable = true } variable "AZTEC_EJECTION_THRESHOLD" { description = "Aztec ejection threshold" type = string + nullable = true } variable "AZTEC_SLASHING_QUORUM" { description = "Aztec slashing quorum" type = string + nullable = true +} + +variable "AZTEC_SLASHING_ROUND_SIZE" { + description = "Aztec slashing round size" + type = string + nullable = true } variable "AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS" { description = "Aztec slashing round size in epochs" type = string + nullable = true } variable "AZTEC_SLASHING_LIFETIME_IN_ROUNDS" { description = "Aztec slashing lifetime in rounds" type = string + nullable = true } variable "AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS" { description = "Aztec slashing execution delay in rounds" type = string + nullable = true } variable "AZTEC_SLASHING_VETOER" { description = "Aztec slashing vetoer address" type = string + nullable = true } variable "AZTEC_SLASHING_OFFSET_IN_ROUNDS" { description = "Aztec slashing offset in rounds" type = string + nullable = true } variable "AZTEC_SLASH_AMOUNT_SMALL" { description = "Small slashing amount for light offenses" type = string + nullable = true } variable "AZTEC_SLASH_AMOUNT_MEDIUM" { description = "Medium slashing amount for moderate offenses" type = string + nullable = true } variable "AZTEC_SLASH_AMOUNT_LARGE" { description = "Large slashing amount for severe offenses" type = string + nullable = true } variable "AZTEC_SLASHER_FLAVOR" { description = "Type of slasher proposer (empire, tally, or none)" type = string + nullable = true } variable "AZTEC_GOVERNANCE_PROPOSER_QUORUM" { description = "Aztec governance proposer quorum" type = string + nullable = true } variable "AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE" { description = "Aztec governance proposer round size" type = string + nullable = true } variable "AZTEC_MANA_TARGET" { description = "Aztec mana target" type = string + nullable = true } variable "AZTEC_PROVING_COST_PER_MANA" { description = "Aztec proving cost per mana" type = string + nullable = true } variable "JOB_NAME" { diff --git a/spartan/terraform/deploy-testnet/main.tf b/spartan/terraform/deploy-testnet/main.tf index bfc6808ce4ca..8574569af4fb 100644 --- a/spartan/terraform/deploy-testnet/main.tf +++ b/spartan/terraform/deploy-testnet/main.tf @@ -16,7 +16,7 @@ terraform { } provider "google" { - project = var.GCP_PROJECT + project = var.GCP_PROJECT_ID region = var.GCP_REGION } @@ -37,7 +37,7 @@ provider "helm" { module "secret-manager" { source = "GoogleCloudPlatform/secret-manager/google" version = "~> 0.8" - project_id = var.GCP_PROJECT + project_id = var.GCP_PROJECT_ID } data "terraform_remote_state" "metrics" { diff --git a/spartan/terraform/deploy-testnet/variables.tf b/spartan/terraform/deploy-testnet/variables.tf index 74a1b91e5e45..2d5139d3e3ca 100644 --- a/spartan/terraform/deploy-testnet/variables.tf +++ b/spartan/terraform/deploy-testnet/variables.tf @@ -1,4 +1,4 @@ -variable "GCP_PROJECT" { +variable "GCP_PROJECT_ID" { description = "GCP project id" type = string default = "testnet-440309" diff --git a/yarn-project/end-to-end/src/spartan/DEVELOP.md b/yarn-project/end-to-end/src/spartan/DEVELOP.md new file mode 100644 index 000000000000..ddadcbc62d75 --- /dev/null +++ b/yarn-project/end-to-end/src/spartan/DEVELOP.md @@ -0,0 +1,116 @@ +The flow is as follows: + +1. Install/start KIND locally +2. Bootstrap (to build an aztec image) +3. Load image into kind +4. Deploy networks +5. Run tests in `yarn-project/end-to-end/src/spartan` + +# Setup KIND + +KIND is a kubernetes cluster that runs locally out of docker containers. + +You can just + +```bash +spartan/bootstrap.sh kind +``` + +You only need to do that once. If you do it again, it will destroy the cluster and recreate it (which you almost never need to do). + +Now you’ll likely want some visibility into your cluster. You can + +```bash +spartan/scripts/create_k8s_dashboard.sh +``` + +And after ~30 seconds or so you can + +```bash +spartan/scripts/forward_k8s_dashboard.sh +``` + +That will run a port forward to your port `8443` . If you’re running in a remote environment (e.g. the mainframe), you’ll need to subsequently forward that back to your local machine. Cursor/VSCode have built in port forwarding (cmd/ctrl shift P, “forward”) + +Open the forwarded page, and copy/paste the token that was generated when you forwarded the dashboard. + +# Build an aztecprotocol:aztec image + +```bash +./bootstrap.sh +export AZTEC_DOCKER_IMAGE="aztecprotocol/aztec:$(docker images "aztecprotocol/aztec" --format json | \ + jq -r 'select(.Tag != "latest") | .Tag' | \ + head -1)" +kind load docker-image $AZTEC_DOCKER_IMAGE +``` + +If you just changed typescript, you can (after the initial bootstrap) + +```bash +./yarn-project/bootstrap.sh +./release-image/bootstrap.sh +export AZTEC_DOCKER_IMAGE="aztecprotocol/aztec:$(docker images "aztecprotocol/aztec" --format json | \ + jq -r 'select(.Tag != "latest") | .Tag' | \ + head -1)" +kind load docker-image $AZTEC_DOCKER_IMAGE +``` + +The export is important there. The `AZTEC_DOCKER_IMAGE` env var is used as both: + +- the container that runs the rollup contract deployment +- the containers for the aztec infrastructure (validators, provers, etc) + +# Deploy stuff + +```bash +./spartan/bootstrap.sh network_deploy scenario.local.env +``` + +That will take 1-3 minutes. But at the end you should have everything you need. + +You can (`k` is just an alias over `kubectl`) + +```bash +❯ k get pods -n scenario +NAME READY STATUS RESTARTS AGE +deploy-rollup-contracts-2025-08-31-1511-w2dlb 0/1 Completed 0 2m34s +scenario-eth-beacon-0 1/1 Running 0 39m +scenario-eth-execution-0 1/1 Running 0 39m +scenario-eth-validator-0 1/1 Running 0 39m +scenario-p2p-bootstrap-node-5cbf9658b9-6vd9b 1/1 Running 0 20m +scenario-prover-agent-59bd96899d-46k5s 1/1 Running 0 116s +scenario-prover-agent-59bd96899d-vzvkd 1/1 Running 0 116s +scenario-prover-broker-0 1/1 Running 0 116s +scenario-prover-node-0 1/1 Running 0 116s +scenario-rpc-aztec-node-0 1/1 Running 0 116s +scenario-validator-0 1/1 Running 0 116s +scenario-validator-1 1/1 Running 0 116s +scenario-validator-2 1/1 Running 0 116s +scenario-validator-3 1/1 Running 0 116s +``` + +For example, you can forward back the ethereum node with + +```bash + k port-forward -n scenario services/eth-devnet-eth-execution 8545:8545 +``` + +And then do whatever you like with it. + +# Run tests + +With the cluster running, you can now easily run tests. + +```bash +# run one +./spartan/bootstrap.sh single_test scenario.local.env spartan/smoke.test.ts + +# run all (serially) +./spartan/bootstrap.sh network_tests scenario.local.env +``` + +Right now, I recommend running the smoke test first, always, as it waits for the committee to exist. + +# Teardown + +You can just `k delete namespace scenario`. That will destroy everything in your kind cluster. To destroy the associated terraform state that was stored locally, just `./spartan/terraform/purge_local_state.sh`. diff --git a/yarn-project/end-to-end/src/spartan/smoke.test.ts b/yarn-project/end-to-end/src/spartan/smoke.test.ts index d7dcc630939b..4eb0f3600f5a 100644 --- a/yarn-project/end-to-end/src/spartan/smoke.test.ts +++ b/yarn-project/end-to-end/src/spartan/smoke.test.ts @@ -1,18 +1,25 @@ -import type { PXE } from '@aztec/aztec.js'; -import { RollupContract, getPublicClient } from '@aztec/ethereum'; +import { type PXE, retryUntil } from '@aztec/aztec.js'; +import { RollupContract, type ViemPublicClient, createEthereumChain } from '@aztec/ethereum'; import { createLogger } from '@aztec/foundation/log'; import type { ChildProcess } from 'child_process'; -import { foundry } from 'viem/chains'; +import { createPublicClient, fallback, http } from 'viem'; import { startCompatiblePXE } from './setup_test_wallets.js'; -import { setupEnvironment, startPortForwardForRPC } from './utils.js'; +import { + getGitProjectRoot, + installChaosMeshChart, + setupEnvironment, + startPortForwardForEthereum, + startPortForwardForRPC, +} from './utils.js'; const config = setupEnvironment(process.env); describe('smoke test', () => { const logger = createLogger('e2e:spartan-test:smoke'); let pxe: PXE; + let ethereumClient: ViemPublicClient; const forwardProcesses: ChildProcess[] = []; let cleanup: undefined | (() => Promise); @@ -23,10 +30,23 @@ describe('smoke test', () => { beforeAll(async () => { logger.info('Starting port forward for PXE'); - const { process, port } = await startPortForwardForRPC(config.NAMESPACE); - forwardProcesses.push(process); - const rpcUrl = `http://127.0.0.1:${port}`; - ({ pxe, cleanup } = await startCompatiblePXE(rpcUrl, config.AZTEC_REAL_PROOFS, logger)); + const { process: aztecRpcProcess, port: aztecRpcPort } = await startPortForwardForRPC(config.NAMESPACE); + const { process: ethereumProcess, port: ethereumPort } = await startPortForwardForEthereum(config.NAMESPACE); + forwardProcesses.push(aztecRpcProcess); + forwardProcesses.push(ethereumProcess); + const rpcUrl = `http://127.0.0.1:${aztecRpcPort}`; + + ({ pxe, cleanup } = await startCompatiblePXE(rpcUrl, config.REAL_VERIFIER, logger)); + // docs:start:get_node_info_pub_client + const nodeInfo = await pxe.getNodeInfo(); + + const ethereumUrl = `http://127.0.0.1:${ethereumPort}`; + const chain = createEthereumChain([ethereumUrl], nodeInfo.l1ChainId); + ethereumClient = createPublicClient({ + chain: chain.chainInfo, + transport: fallback([http(ethereumUrl)]), + }); + // docs:end:get_node_info_pub_client }); it('should be able to get node enr', async () => { @@ -34,34 +54,43 @@ describe('smoke test', () => { logger.info(`info: ${JSON.stringify(info)}`); expect(info).toBeDefined(); - // expect enr to be a string starting with 'enr:-' expect(info.enr).toMatch(/^enr:-/); }); - // Leaving this test skipped commented out because it requires the ethereum node - // to be running and forwarded, e.g. - // kubectl port-forward -n smoke service/spartan-aztec-network-eth-execution 8545:8545 - // also because it assumes foundry. + it( + 'should have a committee', + async () => { + const nodeInfo = await pxe.getNodeInfo(); + const rollup = new RollupContract(ethereumClient, nodeInfo.l1ContractAddresses.rollupAddress); + const epochDuration = await rollup.getEpochDuration(); + logger.info(`Epoch duration: ${epochDuration}`); + logger.info('Waiting for committee'); + await retryUntil( + async () => { + const slot = await rollup.getSlotNumber(); + logger.info(`Slot: ${slot}`); - it.skip('should be able to get rollup info', async () => { - // docs:start:get_node_info_pub_client - const info = await pxe.getNodeInfo(); - const publicClient = getPublicClient({ - l1RpcUrls: ['http://localhost:8545'], - l1ChainId: foundry.id, - }); - // docs:end:get_node_info_pub_client + const committee = await rollup.getCurrentEpochCommittee(); + return committee !== undefined; + }, + 'committee', + 60 * 60, // wait up to 1 hour, since if the rollup was just deployed there will be no committee for 2 epochs + 12, // 12 seconds between each check + ); + }, + 60 * 60 * 1000, + ); - const rollupContract = new RollupContract(publicClient, info.l1ContractAddresses.rollupAddress); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [pendingBlockNum, pendingArchive, provenBlockNum, provenArchive, myArchive, provenEpochNumber] = - await rollupContract.status(60n); - // console.log('pendingBlockNum', pendingBlockNum.toString()); - // console.log('pendingArchive', pendingArchive.toString()); - // console.log('provenBlockNum', provenBlockNum.toString()); - // console.log('provenArchive', provenArchive.toString()); - // console.log('myArchive', myArchive.toString()); - // console.log('provenEpochNumber', provenEpochNumber.toString()); + it('can add chaos', async () => { + const chaosValuesFile = process.env.CHAOS_SCENARIO_VALUES || 'prover-kill.yaml'; + const spartanDir = `${getGitProjectRoot()}/spartan`; + logger.info(`Applying Chaos Mesh scenario: ${chaosValuesFile}`); + await installChaosMeshChart({ + instanceName: 'smoke-chaos', + targetNamespace: config.NAMESPACE, + valuesFile: chaosValuesFile, + helmChartDir: `${spartanDir}/aztec-chaos-scenarios`, + logger, + }); }); }); diff --git a/yarn-project/end-to-end/src/spartan/transfer.test.ts b/yarn-project/end-to-end/src/spartan/transfer.test.ts index 87dc1e9a096f..cc74109b0c56 100644 --- a/yarn-project/end-to-end/src/spartan/transfer.test.ts +++ b/yarn-project/end-to-end/src/spartan/transfer.test.ts @@ -34,7 +34,7 @@ describe('token transfer test', () => { forwardProcesses.push(process); const rpcUrl = `http://127.0.0.1:${port}`; - ({ pxe, cleanup } = await startCompatiblePXE(rpcUrl, config.AZTEC_REAL_PROOFS, logger)); + ({ pxe, cleanup } = await startCompatiblePXE(rpcUrl, config.REAL_VERIFIER, logger)); testWallets = await deploySponsoredTestWallets(pxe, MINT_AMOUNT, logger); expect(ROUNDS).toBeLessThanOrEqual(MINT_AMOUNT); }); diff --git a/yarn-project/end-to-end/src/spartan/utils.ts b/yarn-project/end-to-end/src/spartan/utils.ts index 58241dc60e75..fd13cb28194c 100644 --- a/yarn-project/end-to-end/src/spartan/utils.ts +++ b/yarn-project/end-to-end/src/spartan/utils.ts @@ -9,31 +9,19 @@ import path from 'path'; import { promisify } from 'util'; import { z } from 'zod'; -export const RPC_SERVICE_NAME = 'services/aztec-infra-rpc-aztec-node'; - const execAsync = promisify(exec); const logger = createLogger('e2e:k8s-utils'); const testConfigSchema = z.object({ - NAMESPACE: z.string().min(1, 'NAMESPACE env variable must be set'), - L1_ACCOUNT_MNEMONIC: z.string().default('test test test test test test test test test test test junk'), - K8S_CLUSTER: z.string().min(1, 'K8S_CLUSTER env variable must be set'), - REGION: z.string().optional(), - PROJECT_ID: z.string().optional(), - AZTEC_REAL_PROOFS: z.coerce.boolean().default(false), + NAMESPACE: z.string().default('scenario'), + REAL_VERIFIER: z.coerce.boolean().default(true), }); export type TestConfig = z.infer; export function setupEnvironment(env: unknown): TestConfig { - const config = testConfigSchema.parse(env); - - if (config.K8S_CLUSTER !== 'kind') { - const command = `gcloud container clusters get-credentials ${config.K8S_CLUSTER} --region=${config.REGION} --project=${config.PROJECT_ID}`; - execSync(command); - } - return config; + return testConfigSchema.parse(env); } /** @@ -158,12 +146,20 @@ export async function startPortForward({ export function startPortForwardForRPC(namespace: string) { return startPortForward({ - resource: RPC_SERVICE_NAME, + resource: `services/${namespace}-rpc-aztec-node`, namespace, containerPort: 8080, }); } +export function startPortForwardForEthereum(namespace: string) { + return startPortForward({ + resource: `services/${namespace}-eth-execution`, + namespace, + containerPort: 8545, + }); +} + export async function deleteResourceByName({ resource, namespace, @@ -188,13 +184,17 @@ export async function deleteResourceByLabel({ namespace, label, timeout = '5m', + force = false, }: { resource: string; namespace: string; label: string; timeout?: string; + force?: boolean; }) { - const command = `kubectl delete ${resource} -l ${label} -n ${namespace} --ignore-not-found=true --wait=true --timeout=${timeout}`; + const command = `kubectl delete ${resource} -l ${label} -n ${namespace} --ignore-not-found=true --wait=true --timeout=${timeout} ${ + force ? '--force' : '' + }`; logger.info(`command: ${command}`); const { stdout } = await execAsync(command); return stdout; @@ -306,13 +306,13 @@ export async function installChaosMeshChart({ const deleteArgs = { resource: 'podchaos', namespace: chaosMeshNamespace, - name: `${targetNamespace}-${instanceName}`, + label: `app.kubernetes.io/instance=${instanceName}`, }; logger.info(`Deleting podchaos resource`); - await deleteResourceByName(deleteArgs).catch(e => { + await deleteResourceByLabel(deleteArgs).catch(e => { logger.error(`Error deleting podchaos resource: ${e}`); logger.info(`Force deleting podchaos resource`); - return deleteResourceByName({ ...deleteArgs, force: true }); + return deleteResourceByLabel({ ...deleteArgs, force: true }); }); } diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index 85bac442cf8c..29d1a4cc0f74 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -844,19 +844,51 @@ export const addMultipleValidators = async ( logger.info(`Adding ${validators.length} validators to the rollup`); - await deployer.l1TxUtils.sendAndMonitorTransaction( - { - to: multiAdder.toString(), - data: encodeFunctionData({ - abi: MultiAdderArtifact.contractAbi, - functionName: 'addValidators', - args: [validatorsTuples], - }), - }, - { - gasLimit: 45_000_000n, - }, - ); + // Adding to the queue and flushing need to be done in two transactions + // if we are adding many validators. + if (validatorsTuples.length > 10) { + await deployer.l1TxUtils.sendAndMonitorTransaction( + { + to: multiAdder.toString(), + data: encodeFunctionData({ + abi: MultiAdderArtifact.contractAbi, + functionName: 'addValidators', + args: [validatorsTuples, true], + }), + }, + { + gasLimit: 40_000_000n, + }, + ); + + await deployer.l1TxUtils.sendAndMonitorTransaction( + { + to: rollupAddress, + data: encodeFunctionData({ + abi: RollupArtifact.contractAbi, + functionName: 'flushEntryQueue', + args: [], + }), + }, + { + gasLimit: 40_000_000n, + }, + ); + } else { + await deployer.l1TxUtils.sendAndMonitorTransaction( + { + to: multiAdder.toString(), + data: encodeFunctionData({ + abi: MultiAdderArtifact.contractAbi, + functionName: 'addValidators', + args: [validatorsTuples, false], + }), + }, + { + gasLimit: 45_000_000n, + }, + ); + } const entryQueueLengthAfter = await rollup.getEntryQueueLength(); const validatorCountAfter = await rollup.getActiveAttesterCount(); @@ -933,6 +965,7 @@ export const deployL1Contracts = async ( txUtilsConfig: L1TxUtilsConfig = getL1TxUtilsConfigEnvVars(), createVerificationJson: string | false = false, ): Promise => { + logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`); validateConfig(args); const l1Client = createExtendedL1Client(rpcUrls, account, chain); diff --git a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh index 091c728dec18..c0d461040c70 100755 --- a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh +++ b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh @@ -51,7 +51,7 @@ contracts=( combined_errors_abi=$( jq -s ' .[0].abi + .[1].abi - | unique_by({type: .type, name: .name}) + | unique_by({type: .type, name: .name, inputs_len: (.inputs | length)}) ' \ ../../l1-contracts/out/Errors.sol/Errors.json \ ../../l1-contracts/out/libraries/Errors.sol/Errors.json @@ -92,7 +92,7 @@ for contract_name in "${contracts[@]}"; do # Just merging it into all, it is not the cleanest, but it does the job. jq -j --argjson errs "$combined_errors_abi" ' .abi + $errs - | unique_by({type: .type, name: .name}) + | unique_by({type: .type, name: .name, inputs_len: (.inputs | length)}) ' \ "../../l1-contracts/out/${contract_name}.sol/${contract_name}.json" echo " as const;"