mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 18:01:03 +00:00
More tests for council voting.
Also allow AsRef to be used for Public keys to simplify test code.
This commit is contained in:
Generated
+1
@@ -1598,6 +1598,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ed25519 0.1.0",
|
"ed25519 0.1.0",
|
||||||
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ enum InternalFunctionId {
|
|||||||
StakingSetValidatorCount = 0x22,
|
StakingSetValidatorCount = 0x22,
|
||||||
/// Force a new staking era.
|
/// Force a new staking era.
|
||||||
StakingForceNewEra = 0x23,
|
StakingForceNewEra = 0x23,
|
||||||
|
/// See below.
|
||||||
|
DemocracyCancelReferendum = 0x30,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InternalFunctionId {
|
impl InternalFunctionId {
|
||||||
@@ -57,6 +59,7 @@ impl InternalFunctionId {
|
|||||||
InternalFunctionId::StakingSetBondingDuration,
|
InternalFunctionId::StakingSetBondingDuration,
|
||||||
InternalFunctionId::StakingSetValidatorCount,
|
InternalFunctionId::StakingSetValidatorCount,
|
||||||
InternalFunctionId::StakingForceNewEra,
|
InternalFunctionId::StakingForceNewEra,
|
||||||
|
InternalFunctionId::DemocracyCancelReferendum,
|
||||||
];
|
];
|
||||||
functions.iter().map(|&f| f).find(|&f| value == f as u8)
|
functions.iter().map(|&f| f).find(|&f| value == f as u8)
|
||||||
}
|
}
|
||||||
@@ -80,24 +83,27 @@ pub enum Proposal {
|
|||||||
StakingSetValidatorCount(u32),
|
StakingSetValidatorCount(u32),
|
||||||
/// Force a new staking era.
|
/// Force a new staking era.
|
||||||
StakingForceNewEra,
|
StakingForceNewEra,
|
||||||
|
/// Cancel a referendum.
|
||||||
|
DemocracyCancelReferendum(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Slicable for Proposal {
|
impl Slicable for Proposal {
|
||||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||||
let id = try_opt!(u8::decode(input).and_then(InternalFunctionId::from_u8));
|
let id = u8::decode(input).and_then(InternalFunctionId::from_u8)?;
|
||||||
let function = match id {
|
let function = match id {
|
||||||
InternalFunctionId::SystemSetCode =>
|
InternalFunctionId::SystemSetCode =>
|
||||||
Proposal::SystemSetCode(try_opt!(Slicable::decode(input))),
|
Proposal::SystemSetCode(Slicable::decode(input)?),
|
||||||
InternalFunctionId::SessionSetLength =>
|
InternalFunctionId::SessionSetLength =>
|
||||||
Proposal::SessionSetLength(try_opt!(Slicable::decode(input))),
|
Proposal::SessionSetLength(Slicable::decode(input)?),
|
||||||
InternalFunctionId::SessionForceNewSession => Proposal::SessionForceNewSession,
|
InternalFunctionId::SessionForceNewSession => Proposal::SessionForceNewSession,
|
||||||
InternalFunctionId::StakingSetSessionsPerEra =>
|
InternalFunctionId::StakingSetSessionsPerEra =>
|
||||||
Proposal::StakingSetSessionsPerEra(try_opt!(Slicable::decode(input))),
|
Proposal::StakingSetSessionsPerEra(Slicable::decode(input)?),
|
||||||
InternalFunctionId::StakingSetBondingDuration =>
|
InternalFunctionId::StakingSetBondingDuration =>
|
||||||
Proposal::StakingSetBondingDuration(try_opt!(Slicable::decode(input))),
|
Proposal::StakingSetBondingDuration(Slicable::decode(input)?),
|
||||||
InternalFunctionId::StakingSetValidatorCount =>
|
InternalFunctionId::StakingSetValidatorCount =>
|
||||||
Proposal::StakingSetValidatorCount(try_opt!(Slicable::decode(input))),
|
Proposal::StakingSetValidatorCount(Slicable::decode(input)?),
|
||||||
InternalFunctionId::StakingForceNewEra => Proposal::StakingForceNewEra,
|
InternalFunctionId::StakingForceNewEra => Proposal::StakingForceNewEra,
|
||||||
|
InternalFunctionId::DemocracyCancelReferendum => Proposal::DemocracyCancelReferendum(Slicable::decode(input)?),
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(function)
|
Some(function)
|
||||||
@@ -132,6 +138,10 @@ impl Slicable for Proposal {
|
|||||||
Proposal::StakingForceNewEra => {
|
Proposal::StakingForceNewEra => {
|
||||||
(InternalFunctionId::StakingForceNewEra as u8).using_encoded(|s| v.extend(s));
|
(InternalFunctionId::StakingForceNewEra as u8).using_encoded(|s| v.extend(s));
|
||||||
}
|
}
|
||||||
|
Proposal::DemocracyCancelReferendum(ref data) => {
|
||||||
|
(InternalFunctionId::DemocracyCancelReferendum as u8).using_encoded(|s| v.extend(s));
|
||||||
|
data.using_encoded(|s| v.extend(s));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v
|
v
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
//! Democratic system: Handles administration of general stakeholder voting.
|
//! Democratic system: Handles administration of general stakeholder voting.
|
||||||
|
|
||||||
use demo_primitives::Proposal;
|
use demo_primitives::Proposal;
|
||||||
use runtime::{staking, system, session};
|
use runtime::{staking, system, session, democracy};
|
||||||
|
|
||||||
pub fn enact_proposal(proposal: Proposal) {
|
pub fn enact_proposal(proposal: Proposal) {
|
||||||
match proposal {
|
match proposal {
|
||||||
@@ -42,5 +42,8 @@ pub fn enact_proposal(proposal: Proposal) {
|
|||||||
Proposal::StakingForceNewEra => {
|
Proposal::StakingForceNewEra => {
|
||||||
staking::privileged::force_new_era()
|
staking::privileged::force_new_era()
|
||||||
}
|
}
|
||||||
|
Proposal::DemocracyCancelReferendum(ref_index) => {
|
||||||
|
democracy::privileged::clear_referendum(ref_index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ pub const TERM_DURATION: &[u8] = b"cou:trm";
|
|||||||
pub const DESIRED_SEATS: &[u8] = b"cou:sts";
|
pub const DESIRED_SEATS: &[u8] = b"cou:sts";
|
||||||
|
|
||||||
// permanent state (always relevant, changes only at the finalisation of voting)
|
// permanent state (always relevant, changes only at the finalisation of voting)
|
||||||
pub const ACTIVE_COUNCIL: &[u8] = b"cou:act";
|
pub const ACTIVE_COUNCIL: &[u8] = b"cou:act"; // Vec<(AccountId, expiry: BlockNumber)>
|
||||||
pub const VOTE_COUNT: &[u8] = b"cou:vco";
|
pub const VOTE_COUNT: &[u8] = b"cou:vco"; // VoteIndex
|
||||||
|
|
||||||
// persistent state (always relevant, changes constantly)
|
// persistent state (always relevant, changes constantly)
|
||||||
pub const APPROVALS_OF: &[u8] = b"cou:apr:"; // Vec<bool>
|
pub const APPROVALS_OF: &[u8] = b"cou:apr:"; // Vec<bool>
|
||||||
|
|||||||
@@ -51,27 +51,27 @@ pub fn was_vetoed(proposal: &ProposalHash) -> bool {
|
|||||||
storage::exists(&proposal.to_keyed_vec(VETOED_PROPOSAL))
|
storage::exists(&proposal.to_keyed_vec(VETOED_PROPOSAL))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn will_still_be_councillor_at(who: &AccountId, n: BlockNumber) -> bool {
|
pub fn will_still_be_councillor_at<P: AsRef<AccountId>>(who: P, n: BlockNumber) -> bool {
|
||||||
council::active_council().iter()
|
council::active_council().iter()
|
||||||
.find(|&&(ref a, _)| a == who)
|
.find(|&&(ref a, _)| a == who.as_ref())
|
||||||
.map(|&(_, expires)| expires > n)
|
.map(|&(_, expires)| expires > n)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vote_of(who: &AccountId, proposal: &ProposalHash) -> Option<bool> {
|
pub fn vote_of<P: AsRef<AccountId>>(who: P, proposal: &ProposalHash) -> Option<bool> {
|
||||||
storage::get(&(*who, *proposal).to_keyed_vec(COUNCIL_VOTE_OF))
|
storage::get(&(*proposal, *who.as_ref()).to_keyed_vec(COUNCIL_VOTE_OF))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_vote_of(who: &AccountId, proposal: &ProposalHash) -> Option<bool> {
|
pub fn proposal_voters(proposal: &ProposalHash) -> Vec<AccountId> {
|
||||||
storage::get(&(*who, *proposal).to_keyed_vec(COUNCIL_VOTE_OF))
|
storage::get_or_default(&proposal.to_keyed_vec(PROPOSAL_VOTERS))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) {
|
pub fn tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) {
|
||||||
generic_tally(proposal_hash, vote_of)
|
generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| storage::get(&(*p, *w).to_keyed_vec(COUNCIL_VOTE_OF)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) {
|
fn take_tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) {
|
||||||
generic_tally(proposal_hash, take_vote_of)
|
generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| storage::get(&(*p, *w).to_keyed_vec(COUNCIL_VOTE_OF)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generic_tally<F: Fn(&AccountId, &ProposalHash) -> Option<bool>>(proposal_hash: &ProposalHash, vote_of: F) -> (u32, u32, u32) {
|
fn generic_tally<F: Fn(&AccountId, &ProposalHash) -> Option<bool>>(proposal_hash: &ProposalHash, vote_of: F) -> (u32, u32, u32) {
|
||||||
@@ -103,7 +103,7 @@ fn take_proposal_if_expiring_at(n: BlockNumber) -> Option<(Proposal, ProposalHas
|
|||||||
pub mod public {
|
pub mod public {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn propose(signed: &AccountId, proposal: &Proposal) {
|
pub fn propose<P: AsRef<AccountId> + Copy>(signed: P, proposal: &Proposal) {
|
||||||
let expiry = system::block_number() + voting_period();
|
let expiry = system::block_number() + voting_period();
|
||||||
assert!(will_still_be_councillor_at(signed, expiry));
|
assert!(will_still_be_councillor_at(signed, expiry));
|
||||||
|
|
||||||
@@ -116,19 +116,24 @@ pub mod public {
|
|||||||
set_proposals(&proposals);
|
set_proposals(&proposals);
|
||||||
|
|
||||||
storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_OF), proposal);
|
storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_OF), proposal);
|
||||||
storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS), &vec![*signed]);
|
storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS), &vec![*signed.as_ref()]);
|
||||||
storage::put(&(proposal_hash, *signed).to_keyed_vec(COUNCIL_VOTE_OF), &true);
|
storage::put(&(proposal_hash, *(signed.as_ref())).to_keyed_vec(COUNCIL_VOTE_OF), &true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vote(signed: AccountId, proposal: &ProposalHash, approve: bool) {
|
pub fn vote<P: AsRef<AccountId> + Copy>(signed: P, proposal: &ProposalHash, approve: bool) {
|
||||||
|
if vote_of(signed, proposal).is_none() {
|
||||||
|
let mut voters = proposal_voters(proposal);
|
||||||
|
voters.push(*signed.as_ref());
|
||||||
|
storage::put(&proposal.to_keyed_vec(PROPOSAL_VOTERS), &voters);
|
||||||
|
}
|
||||||
|
storage::put(&(*proposal, *(signed.as_ref())).to_keyed_vec(COUNCIL_VOTE_OF), &approve);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn veto<P: AsRef<AccountId> + Copy>(signed: P, proposal: &ProposalHash) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn veto(signed: AccountId, proposal: &ProposalHash) {
|
pub fn repropose<P: AsRef<AccountId> + Copy>(signed: P, proposal: &Proposal) {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn repropose(signed: AccountId, proposal: &Proposal) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,17 +158,147 @@ pub mod internal {
|
|||||||
pub fn end_block(now: BlockNumber) {
|
pub fn end_block(now: BlockNumber) {
|
||||||
while let Some((proposal, proposal_hash)) = take_proposal_if_expiring_at(now) {
|
while let Some((proposal, proposal_hash)) = take_proposal_if_expiring_at(now) {
|
||||||
let tally = take_tally(&proposal_hash);
|
let tally = take_tally(&proposal_hash);
|
||||||
let vote_threshold = match tally.0 {
|
if let Proposal::DemocracyCancelReferendum(ref_index) = proposal {
|
||||||
x if x == tally.2 => VoteThreshold::SuperMajorityAgainst,
|
if tally.0 == tally.2 {
|
||||||
x if x > tally.2 / 2 => VoteThreshold::SimpleMajority,
|
democracy::privileged::clear_referendum(ref_index);
|
||||||
_ => VoteThreshold::SuperMajorityApprove,
|
}
|
||||||
|
} else {
|
||||||
|
match tally {
|
||||||
|
(_, 0, 0) => start_referendum(proposal, VoteThreshold::SuperMajorityAgainst),
|
||||||
|
(y, n, x) if y > n + x => start_referendum(proposal, VoteThreshold::SimpleMajority),
|
||||||
|
_ => {},
|
||||||
};
|
};
|
||||||
start_referendum(proposal, vote_threshold);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
pub mod testing {
|
||||||
|
use super::*;
|
||||||
|
use runtime_io::{twox_128, TestExternalities};
|
||||||
|
use keyring::Keyring::{Alice, Bob, Charlie};
|
||||||
|
use codec::Joiner;
|
||||||
|
use runtime::council;
|
||||||
|
|
||||||
|
pub fn externalities() -> TestExternalities {
|
||||||
|
let expiry: BlockNumber = 10;
|
||||||
|
let extras: TestExternalities = map![
|
||||||
|
twox_128(council::ACTIVE_COUNCIL).to_vec() => vec![].and(&vec![
|
||||||
|
(Alice.to_raw_public(), expiry),
|
||||||
|
(Bob.into(), expiry),
|
||||||
|
(Charlie.into(), expiry)
|
||||||
|
]),
|
||||||
|
twox_128(COOLOFF_PERIOD).to_vec() => vec![].and(&2u64),
|
||||||
|
twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64)
|
||||||
|
];
|
||||||
|
council::testing::externalities()
|
||||||
|
.into_iter().chain(extras.into_iter()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use runtime_io::{with_externalities, twox_128, TestExternalities};
|
||||||
|
use codec::{KeyedVec, Joiner};
|
||||||
|
use keyring::Keyring::{Alice, Bob, Charlie, Dave};
|
||||||
|
use environment::with_env;
|
||||||
|
use demo_primitives::{AccountId, Proposal};
|
||||||
|
use runtime::{staking, council, democracy};
|
||||||
|
use runtime::democracy::VoteThreshold;
|
||||||
|
|
||||||
|
fn new_test_ext() -> TestExternalities {
|
||||||
|
testing::externalities()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_environment_works() {
|
||||||
|
with_externalities(&mut new_test_ext(), || {
|
||||||
|
with_env(|e| e.block_number = 1);
|
||||||
|
assert_eq!(staking::bonding_duration(), 0);
|
||||||
|
assert_eq!(cooloff_period(), 2);
|
||||||
|
assert_eq!(voting_period(), 1);
|
||||||
|
assert_eq!(will_still_be_councillor_at(Alice, 1), true);
|
||||||
|
assert_eq!(will_still_be_councillor_at(Alice, 10), false);
|
||||||
|
assert_eq!(will_still_be_councillor_at(Dave, 10), false);
|
||||||
|
assert_eq!(proposals(), Vec::<(BlockNumber, ProposalHash)>::new());
|
||||||
|
assert_eq!(proposal_voters(&ProposalHash::default()), Vec::<AccountId>::new());
|
||||||
|
assert_eq!(was_vetoed(&ProposalHash::default()), false);
|
||||||
|
assert_eq!(vote_of(Alice, &ProposalHash::default()), None);
|
||||||
|
assert_eq!(tally(&ProposalHash::default()), (0, 0, 3));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_propose_should_work() {
|
||||||
|
with_externalities(&mut new_test_ext(), || {
|
||||||
|
with_env(|e| e.block_number = 1);
|
||||||
|
let proposal = Proposal::StakingSetBondingDuration(42);
|
||||||
|
let hash = proposal.blake2_256();
|
||||||
|
public::propose(Alice, &proposal);
|
||||||
|
assert_eq!(proposals().len(), 1);
|
||||||
|
assert_eq!(proposal_voters(&hash), vec![Alice.to_raw_public()]);
|
||||||
|
assert_eq!(vote_of(Alice, &hash), Some(true));
|
||||||
|
assert_eq!(tally(&hash), (1, 0, 2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unvoted_proposal_should_expire_without_action() {
|
||||||
|
with_externalities(&mut new_test_ext(), || {
|
||||||
|
with_env(|e| e.block_number = 1);
|
||||||
|
public::propose(Alice, &Proposal::StakingSetBondingDuration(42));
|
||||||
|
assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (1, 0, 2));
|
||||||
|
internal::end_block(1);
|
||||||
|
|
||||||
|
with_env(|e| e.block_number = 2);
|
||||||
|
internal::end_block(2);
|
||||||
|
assert_eq!(proposals().len(), 0);
|
||||||
|
assert_eq!(democracy::active_referendums().len(), 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unanimous_proposal_should_expire_with_biased_referendum() {
|
||||||
|
with_externalities(&mut new_test_ext(), || {
|
||||||
|
with_env(|e| e.block_number = 1);
|
||||||
|
public::propose(Alice, &Proposal::StakingSetBondingDuration(42));
|
||||||
|
public::vote(Bob, &Proposal::StakingSetBondingDuration(42).blake2_256(), true);
|
||||||
|
public::vote(Charlie, &Proposal::StakingSetBondingDuration(42).blake2_256(), true);
|
||||||
|
assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (3, 0, 0));
|
||||||
|
internal::end_block(1);
|
||||||
|
|
||||||
|
with_env(|e| e.block_number = 2);
|
||||||
|
internal::end_block(2);
|
||||||
|
assert_eq!(proposals().len(), 0);
|
||||||
|
assert_eq!(democracy::active_referendums(), vec![(0, 3, Proposal::StakingSetBondingDuration(42), VoteThreshold::SuperMajorityAgainst)]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn majority_proposal_should_expire_with_unbiased_referendum() {
|
||||||
|
with_externalities(&mut new_test_ext(), || {
|
||||||
|
with_env(|e| e.block_number = 1);
|
||||||
|
public::propose(Alice, &Proposal::StakingSetBondingDuration(42));
|
||||||
|
public::vote(Bob, &Proposal::StakingSetBondingDuration(42).blake2_256(), true);
|
||||||
|
public::vote(Charlie, &Proposal::StakingSetBondingDuration(42).blake2_256(), false);
|
||||||
|
assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (2, 1, 0));
|
||||||
|
internal::end_block(1);
|
||||||
|
|
||||||
|
with_env(|e| e.block_number = 2);
|
||||||
|
internal::end_block(2);
|
||||||
|
assert_eq!(proposals().len(), 0);
|
||||||
|
assert_eq!(democracy::active_referendums(), vec![(0, 3, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn propose_by_public_should_panic() {
|
||||||
|
with_externalities(&mut new_test_ext(), || {
|
||||||
|
with_env(|e| e.block_number = 1);
|
||||||
|
public::propose(Dave, &Proposal::StakingSetBondingDuration(42));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ use runtime::staking::Balance;
|
|||||||
pub type PropIndex = u32;
|
pub type PropIndex = u32;
|
||||||
pub type ReferendumIndex = u32;
|
pub type ReferendumIndex = u32;
|
||||||
|
|
||||||
|
#[cfg_attr(test, derive(Debug))]
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum VoteThreshold {
|
pub enum VoteThreshold {
|
||||||
SuperMajorityApprove,
|
SuperMajorityApprove,
|
||||||
SuperMajorityAgainst,
|
SuperMajorityAgainst,
|
||||||
@@ -138,6 +140,15 @@ pub fn referendum_info(ref_index: ReferendumIndex) -> Option<(BlockNumber, Propo
|
|||||||
storage::get(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF))
|
storage::get(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all referendums currently active.
|
||||||
|
pub fn active_referendums() -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> {
|
||||||
|
let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY);
|
||||||
|
let last: ReferendumIndex = storage::get_or_default(REFERENDUM_COUNT);
|
||||||
|
(next..last).into_iter()
|
||||||
|
.filter_map(|i| referendum_info(i).map(|(n, p, t)| (i, n, p, t)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get all referendums ready for tally at block `n`.
|
/// Get all referendums ready for tally at block `n`.
|
||||||
pub fn maturing_referendums_at(n: BlockNumber) -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> {
|
pub fn maturing_referendums_at(n: BlockNumber) -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> {
|
||||||
let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY);
|
let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY);
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ pub struct LocalizedSignature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a message without type checking the parameters' types for the right size.
|
/// Verify a message without type checking the parameters' types for the right size.
|
||||||
pub fn verify(sig: &[u8], message: &[u8], public: &[u8]) -> bool {
|
pub fn verify<P: AsRef<[u8]>>(sig: &[u8], message: &[u8], public: P) -> bool {
|
||||||
let public_key = untrusted::Input::from(public);
|
let public_key = untrusted::Input::from(public.as_ref());
|
||||||
let msg = untrusted::Input::from(message);
|
let msg = untrusted::Input::from(message);
|
||||||
let sig = untrusted::Input::from(sig);
|
let sig = untrusted::Input::from(sig);
|
||||||
|
|
||||||
@@ -104,6 +104,18 @@ impl Into<[u8; 32]> for Public {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsRef<Public> for Public {
|
||||||
|
fn as_ref(&self) -> &Public {
|
||||||
|
&self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Pair> for Pair {
|
||||||
|
fn as_ref(&self) -> &Pair {
|
||||||
|
&self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Pair {
|
impl Pair {
|
||||||
/// Generate new secure (random) key pair.
|
/// Generate new secure (random) key pair.
|
||||||
pub fn new() -> Pair {
|
pub fn new() -> Pair {
|
||||||
@@ -144,8 +156,8 @@ impl Pair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a signature on a message.
|
/// Verify a signature on a message.
|
||||||
pub fn verify_strong(sig: &Signature, message: &[u8], pubkey: &Public) -> bool {
|
pub fn verify_strong<P: AsRef<Public>>(sig: &Signature, message: &[u8], pubkey: P) -> bool {
|
||||||
let public_key = untrusted::Input::from(&pubkey.0[..]);
|
let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]);
|
||||||
let msg = untrusted::Input::from(message);
|
let msg = untrusted::Input::from(message);
|
||||||
let sig = untrusted::Input::from(&sig.0[..]);
|
let sig = untrusted::Input::from(&sig.0[..]);
|
||||||
|
|
||||||
@@ -157,19 +169,19 @@ pub fn verify_strong(sig: &Signature, message: &[u8], pubkey: &Public) -> bool {
|
|||||||
|
|
||||||
pub trait Verifiable {
|
pub trait Verifiable {
|
||||||
/// Verify something that acts like a signature.
|
/// Verify something that acts like a signature.
|
||||||
fn verify(&self, message: &[u8], pubkey: &Public) -> bool;
|
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Verifiable for Signature {
|
impl Verifiable for Signature {
|
||||||
/// Verify something that acts like a signature.
|
/// Verify something that acts like a signature.
|
||||||
fn verify(&self, message: &[u8], pubkey: &Public) -> bool {
|
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
|
||||||
verify_strong(&self, message, pubkey)
|
verify_strong(&self, message, pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Verifiable for LocalizedSignature {
|
impl Verifiable for LocalizedSignature {
|
||||||
fn verify(&self, message: &[u8], pubkey: &Public) -> bool {
|
fn verify<P: AsRef<Public>>(&self, message: &[u8], pubkey: P) -> bool {
|
||||||
pubkey == &self.signer && self.signature.verify(message, pubkey)
|
pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ed25519 = { path = "../ed25519" }
|
ed25519 = { path = "../ed25519" }
|
||||||
hex-literal = { version = "0.1.0" }
|
hex-literal = { version = "0.1.0" }
|
||||||
|
lazy_static = { version = "1.0" }
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
//! Support code for the runtime.
|
//! Support code for the runtime.
|
||||||
|
|
||||||
#[macro_use] extern crate hex_literal;
|
#[macro_use] extern crate hex_literal;
|
||||||
|
#[macro_use] extern crate lazy_static;
|
||||||
extern crate ed25519;
|
extern crate ed25519;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use ed25519::{Pair, Public, Signature};
|
use ed25519::{Pair, Public, Signature};
|
||||||
|
|
||||||
/// Set of test accounts.
|
/// Set of test accounts.
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum Keyring {
|
pub enum Keyring {
|
||||||
Alice,
|
Alice,
|
||||||
Bob,
|
Bob,
|
||||||
@@ -63,7 +65,7 @@ impl Keyring {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign(self, msg: &[u8]) -> Signature {
|
pub fn sign(self, msg: &[u8]) -> Signature {
|
||||||
Pair::from(self).sign(msg)
|
AsRef::<Pair>::as_ref(&self).sign(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,32 +84,64 @@ impl From<Keyring> for &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Keyring> for Pair {
|
lazy_static! {
|
||||||
fn from(k: Keyring) -> Self {
|
static ref PRIVATE_KEYS: HashMap<Keyring, Pair> = {
|
||||||
match k {
|
let mut m = HashMap::new();
|
||||||
Keyring::Alice => Pair::from_seed(b"Alice "),
|
m.insert(Keyring::Alice, Pair::from_seed(b"Alice "));
|
||||||
Keyring::Bob => Pair::from_seed(b"Bob "),
|
m.insert(Keyring::Bob, Pair::from_seed(b"Bob "));
|
||||||
Keyring::Charlie => Pair::from_seed(b"Charlie "),
|
m.insert(Keyring::Charlie, Pair::from_seed(b"Charlie "));
|
||||||
Keyring::Dave => Pair::from_seed(b"Dave "),
|
m.insert(Keyring::Dave, Pair::from_seed(b"Dave "));
|
||||||
Keyring::Eve => Pair::from_seed(b"Eve "),
|
m.insert(Keyring::Eve, Pair::from_seed(b"Eve "));
|
||||||
Keyring::Ferdie => Pair::from_seed(b"Ferdie "),
|
m.insert(Keyring::Ferdie, Pair::from_seed(b"Ferdie "));
|
||||||
Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"),
|
m.insert(Keyring::One, Pair::from_seed(b"12345678901234567890123456789012"));
|
||||||
Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")),
|
m.insert(Keyring::Two, Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")));
|
||||||
}
|
m
|
||||||
}
|
};
|
||||||
|
|
||||||
|
static ref PUBLIC_KEYS: HashMap<Keyring, Public> = {
|
||||||
|
PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Keyring> for Public {
|
impl From<Keyring> for Public {
|
||||||
fn from(k: Keyring) -> Self {
|
fn from(k: Keyring) -> Self {
|
||||||
let pair: Pair = k.into();
|
(*PUBLIC_KEYS).get(&k).unwrap().clone()
|
||||||
pair.public()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Keyring> for [u8; 32] {
|
impl From<Keyring> for [u8; 32] {
|
||||||
fn from(k: Keyring) -> Self {
|
fn from(k: Keyring) -> Self {
|
||||||
let pair: Pair = k.into();
|
*(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref()
|
||||||
*pair.public().as_array_ref()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Keyring> for &'static [u8; 32] {
|
||||||
|
fn from(k: Keyring) -> Self {
|
||||||
|
(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8; 32]> for Keyring {
|
||||||
|
fn as_ref(&self) -> &[u8; 32] {
|
||||||
|
(*PUBLIC_KEYS).get(self).unwrap().as_array_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Keyring {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
(*PUBLIC_KEYS).get(self).unwrap().as_array_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Public> for Keyring {
|
||||||
|
fn as_ref(&self) -> &Public {
|
||||||
|
(*PUBLIC_KEYS).get(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Pair> for Keyring {
|
||||||
|
fn as_ref(&self) -> &Pair {
|
||||||
|
(*PRIVATE_KEYS).get(self).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +152,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_work() {
|
fn should_work() {
|
||||||
assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", &Keyring::Alice.into()));
|
assert!(Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Alice));
|
||||||
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", &Keyring::Alice.into()));
|
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Bob!", Keyring::Alice));
|
||||||
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", &Keyring::Bob.into()));
|
assert!(!Keyring::Alice.sign(b"I am Alice!").verify(b"I am Alice!", Keyring::Bob));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ pub fn enumerated_trie_root(serialised_values: &[&[u8]]) -> [u8; 32] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a ed25519 signature.
|
/// Verify a ed25519 signature.
|
||||||
pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool {
|
pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||||
ed25519::verify(sig, msg, pubkey)
|
ed25519::verify(sig, msg, pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,9 +161,9 @@ pub fn twox_128(data: &[u8]) -> [u8; 16] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a ed25519 signature.
|
/// Verify a ed25519 signature.
|
||||||
pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool {
|
pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ptr()) == 0
|
ext_ed25519_verify(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user