From 8d9947d3584b2596d7d4e0d75e8534efc9fab7a4 Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Tue, 3 Sep 2024 10:56:29 -0400 Subject: [PATCH] feat: sequencer selection in k8s tests (#8313) Update the k8s e2e tests to use proper validators. --- .../files/config/config-prover-env.sh | 34 ++++ .../files/config/config-validator-env.sh | 48 ++++++ .../aztec-network/templates/_helpers.tpl | 14 +- .../templates/anvil.deployment.yaml | 23 ++- .../configure-validator-env.config-map.yaml | 38 ----- .../templates/deploy-l2-contracts.job.yaml | 2 + .../templates/prover-node.stateful-set.yaml | 17 +- .../templates/validator.stateful-set.yaml | 15 +- helm-charts/aztec-network/values.yaml | 6 +- .../aztec-network/values/3-validators.yaml | 3 +- yarn-project/Earthfile | 2 +- .../aztec.js/src/utils/cheat_codes.ts | 13 ++ yarn-project/cli/src/cmds/l1/index.ts | 87 ++++++++++ .../cli/src/cmds/l1/update_l1_validators.ts | 153 ++++++++++++++++++ yarn-project/ethereum/src/index.ts | 2 +- .../src/publisher/l1-publisher.ts | 1 + .../src/sequencer/sequencer.ts | 1 + 17 files changed, 397 insertions(+), 62 deletions(-) create mode 100644 helm-charts/aztec-network/files/config/config-prover-env.sh create mode 100644 helm-charts/aztec-network/files/config/config-validator-env.sh delete mode 100644 helm-charts/aztec-network/templates/configure-validator-env.config-map.yaml create mode 100644 yarn-project/cli/src/cmds/l1/update_l1_validators.ts diff --git a/helm-charts/aztec-network/files/config/config-prover-env.sh b/helm-charts/aztec-network/files/config/config-prover-env.sh new file mode 100644 index 00000000000..a4bd508a111 --- /dev/null +++ b/helm-charts/aztec-network/files/config/config-prover-env.sh @@ -0,0 +1,34 @@ +#!/bin/sh +set -e + +alias aztec='node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js' + +# Pass the bootnode url as an argument +# Ask the bootnode for l1 contract addresses +output=$(aztec get-node-info -u $1) + +echo "$output" + +boot_node_enr=$(echo "$output" | grep -oP 'Node ENR: \Kenr:[a-zA-Z0-9\-\_\.]+') +rollup_address=$(echo "$output" | grep -oP 'Rollup Address: \K0x[a-fA-F0-9]{40}') +registry_address=$(echo "$output" | grep -oP 'Registry Address: \K0x[a-fA-F0-9]{40}') +inbox_address=$(echo "$output" | grep -oP 'L1 -> L2 Inbox Address: \K0x[a-fA-F0-9]{40}') +outbox_address=$(echo "$output" | grep -oP 'L2 -> L1 Outbox Address: \K0x[a-fA-F0-9]{40}') +availability_oracle_address=$(echo "$output" | grep -oP 'Availability Oracle Address: \K0x[a-fA-F0-9]{40}') +fee_juice_address=$(echo "$output" | grep -oP 'Fee Juice Address: \K0x[a-fA-F0-9]{40}') +fee_juice_portal_address=$(echo "$output" | grep -oP 'Fee Juice Portal Address: \K0x[a-fA-F0-9]{40}') + + +# Write the addresses to a file in the shared volume +cat < /shared/contracts.env +export BOOTSTRAP_NODES=$boot_node_enr +export ROLLUP_CONTRACT_ADDRESS=$rollup_address +export REGISTRY_CONTRACT_ADDRESS=$registry_address +export INBOX_CONTRACT_ADDRESS=$inbox_address +export OUTBOX_CONTRACT_ADDRESS=$outbox_address +export AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$availability_oracle_address +export FEE_JUICE_CONTRACT_ADDRESS=$fee_juice_address +export FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$fee_juice_portal_address +EOF + +cat /shared/contracts.env \ No newline at end of file diff --git a/helm-charts/aztec-network/files/config/config-validator-env.sh b/helm-charts/aztec-network/files/config/config-validator-env.sh new file mode 100644 index 00000000000..e2b29694bc7 --- /dev/null +++ b/helm-charts/aztec-network/files/config/config-validator-env.sh @@ -0,0 +1,48 @@ +#!/bin/sh +set -e + +alias aztec='node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js' + +# Pass the bootnode url as an argument +# Ask the bootnode for l1 contract addresses +output=$(aztec get-node-info -u $1) + +echo "$output" + +boot_node_enr=$(echo "$output" | grep -oP 'Node ENR: \Kenr:[a-zA-Z0-9\-\_\.]+') +rollup_address=$(echo "$output" | grep -oP 'Rollup Address: \K0x[a-fA-F0-9]{40}') +registry_address=$(echo "$output" | grep -oP 'Registry Address: \K0x[a-fA-F0-9]{40}') +inbox_address=$(echo "$output" | grep -oP 'L1 -> L2 Inbox Address: \K0x[a-fA-F0-9]{40}') +outbox_address=$(echo "$output" | grep -oP 'L2 -> L1 Outbox Address: \K0x[a-fA-F0-9]{40}') +availability_oracle_address=$(echo "$output" | grep -oP 'Availability Oracle Address: \K0x[a-fA-F0-9]{40}') +fee_juice_address=$(echo "$output" | grep -oP 'Fee Juice Address: \K0x[a-fA-F0-9]{40}') +fee_juice_portal_address=$(echo "$output" | grep -oP 'Fee Juice Portal Address: \K0x[a-fA-F0-9]{40}') + +# Generate a private key for the validator +json_account=$(aztec generate-l1-account) + +echo "$json_account" +address=$(echo $json_account | jq -r '.address') +private_key=$(echo $json_account | jq -r '.privateKey') + +aztec add-l1-validator --validator $address --rollup $rollup_address + +aztec fast-forward-epochs --rollup $rollup_address --count 1 + + +# Write the addresses to a file in the shared volume +cat < /shared/contracts.env +export BOOTSTRAP_NODES=$boot_node_enr +export ROLLUP_CONTRACT_ADDRESS=$rollup_address +export REGISTRY_CONTRACT_ADDRESS=$registry_address +export INBOX_CONTRACT_ADDRESS=$inbox_address +export OUTBOX_CONTRACT_ADDRESS=$outbox_address +export AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$availability_oracle_address +export FEE_JUICE_CONTRACT_ADDRESS=$fee_juice_address +export FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$fee_juice_portal_address +export VALIDATOR_PRIVATE_KEY=$private_key +export L1_PRIVATE_KEY=$private_key +export SEQ_PUBLISHER_PRIVATE_KEY=$private_key +EOF + +cat /shared/contracts.env \ No newline at end of file diff --git a/helm-charts/aztec-network/templates/_helpers.tpl b/helm-charts/aztec-network/templates/_helpers.tpl index dea62e55f6d..632b4614882 100644 --- a/helm-charts/aztec-network/templates/_helpers.tpl +++ b/helm-charts/aztec-network/templates/_helpers.tpl @@ -76,4 +76,16 @@ http://{{ include "aztec-network.fullname" . }}-metrics.{{ .Release.Namespace }} - +{{- define "helpers.flag" -}} +{{- $name := index . 0 -}} +{{- $value := index . 1 -}} +{{- if $value -}} + {{- if kindIs "string" $value -}} + {{- if ne $value "" -}} +--{{ $name }} {{ $value }} + {{- end -}} + {{- else -}} +--{{ $name }} {{ $value }} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/helm-charts/aztec-network/templates/anvil.deployment.yaml b/helm-charts/aztec-network/templates/anvil.deployment.yaml index 05917e1ad36..3894ee5607e 100644 --- a/helm-charts/aztec-network/templates/anvil.deployment.yaml +++ b/helm-charts/aztec-network/templates/anvil.deployment.yaml @@ -22,23 +22,18 @@ spec: imagePullPolicy: {{ .Values.images.foundry.pullPolicy }} command: ["/bin/sh", "-c"] args: - - | - [ -n "$FORK_URL" ] && ARGS="$ARGS --fork-url $FORK_URL"; - [ -n "$FORK_BLOCK_NUMBER" ] && ARGS="$ARGS --fork-block-number $FORK_BLOCK_NUMBER"; - echo anvil --block-time 12 -p $ANVIL_PORT --host 0.0.0.0 --chain-id {{ .Values.ethereum.chainId }} $ARGS; - anvil --block-time 12 -p $ANVIL_PORT --host 0.0.0.0 --chain-id {{ .Values.ethereum.chainId }} $ARGS; + - >- + anvil + --host 0.0.0.0 + {{ include "helpers.flag" (list "block-time" .Values.ethereum.blockTime) }} + {{ include "helpers.flag" (list "chain-id" .Values.ethereum.chainId) }} + {{ include "helpers.flag" (list "gas-limit" .Values.ethereum.gasLimit) }} + {{ include "helpers.flag" (list "fork-url" .Values.ethereum.forkUrl) }} + {{ include "helpers.flag" (list "fork-block-number" .Values.ethereum.forkBlockNumber) }} + -p {{ .Values.ethereum.service.port }} ports: - containerPort: {{ .Values.ethereum.service.port }} name: anvil - env: - - name: FORK_URL - value: {{ .Values.ethereum.forkUrl | quote }} - - name: FORK_BLOCK_NUMBER - value: {{ .Values.ethereum.forkBlockNumber | quote }} - - name: ANVIL_PORT - value: {{ .Values.ethereum.service.port | quote }} - - name: ARGS - value: {{ .Values.ethereum.args | quote }} readinessProbe: exec: command: diff --git a/helm-charts/aztec-network/templates/configure-validator-env.config-map.yaml b/helm-charts/aztec-network/templates/configure-validator-env.config-map.yaml deleted file mode 100644 index 47ddeba836c..00000000000 --- a/helm-charts/aztec-network/templates/configure-validator-env.config-map.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "aztec-network.fullname" . }}-configure-validator-env - labels: - {{- include "aztec-network.labels" . | nindent 4 }} -data: - configure-validator-env.sh: | - #!/bin/sh - set -e - - # Ask the bootnode for l1 contract addresses - output=$(node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js get-node-info -u {{ include "aztec-network.bootNodeUrl" . }}) - - echo "$output" - - boot_node_enr=$(echo "$output" | grep -oP 'Node ENR: \Kenr:[a-zA-Z0-9\-\_\.]+') - rollup_address=$(echo "$output" | grep -oP 'Rollup Address: \K0x[a-fA-F0-9]{40}') - registry_address=$(echo "$output" | grep -oP 'Registry Address: \K0x[a-fA-F0-9]{40}') - inbox_address=$(echo "$output" | grep -oP 'L1 -> L2 Inbox Address: \K0x[a-fA-F0-9]{40}') - outbox_address=$(echo "$output" | grep -oP 'L2 -> L1 Outbox Address: \K0x[a-fA-F0-9]{40}') - availability_oracle_address=$(echo "$output" | grep -oP 'Availability Oracle Address: \K0x[a-fA-F0-9]{40}') - fee_juice_address=$(echo "$output" | grep -oP 'Fee Juice Address: \K0x[a-fA-F0-9]{40}') - fee_juice_portal_address=$(echo "$output" | grep -oP 'Fee Juice Portal Address: \K0x[a-fA-F0-9]{40}') - - # Write the addresses to a file in the shared volume - cat < /shared/contracts.env - export BOOTSTRAP_NODES=$boot_node_enr - export ROLLUP_CONTRACT_ADDRESS=$rollup_address - export REGISTRY_CONTRACT_ADDRESS=$registry_address - export INBOX_CONTRACT_ADDRESS=$inbox_address - export OUTBOX_CONTRACT_ADDRESS=$outbox_address - export AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$availability_oracle_address - export FEE_JUICE_CONTRACT_ADDRESS=$fee_juice_address - export FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$fee_juice_portal_address - EOF - - cat /shared/contracts.env \ No newline at end of file diff --git a/helm-charts/aztec-network/templates/deploy-l2-contracts.job.yaml b/helm-charts/aztec-network/templates/deploy-l2-contracts.job.yaml index 56f2dd3b998..aeb84cc4eae 100644 --- a/helm-charts/aztec-network/templates/deploy-l2-contracts.job.yaml +++ b/helm-charts/aztec-network/templates/deploy-l2-contracts.job.yaml @@ -26,7 +26,9 @@ spec: sleep 5 done echo "PXE service is ready!" + set -e node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js deploy-protocol-contracts + echo "Deployed L2 contracts" env: - name: PXE_URL value: {{ include "aztec-network.pxeUrl" . | quote }} diff --git a/helm-charts/aztec-network/templates/prover-node.stateful-set.yaml b/helm-charts/aztec-network/templates/prover-node.stateful-set.yaml index 79a2da1f581..a1804ac40d9 100644 --- a/helm-charts/aztec-network/templates/prover-node.stateful-set.yaml +++ b/helm-charts/aztec-network/templates/prover-node.stateful-set.yaml @@ -18,13 +18,13 @@ spec: app: prover-node spec: initContainers: - - name: configure-validator-env + - name: configure-prover-env image: "{{ .Values.images.aztec.image }}" imagePullPolicy: {{ .Values.images.aztec.pullPolicy }} command: - "/bin/sh" - "-c" - - "cp /scripts/configure-validator-env.sh /tmp/configure-validator-env.sh && chmod +x /tmp/configure-validator-env.sh && /tmp/configure-validator-env.sh" + - "cp /scripts/configure-prover-env.sh /tmp/configure-prover-env.sh && chmod +x /tmp/configure-prover-env.sh && /tmp/configure-prover-env.sh {{ include "aztec-network.bootNodeUrl" . }}" volumeMounts: - name: shared-volume mountPath: /shared @@ -84,4 +84,15 @@ spec: emptyDir: {} - name: scripts configMap: - name: {{ include "aztec-network.fullname" . }}-configure-validator-env \ No newline at end of file + name: {{ include "aztec-network.fullname" . }}-configure-prover-env + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "aztec-network.fullname" . }}-configure-prover-env + labels: + {{- include "aztec-network.labels" . | nindent 4 }} +data: + configure-prover-env.sh: | + {{ .Files.Get "files/config/config-prover-env.sh" | nindent 4 }} diff --git a/helm-charts/aztec-network/templates/validator.stateful-set.yaml b/helm-charts/aztec-network/templates/validator.stateful-set.yaml index 99ab91363e5..fec535503c3 100644 --- a/helm-charts/aztec-network/templates/validator.stateful-set.yaml +++ b/helm-charts/aztec-network/templates/validator.stateful-set.yaml @@ -24,7 +24,7 @@ spec: command: - "/bin/sh" - "-c" - - "cp /scripts/configure-validator-env.sh /tmp/configure-validator-env.sh && chmod +x /tmp/configure-validator-env.sh && /tmp/configure-validator-env.sh" + - "cp /scripts/configure-validator-env.sh /tmp/configure-validator-env.sh && chmod +x /tmp/configure-validator-env.sh && /tmp/configure-validator-env.sh {{ include "aztec-network.bootNodeUrl" . }}" volumeMounts: - name: shared-volume mountPath: /shared @@ -93,4 +93,15 @@ spec: emptyDir: {} - name: scripts configMap: - name: {{ include "aztec-network.fullname" . }}-configure-validator-env \ No newline at end of file + name: {{ include "aztec-network.fullname" . }}-configure-validator-env + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "aztec-network.fullname" . }}-configure-validator-env + labels: + {{- include "aztec-network.labels" . | nindent 4 }} +data: + configure-validator-env.sh: | + {{ .Files.Get "files/config/config-validator-env.sh" | nindent 4 }} diff --git a/helm-charts/aztec-network/values.yaml b/helm-charts/aztec-network/values.yaml index afad21361c4..13acf19ddbe 100644 --- a/helm-charts/aztec-network/values.yaml +++ b/helm-charts/aztec-network/values.yaml @@ -9,7 +9,7 @@ images: image: curlimages/curl:7.81.0 pullPolicy: IfNotPresent foundry: - image: ghcr.io/foundry-rs/foundry@sha256:29ba6e34379e79c342ec02d437beb7929c9e254261e8032b17e187be71a2609f + image: ghcr.io/foundry-rs/foundry@sha256:ce4b236f6760fdeb08e82267c9fa17647d29a374760bfe7ee01998fb8c0aaad7 pullPolicy: IfNotPresent otelCollector: image: otel/opentelemetry-collector-contrib @@ -83,6 +83,10 @@ pxe: ethereum: replicas: 1 chainId: 31337 + blockTime: 12 + # 1 billion gas limit + # helps ensure we can deploy public contracts + gasLimit: "1000000000" forkUrl: "" forkBlockNumber: "" args: "" diff --git a/helm-charts/aztec-network/values/3-validators.yaml b/helm-charts/aztec-network/values/3-validators.yaml index eeef1a6136e..54c33daf0c4 100644 --- a/helm-charts/aztec-network/values/3-validators.yaml +++ b/helm-charts/aztec-network/values/3-validators.yaml @@ -1,8 +1,9 @@ validator: + debug: "aztec:*,-aztec:avm_simulator:*,-aztec:libp2p_service" replicas: 3 validator: disabled: false bootNode: validator: - disabled: false + disabled: true diff --git a/yarn-project/Earthfile b/yarn-project/Earthfile index a9b151cd7ec..0098093957e 100644 --- a/yarn-project/Earthfile +++ b/yarn-project/Earthfile @@ -150,7 +150,7 @@ aztec-prod: aztec: FROM ubuntu:noble - RUN apt update && apt install nodejs curl -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + RUN apt update && apt install nodejs curl jq -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* COPY +aztec-prod/usr/src /usr/src ENV BB_WORKING_DIRECTORY=/usr/src/bb ENV BB_BINARY_PATH=/usr/src/barretenberg/cpp/build/bin/bb diff --git a/yarn-project/aztec.js/src/utils/cheat_codes.ts b/yarn-project/aztec.js/src/utils/cheat_codes.ts index 83266fd6275..95d8d4710b3 100644 --- a/yarn-project/aztec.js/src/utils/cheat_codes.ts +++ b/yarn-project/aztec.js/src/utils/cheat_codes.ts @@ -94,6 +94,19 @@ export class EthCheatCodes { this.logger.info(`Mined ${numberOfBlocks} blocks`); } + /** + * Set the balance of an account + * @param account - The account to set the balance for + * @param balance - The balance to set + */ + public async setBalance(account: EthAddress, balance: bigint): Promise { + const res = await this.rpcCall('anvil_setBalance', [account.toString(), toHex(balance)]); + if (res.error) { + throw new Error(`Error setting balance for ${account}: ${res.error.message}`); + } + this.logger.info(`Set balance for ${account} to ${balance}`); + } + /** * Set the interval between blocks (block time) * @param interval - The interval to use between blocks diff --git a/yarn-project/cli/src/cmds/l1/index.ts b/yarn-project/cli/src/cmds/l1/index.ts index f3ca73f3683..50dfa071e2e 100644 --- a/yarn-project/cli/src/cmds/l1/index.ts +++ b/yarn-project/cli/src/cmds/l1/index.ts @@ -46,6 +46,93 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: DebugL ); }); + program + .command('generate-l1-account') + .description('Generates a new private key for an account on L1.') + .option('--json', 'Output the private key in JSON format') + .action(async () => { + const { generateL1Account } = await import('./update_l1_validators.js'); + const account = generateL1Account(); + log(JSON.stringify(account, null, 2)); + }); + + program + .command('add-l1-validator') + .description('Adds a validator to the L1 rollup contract.') + .requiredOption( + '-u, --rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .option('-pk, --private-key ', 'The private key to use for deployment', PRIVATE_KEY) + .option( + '-m, --mnemonic ', + 'The mnemonic to use in deployment', + 'test test test test test test test test test test test junk', + ) + .addOption(l1ChainIdOption) + .option('--validator ', 'ethereum address of the validator', parseEthereumAddress) + .option('--rollup
', 'ethereum address of the rollup contract', parseEthereumAddress) + .action(async options => { + const { addL1Validator } = await import('./update_l1_validators.js'); + await addL1Validator({ + rpcUrl: options.rpcUrl, + chainId: options.l1ChainId, + privateKey: options.privateKey, + mnemonic: options.mnemonic, + validatorAddress: options.validator, + rollupAddress: options.rollup, + log, + debugLogger, + }); + }); + + program + .command('fast-forward-epochs') + .description('Fast forwards the epoch of the L1 rollup contract.') + .requiredOption( + '-u, --rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .addOption(l1ChainIdOption) + .option('--rollup
', 'ethereum address of the rollup contract', parseEthereumAddress) + .option('--count ', 'The number of epochs to fast forward', arg => BigInt(parseInt(arg)), 1n) + .action(async options => { + const { fastForwardEpochs } = await import('./update_l1_validators.js'); + await fastForwardEpochs({ + rpcUrl: options.rpcUrl, + chainId: options.l1ChainId, + rollupAddress: options.rollup, + numEpochs: options.count, + log, + debugLogger, + }); + }); + + program + .command('debug-rollup') + .description('Debugs the rollup contract.') + .requiredOption( + '-u, --rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .addOption(l1ChainIdOption) + .option('--rollup
', 'ethereum address of the rollup contract', parseEthereumAddress) + .action(async options => { + const { debugRollup } = await import('./update_l1_validators.js'); + await debugRollup({ + rpcUrl: options.rpcUrl, + chainId: options.l1ChainId, + privateKey: options.privateKey, + mnemonic: options.mnemonic, + rollupAddress: options.rollup, + log, + debugLogger, + }); + }); + program .command('deploy-l1-verifier') .description('Deploys the rollup verifier contract') diff --git a/yarn-project/cli/src/cmds/l1/update_l1_validators.ts b/yarn-project/cli/src/cmds/l1/update_l1_validators.ts new file mode 100644 index 00000000000..a230ed32b3b --- /dev/null +++ b/yarn-project/cli/src/cmds/l1/update_l1_validators.ts @@ -0,0 +1,153 @@ +import { EthCheatCodes } from '@aztec/aztec.js'; +import { ETHEREUM_SLOT_DURATION, type EthAddress } from '@aztec/circuits.js'; +import { createEthereumChain } from '@aztec/ethereum'; +import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; +import { RollupAbi } from '@aztec/l1-artifacts'; + +import { createPublicClient, createWalletClient, getContract, http } from 'viem'; +import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts'; + +export interface RollupCommandArgs { + rpcUrl: string; + chainId: number; + privateKey?: string; + mnemonic?: string; + rollupAddress: EthAddress; +} + +export interface LoggerArgs { + log: LogFn; + debugLogger: DebugLogger; +} + +export function generateL1Account() { + const privateKey = generatePrivateKey(); + const account = privateKeyToAccount(privateKey); + account.address; + return { + privateKey, + address: account.address, + }; +} + +export async function addL1Validator({ + rpcUrl, + chainId, + privateKey, + mnemonic, + validatorAddress, + rollupAddress, + log, + debugLogger, +}: RollupCommandArgs & LoggerArgs & { validatorAddress: EthAddress }) { + const dualLog = makeDualLog(log, debugLogger); + const publicClient = getPublicClient(rpcUrl, chainId); + const walletClient = getWalletClient(rpcUrl, chainId, privateKey, mnemonic); + const rollup = getContract({ + address: rollupAddress.toString(), + abi: RollupAbi, + client: walletClient, + }); + + dualLog(`Adding validator ${validatorAddress.toString()} to rollup ${rollupAddress.toString()}`); + const txHash = await rollup.write.addValidator([validatorAddress.toString()]); + dualLog(`Transaction hash: ${txHash}`); + await publicClient.waitForTransactionReceipt({ hash: txHash }); + dualLog(`Funding validator on L1`); + const cheatCodes = new EthCheatCodes(rpcUrl, debugLogger); + await cheatCodes.setBalance(validatorAddress, 10n ** 20n); +} + +export async function fastForwardEpochs({ + rpcUrl, + chainId, + rollupAddress, + numEpochs, + log, + debugLogger, +}: RollupCommandArgs & LoggerArgs & { numEpochs: bigint }) { + const dualLog = makeDualLog(log, debugLogger); + const publicClient = getPublicClient(rpcUrl, chainId); + const rollup = getContract({ + address: rollupAddress.toString(), + abi: RollupAbi, + client: publicClient, + }); + + const cheatCodes = new EthCheatCodes(rpcUrl, debugLogger); + const currentSlot = await rollup.read.getCurrentSlot(); + const l2SlotsInEpoch = await rollup.read.EPOCH_DURATION(); + const timestamp = await rollup.read.getTimestampForSlot([currentSlot + l2SlotsInEpoch * numEpochs]); + dualLog(`Fast forwarding ${numEpochs} epochs to ${timestamp}`); + try { + await cheatCodes.warp(Number(timestamp)); + dualLog(`Fast forwarded ${numEpochs} epochs to ${timestamp}`); + } catch (error) { + if (error instanceof Error && error.message.includes("is lower than or equal to previous block's timestamp")) { + dualLog(`Someone else fast forwarded the chain to a point after/equal to the target time`); + } else { + // Re-throw other errors + throw error; + } + } +} + +export async function debugRollup({ rpcUrl, chainId, rollupAddress, log }: RollupCommandArgs & LoggerArgs) { + const publicClient = getPublicClient(rpcUrl, chainId); + const rollup = getContract({ + address: rollupAddress.toString(), + abi: RollupAbi, + client: publicClient, + }); + + const pendingCount = await rollup.read.pendingBlockCount(); + log(`Pending block count: ${pendingCount}`); + const provenCount = await rollup.read.provenBlockCount(); + log(`Proven block count: ${provenCount}`); + const validators = await rollup.read.getValidators(); + log(`Validators: ${validators.map(v => v.toString()).join(', ')}`); + const committee = await rollup.read.getCurrentEpochCommittee(); + log(`Committee: ${committee.map(v => v.toString()).join(', ')}`); + const archive = await rollup.read.archive(); + log(`Archive: ${archive}`); + const epochNum = await rollup.read.getCurrentEpoch(); + log(`Current epoch: ${epochNum}`); + const epoch = await rollup.read.epochs([epochNum]); + log(`Epoch Sample Seed: ${epoch[0].toString()}, Next Seed: ${epoch[1].toString()}`); + const slot = await rollup.read.getCurrentSlot(); + log(`Current slot: ${slot}`); + const proposerDuringPrevL1Block = await rollup.read.getCurrentProposer(); + log(`Proposer during previous L1 block: ${proposerDuringPrevL1Block}`); + const nextBlockTS = BigInt((await publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION)); + const proposer = await rollup.read.getProposerAt([nextBlockTS]); + log(`Proposer NOW: ${proposer.toString()}`); +} + +function makeDualLog(log: LogFn, debugLogger: DebugLogger) { + return (msg: string) => { + log(msg); + debugLogger.info(msg); + }; +} + +function getPublicClient(rpcUrl: string, chainId: number) { + const chain = createEthereumChain(rpcUrl, chainId); + return createPublicClient({ chain: chain.chainInfo, transport: http(rpcUrl) }); +} + +function getWalletClient( + rpcUrl: string, + chainId: number, + privateKey: string | undefined, + mnemonic: string | undefined, +) { + if (!privateKey && !mnemonic) { + throw new Error('Either privateKey or mnemonic must be provided to create a wallet client'); + } + + const chain = createEthereumChain(rpcUrl, chainId); + const account = !privateKey + ? mnemonicToAccount(mnemonic!) + : privateKeyToAccount(`${privateKey.startsWith('0x') ? '' : '0x'}${privateKey}` as `0x${string}`); + return createWalletClient({ account, chain: chain.chainInfo, transport: http(rpcUrl) }); +} diff --git a/yarn-project/ethereum/src/index.ts b/yarn-project/ethereum/src/index.ts index 4474be5894e..c136dcdb263 100644 --- a/yarn-project/ethereum/src/index.ts +++ b/yarn-project/ethereum/src/index.ts @@ -2,9 +2,9 @@ import { foundry } from 'viem/chains'; import { type EthereumChain } from './ethereum_chain.js'; +export * from './constants.js'; export * from './deploy_l1_contracts.js'; export * from './l1_contract_addresses.js'; -export * from './constants.js'; export * from './l1_reader.js'; /** diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index dc36dee4f9c..b8521cf5247 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -137,6 +137,7 @@ export class L1Publisher { const { l1RpcUrl: rpcUrl, l1ChainId: chainId, publisherPrivateKey, l1Contracts } = config; const chain = createEthereumChain(rpcUrl, chainId); this.account = privateKeyToAccount(publisherPrivateKey); + this.log.debug(`Publishing from address ${this.account.address}`); const walletClient = createWalletClient({ account: this.account, chain: chain.chainInfo, diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 2f90618e58f..acc7851b43f 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -307,6 +307,7 @@ export class Sequencer { throw new Error(msg); } + this.log.debug(`Can propose block ${proposalBlockNumber} at slot ${slot}`); return slot; } catch (err) { if (err instanceof BaseError) {