Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spartan/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ environments/*
!environments/tps-scenario.env
!environments/kind-minimal.env
!environments/kind-provers.env
!environments/alpha-net.env
*.tfvars
89 changes: 89 additions & 0 deletions spartan/environments/alpha-net.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
NAMESPACE=${NAMESPACE:-alpha-net}
CLUSTER=aztec-gke-private
GCP_REGION=us-west1-a
DESTROY_NAMESPACE=true
DESTROY_ETH_DEVNET=true
CREATE_ETH_DEVNET=${CREATE_ETH_DEVNET:-true}
AZTEC_EPOCH_DURATION=8
AZTEC_SLOT_DURATION=72
AZTEC_PROOF_SUBMISSION_EPOCHS=2
ETHEREUM_CHAIN_ID=1337
LABS_INFRA_MNEMONIC="test test test test test test test test test test test junk"
FUNDING_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
# CREATE_CHAOS_MESH=true

# Install chaos mesh peer isolation after Aztec infra deploys. Validators,
# RPC nodes, and prover nodes can only peer with full-nodes, not each other.
# Requires P2P_PUBLIC_IP=false so P2P uses pod IPs that iptables rules can match.
P2P_PUBLIC_IP=false
CHAOS_MESH_SCENARIOS_FILE=network-requirements.yaml

AZTEC_MANA_TARGET=2147483647

P2P_TX_POOL_DELETE_TXS_AFTER_REORG=true

# For mbps
SEQ_BUILD_CHECKPOINT_IF_EMPTY=true
SEQ_BLOCK_DURATION_MS=6000
SEQ_SKIP_CHECKPOINT_PUBLISH_PERCENT=5

CREATE_ROLLUP_CONTRACTS=true
REDEPLOY_ROLLUP_CONTRACTS=true
VERIFY_CONTRACTS=false
DESTROY_AZTEC_INFRA=true

AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=1
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=1

OTEL_COLLECTOR_ENDPOINT=REPLACE_WITH_GCP_SECRET

VALIDATOR_REPLICAS=12
VALIDATORS_PER_NODE=4
PUBLISHERS_PER_VALIDATOR_KEY=2
VALIDATOR_PUBLISHER_MNEMONIC_START_INDEX=5000
VALIDATOR_RESOURCE_PROFILE="2-core-dedicated"

REAL_VERIFIER=false

RPC_REPLICAS=12
RPC_INGRESS_ENABLED=false

FULL_NODE_REPLICAS=500
FULL_NODE_RESOURCE_PROFILE="2-core-spot"

PUBLISHERS_PER_PROVER=2
PROVER_PUBLISHER_MNEMONIC_START_INDEX=8000
PROVER_REPLICAS=128
PROVER_RESOURCE_PROFILE="hi-tps"
PROVER_AGENT_POLL_INTERVAL_MS=10000

RUN_TESTS=false

PROVER_TEST_DELAY_TYPE=fixed

AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS=1
AZTEC_SLASHING_QUORUM=5
AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS=0
AZTEC_SLASHING_OFFSET_IN_ROUNDS=1
AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000

SEQ_MAX_TX_PER_BLOCK=10
SEQ_MIN_TX_PER_BLOCK=0

# Override L1 tx utils bump percentages for scenario tests
VALIDATOR_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0
VALIDATOR_L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE=0
PROVER_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0
PROVER_L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE=0

# Enable latency mesaruement for p2p messages
DEBUG_P2P_INSTRUMENT_MESSAGES=true

# Inject artificial delay of proof verification for all nodes
PROVER_TEST_VERIFICATION_DELAY_MS=250

# Reduce the amount of metrics produced by prover agents and full nodes
PROVER_AGENT_INCLUDE_METRICS="aztec.circuit"
FULL_NODE_INCLUDE_METRICS="aztec.p2p.gossip.agg_"
LOG_LEVEL=info

60 changes: 54 additions & 6 deletions spartan/scripts/deploy_network.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ LABS_INFRA_INDICES=${LABS_INFRA_INDICES:-0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1
########################
# ROLLUP VARIABLES
########################
CREATE_ROLLUP_CONTRACTS=${CREATE_ROLLUP_CONTRACTS:-false}
REDEPLOY_ROLLUP_CONTRACTS=${REDEPLOY_ROLLUP_CONTRACTS:-false}
CREATE_ROLLUP_CONTRACTS=${CREATE_ROLLUP_CONTRACTS:-true}
SPONSORED_FPC=${SPONSORED_FPC:-true}
TEST_ACCOUNTS=${TEST_ACCOUNTS:-false}
REAL_VERIFIER=${REAL_VERIFIER:-true}
Expand Down Expand Up @@ -196,6 +197,12 @@ P2P_GOSSIPSUB_DHI=${P2P_GOSSIPSUB_DHI:-12}

P2P_DROP_TX_CHANCE=${P2P_DROP_TX_CHANCE:-0}

# Chaos mesh scenarios values file (e.g., "network-requirements.yaml")
# If set, the experiment is installed after Aztec infra, rules are injected,
# then all pods are restarted so they come up clean with partition rules active.
# Requires the chaos mesh operator to already be running (see deploy_chaos_mesh.sh).
CHAOS_MESH_SCENARIOS_FILE=${CHAOS_MESH_SCENARIOS_FILE:-}

# Compute validator addresses (skip if no validators)
if [[ $VALIDATOR_REPLICAS -gt 0 ]]; then
VALIDATOR_ADDRESSES=$(echo "$VALIDATOR_INDICES" | tr ',' '\n' | xargs -I{} cast wallet address --mnemonic "$LABS_INFRA_MNEMONIC" --mnemonic-index {} | tr '\n' ',' | sed 's/,$//')
Expand Down Expand Up @@ -360,7 +367,7 @@ fi
# Check for ETHERSCAN_API_KEY when VERIFY_CONTRACTS is enabled
# Contract verification happens automatically in the yarn-project code when on mainnet/sepolia
# and ETHERSCAN_API_KEY is set. This check ensures we fail early if verification is expected.
if [[ "${VERIFY_CONTRACTS:-}" == "true" && "${CREATE_ROLLUP_CONTRACTS}" == "true" && -z "${ETHERSCAN_API_KEY:-}" ]]; then
if [[ "${VERIFY_CONTRACTS:-}" == "true" && ("${CREATE_ROLLUP_CONTRACTS}" == "true" || "${REDEPLOY_ROLLUP_CONTRACTS}" == "true") && -z "${ETHERSCAN_API_KEY:-}" ]]; then
die "Error: ETHERSCAN_API_KEY is not set but VERIFY_CONTRACTS=true. Contract verification requires an Etherscan API key. Set ETHERSCAN_API_KEY environment variable."
fi

Expand All @@ -369,7 +376,7 @@ 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"

# Handle ETHERSCAN_API_KEY - only set when deploying or redeploying contracts
if [[ "${VERIFY_CONTRACTS:-}" == "true" && "${CREATE_ROLLUP_CONTRACTS}" == "true" ]]; then
if [[ "${VERIFY_CONTRACTS:-}" == "true" && ("${CREATE_ROLLUP_CONTRACTS}" == "true" || "${REDEPLOY_ROLLUP_CONTRACTS}" == "true") ]]; then
ETHERSCAN_API_KEY_TF="\"${ETHERSCAN_API_KEY:-}\""
else
ETHERSCAN_API_KEY_TF=null
Expand Down Expand Up @@ -427,11 +434,11 @@ EXISTING_REGISTRY=$(terraform -chdir="${DEPLOY_ROLLUP_CONTRACTS_DIR}" output -ra
if [[ "${USE_NETWORK_CONFIG:-false}" == "true" ]]; then
log "Using network configuration, skipping contracts deployment"
else
if [[ -n "${EXISTING_REGISTRY}" && "${CREATE_ROLLUP_CONTRACTS}" != "true" ]]; then
if [[ -n "${EXISTING_REGISTRY}" && "${REDEPLOY_ROLLUP_CONTRACTS}" != "true" ]]; then
log "Contracts already deployed (registry=${EXISTING_REGISTRY}), skipping deployment"
else
if [[ "${CREATE_ROLLUP_CONTRACTS}" == "true" ]]; then
log "CREATE_ROLLUP_CONTRACTS=true, destroying existing deployment"
if [[ "${REDEPLOY_ROLLUP_CONTRACTS}" == "true" ]]; then
log "REDEPLOY_ROLLUP_CONTRACTS=true, destroying existing deployment"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This undoes some work in the merge train to remove REDEPLOY if favour of only using CREATE_ to control contracts

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I wondered about that. I'll get ride of REDEPLOY.

k8s_denoise "terraform -chdir="${DEPLOY_ROLLUP_CONTRACTS_DIR}" destroy -auto-approve"
fi
k8s_denoise "terraform -chdir=${DEPLOY_ROLLUP_CONTRACTS_DIR} plan -out=tfplan"
Expand Down Expand Up @@ -617,6 +624,47 @@ k8s_denoise "tf_run "${DEPLOY_AZTEC_INFRA_DIR}" "${DESTROY_AZTEC_INFRA}" "${CREA
STAGE_TIMINGS[aztec_infra]=$(($(date +%s) - AZTEC_INFRA_START))
log "Deployed aztec infra"

# -------------------------------------------------------
# Optionally install chaos mesh scenarios after Aztec infra
# -------------------------------------------------------
# Chaos Mesh resolves pod selectors at experiment creation time, so the target
# pods must already exist. The chaos-daemon injects iptables DROP rules into
# each matched pod's network namespace. For partition experiments, this
# immediately blocks packets between the partitioned pods, causing existing
# TCP connections to timeout and preventing new ones from forming.
#
# IMPORTANT: Do NOT restart pods after chaos injection. Chaos Mesh does not
# automatically re-inject rules into recreated pods, leaving them unpartitioned.
if [[ -n "${CHAOS_MESH_SCENARIOS_FILE}" ]]; then
CHAOS_SCENARIOS_DIR="${SCRIPT_DIR}/../aztec-chaos-scenarios"
log "Installing chaos mesh scenarios from ${CHAOS_MESH_SCENARIOS_FILE}"
helm upgrade --install network-shaping "${CHAOS_SCENARIOS_DIR}" \
--namespace "${NAMESPACE}" \
--values "${CHAOS_SCENARIOS_DIR}/values/${CHAOS_MESH_SCENARIOS_FILE}" \
--set "global.targetNamespace=${NAMESPACE}" \
--wait --timeout=5m
log "Chaos mesh scenarios installed, waiting for rules to be injected..."

# Wait for all NetworkChaos experiments to have their rules injected.
# The AllInjected condition confirms iptables rules are active on every matched pod.
CHAOS_WAIT_TIMEOUT=120
CHAOS_WAITED=0
while true; do
NOT_INJECTED=$(kubectl get networkchaos -n "${NAMESPACE}" -o jsonpath='{range .items[*]}{.status.conditions[?(@.type=="AllInjected")].status}{"\n"}{end}' 2>/dev/null | grep -c "False" || true)
if [[ "${NOT_INJECTED}" -eq 0 ]]; then
log "All chaos mesh rules injected"
break
fi
if [[ "${CHAOS_WAITED}" -ge "${CHAOS_WAIT_TIMEOUT}" ]]; then
log "WARNING: Timed out waiting for chaos mesh injection after ${CHAOS_WAIT_TIMEOUT}s (${NOT_INJECTED} experiments not yet injected)"
break
fi
sleep 5
CHAOS_WAITED=$((CHAOS_WAITED + 5))
done
log "Chaos mesh partition active — existing connections will break as packets are dropped"
fi

# Calculate total deployment time
DEPLOY_END_TIME=$(date +%s)
TOTAL_DEPLOY_TIME=$((DEPLOY_END_TIME - DEPLOY_START_TIME))
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -844,8 +844,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
}

await this.p2pClient!.sendTx(tx);
this.metrics.receivedTx(timer.ms(), true);
this.log.info(`Received tx ${txHash}`, { txHash });
const duration = timer.ms();
this.metrics.receivedTx(duration, true);
this.log.info(`Received tx ${txHash} in ${duration}ms`, { txHash });
}

public async getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
Expand Down
89 changes: 64 additions & 25 deletions yarn-project/end-to-end/src/spartan/n_tps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
getChartDir,
getGitProjectRoot,
getRPCEndpoint,
hasDeployedHelmRelease,
installChaosMeshChart,
setupEnvironment,
startPortForwardForPrometeheus,
Expand Down Expand Up @@ -226,6 +227,32 @@ describe('sustained N TPS test', () => {
});
const spartanDir = `${getGitProjectRoot()}/spartan`;

// Skip chaos mesh installation if it was already deployed by deploy_network.sh
// (via CHAOS_MESH_SCENARIOS_FILE). Installing before infra ensures partition
// rules are in place when pods start, preventing unwanted peer connections.
const alreadyDeployed = await hasDeployedHelmRelease(CHAOS_MESH_NAME, config.NAMESPACE);
if (alreadyDeployed) {
logger.info('Chaos mesh chart already deployed, skipping installation');
} else {
logger.info('Installing chaos mesh chart', {
name: CHAOS_MESH_NAME,
namespace: config.NAMESPACE,
valuesFile: 'network-requirements.yaml',
});
await installChaosMeshChart({
logger,
targetNamespace: config.NAMESPACE,
instanceName: CHAOS_MESH_NAME,
valuesFile: 'network-requirements.yaml',
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
});
Comment on lines +242 to +248

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW this removes existing Chaos experiments so if both the deployment and the test install Chaos mesh then it's losing some time.

logger.info('Chaos mesh installation complete');

logger.info('Waiting for network to stabilize after chaos mesh installation...');
await sleep(30 * 1000);
logger.info('Network stabilization wait complete');
}

const rpcEndpoint = await getRPCEndpoint(config.NAMESPACE);
endpoints.push(rpcEndpoint);
const rpcUrl = rpcEndpoint.url;
Expand Down Expand Up @@ -285,24 +312,6 @@ describe('sustained N TPS test', () => {
});
logger.info('Benchmark contract deployed', { address: benchmarkContract.address.toString() });

logger.info('Installing chaos mesh chart', {
name: CHAOS_MESH_NAME,
namespace: config.NAMESPACE,
valuesFile: 'network-requirements.yaml',
});
await installChaosMeshChart({
logger,
targetNamespace: config.NAMESPACE,
instanceName: CHAOS_MESH_NAME,
valuesFile: 'network-requirements.yaml',
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
});
logger.info('Chaos mesh installation complete');

logger.info('Waiting for network to stabilize after chaos mesh installation...');
await sleep(30 * 1000);
logger.info('Network stabilization wait complete');

logger.info(`Test setup complete`);
});

Expand All @@ -328,7 +337,7 @@ describe('sustained N TPS test', () => {
prototypeTxs.set(from.toString(), prototypeTx);
}

const tx = await cloneTx(prototypeTx, priorytFee);
const tx = await cloneTx(prototypeTx, priorytFee, logger);
return tx;
};

Expand All @@ -345,15 +354,23 @@ describe('sustained N TPS test', () => {
let lowValueTxs = 0;
const lowValueSendTx = async (wallet: TestWallet) => {
lowValueTxs++;
//const feeAmount = Number(randomBigInt(100n)) + 1;
//const feeAmount = 1;
const feeAmount = Math.floor(lowValueTxs / 1000) + 1;
const fee = new GasFees(0, feeAmount);
logger.info('Sending low value tx ' + lowValueTxs + ' with fee ' + feeAmount);

const t0 = performance.now();
const tx = await (config.REAL_VERIFIER ? submitProven(wallet, fee) : submitUnproven(wallet, fee));
const t1 = performance.now();

const txHash = await tx.send({ wait: NO_WAIT });
const t2 = performance.now();

logger.info('Low value tx sent', {
txNum: lowValueTxs,
feeAmount,
cloneMs: Math.round(t1 - t0),
sendMs: Math.round(t2 - t1),
totalMs: Math.round(t2 - t0),
});
return txHash.toString();
};

Expand All @@ -362,13 +379,23 @@ describe('sustained N TPS test', () => {
highValueTxs++;
const feeAmount = Number(randomBigInt(10n)) + 1000;
const fee = new GasFees(0, feeAmount);
logger.info('Sending high value tx ' + highValueTxs + ' with fee ' + feeAmount);

const t0 = performance.now();
const tx = await (config.REAL_VERIFIER ? submitProven(wallet, fee) : submitUnproven(wallet, fee));
const t1 = performance.now();

metrics.recordSentTx(tx, `high_value_${highValueTps}tps`);

const txHash = await tx.send({ wait: NO_WAIT });
const t2 = performance.now();

logger.info('High value tx sent', {
txNum: highValueTxs,
feeAmount,
cloneMs: Math.round(t1 - t0),
sendMs: Math.round(t2 - t1),
totalMs: Math.round(t2 - t0),
});
return txHash.toString();
};

Expand Down Expand Up @@ -514,9 +541,11 @@ function sendTxsAtTps(
return txHashes;
}

async function cloneTx(tx: ProvenTx, priorityFee: GasFees): Promise<ProvenTx> {
// Clone the transaction
async function cloneTx(tx: ProvenTx, priorityFee: GasFees, logger: Logger): Promise<ProvenTx> {
const t0 = performance.now();
const clonedTxData = Tx.clone(tx, false);
const t1 = performance.now();

(clonedTxData.data.constants.txContext.gasSettings as any).maxPriorityFeesPerGas = priorityFee;

if (clonedTxData.data.forRollup) {
Expand All @@ -534,7 +563,17 @@ async function cloneTx(tx: ProvenTx, priorityFee: GasFees): Promise<ProvenTx> {
clonedTxData.data.forPublic.nonRevertibleAccumulatedData.nullifiers[i] = Fr.random();
}
}
const t2 = performance.now();

const clonedTx = new ProvenTx((tx as any).node, clonedTxData, tx.offchainEffects, tx.stats);
await clonedTx.recomputeHash();
const t3 = performance.now();

logger.debug('cloneTx timing', {
cloneMs: Math.round(t1 - t0),
mutateMs: Math.round(t2 - t1),
rehashMs: Math.round(t3 - t2),
totalMs: Math.round(t3 - t0),
});
return clonedTx;
}
3 changes: 3 additions & 0 deletions yarn-project/end-to-end/src/spartan/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export {
applyNetworkShaping,
} from './chaos.js';

// Helm
export { hasDeployedHelmRelease } from './helm.js';

// Bot management
export { restartBot, installTransferBot, uninstallTransferBot } from './bot.js';

Expand Down
2 changes: 1 addition & 1 deletion yarn-project/sequencer-client/src/sequencer/timetable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class SequencerTimetable {
const initializeDeadline = this.aztecSlotDuration - minWorkToDo;
this.initializeDeadline = initializeDeadline;

this.log.verbose(
this.log.info(
`Sequencer timetable initialized with ${this.maxNumberOfBlocks} blocks per slot (${this.enforce ? 'enforced' : 'not enforced'})`,
{
ethereumSlotDuration: this.ethereumSlotDuration,
Expand Down