diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index dd81690e5f..e29aa3a664 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1598,6 +1598,7 @@ version = "0.1.0" dependencies = [ "ed25519 0.1.0", "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]] diff --git a/substrate/demo/primitives/src/transaction.rs b/substrate/demo/primitives/src/transaction.rs index 090b64b27d..3af7dbdcf4 100644 --- a/substrate/demo/primitives/src/transaction.rs +++ b/substrate/demo/primitives/src/transaction.rs @@ -44,6 +44,8 @@ enum InternalFunctionId { StakingSetValidatorCount = 0x22, /// Force a new staking era. StakingForceNewEra = 0x23, + /// See below. + DemocracyCancelReferendum = 0x30, } impl InternalFunctionId { @@ -57,6 +59,7 @@ impl InternalFunctionId { InternalFunctionId::StakingSetBondingDuration, InternalFunctionId::StakingSetValidatorCount, InternalFunctionId::StakingForceNewEra, + InternalFunctionId::DemocracyCancelReferendum, ]; functions.iter().map(|&f| f).find(|&f| value == f as u8) } @@ -80,24 +83,27 @@ pub enum Proposal { StakingSetValidatorCount(u32), /// Force a new staking era. StakingForceNewEra, + /// Cancel a referendum. + DemocracyCancelReferendum(u32), } impl Slicable for Proposal { fn decode(input: &mut I) -> Option { - 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 { InternalFunctionId::SystemSetCode => - Proposal::SystemSetCode(try_opt!(Slicable::decode(input))), + Proposal::SystemSetCode(Slicable::decode(input)?), InternalFunctionId::SessionSetLength => - Proposal::SessionSetLength(try_opt!(Slicable::decode(input))), + Proposal::SessionSetLength(Slicable::decode(input)?), InternalFunctionId::SessionForceNewSession => Proposal::SessionForceNewSession, InternalFunctionId::StakingSetSessionsPerEra => - Proposal::StakingSetSessionsPerEra(try_opt!(Slicable::decode(input))), + Proposal::StakingSetSessionsPerEra(Slicable::decode(input)?), InternalFunctionId::StakingSetBondingDuration => - Proposal::StakingSetBondingDuration(try_opt!(Slicable::decode(input))), + Proposal::StakingSetBondingDuration(Slicable::decode(input)?), InternalFunctionId::StakingSetValidatorCount => - Proposal::StakingSetValidatorCount(try_opt!(Slicable::decode(input))), + Proposal::StakingSetValidatorCount(Slicable::decode(input)?), InternalFunctionId::StakingForceNewEra => Proposal::StakingForceNewEra, + InternalFunctionId::DemocracyCancelReferendum => Proposal::DemocracyCancelReferendum(Slicable::decode(input)?), }; Some(function) @@ -132,6 +138,10 @@ impl Slicable for Proposal { Proposal::StakingForceNewEra => { (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 diff --git a/substrate/demo/runtime/src/dispatch.rs b/substrate/demo/runtime/src/dispatch.rs index b473a6a878..980025e3ee 100644 --- a/substrate/demo/runtime/src/dispatch.rs +++ b/substrate/demo/runtime/src/dispatch.rs @@ -17,7 +17,7 @@ //! Democratic system: Handles administration of general stakeholder voting. use demo_primitives::Proposal; -use runtime::{staking, system, session}; +use runtime::{staking, system, session, democracy}; pub fn enact_proposal(proposal: Proposal) { match proposal { @@ -42,5 +42,8 @@ pub fn enact_proposal(proposal: Proposal) { Proposal::StakingForceNewEra => { staking::privileged::force_new_era() } + Proposal::DemocracyCancelReferendum(ref_index) => { + democracy::privileged::clear_referendum(ref_index) + } } } diff --git a/substrate/demo/runtime/src/runtime/council.rs b/substrate/demo/runtime/src/runtime/council.rs index 93c09dea11..8ff832faf4 100644 --- a/substrate/demo/runtime/src/runtime/council.rs +++ b/substrate/demo/runtime/src/runtime/council.rs @@ -91,8 +91,8 @@ pub const TERM_DURATION: &[u8] = b"cou:trm"; pub const DESIRED_SEATS: &[u8] = b"cou:sts"; // permanent state (always relevant, changes only at the finalisation of voting) -pub const ACTIVE_COUNCIL: &[u8] = b"cou:act"; -pub const VOTE_COUNT: &[u8] = b"cou:vco"; +pub const ACTIVE_COUNCIL: &[u8] = b"cou:act"; // Vec<(AccountId, expiry: BlockNumber)> +pub const VOTE_COUNT: &[u8] = b"cou:vco"; // VoteIndex // persistent state (always relevant, changes constantly) pub const APPROVALS_OF: &[u8] = b"cou:apr:"; // Vec diff --git a/substrate/demo/runtime/src/runtime/council_vote.rs b/substrate/demo/runtime/src/runtime/council_vote.rs index 394316a66e..10e07850d1 100644 --- a/substrate/demo/runtime/src/runtime/council_vote.rs +++ b/substrate/demo/runtime/src/runtime/council_vote.rs @@ -51,27 +51,27 @@ pub fn was_vetoed(proposal: &ProposalHash) -> bool { 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>(who: P, n: BlockNumber) -> bool { council::active_council().iter() - .find(|&&(ref a, _)| a == who) + .find(|&&(ref a, _)| a == who.as_ref()) .map(|&(_, expires)| expires > n) .unwrap_or(false) } -pub fn vote_of(who: &AccountId, proposal: &ProposalHash) -> Option { - storage::get(&(*who, *proposal).to_keyed_vec(COUNCIL_VOTE_OF)) +pub fn vote_of>(who: P, proposal: &ProposalHash) -> Option { + storage::get(&(*proposal, *who.as_ref()).to_keyed_vec(COUNCIL_VOTE_OF)) } -pub fn take_vote_of(who: &AccountId, proposal: &ProposalHash) -> Option { - storage::get(&(*who, *proposal).to_keyed_vec(COUNCIL_VOTE_OF)) +pub fn proposal_voters(proposal: &ProposalHash) -> Vec { + storage::get_or_default(&proposal.to_keyed_vec(PROPOSAL_VOTERS)) } 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) { - 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 Option>(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 { use super::*; - pub fn propose(signed: &AccountId, proposal: &Proposal) { + pub fn propose + Copy>(signed: P, proposal: &Proposal) { let expiry = system::block_number() + voting_period(); assert!(will_still_be_councillor_at(signed, expiry)); @@ -116,19 +116,24 @@ pub mod public { set_proposals(&proposals); 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, *signed).to_keyed_vec(COUNCIL_VOTE_OF), &true); + storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS), &vec![*signed.as_ref()]); + 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 + 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 + Copy>(signed: P, proposal: &ProposalHash) { } - pub fn veto(signed: AccountId, proposal: &ProposalHash) { - - } - - pub fn repropose(signed: AccountId, proposal: &Proposal) { + pub fn repropose + Copy>(signed: P, proposal: &Proposal) { } } @@ -153,17 +158,147 @@ pub mod internal { pub fn end_block(now: BlockNumber) { while let Some((proposal, proposal_hash)) = take_proposal_if_expiring_at(now) { let tally = take_tally(&proposal_hash); - let vote_threshold = match tally.0 { - x if x == tally.2 => VoteThreshold::SuperMajorityAgainst, - x if x > tally.2 / 2 => VoteThreshold::SimpleMajority, - _ => VoteThreshold::SuperMajorityApprove, - }; - start_referendum(proposal, vote_threshold); + if let Proposal::DemocracyCancelReferendum(ref_index) = proposal { + if tally.0 == tally.2 { + democracy::privileged::clear_referendum(ref_index); + } + } else { + match tally { + (_, 0, 0) => start_referendum(proposal, VoteThreshold::SuperMajorityAgainst), + (y, n, x) if y > n + x => start_referendum(proposal, VoteThreshold::SimpleMajority), + _ => {}, + }; + } } } } #[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::::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)); + }); + } } diff --git a/substrate/demo/runtime/src/runtime/democracy.rs b/substrate/demo/runtime/src/runtime/democracy.rs index cbc82f458d..3148614999 100644 --- a/substrate/demo/runtime/src/runtime/democracy.rs +++ b/substrate/demo/runtime/src/runtime/democracy.rs @@ -27,6 +27,8 @@ use runtime::staking::Balance; pub type PropIndex = u32; pub type ReferendumIndex = u32; +#[cfg_attr(test, derive(Debug))] +#[derive(Clone, Copy, PartialEq)] pub enum VoteThreshold { SuperMajorityApprove, 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)) } +/// 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`. pub fn maturing_referendums_at(n: BlockNumber) -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> { let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY); diff --git a/substrate/substrate/ed25519/src/lib.rs b/substrate/substrate/ed25519/src/lib.rs index 4d8117186b..f8a2ec0ce6 100644 --- a/substrate/substrate/ed25519/src/lib.rs +++ b/substrate/substrate/ed25519/src/lib.rs @@ -37,8 +37,8 @@ pub struct LocalizedSignature { } /// Verify a message without type checking the parameters' types for the right size. -pub fn verify(sig: &[u8], message: &[u8], public: &[u8]) -> bool { - let public_key = untrusted::Input::from(public); +pub fn verify>(sig: &[u8], message: &[u8], public: P) -> bool { + let public_key = untrusted::Input::from(public.as_ref()); let msg = untrusted::Input::from(message); let sig = untrusted::Input::from(sig); @@ -104,6 +104,18 @@ impl Into<[u8; 32]> for Public { } } +impl AsRef for Public { + fn as_ref(&self) -> &Public { + &self + } +} + +impl AsRef for Pair { + fn as_ref(&self) -> &Pair { + &self + } +} + impl Pair { /// Generate new secure (random) key pair. pub fn new() -> Pair { @@ -144,8 +156,8 @@ impl Pair { } /// Verify a signature on a message. -pub fn verify_strong(sig: &Signature, message: &[u8], pubkey: &Public) -> bool { - let public_key = untrusted::Input::from(&pubkey.0[..]); +pub fn verify_strong>(sig: &Signature, message: &[u8], pubkey: P) -> bool { + let public_key = untrusted::Input::from(&pubkey.as_ref().0[..]); let msg = untrusted::Input::from(message); 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 { /// Verify something that acts like a signature. - fn verify(&self, message: &[u8], pubkey: &Public) -> bool; + fn verify>(&self, message: &[u8], pubkey: P) -> bool; } impl Verifiable for Signature { /// Verify something that acts like a signature. - fn verify(&self, message: &[u8], pubkey: &Public) -> bool { + fn verify>(&self, message: &[u8], pubkey: P) -> bool { verify_strong(&self, message, pubkey) } } impl Verifiable for LocalizedSignature { - fn verify(&self, message: &[u8], pubkey: &Public) -> bool { - pubkey == &self.signer && self.signature.verify(message, pubkey) + fn verify>(&self, message: &[u8], pubkey: P) -> bool { + pubkey.as_ref() == &self.signer && self.signature.verify(message, pubkey) } } diff --git a/substrate/substrate/keyring/Cargo.toml b/substrate/substrate/keyring/Cargo.toml index f59caf2caf..69bd55a6f3 100644 --- a/substrate/substrate/keyring/Cargo.toml +++ b/substrate/substrate/keyring/Cargo.toml @@ -6,3 +6,4 @@ authors = ["Parity Technologies "] [dependencies] ed25519 = { path = "../ed25519" } hex-literal = { version = "0.1.0" } +lazy_static = { version = "1.0" } diff --git a/substrate/substrate/keyring/src/lib.rs b/substrate/substrate/keyring/src/lib.rs index 97e5ed6951..c2eee02a0c 100644 --- a/substrate/substrate/keyring/src/lib.rs +++ b/substrate/substrate/keyring/src/lib.rs @@ -17,12 +17,14 @@ //! Support code for the runtime. #[macro_use] extern crate hex_literal; +#[macro_use] extern crate lazy_static; extern crate ed25519; +use std::collections::HashMap; use ed25519::{Pair, Public, Signature}; /// Set of test accounts. -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum Keyring { Alice, Bob, @@ -63,7 +65,7 @@ impl Keyring { } pub fn sign(self, msg: &[u8]) -> Signature { - Pair::from(self).sign(msg) + AsRef::::as_ref(&self).sign(msg) } } @@ -82,32 +84,64 @@ impl From for &'static str { } } -impl From for Pair { - fn from(k: Keyring) -> Self { - match k { - Keyring::Alice => Pair::from_seed(b"Alice "), - Keyring::Bob => Pair::from_seed(b"Bob "), - Keyring::Charlie => Pair::from_seed(b"Charlie "), - Keyring::Dave => Pair::from_seed(b"Dave "), - Keyring::Eve => Pair::from_seed(b"Eve "), - Keyring::Ferdie => Pair::from_seed(b"Ferdie "), - Keyring::One => Pair::from_seed(b"12345678901234567890123456789012"), - Keyring::Two => Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")), - } - } +lazy_static! { + static ref PRIVATE_KEYS: HashMap = { + let mut m = HashMap::new(); + m.insert(Keyring::Alice, Pair::from_seed(b"Alice ")); + m.insert(Keyring::Bob, Pair::from_seed(b"Bob ")); + m.insert(Keyring::Charlie, Pair::from_seed(b"Charlie ")); + m.insert(Keyring::Dave, Pair::from_seed(b"Dave ")); + m.insert(Keyring::Eve, Pair::from_seed(b"Eve ")); + m.insert(Keyring::Ferdie, Pair::from_seed(b"Ferdie ")); + m.insert(Keyring::One, Pair::from_seed(b"12345678901234567890123456789012")); + m.insert(Keyring::Two, Pair::from_seed(&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"))); + m + }; + + static ref PUBLIC_KEYS: HashMap = { + PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect() + }; } impl From for Public { fn from(k: Keyring) -> Self { - let pair: Pair = k.into(); - pair.public() + (*PUBLIC_KEYS).get(&k).unwrap().clone() } } impl From for [u8; 32] { fn from(k: Keyring) -> Self { - let pair: Pair = k.into(); - *pair.public().as_array_ref() + *(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() + } +} + +impl From 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 for Keyring { + fn as_ref(&self) -> &Public { + (*PUBLIC_KEYS).get(self).unwrap() + } +} + +impl AsRef for Keyring { + fn as_ref(&self) -> &Pair { + (*PRIVATE_KEYS).get(self).unwrap() } } @@ -118,8 +152,8 @@ mod tests { #[test] 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 Bob!", &Keyring::Alice.into())); - 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::Alice)); + 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)); } } diff --git a/substrate/substrate/runtime-io/with_std.rs b/substrate/substrate/runtime-io/with_std.rs index 5d785119c5..8c1bad8d7f 100644 --- a/substrate/substrate/runtime-io/with_std.rs +++ b/substrate/substrate/runtime-io/with_std.rs @@ -86,7 +86,7 @@ pub fn enumerated_trie_root(serialised_values: &[&[u8]]) -> [u8; 32] { } /// Verify a ed25519 signature. -pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool { +pub fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { ed25519::verify(sig, msg, pubkey) } diff --git a/substrate/substrate/runtime-io/without_std.rs b/substrate/substrate/runtime-io/without_std.rs index ad31020cc4..64d69957cf 100644 --- a/substrate/substrate/runtime-io/without_std.rs +++ b/substrate/substrate/runtime-io/without_std.rs @@ -161,9 +161,9 @@ pub fn twox_128(data: &[u8]) -> [u8; 16] { } /// Verify a ed25519 signature. -pub fn ed25519_verify(sig: &[u8; 64], msg: &[u8], pubkey: &[u8; 32]) -> bool { +pub fn ed25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { 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 } }