Skip to content

Commit

Permalink
[framework] Partial governance voting support for delegation pool (#8090
Browse files Browse the repository at this point in the history
)

* Support partial voting in aptos-governance

* Support delegation partial governance voting

* Add comments

* Refactor naming.
Fix a edge case when a delegation pool voter votes before enabling partial governance voting on this delegation pool.
Add DelegateVotingPowerEvent.
Fix typos.

* Remove redundant condition checking

* Fix naming
Fix comments
Remove get_latest_delegator_vote_delegation and get_latest_vote_delegation
Wrap logic of updating governance records into functions
Fix a bug of governance records when withdrawing inactive shares
Fix get_remaining_voting_power in aptos_governance when proposals expire

* Add TODOs

* Fix lint

* Fix struct annotation

* Fix a typo

* Fix a bug about voting power
Fix a comment
Add additional feature flag checking in delegation_pool.move

* Fix specs

* Remove unnecessary move prover change

* Fix enable_partial_governance_voting condition in initialize_delegation_pool

* Remove redundant borrow
Remove unnecessary prover spec pragma

* Use smart_table instead of table in aptos_governance

---------

Co-authored-by: Teng Zhang <[email protected]>
  • Loading branch information
2 people authored and gedigi committed Aug 2, 2023
1 parent 094b8e7 commit e214c2f
Show file tree
Hide file tree
Showing 19 changed files with 4,812 additions and 523 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub enum FeatureFlag {
SignatureCheckerV2,
StorageSlotMetadata,
ChargeInvariantViolation,
DelegationPoolPartialGovernanceVoting,
}

fn generate_features_blob(writer: &CodeWriter, data: &[u64]) {
Expand Down Expand Up @@ -156,6 +157,9 @@ impl From<FeatureFlag> for AptosFeatureFlag {
FeatureFlag::SignatureCheckerV2 => AptosFeatureFlag::SIGNATURE_CHECKER_V2,
FeatureFlag::StorageSlotMetadata => AptosFeatureFlag::STORAGE_SLOT_METADATA,
FeatureFlag::ChargeInvariantViolation => AptosFeatureFlag::CHARGE_INVARIANT_VIOLATION,
FeatureFlag::DelegationPoolPartialGovernanceVoting => {
AptosFeatureFlag::DELEGATION_POOL_PARTIAL_GOVERNANCE_VOTING
},
}
}
}
Expand Down Expand Up @@ -196,6 +200,9 @@ impl From<AptosFeatureFlag> for FeatureFlag {
AptosFeatureFlag::SIGNATURE_CHECKER_V2 => FeatureFlag::SignatureCheckerV2,
AptosFeatureFlag::STORAGE_SLOT_METADATA => FeatureFlag::StorageSlotMetadata,
AptosFeatureFlag::CHARGE_INVARIANT_VIOLATION => FeatureFlag::ChargeInvariantViolation,
AptosFeatureFlag::DELEGATION_POOL_PARTIAL_GOVERNANCE_VOTING => {
FeatureFlag::DelegationPoolPartialGovernanceVoting
},
}
}
}
Expand Down
84 changes: 84 additions & 0 deletions aptos-move/e2e-move-tests/src/aptos_governance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use crate::harness::MoveHarness;
use aptos::move_tool::MemberId;
use aptos_cached_packages::aptos_stdlib;
use aptos_language_e2e_tests::account::Account;
use aptos_types::{
account_address::AccountAddress, state_store::table::TableHandle,
transaction::TransactionStatus,
};
use serde::{Deserialize, Serialize};
use std::str::FromStr;

#[derive(Deserialize, Serialize)]
struct PartialVotingProposals {
pub proposals: TableHandle,
}

#[derive(Deserialize, Serialize)]
struct RecordKey {
pub stake_pool: AccountAddress,
pub proposal_id: u64,
}

#[derive(Deserialize, Serialize)]
struct VotingRecordsV2 {
pub votes: TableHandle,
}

pub fn create_proposal_v2(
harness: &mut MoveHarness,
account: &Account,
stake_pool: AccountAddress,
execution_hash: Vec<u8>,
metadata_location: Vec<u8>,
metadata_hash: Vec<u8>,
is_multi_step_proposal: bool,
) -> TransactionStatus {
harness.run_transaction_payload(
account,
aptos_stdlib::aptos_governance_create_proposal_v2(
stake_pool,
execution_hash,
metadata_location,
metadata_hash,
is_multi_step_proposal,
),
)
}

pub fn partial_vote(
harness: &mut MoveHarness,
account: &Account,
stake_pool: AccountAddress,
proposal_id: u64,
voting_power: u64,
should_pass: bool,
) -> TransactionStatus {
harness.run_transaction_payload(
account,
aptos_stdlib::aptos_governance_partial_vote(
stake_pool,
proposal_id,
voting_power,
should_pass,
),
)
}

pub fn get_remaining_voting_power(
harness: &mut MoveHarness,
stake_pool: AccountAddress,
proposal_id: u64,
) -> u64 {
let fun = MemberId::from_str("0x1::aptos_governance::get_remaining_voting_power").unwrap();
let res = harness
.execute_view_function(fun, vec![], vec![
bcs::to_bytes(&stake_pool).unwrap(),
bcs::to_bytes(&proposal_id).unwrap(),
])
.unwrap();
bcs::from_bytes::<u64>(&res[0]).unwrap()
}
1 change: 1 addition & 0 deletions aptos-move/e2e-move-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

pub mod aggregator;
pub mod aptos_governance;
pub mod harness;
pub mod stake;
pub mod transaction_fee;
Expand Down
4 changes: 4 additions & 0 deletions aptos-move/e2e-move-tests/src/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ pub fn leave_validator_set(
)
}

pub fn increase_lockup(harness: &mut MoveHarness, account: &Account) -> TransactionStatus {
harness.run_transaction_payload(account, aptos_stdlib::stake_increase_lockup())
}

pub fn get_stake_pool(harness: &MoveHarness, pool_address: &AccountAddress) -> StakePool {
harness
.read_resource::<StakePool>(
Expand Down
1 change: 1 addition & 0 deletions aptos-move/e2e-move-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ mod token_objects;
mod transaction_fee;
mod type_too_large;
mod vector_numeric_address;
mod vote;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = 'EnablePartialGovernanceVoting'
version = "0.0.0"

[dependencies]
AptosFramework = { local = "../../../../../framework/aptos-framework" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
script {
use aptos_framework::aptos_governance;
use std::features;
use aptos_framework::aptos_governance::reconfigure;

fun main(core_resources: &signer) {
let framework_signer = aptos_governance::get_signer_testnet_only(core_resources, @aptos_framework);
aptos_governance::initialize_partial_voting(&framework_signer);
let feature = features::get_partial_governance_voting();
features::change_feature_flags(&framework_signer, vector[feature], vector[]);
reconfigure(&framework_signer);
}
}
155 changes: 155 additions & 0 deletions aptos-move/e2e-move-tests/src/tests/vote.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use crate::{
aptos_governance::*, assert_abort, assert_success, increase_lockup, setup_staking,
tests::common, MoveHarness,
};
use aptos_types::account_address::AccountAddress;
use once_cell::sync::Lazy;
use std::collections::BTreeMap;

pub static PROPOSAL_SCRIPTS: Lazy<BTreeMap<String, Vec<u8>>> = Lazy::new(build_scripts);

fn build_scripts() -> BTreeMap<String, Vec<u8>> {
let package_folder = "vote.data";
let package_names = vec!["enable_partial_governance_voting"];
common::build_scripts(package_folder, package_names)
}

#[test]
fn test_vote() {
// Genesis starts with one validator with index 0
let mut harness = MoveHarness::new();
let validator_1 = harness.new_account_at(AccountAddress::from_hex_literal("0x123").unwrap());
let validator_2 = harness.new_account_at(AccountAddress::from_hex_literal("0x234").unwrap());
let validator_1_address = *validator_1.address();
let validator_2_address = *validator_2.address();

let stake_amount_1 = 25_000_000;
assert_success!(setup_staking(&mut harness, &validator_1, stake_amount_1));
assert_success!(increase_lockup(&mut harness, &validator_1));
let stake_amount_2 = 25_000_000;
assert_success!(setup_staking(&mut harness, &validator_2, stake_amount_2));
assert_success!(increase_lockup(&mut harness, &validator_2));

let mut proposal_id: u64 = 0;
assert_success!(create_proposal_v2(
&mut harness,
&validator_2,
validator_2_address,
vec![1],
vec![],
vec![],
true
));
// Voters can vote on a partial voting proposal but argument voting_power will be ignored.
assert_success!(partial_vote(
&mut harness,
&validator_1,
validator_1_address,
proposal_id,
100,
true
));
// No remaining voting power.
assert_eq!(
get_remaining_voting_power(&mut harness, validator_1_address, proposal_id),
0
);

// Enable partial governance voting. In production it requires governance.
let core_resources =
harness.new_account_at(AccountAddress::from_hex_literal("0xA550C18").unwrap());
let script_code = PROPOSAL_SCRIPTS
.get("enable_partial_governance_voting")
.expect("proposal script should be built");
let txn = harness.create_script(&core_resources, script_code.clone(), vec![], vec![]);
assert_success!(harness.run(txn));

// If a voter has already voted on a proposal before partial voting is enabled, the voter cannot vote on the proposal again.
assert_abort!(
partial_vote(
&mut harness,
&validator_1,
validator_1_address,
proposal_id,
100,
true
),
0x10005
);

assert_success!(create_proposal_v2(
&mut harness,
&validator_1,
validator_1_address,
vec![1],
vec![],
vec![],
true
));

// Cannot vote on a non-exist proposal.
let wrong_proposal_id: u64 = 2;
assert_abort!(
partial_vote(
&mut harness,
&validator_1,
validator_1_address,
wrong_proposal_id,
100,
true
),
25863
);

proposal_id = 1;
assert_eq!(
get_remaining_voting_power(&mut harness, validator_1_address, proposal_id),
stake_amount_1
);
assert_eq!(
get_remaining_voting_power(&mut harness, validator_2_address, proposal_id),
stake_amount_1
);

// A voter can vote on a proposal multiple times with both Yes/No.
assert_success!(partial_vote(
&mut harness,
&validator_1,
validator_1_address,
proposal_id,
100,
true
));
assert_eq!(
get_remaining_voting_power(&mut harness, validator_1_address, proposal_id),
stake_amount_1 - 100
);
assert_success!(partial_vote(
&mut harness,
&validator_1,
validator_1_address,
proposal_id,
1000,
false
));
assert_eq!(
get_remaining_voting_power(&mut harness, validator_1_address, proposal_id),
stake_amount_1 - 1100
);
// A voter cannot use voting power more than it has.
assert_success!(partial_vote(
&mut harness,
&validator_1,
validator_1_address,
proposal_id,
stake_amount_1,
true
));
assert_eq!(
get_remaining_voting_power(&mut harness, validator_1_address, proposal_id),
0
);
}
Loading

0 comments on commit e214c2f

Please sign in to comment.