diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000000..5fb83c32c5 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,26 @@ +{ + "servers": { + "io.github.upstash/context7": { + "type": "stdio", + "command": "npx", + "args": ["@upstash/context7-mcp@1.0.31"], + "env": { + "CONTEXT7_API_KEY": "${input:CONTEXT7_API_KEY}" + }, + "gallery": "https://api.mcp.github.com", + "version": "1.0.31" + }, + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/" + } + }, + "inputs": [ + { + "id": "CONTEXT7_API_KEY", + "type": "promptString", + "description": "API key for authentication", + "password": true + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000..ab8d595a38 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,137 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "CRISP: Start All", + "detail": "Starts all 10 CRISP services in parallel (each in its own dedicated VS Code terminal). Terminate Task works on the compound task.", + "dependsOn": [ + "CRISP: Anvil", + "CRISP: Deploy + Setup", + "CRISP: cn1", + "CRISP: cn2", + "CRISP: cn3", + "CRISP: cn4", + "CRISP: cn5", + "CRISP: Program Server", + "CRISP: Server", + "CRISP: Client" + ], + "dependsOrder": "parallel", + "problemMatcher": [] + }, + { + "label": "CRISP: Anvil", + "type": "shell", + "command": "anvil", + "args": [ + "--host", + "0.0.0.0", + "--chain-id", + "31337", + "--block-time", + "1", + "--mnemonic", + "test test test test test test test test test test test junk" + ], + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-anvil" }, + "problemMatcher": { + "pattern": { "regexp": "^$" }, + "background": { + "activeOnStart": true, + "beginsPattern": "^.*$", + "endsPattern": "^.*Listening on.*$" + } + } + }, + { + "label": "CRISP: Deploy + Setup", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "deploy"], + "options": { "cwd": "${workspaceFolder}" }, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-deploy" }, + "problemMatcher": [] + }, + { + "label": "CRISP: cn1", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "cn1"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-cn1", "clear": false }, + "problemMatcher": [] + }, + { + "label": "CRISP: cn2", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "cn2"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-cn2", "clear": false }, + "problemMatcher": [] + }, + { + "label": "CRISP: cn3", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "cn3"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-cn3", "clear": false }, + "problemMatcher": [] + }, + { + "label": "CRISP: cn4", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "cn4"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-cn4", "clear": false }, + "problemMatcher": [] + }, + { + "label": "CRISP: cn5", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "cn5"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-cn5", "clear": false }, + "problemMatcher": [] + }, + { + "label": "CRISP: Program Server", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "program"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-program", "clear": false }, + "problemMatcher": [] + }, + { + "label": "CRISP: Server", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "server"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-server", "clear": false }, + "problemMatcher": [] + }, + { + "label": "CRISP: Client", + "type": "shell", + "command": "bash", + "args": ["${workspaceFolder}/deploy/local/run_service.sh", "client"], + "options": { "cwd": "${workspaceFolder}" }, + "isBackground": true, + "presentation": { "reveal": "always", "panel": "dedicated", "group": "crisp-client", "clear": false }, + "problemMatcher": [] + } + ] +} diff --git a/crates/events/src/enclave_event/mod.rs b/crates/events/src/enclave_event/mod.rs index 5437e9812d..c0fc3c6faf 100644 --- a/crates/events/src/enclave_event/mod.rs +++ b/crates/events/src/enclave_event/mod.rs @@ -544,6 +544,7 @@ impl EnclaveEventData { EnclaveEventData::ProofVerificationPassed(ref data) => Some(data.e3_id.clone()), EnclaveEventData::KeyshareCreated(ref data) => Some(data.e3_id.clone()), EnclaveEventData::E3Requested(ref data) => Some(data.e3_id.clone()), + EnclaveEventData::E3RequestComplete(ref data) => Some(data.e3_id.clone()), EnclaveEventData::PublicKeyAggregated(ref data) => Some(data.e3_id.clone()), EnclaveEventData::CiphertextOutputPublished(ref data) => Some(data.e3_id.clone()), EnclaveEventData::DecryptionKeyShared(ref data) => Some(data.e3_id.clone()), diff --git a/crates/evm/src/actors/evm_parser.rs b/crates/evm/src/actors/evm_parser.rs index ca0300ff87..b9f8dd02f2 100644 --- a/crates/evm/src/actors/evm_parser.rs +++ b/crates/evm/src/actors/evm_parser.rs @@ -13,7 +13,7 @@ use tracing::debug; use crate::domain::log_timestamp::from_log_chain_id_to_ts; use crate::messages::{EnclaveEvmEvent, EvmEvent, EvmEventProcessor, EvmLog}; -pub type ExtractorFn = fn(&LogData, Option<&B256>, u64) -> Option; +pub type ExtractorFn = fn(&LogData, &[B256], u64) -> Option; pub struct EvmParser { next: EvmEventProcessor, @@ -49,7 +49,7 @@ impl Handler for EvmParser { debug!("processing event({})", msg.get_id()); let extractor = self.extractor; - if let Some(event) = extractor(log.data(), log.topic0(), chain_id) { + if let Some(event) = extractor(log.data(), log.topics(), chain_id) { let err = "Log should always have metadata because we listen to non-pending blocks. If you are seeing this it is likely because there is an issue with how we are subscribing to blocks"; let block = log.block_number.expect(err); let log_index = log.log_index.expect(err); diff --git a/crates/evm/src/domain/bonding_registry_events.rs b/crates/evm/src/domain/bonding_registry_events.rs index 578a4d3cdc..88865e78c0 100644 --- a/crates/evm/src/domain/bonding_registry_events.rs +++ b/crates/evm/src/domain/bonding_registry_events.rs @@ -89,10 +89,10 @@ impl From for EnclaveEventData { pub(crate) fn extractor( data: &LogData, - topic: Option<&B256>, + topics: &[B256], chain_id: u64, ) -> Option { - match topic { + match topics.first() { Some(&IBondingRegistry::TicketBalanceUpdated::SIGNATURE_HASH) => { let Ok(event) = IBondingRegistry::TicketBalanceUpdated::decode_log_data(data) else { error!("Error parsing event TicketBalanceUpdated after topic was matched!"); @@ -121,9 +121,9 @@ pub(crate) fn extractor( event, chain_id, ))) } - _topic => { + _ => { trace!( - topic=?_topic, + topic=?topics.first(), "Unknown event was received by BondingRegistry.sol parser but was ignored" ); None @@ -145,7 +145,7 @@ mod tests { let log_data = event.encode_log_data(); let out = extractor( &log_data, - Some(&IBondingRegistry::OperatorActivationChanged::SIGNATURE_HASH), + &[IBondingRegistry::OperatorActivationChanged::SIGNATURE_HASH], 55, ); match out { @@ -175,6 +175,6 @@ mod tests { #[test] fn test_extractor_ignores_unknown_topic() { let log_data = LogData::default(); - assert!(extractor(&log_data, Some(&B256::ZERO), 1).is_none()); + assert!(extractor(&log_data, &[B256::ZERO], 1).is_none()); } } diff --git a/crates/evm/src/domain/ciphernode_registry_events.rs b/crates/evm/src/domain/ciphernode_registry_events.rs index 61a7bb9bbc..7f8d253fca 100644 --- a/crates/evm/src/domain/ciphernode_registry_events.rs +++ b/crates/evm/src/domain/ciphernode_registry_events.rs @@ -170,10 +170,10 @@ impl From for EnclaveEventData { pub(crate) fn extractor( data: &LogData, - topic: Option<&B256>, + topics: &[B256], chain_id: u64, ) -> Option { - match topic { + match topics.first() { Some(&ICiphernodeRegistry::CiphernodeAdded::SIGNATURE_HASH) => { let Ok(event) = ICiphernodeRegistry::CiphernodeAdded::decode_log_data(data) else { error!("Error parsing event CiphernodeAdded after topic was matched!"); @@ -234,9 +234,9 @@ pub(crate) fn extractor( event, chain_id, ))) } - _topic => { + _ => { trace!( - topic=?_topic, + topic=?topics.first(), "Unknown event was received by CiphernodeRegistry.sol parser but was ignored" ); None @@ -260,7 +260,7 @@ mod tests { let log_data = event.encode_log_data(); let out = extractor( &log_data, - Some(&ICiphernodeRegistry::CiphernodeAdded::SIGNATURE_HASH), + &[ICiphernodeRegistry::CiphernodeAdded::SIGNATURE_HASH], 10, ); match out { @@ -294,6 +294,6 @@ mod tests { #[test] fn test_extractor_ignores_unknown_topic() { let log_data = LogData::default(); - assert!(extractor(&log_data, Some(&B256::ZERO), 1).is_none()); + assert!(extractor(&log_data, &[B256::ZERO], 1).is_none()); } } diff --git a/crates/evm/src/domain/enclave_events.rs b/crates/evm/src/domain/enclave_events.rs index 3536e6410b..b6255a905b 100644 --- a/crates/evm/src/domain/enclave_events.rs +++ b/crates/evm/src/domain/enclave_events.rs @@ -186,10 +186,11 @@ impl From for EnclaveEventData { pub(crate) fn extractor( data: &LogData, - topic: Option<&B256>, + topics: &[B256], chain_id: u64, ) -> Option { - match topic { + let topic0 = topics.first(); + match topic0 { Some(&IEnclave::E3Requested::SIGNATURE_HASH) => { let Ok(event) = IEnclave::E3Requested::decode_log_data(data) else { error!("Error parsing event E3Requested after topic matched!"); @@ -211,10 +212,17 @@ pub(crate) fn extractor( } } Some(&IEnclave::CiphertextOutputPublished::SIGNATURE_HASH) => { - let Ok(event) = IEnclave::CiphertextOutputPublished::decode_log_data(data) else { + let Ok(mut event) = IEnclave::CiphertextOutputPublished::decode_log_data(data) else { error!("Error parsing event CiphertextOutputPublished after topic matched!"); return None; }; + // e3Id is indexed → extract from topics[1], not log data + if let Some(e3_id_topic) = topics.get(1) { + event.e3Id = alloy::primitives::U256::from_be_bytes(e3_id_topic.0); + } else { + error!("CiphertextOutputPublished missing indexed e3Id in topics!"); + return None; + } Some(EnclaveEventData::from( CiphertextOutputPublishedWithChainId(event, chain_id), )) @@ -231,10 +239,17 @@ pub(crate) fn extractor( Some(EnclaveEventData::from(E3FailedWithChainId(event, chain_id))) } Some(&IEnclave::E3StageChanged::SIGNATURE_HASH) => { - let Ok(event) = IEnclave::E3StageChanged::decode_log_data(data) else { + let Ok(mut event) = IEnclave::E3StageChanged::decode_log_data(data) else { error!("Error parsing event E3StageChanged after topic matched!"); return None; }; + // e3Id is indexed → extract from topics[1], not log data + if let Some(e3_id_topic) = topics.get(1) { + event.e3Id = alloy::primitives::U256::from_be_bytes(e3_id_topic.0); + } else { + error!("E3StageChanged missing indexed e3Id in topics!"); + return None; + } trace!( "E3StageChanged event received: e3_id={}, {:?} -> {:?}", event.e3Id, @@ -245,9 +260,9 @@ pub(crate) fn extractor( event, chain_id, ))) } - _topic => { + _ => { trace!( - topic=?_topic, + topic=?topic0, "Unknown event received by Enclave.sol parser but was ignored" ); None @@ -286,9 +301,12 @@ mod tests { newStage: 6, // Failed }; let log_data = event.encode_log_data(); + // e3Id is indexed → it must be in topics[1] (not in log data) + let e3_id_bytes: [u8; 32] = U256::from(42u64).to_be_bytes(); + let e3_id_topic = B256::from(e3_id_bytes); let out = extractor( &log_data, - Some(&IEnclave::E3StageChanged::SIGNATURE_HASH), + &[IEnclave::E3StageChanged::SIGNATURE_HASH, e3_id_topic], 7, ); match out { @@ -304,7 +322,7 @@ mod tests { #[test] fn test_extractor_ignores_unknown_topic() { let log_data = LogData::default(); - assert!(extractor(&log_data, Some(&B256::ZERO), 1).is_none()); - assert!(extractor(&log_data, None, 1).is_none()); + assert!(extractor(&log_data, &[B256::ZERO], 1).is_none()); + assert!(extractor(&log_data, &[], 1).is_none()); } } diff --git a/crates/evm/src/domain/slashing_events.rs b/crates/evm/src/domain/slashing_events.rs index c45cc99119..26bf61aa6d 100644 --- a/crates/evm/src/domain/slashing_events.rs +++ b/crates/evm/src/domain/slashing_events.rs @@ -25,10 +25,10 @@ fn safe_u256_to_u128(val: U256) -> Option { pub(crate) fn extractor( data: &LogData, - topic: Option<&B256>, + topics: &[B256], chain_id: u64, ) -> Option { - match topic { + match topics.first() { Some(&ISlashingManager::SlashExecuted::SIGNATURE_HASH) => { let Ok(event) = ISlashingManager::SlashExecuted::decode_log_data(data) else { error!("Error parsing event SlashExecuted after topic was matched!"); @@ -74,9 +74,9 @@ pub(crate) fn extractor( }, })) } - _topic => { + _ => { trace!( - topic=?_topic, + topic=?topics.first(), "Unknown event was received by SlashingManager.sol parser but was ignored" ); None @@ -103,7 +103,7 @@ mod tests { #[test] fn test_extractor_ignores_unknown_topic() { let log_data = LogData::default(); - assert!(extractor(&log_data, Some(&B256::ZERO), 1).is_none()); - assert!(extractor(&log_data, None, 1).is_none()); + assert!(extractor(&log_data, &[B256::ZERO], 1).is_none()); + assert!(extractor(&log_data, &[], 1).is_none()); } } diff --git a/crates/evm/tests/integration.rs b/crates/evm/tests/integration.rs index 6810925ee8..cb29e05e85 100644 --- a/crates/evm/tests/integration.rs +++ b/crates/evm/tests/integration.rs @@ -32,10 +32,10 @@ sol!( fn test_event_extractor( data: &LogData, - topic: Option<&FixedBytes<32>>, + topics: &[FixedBytes<32>], _chain_id: u64, ) -> Option { - match topic { + match topics.first() { Some(&EmitLogs::ValueChanged::SIGNATURE_HASH) => { let Ok(event) = EmitLogs::ValueChanged::decode_log_data(data) else { return None; diff --git a/crates/request/src/domain/routing.rs b/crates/request/src/domain/routing.rs index 89bb7bd9a1..980ca6ff33 100644 --- a/crates/request/src/domain/routing.rs +++ b/crates/request/src/domain/routing.rs @@ -212,15 +212,17 @@ mod tests { } #[test] - fn e3_request_complete_without_e3_id_is_ignored() { - // EnclaveEventData::get_e3_id() returns None for E3RequestComplete, so such an event - // never reaches the Teardown arm: it is ignored. This mirrors the original router's - // `let Some(e3_id) = ... else { return Ok(()) }` guard exactly. + fn e3_request_complete_triggers_teardown() { + // EnclaveEventData::get_e3_id() now returns Some(e3_id) for E3RequestComplete, + // so the event reaches the Teardown arm of the router. let id = e3id(); - let msg = from_data(E3RequestComplete { e3_id: id }); + let msg = from_data(E3RequestComplete { e3_id: id.clone() }); assert_eq!( RequestRouter::route(&msg, &HashSet::new()), - RoutingDecision::Ignore + RoutingDecision::Process { + e3_id: id, + post_forward: PostForward::Teardown, + } ); } diff --git a/deploy/local/run_service.sh b/deploy/local/run_service.sh new file mode 100644 index 0000000000..d76582f74a --- /dev/null +++ b/deploy/local/run_service.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# ============================================================================= +# CRISP Service Runner — called by VS Code tasks. +# Handles dependency waiting and launches one service. +# +# Usage: bash deploy/local/run_service.sh +# anvil → start anvil +# deploy → deploy contracts + setup wallets/noir/ciphernodes + daemon +# cn1..cn5 → start an individual ciphernode (waits for /tmp/crisp-dev-daemon-ready) +# program → start program server (waits for anvil :8545) +# server → start CRISP server (waits for program :13151) +# client → start CRISP client (waits for server :4000 + signal file) +# ============================================================================= +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +CRISP_ROOT="$REPO_ROOT/examples/CRISP" +SIGNAL_FILE="/tmp/crisp-dev-daemon-ready" + +SERVICE="${1:-}" + +die() { echo "[run_service] ERROR: $*" >&2; exit 1; } + +# ── Helpers ───────────────────────────────────────────────────────────────── +wait_for_port() { + local host port label max + host="${1:-localhost}" + port="$2" + label="${3:-$port}" + max="${4:-120}" + local attempt=0 + echo "[run_service] Waiting for $label ($host:$port)..." + while (( attempt <= max )); do + if curl -s "http://${host}:${port}" >/dev/null 2>&1; then + echo "[run_service] $label is ready" + return 0 + fi + sleep 1 + (( attempt++ )) + done + die "$label did not start after ${max}s" +} + +wait_for_file() { + local file label max + file="$1" + label="${2:-$file}" + max="${3:-120}" + local attempt=0 + echo "[run_service] Waiting for $label..." + while (( attempt <= max )); do + if [ -f "$file" ]; then + echo "[run_service] $label found" + return 0 + fi + sleep 1 + (( attempt++ )) + done + die "$label did not appear after ${max}s" +} + +case "$SERVICE" in + anvil) + exec anvil \ + --host 0.0.0.0 \ + --chain-id 31337 \ + --block-time 1 \ + --mnemonic "test test test test test test test test test test test junk" + ;; + + deploy) + # Clean stale signal from a previous run so nodes don't start prematurely + rm -f "$SIGNAL_FILE" + exec bash "${REPO_ROOT}/deploy/local/setup_nodes.sh" + ;; + + cn1|cn2|cn3|cn4|cn5) + cd "${CRISP_ROOT}" + wait_for_file "${SIGNAL_FILE}" "deploy signal file" + echo "[run_service] Deploy done. Starting ${SERVICE} directly..." + exec enclave --name "${SERVICE}" start -v + ;; + + program) + wait_for_port localhost 8545 "Anvil" + echo "[run_service] Anvil ready. Starting program server..." + cd "${CRISP_ROOT}" + exec bash scripts/dev_program.sh + ;; + + server) + wait_for_port localhost 13151 "Program Server" + echo "[run_service] Program server ready. Starting server..." + cd "${CRISP_ROOT}" + exec bash scripts/dev_server.sh + ;; + + client) + wait_for_port localhost 4000 "Server" + wait_for_file "${SIGNAL_FILE}" "deploy signal file" + echo "[run_service] Ready. Starting client..." + cd "${CRISP_ROOT}" + exec bash scripts/dev_client.sh + ;; + + *) + die "Unknown service: '${SERVICE}'. Valid: anvil, deploy, cn1..cn5, program, server, client" + ;; +esac diff --git a/deploy/local/setup_nodes.sh b/deploy/local/setup_nodes.sh new file mode 100644 index 0000000000..945045558b --- /dev/null +++ b/deploy/local/setup_nodes.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# ============================================================================= +# Called by the VS Code "Deploy + Setup" task. +# Waits for Anvil, deploys contracts, sets up wallets/noir/ciphernodes, +# starts the swarm daemon, and signals readiness for node/client tasks. +# ============================================================================= +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +CRISP_ROOT="$REPO_ROOT/examples/CRISP" +SIGNAL_FILE="/tmp/crisp-dev-daemon-ready" +READYFILE="$CRISP_ROOT/.enclave/ready" + +# ── Node config (must match start.sh) ────────────────────────────────────── +NODE_IDS=(cn1 cn2 cn3 cn4 cn5) +NODE_KEYS=( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" + "0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" + "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" + "0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" +) +NODE_ADDRS=( + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" + "0x90F79bf6EB2c4f870365E785982E1f101E93b906" + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" + "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" +) + +# ── Clean previous state ──────────────────────────────────────────────────── +echo "[deploy+setup] Cleaning previous state..." +rm -rf "$CRISP_ROOT/.enclave/data" "$CRISP_ROOT/.enclave/config" +rm -rf "$CRISP_ROOT/server/database" +rm -f "$READYFILE" "$SIGNAL_FILE" + +echo "[deploy+setup] Waiting for Anvil (port 8545)..." +until curl -s http://localhost:8545 >/dev/null 2>&1; do sleep 1; done +echo "[deploy+setup] Anvil is ready." + +echo "[deploy+setup] Deploying contracts..." +cd "$CRISP_ROOT" +bash scripts/crisp_deploy.sh + +echo "[deploy+setup] Importing wallets..." +for i in "${!NODE_IDS[@]}"; do + enclave wallet set --name "${NODE_IDS[$i]}" --private-key "${NODE_KEYS[$i]}" +done + +echo "[deploy+setup] Running enclave noir setup..." +enclave noir setup + +echo "[deploy+setup] Registering ciphernodes..." +for i in "${!NODE_IDS[@]}"; do + pnpm ciphernode:add --ciphernode-address "${NODE_ADDRS[$i]}" --network "localhost" +done +echo 1 > "$READYFILE" + +echo "[deploy+setup] Done. Signaling readiness." +touch "$SIGNAL_FILE" +echo "[deploy+setup] Signal file created: $SIGNAL_FILE — nodes can now start." diff --git a/deploy/local/start.sh b/deploy/local/start.sh index 0990164938..d2bfc8186e 100755 --- a/deploy/local/start.sh +++ b/deploy/local/start.sh @@ -1,132 +1,310 @@ -#!/bin/bash +#!/usr/bin/env bash +# ============================================================================= +# CRISP Development Launcher — VS Code terminals per service +# ============================================================================= +# +# Primary (recommended): +# Ctrl+Shift+P → "Tasks: Run Task" → "CRISP: Start All" +# Opens 9 VS Code terminals: Anvil, Deploy+Setup, cn1-cn5, Program, Server, Client. +# Each terminal handles its own waiting — no manual ordering needed. +# +# Tmux fallback: +# bash deploy/local/start.sh # 9 tmux windows +# +# Usage: +# bash deploy/local/start.sh # tmux mode +# bash deploy/local/start.sh --vscode # print VS Code instructions +# bash deploy/local/start.sh --help +# ============================================================================= -set -e +set -euo pipefail -echo "🚀 Starting CRISP Development Environment..." +# ── Resolve paths ─────────────────────────────────────────────────────────── +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +CRISP_ROOT="$REPO_ROOT/examples/CRISP" +TMUX_SESSION="crisp-dev" +READYFILE="$CRISP_ROOT/.enclave/ready" -# Function to check if a command exists -command_exists() { - command -v "$1" >/dev/null 2>&1 -} +# ── Node configuration ────────────────────────────────────────────────────── +# Anvil test accounts #1–#5 (deterministic from the standard mnemonic) +NODE_IDS=(cn1 cn2 cn3 cn4 cn5) +NODE_KEYS=( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" + "0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" + "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" + "0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" +) +NODE_ADDRS=( + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" + "0x90F79bf6EB2c4f870365E785982E1f101E93b906" + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" + "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" +) + +# ── Colors ────────────────────────────────────────────────────────────────── +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' +BLUE='\033[0;34m'; CYAN='\033[0;36m'; NC='\033[0m' +info() { echo -e "${BLUE}[INFO]${NC} $*"; } +ok() { echo -e "${GREEN}[OK]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +err() { echo -e "${RED}[ERROR]${NC} $*"; } +step() { echo -e "${CYAN}[STEP]${NC} $*"; } + +# ── Helpers ───────────────────────────────────────────────────────────────── +command_exists() { command -v "$1" >/dev/null 2>&1; } -# Check dependencies -echo "📋 Checking dependencies..." - -if ! command_exists "cargo"; then - echo "❌ Rust/Cargo is required but not installed" - exit 1 -fi - -if ! command_exists "pnpm"; then - echo "❌ pnpm is required but not installed" - exit 1 -fi - -if ! command_exists "concurrently"; then - echo "❌ concurrently is required but not installed" - echo "Install with: npm install -g concurrently" - exit 1 -fi - -if ! command_exists "anvil"; then - echo "❌ Foundry/Anvil is required but not installed" - exit 1 -fi - -echo "✅ All dependencies found" - -# Install the enclave binary -echo "🔧 Installing Enclave CLI..." -cargo install --locked --path ./crates/cli --bin enclave -f - -# Function to wait for a service to be ready -wait_for_service() { - local url=$1 - local service_name=$2 - local max_attempts=30 +wait_for_port() { + local host="${1:-localhost}" port="$2" label="${3:-$port}" max="${4:-60}" local attempt=1 - - echo "⏳ Waiting for $service_name to be ready..." - - while [ $attempt -le $max_attempts ]; do - if curl -s "$url" >/dev/null 2>&1; then - echo "✅ $service_name is ready!" + info "Waiting for $label ($host:$port)..." + while [ $attempt -le $max ]; do + if curl -s "http://$host:$port" >/dev/null 2>&1; then + ok "$label is ready" return 0 fi - echo " Attempt $attempt/$max_attempts - $service_name not ready yet..." - sleep 2 + sleep 1 attempt=$((attempt + 1)) done - - echo "❌ $service_name failed to start after $max_attempts attempts" + err "$label did not start after ${max}s" return 1 } -# Function to deploy contracts +# ── Dependency checks ─────────────────────────────────────────────────────── +check_deps() { + step "Checking dependencies..." + local missing=() + + for cmd in pnpm anvil; do + if ! command_exists "$cmd"; then + missing+=("$cmd") + fi + done + + if [ ${#missing[@]} -gt 0 ]; then + err "Missing dependencies: ${missing[*]}" + err "Please install them and re-run." + exit 1 + fi + ok "Core dependencies found (pnpm, anvil)" + + # cargo is only needed if we have to install the enclave CLI. + # check_deps runs before install_enclave, so only warn here. + if ! command_exists cargo; then + warn "cargo not found — enclave CLI must be pre-installed (e.g. 'which enclave')" + fi + + if ! command_exists tmux; then + warn "tmux not found — will print VS Code task instructions instead." + warn "Install tmux for the best experience: sudo apt install tmux" + return 1 + fi + ok "tmux found" + return 0 +} + +# ── Install enclave CLI ───────────────────────────────────────────────────── +install_enclave() { + if command_exists enclave; then + info "enclave CLI already installed ($(which enclave))" + return 0 + fi + if ! command_exists cargo; then + err "enclave CLI not found and cargo is not available to install it." + err "Install Rust (https://rustup.rs) or pre-install the enclave binary." + exit 1 + fi + step "Installing enclave CLI..." + cd "$REPO_ROOT" + cargo install --locked --path ./crates/cli --bin enclave -f + ok "enclave CLI installed" +} + +# ── Clean previous state ──────────────────────────────────────────────────── +clean_state() { + step "Cleaning previous dev state..." + rm -rf "$CRISP_ROOT/.enclave/data" + rm -rf "$CRISP_ROOT/.enclave/config" + rm -rf "$CRISP_ROOT/server/database" + rm -f "$READYFILE" + ok "Dev state cleaned" +} + +# ── Deploy contracts + ciphernode registration ────────────────────────────── deploy_contracts() { - echo "📄 Deploying contracts..." - - # Deploy Enclave contracts - echo " Deploying Enclave contracts..." - (cd packages/enclave-contracts && rm -rf deployments/localhost && pnpm deploy:mocks --network localhost) - - # Deploy CRISP contracts - echo " Deploying CRISP contracts..." - (cd examples/CRISP/packages/crisp-contracts && ETH_WALLET_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 FOUNDRY_PROFILE=local forge script --rpc-url http://localhost:8545 --broadcast deploy/Deploy.s.sol) - - # Wait a bit for nodes to be ready - sleep 5 - - # Add ciphernodes to the registry - echo " Adding ciphernodes to registry..." - CN1=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 - CN2=0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC - CN3=0x90F79bf6EB2c4f870365E785982E1f101E93b906 - - pnpm ciphernode:add --ciphernode-address "$CN1" --network "localhost" - pnpm ciphernode:add --ciphernode-address "$CN2" --network "localhost" - pnpm ciphernode:add --ciphernode-address "$CN3" --network "localhost" - - # Clean up local database - echo " Cleaning up local database..." - rm -rf ./examples/CRISP/server/database - - echo "✅ Contracts deployed successfully!" + step "Deploying contracts..." + cd "$CRISP_ROOT" + bash scripts/crisp_deploy.sh + ok "Contracts deployed" +} + +# ── Wallet setup + noir keys + ciphernode registration ────────────────────── +setup_nodes() { + step "Setting up wallets and ciphernodes..." + + # 1. Import wallet keys + for i in "${!NODE_IDS[@]}"; do + info "Importing wallet for ${NODE_IDS[$i]}..." + enclave wallet set --name "${NODE_IDS[$i]}" --private-key "${NODE_KEYS[$i]}" + done + + # 2. Generate ZK keys (noir setup) + info "Running enclave noir setup..." + enclave noir setup + + # 3. Register all ciphernodes in the on-chain registry + for i in "${!NODE_IDS[@]}"; do + info "Registering ${NODE_IDS[$i]} (${NODE_ADDRS[$i]}) in ciphernode registry..." + pnpm ciphernode:add --ciphernode-address "${NODE_ADDRS[$i]}" --network "localhost" + done + + # 4. Signal ready for client + echo 1 > "$READYFILE" + ok "All 5 ciphernodes registered and ready" } -# Start infrastructure (anvil + ciphernodes) in background -echo "🏗️ Starting infrastructure..." -concurrently \ - --names "ANVIL,NODES" \ - --prefix-colors "blue,yellow" \ - "anvil" \ - "cd examples/CRISP && enclave nodes up -v" & +# ── Tmux launcher ─────────────────────────────────────────────────────────── +launch_tmux() { + # Kill existing session if present + if tmux has-session -t "$TMUX_SESSION" 2>/dev/null; then + warn "tmux session '$TMUX_SESSION' already exists — killing it" + tmux kill-session -t "$TMUX_SESSION" + sleep 1 + fi + + step "Creating tmux session: $TMUX_SESSION" + + # ── Window 0: Anvil ───────────────────────────────────────────────── + tmux new-session -d -s "$TMUX_SESSION" -n "anvil" -c "$CRISP_ROOT" \ + "anvil --host 0.0.0.0 --chain-id 31337 --block-time 1 --mnemonic 'test test test test test test test test test test test junk'" + info "Window 0: anvil" + + # ── Wait for anvil, deploy, setup wallets + register ciphernodes ──── + wait_for_port localhost 8545 "Anvil" 60 + deploy_contracts + setup_nodes + # Create the signal file that run_service.sh expects (used by VS Code tasks). + # This keeps tmux mode compatible with the VS Code runner if someone switches. + touch /tmp/crisp-dev-daemon-ready + ok "Signal file created: /tmp/crisp-dev-daemon-ready" + # ── Start the swarm daemon (no nodes yet — we start each individually) + step "Starting swarm daemon (detached, all nodes excluded)..." + enclave nodes up --detach --exclude cn1,cn2,cn3,cn4,cn5 + sleep 3 + ok "Swarm daemon running" + + # ── Windows 1-5: Individual ciphernodes ───────────────────────────── + local win=1 + for id in "${NODE_IDS[@]}"; do + tmux new-window -t "$TMUX_SESSION" -n "$id" -c "$CRISP_ROOT" \ + "enclave nodes start $id; echo '[${id} exited — press Enter to close]'; read" + info "Window $win: $id" + win=$((win + 1)) + done + + # ── Window 6: Program Server ──────────────────────────────────────── + tmux new-window -t "$TMUX_SESSION" -n "program" -c "$CRISP_ROOT" \ + "bash scripts/dev_program.sh; echo '[program exited — press Enter to close]'; read" + info "Window $win: program server" -INFRA_PID=$! + # ── Window 7: Server ──────────────────────────────────────────────── + tmux new-window -t "$TMUX_SESSION" -n "server" -c "$CRISP_ROOT" \ + "bash scripts/dev_server.sh; echo '[server exited — press Enter to close]'; read" + info "Window $((win + 1)): server" -# Wait for Anvil to be ready -wait_for_service "http://localhost:8545" "Anvil" + # ── Window 8: Client ──────────────────────────────────────────────── + tmux new-window -t "$TMUX_SESSION" -n "client" -c "$CRISP_ROOT" \ + "bash scripts/dev_client.sh; echo '[client exited — press Enter to close]'; read" + info "Window $((win + 2)): client" -# Deploy contracts -deploy_contracts + # ── Select window 0 (anvil) and attach ────────────────────────────── + tmux select-window -t "$TMUX_SESSION:anvil" -# Wait a moment for everything to stabilize -echo "⏳ Waiting for infrastructure to stabilize..." -sleep 3 + echo "" + echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}║${NC} ${CYAN}All services launched in tmux session '${TMUX_SESSION}'${NC} ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} ${YELLOW}Windows:${NC} ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 0 → Anvil ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 1 → cn1 ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 2 → cn2 ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 3 → cn3 ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 4 → cn4 ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 5 → cn5 ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 6 → Program Server ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 7 → Server ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} Ctrl+B 8 → Client ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} ${YELLOW}Detach:${NC} Ctrl+B D ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} ${YELLOW}Reattach:${NC} tmux attach -t ${TMUX_SESSION} ${GREEN}║${NC}" + echo -e "${GREEN}║${NC} ${YELLOW}Kill all:${NC} tmux kill-session -t ${TMUX_SESSION} ${GREEN}║${NC}" + echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}" + echo "" -# Install CRISP dependencies -echo "📦 Installing CRISP dependencies..." -(cd examples/CRISP/client && pnpm install) + tmux attach -t "$TMUX_SESSION" +} + +# ── VS Code fallback ─────────────────────────────────────────────────────── +launch_vscode_instructions() { + echo "" + echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${YELLOW}║${NC} ${CYAN}VS Code Tasks — Run each in order (separate terminals)${NC} ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} ${YELLOW}1.${NC} Ctrl+Shift+P → \"Tasks: Run Task\" ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} ${YELLOW}2.${NC} Run tasks in this order: ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} a) CRISP: Anvil ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} b) CRISP: Deploy + Setup ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} c) CRISP: cn1 ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} d) CRISP: cn2 ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} e) CRISP: cn3 ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} f) CRISP: cn4 ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} g) CRISP: cn5 ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} h) CRISP: Program Server ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} i) CRISP: Server ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} j) CRISP: Client ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} Each task opens in a new terminal tab. ${YELLOW}║${NC}" + echo -e "${YELLOW}║${NC} Rename tabs with F2 for clarity. ${YELLOW}║${NC}" + echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}" + echo "" +} -echo "🎯 Starting CRISP applications..." +# ── Main ──────────────────────────────────────────────────────────────────── +main() { + echo "" + echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║${NC} ${GREEN}🚀 CRISP Development Environment Launcher${NC} ${CYAN}║${NC}" + echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" + echo "" -# Start all CRISP applications -concurrently \ - --names "CLIENT,SERVER,PROGRAM" \ - --prefix-colors "green,yellow,magenta" \ - "cd examples/CRISP/client && pnpm dev" \ - "cd examples/CRISP/server && cargo run --bin server" \ - "cd examples/CRISP/program && cargo run" + # Parse flags + case "${1:-}" in + --help|-h) + echo "Usage: bash deploy/local/start.sh [--vscode|--help]" + echo "" + echo " (default) Launch services in tmux windows" + echo " --vscode Print instructions for VS Code task-based launch" + echo " --help Show this help" + exit 0 + ;; + --vscode) + launch_vscode_instructions + exit 0 + ;; + esac + + check_deps && HAS_TMUX=true || HAS_TMUX=false + + install_enclave + clean_state + + if $HAS_TMUX; then + launch_tmux + else + warn "tmux not available — falling back to VS Code task instructions" + launch_vscode_instructions + fi +} -# This will run until interrupted -echo "🚨 CRISP development environment stopped" \ No newline at end of file +main "$@" \ No newline at end of file diff --git a/examples/CRISP/enclave.config.yaml b/examples/CRISP/enclave.config.yaml index 9ebf0b5214..807b53932d 100644 --- a/examples/CRISP/enclave.config.yaml +++ b/examples/CRISP/enclave.config.yaml @@ -6,22 +6,22 @@ chains: contracts: e3_program: address: "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0" - deploy_block: 38 + deploy_block: 40 enclave: address: "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" - deploy_block: 14 + deploy_block: 16 ciphernode_registry: address: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" - deploy_block: 9 + deploy_block: 11 bonding_registry: address: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" - deploy_block: 10 + deploy_block: 12 slashing_manager: address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" - deploy_block: 8 + deploy_block: 10 fee_token: address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" - deploy_block: 4 + deploy_block: 6 program: dev: true # risc0: @@ -59,21 +59,29 @@ nodes: ctrl_port: 50502 autonetkey: true autopassword: true + peers: + - /ip4/127.0.0.1/udp/9201/quic-v1 cn3: address: '0x90F79bf6EB2c4f870365E785982E1f101E93b906' quic_port: 9203 ctrl_port: 50503 autonetkey: true autopassword: true + peers: + - /ip4/127.0.0.1/udp/9201/quic-v1 cn4: address: '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65' quic_port: 9204 ctrl_port: 50504 autonetkey: true autopassword: true + peers: + - /ip4/127.0.0.1/udp/9201/quic-v1 cn5: address: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc' quic_port: 9205 ctrl_port: 50505 autonetkey: true autopassword: true + peers: + - /ip4/127.0.0.1/udp/9201/quic-v1 diff --git a/examples/CRISP/packages/crisp-contracts/deployed_contracts.json b/examples/CRISP/packages/crisp-contracts/deployed_contracts.json index ec705822d0..cf58f56ced 100644 --- a/examples/CRISP/packages/crisp-contracts/deployed_contracts.json +++ b/examples/CRISP/packages/crisp-contracts/deployed_contracts.json @@ -149,21 +149,21 @@ }, "localhost": { "PoseidonT3": { - "blockNumber": 3, + "blockNumber": 5, "address": "0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93" }, "MockUSDC": { "constructorArgs": { "initialSupply": "1000000" }, - "blockNumber": 4, + "blockNumber": 6, "address": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" }, "EnclaveToken": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 5, + "blockNumber": 7, "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" }, "EnclaveTicketToken": { @@ -172,7 +172,7 @@ "registry": "0x0000000000000000000000000000000000000001", "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 7, + "blockNumber": 9, "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" }, "SlashingManager": { @@ -180,7 +180,7 @@ "initialDelay": "172800", "admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 8, + "blockNumber": 10, "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" }, "CiphernodeRegistryOwnable": { @@ -195,7 +195,7 @@ "proxyAdminAddress": "0x9bd03768a7DCc129555dE410FF8E85528A4F88b5", "implementationAddress": "0x0165878A594ca255338adfa4d48449f69242Eb8F" }, - "blockNumber": 9, + "blockNumber": 11, "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" }, "BondingRegistry": { @@ -217,7 +217,7 @@ "proxyAdminAddress": "0x8aCd85898458400f7Db866d53FCFF6f0D49741FF", "implementationAddress": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" }, - "blockNumber": 10, + "blockNumber": 12, "address": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" }, "Enclave": { @@ -237,7 +237,7 @@ "proxyAdminAddress": "0x1F708C24a0D3A740cD47cC0444E9480899f3dA7D", "implementationAddress": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" }, - "blockNumber": 14, + "blockNumber": 16, "address": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" }, "E3RefundManager": { @@ -253,36 +253,36 @@ "proxyAdminAddress": "0x8e80FFe6Dc044F4A766Afd6e5a8732Fe0977A493", "implementationAddress": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82" }, - "blockNumber": 16, + "blockNumber": 18, "address": "0x9A676e781A523b5d0C0e43731313A708CB607508" }, "MockComputeProvider": { - "blockNumber": 30, + "blockNumber": 32, "address": "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00" }, "MockDecryptionVerifier": { - "blockNumber": 31, + "blockNumber": 33, "address": "0x36C02dA8a0983159322a80FFE9F24b1acfF8B570" }, "MockPkVerifier": { - "blockNumber": 32, + "blockNumber": 34, "address": "0x809d550fca64d94Bd9F66E60752A544199cfAC3D" }, "MockE3Program": { - "blockNumber": 33, + "blockNumber": 35, "address": "0x4c5859f0F772848b2D91F1D83E2Fe57935348029" }, "MockRISC0Verifier": { "address": "0xCD8a1C3ba11CF5ECfa6267617243239504a98d90", - "blockNumber": 37 + "blockNumber": 39 }, "HonkVerifier": { "address": "0x2bdCC0de6bE1f7D2ee689a0342D76F52E8EFABa3", - "blockNumber": 38 + "blockNumber": 40 }, "CRISPProgram": { "address": "0x7969c5eD335650692Bc04293B07F5BF2e7A673C0", - "blockNumber": 38, + "blockNumber": 40, "constructorArgs": { "enclave": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", "verifierAddress": "0xCD8a1C3ba11CF5ECfa6267617243239504a98d90", @@ -292,7 +292,7 @@ }, "MockVotingToken": { "address": "0xc351628EB244ec633d5f21fBD6621e1a683B1181", - "blockNumber": 40 + "blockNumber": 42 } } } \ No newline at end of file