Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast Proposal Viewing #10652

Merged
merged 8 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/bitter-cacti-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/contractkit': minor
---

Add MultiSig.getTransaction() now optionally takes a second boolean param to avoid fetching confirmations information
5 changes: 5 additions & 0 deletions .changeset/chilled-carpets-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/celocli': patch
---

Speeds up governance:show command by parallelize async calls, and reducing data fetched
5 changes: 5 additions & 0 deletions .changeset/clean-suns-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/connect': patch
---

Add memoization to Connection.chainId() funciton. this is reset when setProvider is called.
5 changes: 5 additions & 0 deletions .changeset/green-rocks-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/contractkit': minor
---

Add method getConfirmations() to Multisig Wrapper
5 changes: 5 additions & 0 deletions .changeset/sour-trees-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/contractkit': patch
---

parallelize async calls in Governance Wrapper
5 changes: 5 additions & 0 deletions .changeset/thin-cycles-play.md
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions .changeset/thirty-trees-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@celo/governance': patch
---

Parallelize Fetching Proposal Info
2 changes: 2 additions & 0 deletions packages/cli/src/utils/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ class CheckBuilder {

if (!allPassed) {
return this.cmd.error("Some checks didn't pass!")
} else {
console.log(`All checks passed`)
}
}

Expand Down
10 changes: 9 additions & 1 deletion packages/sdk/connect/src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface ConnectionOptions {
*/
export class Connection {
private config: ConnectionOptions
private _chainID: number | undefined
readonly paramsPopulator: TxParamsNormalizer
rpcCaller!: RpcCaller

Expand All @@ -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)
Expand Down Expand Up @@ -395,10 +397,16 @@ export class Connection {
}
}

// An instance of Connection will only change chain id if provider is changed.
chainId = async (): Promise<number> => {
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<number> => {
Expand Down
47 changes: 31 additions & 16 deletions packages/sdk/contractkit/src/wrappers/Governance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,13 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {

// 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()
Expand Down Expand Up @@ -455,11 +457,18 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {
}

async getApprovalStatus(proposalID: BigNumber.Value): Promise<ApprovalStatus> {
const multisig = await this.getApproverMultisig()
const approveTx = await this.approve(proposalID)
const multisigTxs = await multisig.getTransactionDataByContent(this.address, approveTx.txo)
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<Address[]>,
])

const confirmations = multisigTxs ? multisigTxs.confirmations : []
const approvers = await multisig.getOwners()

return {
completion: `${confirmations.length} / ${approvers.length}`,
confirmations,
Expand All @@ -472,9 +481,11 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {
* @param proposalID Governance proposal UUID
*/
async getProposalRecord(proposalID: BigNumber.Value): Promise<ProposalRecord> {
const metadata = await this.getProposalMetadata(proposalID)
const proposal = await this.getProposal(proposalID)
const stage = await this.getProposalStage(proposalID)
const [proposal, metadata, stage] = await Promise.all([
this.getProposal(proposalID),
this.getProposalMetadata(proposalID),
this.getProposalStage(proposalID),
])

const record: ProposalRecord = {
proposal,
Expand All @@ -487,13 +498,17 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {
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)
const [passed, votes, approved, approvals] = await Promise.all([
this.isProposalPassing(proposalID) as Promise<boolean>,
this.getVotes(proposalID),
this.isApproved(proposalID),
this.getApprovalStatus(proposalID),
])
record.passed = passed as boolean
record.votes = votes
record.approved = approved
record.approvals = approvals
}

return record
}

Expand Down
80 changes: 61 additions & 19 deletions packages/sdk/contractkit/src/wrappers/MultiSig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -30,11 +36,7 @@ export class MultiSigWrapper extends BaseWrapper<MultiSig> {
* 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<any>,
value: string = '0'
) {
async submitOrConfirmTransaction(destination: string, txObject: CeloTxObject<any>, value = '0') {
const data = stringToSolidityBytes(txObject.encodeABI())
const transactionCount = await this.contract.methods.getTransactionCount(true, true).call()
let transactionId
Expand Down Expand Up @@ -81,35 +83,75 @@ export class MultiSigWrapper extends BaseWrapper<MultiSig> {
) {
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 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, ...tx }
}
return null
})
)
const wantedTransaction = transactionsOrEmpties.find((tx) => tx !== null)
if (!wantedTransaction) {
return
}
const confirmations = await this.getConfirmations(wantedTransaction.index)
return {
...wantedTransaction,
confirmations,
}
return undefined
}

async getTransaction(i: number): Promise<TransactionData> {
async getTransaction(i: number): Promise<TransactionData>
async getTransaction(
i: number,
includeConfirmations: false
): Promise<TransactionDataWithOutConfirmations>
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 confirmations = await this.getConfirmations(i)
return {
confirmations,
destination,
data,
executed,
confirmations,
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(txId, owner).call()
if (confirmation) {
return owner
} else {
return null
}
})
)
const confirmations = confirmationsOrEmpties.filter((c) => c !== null) as string[]
return confirmations
}

async getTransactions(): Promise<TransactionData[]> {
const txcount = await this.totalTransactionCount()
const res: TransactionData[] = []
Expand Down
25 changes: 18 additions & 7 deletions packages/sdk/explorer/src/block-explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,16 @@ export class BlockExplorer {
getContractMappingFromSourcify = async (
address: string
): Promise<ContractMapping | undefined> => {
const cached = this.addressMapping.get(address)
aaronmgdr marked this conversation as resolved.
Show resolved Hide resolved
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
}

/**
Expand Down Expand Up @@ -369,11 +377,14 @@ export class BlockExplorer {
this.getContractMappingFromSourcifyAsProxy,
]
): Promise<ContractMapping | undefined> {
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)
aaronmgdr marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading
Loading