From 84023f41df420293ffc09357d28435fa0578e93c Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Thu, 12 Oct 2023 18:41:41 +0200 Subject: [PATCH 1/7] speed up viewing of governance proposals by concurrent fetching and some avoided fetches --- packages/cli/src/utils/checks.ts | 2 + .../contractkit/src/wrappers/Governance.ts | 57 +++++-- .../sdk/contractkit/src/wrappers/MultiSig.ts | 70 ++++++--- packages/sdk/explorer/src/block-explorer.ts | 15 +- packages/sdk/governance/src/proposals.ts | 142 +++++++++--------- 5 files changed, 174 insertions(+), 112 deletions(-) diff --git a/packages/cli/src/utils/checks.ts b/packages/cli/src/utils/checks.ts index 6fcd55c75e8..8ab28c6c6f3 100644 --- a/packages/cli/src/utils/checks.ts +++ b/packages/cli/src/utils/checks.ts @@ -503,6 +503,8 @@ class CheckBuilder { if (!allPassed) { return this.cmd.error("Some checks didn't pass!") + } else { + console.log(`All checks passed`) } } diff --git a/packages/sdk/contractkit/src/wrappers/Governance.ts b/packages/sdk/contractkit/src/wrappers/Governance.ts index a52b20f3240..dcc0a0bfcb9 100644 --- a/packages/sdk/contractkit/src/wrappers/Governance.ts +++ b/packages/sdk/contractkit/src/wrappers/Governance.ts @@ -245,11 +245,13 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { // simulates proposal.getSupportWithQuorumPadding async getSupport(proposalID: BigNumber.Value) { - const participation = await this.getParticipationParameters() + const [participation, votes, lockedGold] = await Promise.all([ + this.getParticipationParameters(), + this.getVotes(proposalID), + this.contracts.getLockedGold(), + ]) const quorum = participation.baseline.times(participation.baselineQuorumFactor) - const votes = await this.getVotes(proposalID) const total = votes.Yes.plus(votes.No).plus(votes.Abstain) - const lockedGold = await this.contracts.getLockedGold() // NOTE: this networkWeight is not as governance calculates it, // but we don't have access to proposal.networkWeight const networkWeight = await lockedGold.getTotalLockedGold() @@ -455,11 +457,20 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { } async getApprovalStatus(proposalID: BigNumber.Value): Promise { - const multisig = await this.getApproverMultisig() - const approveTx = await this.approve(proposalID) - const multisigTxs = await multisig.getTransactionDataByContent(this.address, approveTx.txo) + console.time(`getApprovalStatus(${proposalID})`) + const [multisig, approveTx] = await Promise.all([ + this.getApproverMultisig(), + this.approve(proposalID), + ]) + + const [multisigTxs, approvers] = await Promise.all([ + multisig.getTransactionDataByContent(this.address, approveTx.txo), + multisig.getOwners() as Promise, + ]) + const confirmations = multisigTxs ? multisigTxs.confirmations : [] - const approvers = await multisig.getOwners() + + console.timeEnd(`getApprovalStatus(${proposalID})`) return { completion: `${confirmations.length} / ${approvers.length}`, confirmations, @@ -472,9 +483,16 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { * @param proposalID Governance proposal UUID */ async getProposalRecord(proposalID: BigNumber.Value): Promise { - const metadata = await this.getProposalMetadata(proposalID) - const proposal = await this.getProposal(proposalID) - const stage = await this.getProposalStage(proposalID) + console.time(`getProposalRecord(${proposalID})`) + + console.time(`getProposalMetaStage(${proposalID})`) + + const [proposal, metadata, stage] = await Promise.all([ + this.getProposal(proposalID), + this.getProposalMetadata(proposalID), + this.getProposalStage(proposalID), + ]) + console.timeEnd(`getProposalMetaStage(${proposalID})`) const record: ProposalRecord = { proposal, @@ -487,13 +505,20 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { if (stage === ProposalStage.Queued) { record.upvotes = await this.getUpvotes(proposalID) } else if (stage === ProposalStage.Referendum || stage === ProposalStage.Execution) { - record.approved = true - record.passed = await this.isProposalPassing(proposalID) - record.votes = await this.getVotes(proposalID) - record.approved = await this.isApproved(proposalID) - record.approvals = await this.getApprovalStatus(proposalID) + console.time(`getProposalState(${proposalID})`) + const [passed, votes, approved, approvals] = await Promise.all([ + this.isProposalPassing(proposalID) as Promise, + this.getVotes(proposalID), + this.isApproved(proposalID), + this.getApprovalStatus(proposalID), + ]) + console.timeEnd(`getProposalState(${proposalID})`) + record.passed = passed as boolean + record.votes = votes + record.approved = approved + record.approvals = approvals } - + console.timeEnd(`getProposalRecord(${proposalID})`) return record } diff --git a/packages/sdk/contractkit/src/wrappers/MultiSig.ts b/packages/sdk/contractkit/src/wrappers/MultiSig.ts index 9cecd439041..1f83a1bc25e 100644 --- a/packages/sdk/contractkit/src/wrappers/MultiSig.ts +++ b/packages/sdk/contractkit/src/wrappers/MultiSig.ts @@ -19,6 +19,12 @@ export interface TransactionData { executed: boolean confirmations: string[] } +export interface TransactionDataWithOutConfirmations { + destination: string + value: BigNumber + data: string + executed: boolean +} /** * Contract for handling multisig actions @@ -30,11 +36,7 @@ export class MultiSigWrapper extends BaseWrapper { * Otherwise, submits the `txObject` to the multisig and add confirmation. * @param index The index of the pending withdrawal to withdraw. */ - async submitOrConfirmTransaction( - destination: string, - txObject: CeloTxObject, - value: string = '0' - ) { + async submitOrConfirmTransaction(destination: string, txObject: CeloTxObject, value = '0') { const data = stringToSolidityBytes(txObject.encodeABI()) const transactionCount = await this.contract.methods.getTransactionCount(true, true).call() let transactionId @@ -79,33 +81,63 @@ export class MultiSigWrapper extends BaseWrapper { txo: CeloTxObject, value: BigNumber.Value = 0 ) { + console.time('getTransactionDataByContent') const data = stringToSolidityBytes(txo.encodeABI()) const transactionCount = await this.getTransactionCount(true, true) - // reverse order for recency - for (let transactionId = transactionCount - 1; transactionId >= 0; transactionId--) { - const tx = await this.getTransaction(transactionId) - if (tx.data === data && tx.destination === destination && tx.value.isEqualTo(value)) { - return tx - } + const transactionIndexes = await Promise.all( + Array(transactionCount) + .fill(0) + .map(async (_, index) => { + const tx = await this.getTransaction(index, false) + if (tx.data === data && tx.destination === destination && tx.value.isEqualTo(value)) { + return index + } + return null + }) + ) + const txID = transactionIndexes.find((index) => index !== null) + if (!txID) { + return } - return undefined + const transactionWithConfirmations = await this.getTransaction(txID) + console.timeEnd('getTransactionDataByContent') + return transactionWithConfirmations } - - async getTransaction(i: number): Promise { + async getTransaction(i: number): Promise + async getTransaction( + i: number, + includeConfirmations: false + ): Promise + async getTransaction(i: number, includeConfirmations = true) { const { destination, value, data, executed } = await this.contract.methods .transactions(i) .call() - const confirmations = [] - for (const e of await this.getOwners()) { - if (await this.contract.methods.confirmations(i, e).call()) { - confirmations.push(e) + if (!includeConfirmations) { + return { + destination, + data, + executed, + value: new BigNumber(value), } } + + const owners = await this.getOwners() + const confirmationsOrEmpties = await Promise.all( + owners.map(async (owner) => { + const confirmation = await this.contract.methods.confirmations(i, owner).call() + if (confirmation) { + return owner + } else { + return null + } + }) + ) + const confirmations = confirmationsOrEmpties.filter((c) => c !== null) as string[] return { + confirmations, destination, data, executed, - confirmations, value: new BigNumber(value), } } diff --git a/packages/sdk/explorer/src/block-explorer.ts b/packages/sdk/explorer/src/block-explorer.ts index 8c612da6545..c4c2bc235a0 100644 --- a/packages/sdk/explorer/src/block-explorer.ts +++ b/packages/sdk/explorer/src/block-explorer.ts @@ -369,11 +369,14 @@ export class BlockExplorer { this.getContractMappingFromSourcifyAsProxy, ] ): Promise { - for (const strategy of strategies) { - const contractMapping = await strategy(address) - if (contractMapping && contractMapping.fnMapping.get(selector)) { - return contractMapping - } - } + const mappings = await Promise.all( + strategies.map(async (strategy) => { + const contractMapping = await strategy(address) + if (contractMapping && contractMapping.fnMapping.get(selector)) { + return contractMapping + } + }) + ) + return mappings.find((mapping) => mapping !== undefined) } } diff --git a/packages/sdk/governance/src/proposals.ts b/packages/sdk/governance/src/proposals.ts index c1329e17f51..bb54d2290a6 100644 --- a/packages/sdk/governance/src/proposals.ts +++ b/packages/sdk/governance/src/proposals.ts @@ -136,91 +136,91 @@ export const proposalToJSON = async ( debug(`updating registry to reflect ${name} => ${address}`) await blockExplorer.updateContractDetailsMapping(stripProxy(name), address) } - if (registryAdditions) { // Update the registry mapping with registry additions prior to processing the proposal. - for (const nameStr of Object.keys(registryAdditions)) { - const name = nameStr as CeloContract - if (CeloContract[name]) { - await updateRegistryMapping(name, registryAdditions[name]) - } else { - debug(`Name ${nameStr} in registry additions not a CeloContract`) - } - } + await Promise.all( + Object.keys(registryAdditions).map(async (nameStr) => { + const name = nameStr as CeloContract + if (CeloContract[name]) { + await updateRegistryMapping(name, registryAdditions[name]) + } else { + debug(`Name ${nameStr} in registry additions not a CeloContract`) + } + }) + ) } - const abiCoder = kit.connection.getAbiCoder() - const proposalJson: ProposalTransactionJSON[] = [] - - for (const tx of proposal) { - debug(`decoding tx ${JSON.stringify(tx)}`) - const parsedTx = await blockExplorer.tryParseTx(tx as CeloTxPending) - if (parsedTx == null) { - throw new Error(`Unable to parse ${JSON.stringify(tx)} with block explorer`) - } - if (isRegistryRepointRaw(abiCoder, tx) && parsedTx.callDetails.isCoreContract) { - const args = registryRepointRawArgs(abiCoder, tx) - await updateRegistryMapping(args.name, args.address) - } + const proposalJson: ProposalTransactionJSON[] = await Promise.all( + proposal.map(async (tx) => { + debug(`decoding tx ${JSON.stringify(tx)}`) + const parsedTx = await blockExplorer.tryParseTx(tx as CeloTxPending) + if (parsedTx == null) { + throw new Error(`Unable to parse ${JSON.stringify(tx)} with block explorer`) + } + if (isRegistryRepointRaw(abiCoder, tx) && parsedTx.callDetails.isCoreContract) { + const args = registryRepointRawArgs(abiCoder, tx) + await updateRegistryMapping(args.name, args.address) + } - const jsonTx: ProposalTransactionJSON = { - contract: parsedTx.callDetails.contract as CeloContract, - address: parsedTx.callDetails.contractAddress, - function: parsedTx.callDetails.function, - args: parsedTx.callDetails.argList, - params: parsedTx.callDetails.paramMap, - value: parsedTx.tx.value, - } + const jsonTx: ProposalTransactionJSON = { + contract: parsedTx.callDetails.contract as CeloContract, + address: parsedTx.callDetails.contractAddress, + function: parsedTx.callDetails.function, + args: parsedTx.callDetails.argList, + params: parsedTx.callDetails.paramMap, + value: parsedTx.tx.value, + } - if (isProxySetFunction(jsonTx)) { - jsonTx.contract = suffixProxy(jsonTx.contract) - await blockExplorer.setProxyOverride(tx.to!, jsonTx.args[0]) - } else if (isProxySetAndInitFunction(jsonTx)) { - await blockExplorer.setProxyOverride(tx.to!, jsonTx.args[0]) - let initAbi - if (parsedTx.callDetails.isCoreContract) { + if (isProxySetFunction(jsonTx)) { jsonTx.contract = suffixProxy(jsonTx.contract) - initAbi = getInitializeAbiOfImplementation(jsonTx.contract as any) - } else { - const implAddress = jsonTx.args[0] - const metadata = await fetchMetadata(kit.connection, implAddress) - if (metadata && metadata.abi) { - initAbi = metadata?.abiForMethod('initialize')[0] + await blockExplorer.setProxyOverride(tx.to!, jsonTx.args[0]) + } else if (isProxySetAndInitFunction(jsonTx)) { + await blockExplorer.setProxyOverride(tx.to!, jsonTx.args[0]) + let initAbi + if (parsedTx.callDetails.isCoreContract) { + jsonTx.contract = suffixProxy(jsonTx.contract) + initAbi = getInitializeAbiOfImplementation(jsonTx.contract as any) + } else { + const implAddress = jsonTx.args[0] + const metadata = await fetchMetadata(kit.connection, implAddress) + if (metadata && metadata.abi) { + initAbi = metadata?.abiForMethod('initialize')[0] + } } - } - if (initAbi !== undefined) { - // Transform delegate call initialize args into a readable params map - // 8 bytes for function sig - const initSig = trimLeading0x(jsonTx.args[1]).slice(0, 8) - const initArgs = trimLeading0x(jsonTx.args[1]).slice(8) + if (initAbi !== undefined) { + // Transform delegate call initialize args into a readable params map + // 8 bytes for function sig + const initSig = trimLeading0x(jsonTx.args[1]).slice(0, 8) + const initArgs = trimLeading0x(jsonTx.args[1]).slice(8) - const { params: initParams } = parseDecodedParams( - kit.connection.getAbiCoder().decodeParameters(initAbi.inputs!, initArgs) - ) - jsonTx.params![`initialize@${initSig}`] = initParams - } - } else if (isGovernanceConstitutionSetter(jsonTx)) { - const [address, functionId, threshold] = jsonTx.args - const contractMapping = await blockExplorer.getContractMappingWithSelector( - address, - functionId - ) - if (contractMapping === undefined) { - throw new Error( - `Governance.setConstitution targets unknown address ${address} and function id ${functionId}` + const { params: initParams } = parseDecodedParams( + kit.connection.getAbiCoder().decodeParameters(initAbi.inputs!, initArgs) + ) + jsonTx.params![`initialize@${initSig}`] = initParams + } + } else if (isGovernanceConstitutionSetter(jsonTx)) { + const [address, functionId, threshold] = jsonTx.args + const contractMapping = await blockExplorer.getContractMappingWithSelector( + address, + functionId ) + if (contractMapping === undefined) { + throw new Error( + `Governance.setConstitution targets unknown address ${address} and function id ${functionId}` + ) + } + jsonTx.params![`setConstitution[${address}][${functionId}]`] = { + contract: contractMapping.details.name, + method: contractMapping.fnMapping.get(functionId)?.name, + threshold: fromFixed(new BigNumber(threshold)), + } } - jsonTx.params![`setConstitution[${address}][${functionId}]`] = { - contract: contractMapping.details.name, - method: contractMapping.fnMapping.get(functionId)?.name, - threshold: fromFixed(new BigNumber(threshold)), - } - } + return jsonTx + }) + ) - proposalJson.push(jsonTx) - } return proposalJson } From 67ac0768d4585eb9a0d59aa2e0672d31b6303adc Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Fri, 13 Oct 2023 12:23:29 +0200 Subject: [PATCH 2/7] save chain id to the connection, add contracts from sourcify to the contract mapping --- packages/sdk/connect/src/connection.ts | 18 +++++++++++++----- packages/sdk/explorer/src/block-explorer.ts | 10 +++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/sdk/connect/src/connection.ts b/packages/sdk/connect/src/connection.ts index fa11244f123..c7286415d46 100644 --- a/packages/sdk/connect/src/connection.ts +++ b/packages/sdk/connect/src/connection.ts @@ -1,11 +1,11 @@ import { ensureLeading0x, toChecksumAddress } from '@celo/utils/lib/address' import { EIP712TypedData, generateTypedDataHash } from '@celo/utils/lib/sign-typed-data-utils' -import { parseSignatureWithoutPrefix, Signature } from '@celo/utils/lib/signatureUtils' +import { Signature, parseSignatureWithoutPrefix } from '@celo/utils/lib/signatureUtils' import { bufferToHex } from '@ethereumjs/util' import debugFactory from 'debug' import Web3 from 'web3' import { AbiCoder } from './abi-types' -import { assertIsCeloProvider, CeloProvider } from './celo-provider' +import { CeloProvider, assertIsCeloProvider } from './celo-provider' import { Address, Block, @@ -32,9 +32,9 @@ import { outputCeloTxReceiptFormatter, } from './utils/formatter' import { hasProperty } from './utils/provider-utils' -import { getRandomId, HttpRpcCaller, RpcCaller } from './utils/rpc-caller' +import { HttpRpcCaller, RpcCaller, getRandomId } from './utils/rpc-caller' import { TxParamsNormalizer } from './utils/tx-params-normalizer' -import { toTxResult, TransactionResult } from './utils/tx-result' +import { TransactionResult, toTxResult } from './utils/tx-result' import { ReadOnlyWallet } from './wallet' const debugGasEstimation = debugFactory('connection:gas-estimation') @@ -54,6 +54,7 @@ export interface ConnectionOptions { */ export class Connection { private config: ConnectionOptions + private _chainID: number | undefined readonly paramsPopulator: TxParamsNormalizer rpcCaller!: RpcCaller @@ -76,6 +77,7 @@ export class Connection { if (!provider) { throw new Error('Must have a valid Provider') } + this._chainID = undefined try { if (!(provider instanceof CeloProvider)) { this.rpcCaller = new HttpRpcCaller(provider) @@ -395,10 +397,16 @@ export class Connection { } } + // An instance of Connection will only change chain id if provider is changed. chainId = async (): Promise => { + if (this._chainID) { + return this._chainID + } // Reference: https://eth.wiki/json-rpc/API#net_version const response = await this.rpcCaller.call('net_version', []) - return parseInt(response.result.toString(), 10) + const chainID = parseInt(response.result.toString(), 10) + this._chainID = chainID + return chainID } getTransactionCount = async (address: Address): Promise => { diff --git a/packages/sdk/explorer/src/block-explorer.ts b/packages/sdk/explorer/src/block-explorer.ts index c4c2bc235a0..a7b84489087 100644 --- a/packages/sdk/explorer/src/block-explorer.ts +++ b/packages/sdk/explorer/src/block-explorer.ts @@ -315,8 +315,16 @@ export class BlockExplorer { getContractMappingFromSourcify = async ( address: string ): Promise => { + const cached = this.addressMapping.get(address) + if (cached) { + return cached + } const metadata = await fetchMetadata(this.kit.connection, address) - return metadata?.toContractMapping() + const mapping = metadata?.toContractMapping() + if (mapping) { + this.addressMapping.set(address, mapping) + } + return mapping } /** From 89f34d6fa57bd258f1b938c1f3b21bb7edc51b88 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Fri, 13 Oct 2023 12:24:12 +0200 Subject: [PATCH 3/7] remove console.time --- packages/sdk/contractkit/src/wrappers/Governance.ts | 10 ---------- packages/sdk/contractkit/src/wrappers/MultiSig.ts | 2 -- 2 files changed, 12 deletions(-) diff --git a/packages/sdk/contractkit/src/wrappers/Governance.ts b/packages/sdk/contractkit/src/wrappers/Governance.ts index dcc0a0bfcb9..6cc2c23e58c 100644 --- a/packages/sdk/contractkit/src/wrappers/Governance.ts +++ b/packages/sdk/contractkit/src/wrappers/Governance.ts @@ -457,7 +457,6 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { } async getApprovalStatus(proposalID: BigNumber.Value): Promise { - console.time(`getApprovalStatus(${proposalID})`) const [multisig, approveTx] = await Promise.all([ this.getApproverMultisig(), this.approve(proposalID), @@ -470,7 +469,6 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { const confirmations = multisigTxs ? multisigTxs.confirmations : [] - console.timeEnd(`getApprovalStatus(${proposalID})`) return { completion: `${confirmations.length} / ${approvers.length}`, confirmations, @@ -483,16 +481,11 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { * @param proposalID Governance proposal UUID */ async getProposalRecord(proposalID: BigNumber.Value): Promise { - console.time(`getProposalRecord(${proposalID})`) - - console.time(`getProposalMetaStage(${proposalID})`) - const [proposal, metadata, stage] = await Promise.all([ this.getProposal(proposalID), this.getProposalMetadata(proposalID), this.getProposalStage(proposalID), ]) - console.timeEnd(`getProposalMetaStage(${proposalID})`) const record: ProposalRecord = { proposal, @@ -505,20 +498,17 @@ export class GovernanceWrapper extends BaseWrapperForGoverning { if (stage === ProposalStage.Queued) { record.upvotes = await this.getUpvotes(proposalID) } else if (stage === ProposalStage.Referendum || stage === ProposalStage.Execution) { - console.time(`getProposalState(${proposalID})`) const [passed, votes, approved, approvals] = await Promise.all([ this.isProposalPassing(proposalID) as Promise, this.getVotes(proposalID), this.isApproved(proposalID), this.getApprovalStatus(proposalID), ]) - console.timeEnd(`getProposalState(${proposalID})`) record.passed = passed as boolean record.votes = votes record.approved = approved record.approvals = approvals } - console.timeEnd(`getProposalRecord(${proposalID})`) return record } diff --git a/packages/sdk/contractkit/src/wrappers/MultiSig.ts b/packages/sdk/contractkit/src/wrappers/MultiSig.ts index 1f83a1bc25e..38d1c2efd38 100644 --- a/packages/sdk/contractkit/src/wrappers/MultiSig.ts +++ b/packages/sdk/contractkit/src/wrappers/MultiSig.ts @@ -81,7 +81,6 @@ export class MultiSigWrapper extends BaseWrapper { txo: CeloTxObject, value: BigNumber.Value = 0 ) { - console.time('getTransactionDataByContent') const data = stringToSolidityBytes(txo.encodeABI()) const transactionCount = await this.getTransactionCount(true, true) const transactionIndexes = await Promise.all( @@ -100,7 +99,6 @@ export class MultiSigWrapper extends BaseWrapper { return } const transactionWithConfirmations = await this.getTransaction(txID) - console.timeEnd('getTransactionDataByContent') return transactionWithConfirmations } async getTransaction(i: number): Promise From a9652a533b04a10bf9b02f5657045a6ffbbdbfab Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Fri, 13 Oct 2023 13:44:04 +0200 Subject: [PATCH 4/7] lint --- packages/sdk/connect/src/connection.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/sdk/connect/src/connection.ts b/packages/sdk/connect/src/connection.ts index c7286415d46..7b78e768dbe 100644 --- a/packages/sdk/connect/src/connection.ts +++ b/packages/sdk/connect/src/connection.ts @@ -1,11 +1,11 @@ import { ensureLeading0x, toChecksumAddress } from '@celo/utils/lib/address' import { EIP712TypedData, generateTypedDataHash } from '@celo/utils/lib/sign-typed-data-utils' -import { Signature, parseSignatureWithoutPrefix } from '@celo/utils/lib/signatureUtils' +import { parseSignatureWithoutPrefix, Signature } from '@celo/utils/lib/signatureUtils' import { bufferToHex } from '@ethereumjs/util' import debugFactory from 'debug' import Web3 from 'web3' import { AbiCoder } from './abi-types' -import { CeloProvider, assertIsCeloProvider } from './celo-provider' +import { assertIsCeloProvider, CeloProvider } from './celo-provider' import { Address, Block, @@ -32,9 +32,9 @@ import { outputCeloTxReceiptFormatter, } from './utils/formatter' import { hasProperty } from './utils/provider-utils' -import { HttpRpcCaller, RpcCaller, getRandomId } from './utils/rpc-caller' +import { getRandomId, HttpRpcCaller, RpcCaller } from './utils/rpc-caller' import { TxParamsNormalizer } from './utils/tx-params-normalizer' -import { TransactionResult, toTxResult } from './utils/tx-result' +import { toTxResult, TransactionResult } from './utils/tx-result' import { ReadOnlyWallet } from './wallet' const debugGasEstimation = debugFactory('connection:gas-estimation') From 1e385fc15aa9846aa6ad7da1304ef209139a39f3 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Mon, 16 Oct 2023 16:09:32 +0200 Subject: [PATCH 5/7] add cs --- .changeset/bitter-cacti-grow.md | 5 +++++ .changeset/chilled-carpets-deliver.md | 5 +++++ .changeset/clean-suns-dance.md | 5 +++++ .changeset/sour-trees-rush.md | 5 +++++ .changeset/thin-cycles-play.md | 5 +++++ .changeset/thirty-trees-fry.md | 5 +++++ 6 files changed, 30 insertions(+) create mode 100644 .changeset/bitter-cacti-grow.md create mode 100644 .changeset/chilled-carpets-deliver.md create mode 100644 .changeset/clean-suns-dance.md create mode 100644 .changeset/sour-trees-rush.md create mode 100644 .changeset/thin-cycles-play.md create mode 100644 .changeset/thirty-trees-fry.md diff --git a/.changeset/bitter-cacti-grow.md b/.changeset/bitter-cacti-grow.md new file mode 100644 index 00000000000..bd131376f0e --- /dev/null +++ b/.changeset/bitter-cacti-grow.md @@ -0,0 +1,5 @@ +--- +'@celo/contractkit': minor +--- + +Add MultiSig.getTransaction() now optionally takes a second boolean param to avoid fetching confirmations information diff --git a/.changeset/chilled-carpets-deliver.md b/.changeset/chilled-carpets-deliver.md new file mode 100644 index 00000000000..4f45f04ce4c --- /dev/null +++ b/.changeset/chilled-carpets-deliver.md @@ -0,0 +1,5 @@ +--- +'@celo/celocli': patch +--- + +Speeds up governance:show command by parallelize async calls, and reducing data fetched diff --git a/.changeset/clean-suns-dance.md b/.changeset/clean-suns-dance.md new file mode 100644 index 00000000000..76b131b2017 --- /dev/null +++ b/.changeset/clean-suns-dance.md @@ -0,0 +1,5 @@ +--- +'@celo/connect': patch +--- + +Add memoization to Connection.chainId() funciton. this is reset when setProvider is called. diff --git a/.changeset/sour-trees-rush.md b/.changeset/sour-trees-rush.md new file mode 100644 index 00000000000..544dbf20ecc --- /dev/null +++ b/.changeset/sour-trees-rush.md @@ -0,0 +1,5 @@ +--- +'@celo/contractkit': patch +--- + +parallelize async calls in Governance Wrapper diff --git a/.changeset/thin-cycles-play.md b/.changeset/thin-cycles-play.md new file mode 100644 index 00000000000..af311c8b6cc --- /dev/null +++ b/.changeset/thin-cycles-play.md @@ -0,0 +1,5 @@ +--- +'@celo/explorer': patch +--- + +Calls to getContractMappingFromSourcify() are now memoized in the same structure (this.addressMapping) as getContractMappingFromCore, getContractMappingWithSelector now runs in parallel diff --git a/.changeset/thirty-trees-fry.md b/.changeset/thirty-trees-fry.md new file mode 100644 index 00000000000..9dc9769ae0c --- /dev/null +++ b/.changeset/thirty-trees-fry.md @@ -0,0 +1,5 @@ +--- +'@celo/governance': patch +--- + +Parallelize Fetching Proposal Info From 22e8669ec382f9ed597483a8030a3a855b8e265c Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Mon, 16 Oct 2023 16:11:19 +0200 Subject: [PATCH 6/7] Bump zod from 3.22.2 to 3.22.4 --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index efc2d29bd97..40a791595c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25343,6 +25343,6 @@ yocto-queue@^0.1.0: integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zod@^3.21.4: - version "3.22.2" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.2.tgz#3add8c682b7077c05ac6f979fea6998b573e157b" - integrity sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg== + version "3.22.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" + integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== From b4b75d26b5ce9cbb39e3e1327ce32d4867df01c4 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Mon, 16 Oct 2023 18:53:45 +0200 Subject: [PATCH 7/7] Avoid refetching the correct transaction. --- .changeset/green-rocks-allow.md | 5 +++ .../sdk/contractkit/src/wrappers/MultiSig.ts | 40 ++++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 .changeset/green-rocks-allow.md diff --git a/.changeset/green-rocks-allow.md b/.changeset/green-rocks-allow.md new file mode 100644 index 00000000000..75d6ceebf43 --- /dev/null +++ b/.changeset/green-rocks-allow.md @@ -0,0 +1,5 @@ +--- +'@celo/contractkit': minor +--- + +Add method getConfirmations() to Multisig Wrapper diff --git a/packages/sdk/contractkit/src/wrappers/MultiSig.ts b/packages/sdk/contractkit/src/wrappers/MultiSig.ts index 38d1c2efd38..5944ea4bb43 100644 --- a/packages/sdk/contractkit/src/wrappers/MultiSig.ts +++ b/packages/sdk/contractkit/src/wrappers/MultiSig.ts @@ -83,23 +83,26 @@ export class MultiSigWrapper extends BaseWrapper { ) { const data = stringToSolidityBytes(txo.encodeABI()) const transactionCount = await this.getTransactionCount(true, true) - const transactionIndexes = await Promise.all( + const transactionsOrEmpties = await Promise.all( Array(transactionCount) .fill(0) .map(async (_, index) => { const tx = await this.getTransaction(index, false) if (tx.data === data && tx.destination === destination && tx.value.isEqualTo(value)) { - return index + return { index, ...tx } } return null }) ) - const txID = transactionIndexes.find((index) => index !== null) - if (!txID) { + const wantedTransaction = transactionsOrEmpties.find((tx) => tx !== null) + if (!wantedTransaction) { return } - const transactionWithConfirmations = await this.getTransaction(txID) - return transactionWithConfirmations + const confirmations = await this.getConfirmations(wantedTransaction.index) + return { + ...wantedTransaction, + confirmations, + } } async getTransaction(i: number): Promise async getTransaction( @@ -119,10 +122,25 @@ export class MultiSigWrapper extends BaseWrapper { } } + const confirmations = await this.getConfirmations(i) + return { + confirmations, + destination, + data, + executed, + value: new BigNumber(value), + } + } + + /* + * Returns array of signer addresses which have confirmed a transaction + * when given the index of that transaction. + */ + async getConfirmations(txId: number) { const owners = await this.getOwners() const confirmationsOrEmpties = await Promise.all( owners.map(async (owner) => { - const confirmation = await this.contract.methods.confirmations(i, owner).call() + const confirmation = await this.contract.methods.confirmations(txId, owner).call() if (confirmation) { return owner } else { @@ -131,13 +149,7 @@ export class MultiSigWrapper extends BaseWrapper { }) ) const confirmations = confirmationsOrEmpties.filter((c) => c !== null) as string[] - return { - confirmations, - destination, - data, - executed, - value: new BigNumber(value), - } + return confirmations } async getTransactions(): Promise {