From 03e9738908b5f834b887fc74a692adfd4476a66a Mon Sep 17 00:00:00 2001 From: ctrlc03 <93448202+ctrlc03@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:29:46 +0000 Subject: [PATCH] fix: do not override comments --- examples/CRISP/enclave.config.yaml | 28 ++- packages/enclave-contracts/scripts/utils.ts | 201 ++++++++++++++++---- 2 files changed, 180 insertions(+), 49 deletions(-) diff --git a/examples/CRISP/enclave.config.yaml b/examples/CRISP/enclave.config.yaml index 74c01d0f1d..8925b9d4f9 100644 --- a/examples/CRISP/enclave.config.yaml +++ b/examples/CRISP/enclave.config.yaml @@ -3,25 +3,33 @@ chains: rpc_url: "ws://localhost:8545" contracts: e3_program: - address: '0x851356ae760d987E095750cCeb3bC6014560891C' - deploy_block: 31 + address: "0x851356ae760d987E095750cCeb3bC6014560891C" + deploy_block: 64 enclave: address: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" - deploy_block: 21 + deploy_block: 42 ciphernode_registry: - address: '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853' - deploy_block: 14 + address: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" + deploy_block: 36 bonding_registry: - address: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318' - deploy_block: 10 + address: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" + deploy_block: 39 slashing_manager: - address: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707' - deploy_block: 10 + address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" + deploy_block: 32 fee_token: address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" - deploy_block: 6 + deploy_block: 17 program: dev: true + # risc0: + # risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode (fake proofs) + # boundless: + # rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" + # private_key: "PRIVATE_KEY" # Use env vars for secrets + # pinata_jwt: "PINATA_JWT" # For uploading programs + # program_url: "https://gateway.pinata.cloud/ipfs/QmNMRAB7DW43JSmENfzGmD96G6sqaeBBNfTVrrq5WQae3D" # Pre-uploaded program + # onchain: true # true = onchain requests, false = offchain nodes: cn1: address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" diff --git a/packages/enclave-contracts/scripts/utils.ts b/packages/enclave-contracts/scripts/utils.ts index 23103a5e35..e4f527aef1 100644 --- a/packages/enclave-contracts/scripts/utils.ts +++ b/packages/enclave-contracts/scripts/utils.ts @@ -4,7 +4,6 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. import fs from "fs"; -import yaml from "js-yaml"; import path from "path"; export const deploymentsFile = path.join("deployed_contracts.json"); @@ -164,7 +163,8 @@ export function areArraysEqual(arr1: T[], arr2: T[]): boolean { } /** - * The function to update the enclave.config.yaml file with the deployed contract addresses + * The function to update the enclave.config.yaml file with the deployed contract addresses. + * Uses line-by-line text manipulation to preserve comments, blank lines, and quote style. * @param chainToConfig - The chain name to update in the config * @param pathToConfigFile - The path to the enclave.config.yaml file * @param contractMapping - A mapping of contract names to config keys @@ -175,59 +175,182 @@ export const updateE3Config = ( contractMapping: Record, rpcUrl?: string, ): void => { - const fileContent = fs.readFileSync(pathToConfigFile, "utf8"); - const config = yaml.load(fileContent) as EnclaveConfig; + const content = fs.readFileSync(pathToConfigFile, "utf8"); + const lines = content.split("\n"); - // Find the hardhat chain config - // Find the chain config or create it - let configChain = config.chains.find((chain) => chain.name === chainToConfig); + // Collect deployment data keyed by config key + const updates = new Map(); + for (const [contractName, configKey] of Object.entries(contractMapping)) { + const deployment = readDeploymentArgs(contractName, chainToConfig); + if (deployment) { + updates.set(configKey, { + address: deployment.address, + deployBlock: deployment.blockNumber ?? 1, + }); + } + } + + if (updates.size === 0) { + console.log("No deployments found to update."); + return; + } + + console.log(`\nUpdating contracts for chain: ${chainToConfig}`); + + // State machine to walk through the YAML lines + let inTargetChain = false; + let foundTargetChain = false; + let inContracts = false; + let currentContractKey: string | null = null; + let chainBaseIndent = -1; + let contractsKeyIndent = -1; + let contractEntryIndent = -1; + const foundKeys = new Set(); + let lastContractsLine = -1; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const trimmed = line.trim(); + + if (trimmed === "" || trimmed.startsWith("#")) { + if (inContracts) lastContractsLine = i; + continue; + } + + const indent = line.length - line.trimStart().length; + + // Detect chain name entry: ` - name: "chainName"` + const nameMatch = trimmed.match(/^-\s+name:\s*["']?(.+?)["']?\s*$/); + if (nameMatch) { + if (inTargetChain) { + // We've passed the target chain + break; + } + + if (nameMatch[1] === chainToConfig) { + inTargetChain = true; + foundTargetChain = true; + chainBaseIndent = indent; + } + continue; + } + + // If we hit a top-level key while in the target chain, we've left it + if (inTargetChain && indent <= chainBaseIndent && !trimmed.startsWith("-")) { + break; + } + + if (!inTargetChain) continue; + + // Detect `contracts:` section + if (trimmed === "contracts:") { + inContracts = true; + contractsKeyIndent = indent; + lastContractsLine = i; + continue; + } + + if (!inContracts) continue; + + // Check if we've left the contracts section + if (indent <= contractsKeyIndent) { + break; + } + + lastContractsLine = i; - if (!configChain) { + // Detect contract key line (e.g., ` enclave:`) + const keyMatch = trimmed.match(/^(\w+):$/); + if (keyMatch && (contractEntryIndent === -1 || indent === contractEntryIndent)) { + currentContractKey = keyMatch[1]; + if (contractEntryIndent === -1) contractEntryIndent = indent; + continue; + } + + if (!currentContractKey) continue; + + // We're inside a contract entry — update address/deploy_block if this contract needs updating + const update = updates.get(currentContractKey); + if (!update) continue; + + if (trimmed.startsWith("address:")) { + foundKeys.add(currentContractKey); + const ws = line.match(/^(\s*)/)?.[1] ?? ""; + const comment = trimmed.match(/^address:\s*["']?[^#"']*["']?\s*(#.*)$/)?.[1]; + lines[i] = `${ws}address: "${update.address}"${comment ? " " + comment : ""}`; + console.log( + `✓ Updated ${currentContractKey}: ${update.address} (block ${update.deployBlock})`, + ); + } + + if (trimmed.startsWith("deploy_block:")) { + const ws = line.match(/^(\s*)/)?.[1] ?? ""; + const comment = trimmed.match(/^deploy_block:\s*\S+\s*(#.*)$/)?.[1]; + lines[i] = `${ws}deploy_block: ${update.deployBlock}${comment ? " " + comment : ""}`; + } + } + + if (!foundTargetChain) { + // Chain not found — append a new chain block at the end of the chains section console.log( `Chain "${chainToConfig}" not found in config. Creating new entry...`, ); - if (!rpcUrl) { console.warn( "Warning: No RPC URL provided. You'll need to update it manually in the config.", ); } - configChain = { - name: chainToConfig, - rpc_url: rpcUrl || `ws://localhost:8545`, - contracts: {}, - }; - - config.chains.push(configChain); - console.log(`✓ Created new chain entry for "${chainToConfig}"`); - } - - console.log(`\nUpdating contracts for chain: ${chainToConfig}`); - - // Update contract addresses and deploy blocks - for (const [contractName, configKey] of Object.entries(contractMapping)) { - const deployment = readDeploymentArgs(contractName, chainToConfig); + const chainsIdx = lines.findIndex((l) => l.trim() === "chains:"); + let insertIdx = lines.length; + if (chainsIdx !== -1) { + for (let i = chainsIdx + 1; i < lines.length; i++) { + const t = lines[i].trim(); + if (t === "" || t.startsWith("#")) continue; + if (lines[i].length - lines[i].trimStart().length === 0) { + insertIdx = i; + break; + } + } + } - if (deployment) { - configChain.contracts[configKey as keyof typeof configChain.contracts] = { - address: deployment.address, - deploy_block: deployment.blockNumber ?? 1, - }; + const newLines = [ + ` - name: "${chainToConfig}"`, + ` rpc_url: "${rpcUrl || "ws://localhost:8545"}"`, + ` contracts:`, + ]; + for (const [configKey, update] of updates) { + newLines.push(` ${configKey}:`); + newLines.push(` address: "${update.address}"`); + newLines.push(` deploy_block: ${update.deployBlock}`); console.log( - `✓ Updated ${configKey}: ${deployment.address} (block ${deployment.blockNumber ?? 1})`, + `✓ Added ${configKey}: ${update.address} (block ${update.deployBlock})`, ); } - } + lines.splice(insertIdx, 0, ...newLines); + } else { + // Insert any contracts that weren't found in the existing config + const missingKeys = [...updates.keys()].filter((k) => !foundKeys.has(k)); + if (missingKeys.length > 0 && lastContractsLine !== -1) { + const keyIndent = + contractEntryIndent !== -1 ? contractEntryIndent : contractsKeyIndent + 2; + const valIndent = keyIndent + 2; - // Write updated config back to file - const yamlStr = yaml.dump(config, { - indent: 2, - lineWidth: -1, // Don't wrap lines - quotingType: '"', - forceQuotes: true, - }); + const newLines: string[] = []; + for (const configKey of missingKeys) { + const update = updates.get(configKey)!; + newLines.push(`${" ".repeat(keyIndent)}${configKey}:`); + newLines.push(`${" ".repeat(valIndent)}address: "${update.address}"`); + newLines.push(`${" ".repeat(valIndent)}deploy_block: ${update.deployBlock}`); + console.log( + `✓ Added ${configKey}: ${update.address} (block ${update.deployBlock})`, + ); + } + + lines.splice(lastContractsLine + 1, 0, ...newLines); + } + } - fs.writeFileSync(pathToConfigFile, yamlStr + "\n", "utf8"); + fs.writeFileSync(pathToConfigFile, lines.join("\n"), "utf8"); console.log("\n✓ enclave.config.yaml updated successfully!"); };