From 1ab2d9f7140f315ff2630276837d106712972fdb Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Wed, 23 Apr 2025 22:40:25 +0100 Subject: [PATCH] feat[upa]: support config content in env vars (avoid files) --- upa/scripts/test_upa | 11 +++++---- upa/src/tool/config.ts | 19 ++++++++++----- upa/src/tool/options.ts | 54 ++++++++++++++++------------------------- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/upa/scripts/test_upa b/upa/scripts/test_upa index 4554a68..8f43303 100755 --- a/upa/scripts/test_upa +++ b/upa/scripts/test_upa @@ -66,11 +66,10 @@ pushd _test_upa --dump-tx \ ${UPA_DIR}/upa/test/data/test.bin \ > new_agg_proof_verifier.tx - KEYFILE_PASSWORD=${DUMMY_PW} upa owner deploy-binary \ - --keyfile ${KEYFILE} \ + KEYFILE_PASSWORD=${DUMMY_PW} KEYFILE=`cat ${KEYFILE}` upa owner deploy-binary \ ${UPA_DIR}/upa/test/data/test.bin \ > new_agg_proof_verifier.addr - # Test dumpt-tx with a different --from address + # Test dump-tx with a different --from address upa owner set-aggregated-proof-verifier \ --keyfile ${USER_KEYFILE} \ --from ${deployer_addr} \ @@ -84,8 +83,10 @@ pushd _test_upa ${orig_max_num_inputs} --wait [ `cat new_agg_proof_verifier.addr` == `upa query aggregated-proof-verifier` ] - # Print the config - upa query config > config.upa.json + # Print the config. Test UPA_INSTANCE as content + mv upa.instance upa.instance.bak + UPA_INSTANCE=`cat upa.instance.bak` upa query config > config.upa.json + mv upa.instance.bak upa.instance # Test data: # vk diff --git a/upa/src/tool/config.ts b/upa/src/tool/config.ts index 33f7027..e8d94be 100644 --- a/upa/src/tool/config.ts +++ b/upa/src/tool/config.ts @@ -21,11 +21,16 @@ import { GnarkInputs, GnarkProof, GnarkVerificationKey } from "../sdk/gnark"; import { computeCircuitId } from "../sdk/utils"; import { SP1ProofFixture } from "../sdk/sp1"; +/// Infer whether value is JSON or a filename. Return the JSON string. +export function readJSONContentOrFile(value: string): string { + // Infer from the first character. If it's '{', assume JSON. + return value.startsWith("{") ? value : fs.readFileSync(value, "ascii"); +} + /// Load an instance descriptor file export function loadInstance(instanceFile: string): UpaInstanceDescriptor { - return JSON.parse( - fs.readFileSync(instanceFile, "ascii") - ) as UpaInstanceDescriptor; + const instanceStr = readJSONContentOrFile(instanceFile); + return JSON.parse(instanceStr) as UpaInstanceDescriptor; } /// Load an instance descriptor file and initialize and instance. Optionally @@ -40,7 +45,8 @@ export async function upaFromInstanceFile( /// Create a Signer from an encrypted keyfile, allowing overriding by a /// VoidSigner (which cannot actually sign) for a specific fromAddress (for -/// simulating txs). +/// simulating txs). Keyfile can be either keyfile contents (JSON) or a +/// filename. export async function loadWallet( keyfile: string, password: string, @@ -52,7 +58,7 @@ export async function loadWallet( return new ethers.VoidSigner(fromAddress, provider); } - const keystoreStr = fs.readFileSync(keyfile, "ascii"); + const keystoreStr = readJSONContentOrFile(keyfile); let wallet = await ethers.Wallet.fromEncryptedJson(keystoreStr, password); if (provider) { wallet = wallet.connect(provider); @@ -62,7 +68,8 @@ export async function loadWallet( /// Read an address from a keyfile export function readAddressFromKeyfile(keyfile: string): string { - const keystoreObj = JSON.parse(fs.readFileSync(keyfile, "ascii")); + const keystoreStr = readJSONContentOrFile(keyfile); + const keystoreObj = JSON.parse(keystoreStr); return ethers.getAddress(keystoreObj.address); } diff --git a/upa/src/tool/options.ts b/upa/src/tool/options.ts index c66a934..959ad40 100644 --- a/upa/src/tool/options.ts +++ b/upa/src/tool/options.ts @@ -24,21 +24,19 @@ export function keyfile( required: boolean = true ): Option { const defaultValue = () => { - const value = process.env.KEYFILE; - if (!value && required) { + if (required) { // Caught by the CLI framework throw "Keyfile not specified"; } - - return value || ""; + return ""; }; return option({ type: string, long: "keyfile", short: "k", + env: "KEYFILE", defaultValue, - description: - description || "Keyfile to sign tx (defaults to KEYFILE env var)", + description: description || "Keyfile to sign tx (file or contents)", }); } @@ -47,10 +45,9 @@ export function password(description?: string | undefined): Option { return option({ type: string, long: "password", - defaultValue: () => process.env.KEYFILE_PASSWORD || "", - description: - description || - "Password for keyfile (defaults to KEYFILE_PASSWORD env var)", + env: "KEYFILE_PASSWORD", + defaultValue: () => "", + description: description || "Password for keyfile", }); } @@ -79,19 +76,18 @@ export function getPassword(password?: string): string { export function chainEndpoint(required: boolean = true): Option { const defaultValue = () => { - const value = process.env.CHAIN_ENDPOINT; - if (!value && required) { + if (required) { throw "CHAIN_ENDPOINT not specified"; } - - return value || "http://127.0.0.1:8545/"; + return "http://127.0.0.1:8545/"; }; return option({ type: string, long: "chain-endpoint", short: "e", + env: "CHAIN_ENDPOINT", defaultValue, - description: "Chain RPC endpoint (defaults to CHAIN_ENDPOINT env var)", + description: "Chain RPC endpoint", }); } @@ -99,9 +95,9 @@ export function submissionEndpoint(): Option { return option({ type: string, long: "submission-endpoint", - defaultValue: () => process.env.SUBMISSION_ENDPOINT || "", - description: - "Submission endpoint (defaults to SUBMISSION_ENDPOINT env var)", + env: "SUBMISSION_ENDPOINT", + defaultValue: () => "", + description: "Submission endpoint", }); } @@ -109,16 +105,8 @@ export function depositContract() { return option({ type: string, long: "deposit-contract", - description: - "Aggregator's deposit contract (DEPOSIT_CONTRACT or query server)", - defaultValue: () => { - const val = process.env.DEPOSIT_CONTRACT; - if (val) { - return val; - } - - throw "deposit contract not specified"; - }, + description: "Aggregator's deposit contract", + env: "DEPOSIT_CONTRACT", }); } @@ -126,8 +114,9 @@ export function instance(description?: string | undefined): Option { return option({ type: string, long: "instance", + env: "UPA_INSTANCE", defaultValue: () => "upa.instance", - description: description || "UPA instance file", + description: description || "UPA instance file or contents", }); } @@ -254,10 +243,9 @@ export function maxFeePerGasGwei(): Option { return option({ type: string, long: "max-fee-per-gas", - defaultValue: () => { - return process.env.MAX_FEE_PER_GAS_GWEI || ""; - }, - description: "Maximum fee per gas(Gwei) (or env var MAX_FEE_PER_GAS_GWEI)", + env: "MAX_FEE_PER_GAS_GWEI", + defaultValue: () => "", + description: "Maximum fee per gas(Gwei)", }); }