From 3b563f2186e41e836242adccaa3d0e66338b005b Mon Sep 17 00:00:00 2001 From: Aaron Lu <50029043+aalu1418@users.noreply.github.com> Date: Tue, 4 Jun 2024 07:37:32 -0600 Subject: [PATCH] write config digest after proposal acceptance + add inspection (#729) --- .../contracts/ocr2/inspection/inspect.ts | 6 ++++++ .../ocr2/inspection/inspectResponses.ts | 4 +++- .../contracts/ocr2/proposal/acceptProposal.ts | 21 +++++++++++++++++++ .../gauntlet-solana-contracts/src/lib/rdd.ts | 12 ++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspect.ts b/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspect.ts index 3ba82c1dd..2c4572770 100644 --- a/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspect.ts +++ b/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspect.ts @@ -10,6 +10,7 @@ import RDD from '../../../../lib/rdd' type Input = { description: string + lastConfigDigest: string decimals: string | number minAnswer: string | number maxAnswer: string | number @@ -56,6 +57,7 @@ export default class OCR2Inspect extends SolanaCommand { return { description: aggregator.name, + lastConfigDigest: aggregator.config.lastConfigDigest, decimals: aggregator.decimals, minAnswer: aggregator.minSubmissionValue, maxAnswer: aggregator.maxSubmissionValue, @@ -181,6 +183,8 @@ export default class OCR2Inspect extends SolanaCommand { ) }) + const configDigestHex = `0x${this.toHexString(onChainState.config.latestConfigDigest)}` + const input = this.makeInput(this.flags.input) // If input does not exist, just print config if (!input) { @@ -192,6 +196,7 @@ export default class OCR2Inspect extends SolanaCommand { - Observation Payment: ${onChainState.config.billing.observationPaymentGjuels} - Requester Access Controller: ${onChainState.config.requesterAccessController} - Billing Access Controller: ${onChainState.config.billingAccessController} + - Latest Config Digest: ${configDigestHex} `, ) return { @@ -228,6 +233,7 @@ export default class OCR2Inspect extends SolanaCommand { ) const inspections: inspection.Inspection[] = [ + inspection.makeInspection(configDigestHex, input.lastConfigDigest, 'Config Digest'), inspection.makeInspection( toComparableNumber(onChainState.config.minAnswer), toComparableNumber(input.minAnswer), diff --git a/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspectResponses.ts b/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspectResponses.ts index 6a904cd2d..f37f367a5 100644 --- a/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspectResponses.ts +++ b/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/inspection/inspectResponses.ts @@ -96,6 +96,8 @@ export default class OCR2InspectResponses extends SolanaCommand { super(flags, args) } + toHexString = (n: number[]) => Buffer.from(n).toString('hex') + execute = async () => { const ocr2 = getContract(CONTRACT_LIST.OCR_2, '') const program = this.loadProgram(ocr2.idl, ocr2.programId.toString()) @@ -109,7 +111,7 @@ export default class OCR2InspectResponses extends SolanaCommand { - Latest Transmitter: ${onChainState.config.latestTransmitter} - Latest Aggregator Round ID: ${onChainState.config.latestAggregatorRoundId} - - Latest Config Digest: ${onChainState.config.latestConfigDigest} + - Latest Config Digest: 0x${this.toHexString(onChainState.config.latestConfigDigest)} - Latest Config Block Number: ${onChainState.config.latestConfigBlockNumber} `, ) diff --git a/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/proposal/acceptProposal.ts b/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/proposal/acceptProposal.ts index 2b3eefca9..36e6d9e3e 100644 --- a/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/proposal/acceptProposal.ts +++ b/gauntlet/packages/gauntlet-solana-contracts/src/commands/contracts/ocr2/proposal/acceptProposal.ts @@ -271,6 +271,25 @@ export default class AcceptProposal extends SolanaCommand { await prompt('Accept config proposal?') } + afterExecute = async () => { + const address = this.args[0] + const contractState = (await this.program.account.state.fetch(new PublicKey(address))) as any + const configDigest = `0x${Buffer.from(contractState.config.latestConfigDigest).toString('hex')}` + + logger.info(`lastConfigDigest to save in RDD: ${configDigest}`) + if (this.flags.rdd) { + logger.info(`RDD file ${this.flags.rdd} found! Will automatically update lastConfigDigest for you`) + const rdd = RDD.load(this.flags.network, this.flags.rdd) + rdd.contracts[address]['config']['lastConfigDigest'] = configDigest + RDD.write(this.flags.network, this.flags.rdd, rdd) + logger.success( + `RDD file ${this.flags.rdd} updated. Please reformat RDD (run ./bin/degenerate and ./bin/generate) as needed`, + ) + } else { + logger.warn(`no rdd file input, you must manually update lastConfigDigest in rdd yourself`) + } + } + execute = async () => { await this.buildCommand(this.flags, this.args) @@ -284,6 +303,8 @@ export default class AcceptProposal extends SolanaCommand { const txhash = await this.sendTxWithIDL(this.signAndSendRawTx, this.program.idl)(rawTx) logger.success(`Accepted proposal on tx ${txhash}`) + await this.afterExecute() + return { responses: [ { diff --git a/gauntlet/packages/gauntlet-solana-contracts/src/lib/rdd.ts b/gauntlet/packages/gauntlet-solana-contracts/src/lib/rdd.ts index 9f9b8429f..5e14f6099 100644 --- a/gauntlet/packages/gauntlet-solana-contracts/src/lib/rdd.ts +++ b/gauntlet/packages/gauntlet-solana-contracts/src/lib/rdd.ts @@ -1,4 +1,4 @@ -import { readFileSync } from 'fs' +import { readFileSync, writeFileSync } from 'fs' import { join } from 'path' const RDD_DIR = '../../reference-data-directory' @@ -22,6 +22,15 @@ function load(network = DEFAULT_NETWORK, path = `${RDD_DIR}/directory-solana-${n } } +function write(network = DEFAULT_NETWORK, path = `${RDD_DIR}/directory-solana-${network}.json`, rdd: any) { + try { + writeFileSync(path, JSON.stringify(rdd, null, 2)) + return + } catch (e) { + throw new Error('An error ocurred while parsing the RDD. Make sure you provided a valid RDD path') + } +} + // TODO: repeated code - get rid of laodAggregator in favor for getContractFromRDD function loadAggregator(contractAddress: string, network?: string, rddPath?: string) { if (!contractAddress) throw new Error('Could not fetch RDD without a valid aggregator address') @@ -48,6 +57,7 @@ function getContractFromRDD(rdd: any, address: string) { const RDD = { load, + write, loadAggregator, getContractFromRDD, }