diff --git a/.changelog/unreleased/improvements/1979-proposal-result-in-storage.md b/.changelog/unreleased/improvements/1979-proposal-result-in-storage.md new file mode 100644 index 0000000000..1eb15aa889 --- /dev/null +++ b/.changelog/unreleased/improvements/1979-proposal-result-in-storage.md @@ -0,0 +1,2 @@ +- Persist the results of governance proposals in storage to allow recovering old + results. ([\#1979](https://github.com/anoma/namada/pull/1979)) \ No newline at end of file diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index d750ccc759..22fb627860 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -1045,23 +1045,39 @@ pub async fn query_proposal_result< return; }; - let is_author_steward = query_pgf_stewards(client) - .await - .iter() - .any(|steward| steward.address.eq(&proposal.author)); - let tally_type = proposal.get_tally_type(is_author_steward); - let total_voting_power = - get_total_staked_tokens(client, proposal.voting_end_epoch).await; + let proposal_result_key = + governance_storage::get_proposal_result_key(proposal_id); + let proposal_result = + // Try to directly query the result in storage first + match query_storage_value(client, &proposal_result_key).await { + Ok(result) => result, + Err(_) => { + // If failure, run the tally + let is_author_steward = query_pgf_stewards(client) + .await + .iter() + .any(|steward| steward.address.eq(&proposal.author)); + let tally_type = proposal.get_tally_type(is_author_steward); + let total_voting_power = get_total_staked_tokens( + client, + proposal.voting_end_epoch, + ) + .await; - let votes = compute_proposal_votes( - client, - proposal_id, - proposal.voting_end_epoch, - ) - .await; + let votes = compute_proposal_votes( + client, + proposal_id, + proposal.voting_end_epoch, + ) + .await; - let proposal_result = - compute_proposal_result(votes, total_voting_power, tally_type); + compute_proposal_result( + votes, + total_voting_power, + tally_type, + ) + } + }; display_line!(IO, "Proposal Id: {} ", proposal_id); display_line!(IO, "{:4}{}", "", proposal_result); diff --git a/apps/src/lib/node/ledger/shell/governance.rs b/apps/src/lib/node/ledger/shell/governance.rs index cc79c9a9f0..712a1a6944 100644 --- a/apps/src/lib/node/ledger/shell/governance.rs +++ b/apps/src/lib/node/ledger/shell/governance.rs @@ -74,6 +74,10 @@ where )?; let proposal_result = compute_proposal_result(votes, total_voting_power, tally_type); + let proposal_result_key = gov_storage::get_proposal_result_key(id); + shell + .wl_storage + .write(&proposal_result_key, proposal_result)?; let transfer_address = match proposal_result.result { TallyResult::Passed => { diff --git a/core/src/ledger/governance/storage/keys.rs b/core/src/ledger/governance/storage/keys.rs index a975b6541f..92beb9da36 100644 --- a/core/src/ledger/governance/storage/keys.rs +++ b/core/src/ledger/governance/storage/keys.rs @@ -26,6 +26,7 @@ struct Keys { min_grace_epoch: &'static str, counter: &'static str, pending: &'static str, + result: &'static str, } /// Check if key is inside governance address space @@ -459,6 +460,15 @@ pub fn get_proposal_execution_key(id: u64) -> Key { .expect("Cannot obtain a storage key") } +/// Get the proposal result key +pub fn get_proposal_result_key(id: u64) -> Key { + proposal_prefix() + .push(&id.to_string()) + .expect("Cannot obtain a storage key") + .push(&Keys::VALUES.result.to_owned()) + .expect("Cannot obtain a storage key") +} + /// Get proposal id from key pub fn get_proposal_id(key: &Key) -> Option { match key.get_at(2) { diff --git a/core/src/ledger/governance/utils.rs b/core/src/ledger/governance/utils.rs index 1a4bf0fc7c..33f032def1 100644 --- a/core/src/ledger/governance/utils.rs +++ b/core/src/ledger/governance/utils.rs @@ -75,6 +75,7 @@ impl TallyType { } /// The result of a proposal +#[derive(Copy, Clone, BorshSerialize, BorshDeserialize)] pub enum TallyResult { /// Proposal was accepted with the associated value Passed, @@ -126,6 +127,7 @@ impl TallyResult { } /// The result with votes of a proposal +#[derive(Clone, Copy, BorshDeserialize, BorshSerialize)] pub struct ProposalResult { /// The result of a proposal pub result: TallyResult,