From 5a30f38992e11071316fc927efeb14c51ed39f9b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 20 Mar 2018 10:48:11 +0800 Subject: [PATCH] A random beacon (#96) * Completely rework dispatch mechanism into something modular. Not yet complete but 75% there. * Council vote tests. * Fix tests. * whitespace. * Fix demo runtime tests. * Fix up tests. * Remove dead code. * Initial util code for random beacon * Timestamp uses new storage API. * Move over system module to new API. * Much nicer storage API, moved over staking module. * More refactoring. * Democracy uses new storage API. * Council uses new RPC. * Fix more tests. * Use match for Id * Generic mix. * Integrate random beacon * Update binaries. * Fixes relating to with_ext removal. * Remove dead code. * Rework mixer into an iterator adaptor. * Link to paper. * Algorithm cleanups * Merge and fix test. * Docs. * Fix typo. * rename * Fix tests. --- polkadot/runtime/src/runtime/governance.rs | 18 +++++------ polkadot/runtime/src/runtime/session.rs | 22 ++++++------- polkadot/runtime/src/runtime/staking.rs | 30 +++++++++--------- polkadot/runtime/src/runtime/system.rs | 9 ++++++ .../release/polkadot_runtime.compact.wasm | Bin 134847 -> 134847 bytes .../release/polkadot_runtime.wasm | Bin 134896 -> 134896 bytes 6 files changed, 44 insertions(+), 35 deletions(-) diff --git a/polkadot/runtime/src/runtime/governance.rs b/polkadot/runtime/src/runtime/governance.rs index 9138a3eddf..80620d578f 100644 --- a/polkadot/runtime/src/runtime/governance.rs +++ b/polkadot/runtime/src/runtime/governance.rs @@ -189,7 +189,7 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Approve it. Era length changes. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); public::approve(&two, 1); staking::internal::check_new_era(); @@ -212,13 +212,13 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Fail it. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 1); // Block 2: Make proposal. Approve it. It should change era length. - with_env(|e| e.block_number = 2); + system::testing::set_block_number(2); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); public::approve(&two, 2); staking::internal::check_new_era(); @@ -241,7 +241,7 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 1); @@ -264,7 +264,7 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); public::approve(&two, 0); staking::internal::check_new_era(); @@ -288,7 +288,7 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); public::approve(&two, 1); public::approve(&two, 1); @@ -313,7 +313,7 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); public::propose(&two, &Proposal::StakingSetSessionsPerEra(2)); staking::internal::check_new_era(); @@ -337,7 +337,7 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::approve(&two, 1); staking::internal::check_new_era(); assert_eq!(staking::era_length(), 1); @@ -361,7 +361,7 @@ mod tests { assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); public::approve(&four, 1); staking::internal::check_new_era(); diff --git a/polkadot/runtime/src/runtime/session.rs b/polkadot/runtime/src/runtime/session.rs index 01a5f78bbc..4eb5bf5055 100644 --- a/polkadot/runtime/src/runtime/session.rs +++ b/polkadot/runtime/src/runtime/session.rs @@ -217,46 +217,46 @@ mod tests { let mut t = simple_setup(); with_externalities(&mut t, || { // Block 1: Change to length 3; no visible change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); set_length(3); check_rotate_session(); assert_eq!(length(), 2); assert_eq!(current_index(), 0); // Block 2: Length now changed to 3. Index incremented. - with_env(|e| e.block_number = 2); + system::testing::set_block_number(2); set_length(3); check_rotate_session(); assert_eq!(length(), 3); assert_eq!(current_index(), 1); // Block 3: Length now changed to 3. Index incremented. - with_env(|e| e.block_number = 3); + system::testing::set_block_number(3); check_rotate_session(); assert_eq!(length(), 3); assert_eq!(current_index(), 1); // Block 4: Change to length 2; no visible change. - with_env(|e| e.block_number = 4); + system::testing::set_block_number(4); set_length(2); check_rotate_session(); assert_eq!(length(), 3); assert_eq!(current_index(), 1); // Block 5: Length now changed to 2. Index incremented. - with_env(|e| e.block_number = 5); + system::testing::set_block_number(5); check_rotate_session(); assert_eq!(length(), 2); assert_eq!(current_index(), 2); // Block 6: No change. - with_env(|e| e.block_number = 6); + system::testing::set_block_number(6); check_rotate_session(); assert_eq!(length(), 2); assert_eq!(current_index(), 2); // Block 7: Next index. - with_env(|e| e.block_number = 7); + system::testing::set_block_number(7); check_rotate_session(); assert_eq!(length(), 2); assert_eq!(current_index(), 3); @@ -268,17 +268,17 @@ mod tests { let mut t = simple_setup(); with_externalities(&mut t, || { // Block 1: No change - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); check_rotate_session(); assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]); // Block 2: Session rollover, but no change. - with_env(|e| e.block_number = 2); + system::testing::set_block_number(2); check_rotate_session(); assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]); // Block 3: Set new key for validator 2; no visible change. - with_env(|e| e.block_number = 3); + system::testing::set_block_number(3); set_key(&[20; 32], &[22; 32]); assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]); @@ -286,7 +286,7 @@ mod tests { assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]); // Block 4: Session rollover, authority 2 changes. - with_env(|e| e.block_number = 4); + system::testing::set_block_number(4); check_rotate_session(); assert_eq!(consensus::authorities(), vec![[11u8; 32], [22u8; 32]]); }); diff --git a/polkadot/runtime/src/runtime/staking.rs b/polkadot/runtime/src/runtime/staking.rs index cca0a92718..7ed94b9202 100644 --- a/polkadot/runtime/src/runtime/staking.rs +++ b/polkadot/runtime/src/runtime/staking.rs @@ -310,7 +310,7 @@ mod tests { assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]); // Block 1: Add three validators. No obvious change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); stake(&one); stake(&two); stake(&four); @@ -318,39 +318,39 @@ mod tests { assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]); // Block 2: New validator set now. - with_env(|e| e.block_number = 2); + system::testing::set_block_number(2); check_new_era(); assert_eq!(session::validators(), vec![four.clone(), two.clone()]); // Block 3: Unstake highest, introduce another staker. No change yet. - with_env(|e| e.block_number = 3); + system::testing::set_block_number(3); stake(&three); unstake(&four); check_new_era(); // Block 4: New era - validators change. - with_env(|e| e.block_number = 4); + system::testing::set_block_number(4); check_new_era(); assert_eq!(session::validators(), vec![three.clone(), two.clone()]); // Block 5: Transfer stake from highest to lowest. No change yet. - with_env(|e| e.block_number = 5); + system::testing::set_block_number(5); transfer(&four, &one, 40); check_new_era(); // Block 6: Lowest now validator. - with_env(|e| e.block_number = 6); + system::testing::set_block_number(6); check_new_era(); assert_eq!(session::validators(), vec![one.clone(), three.clone()]); // Block 7: Unstake three. No change yet. - with_env(|e| e.block_number = 7); + system::testing::set_block_number(7); unstake(&three); check_new_era(); assert_eq!(session::validators(), vec![one.clone(), three.clone()]); // Block 8: Back to one and two. - with_env(|e| e.block_number = 8); + system::testing::set_block_number(8); check_new_era(); assert_eq!(session::validators(), vec![one.clone(), two.clone()]); }); @@ -369,21 +369,21 @@ mod tests { assert_eq!(current_era(), 0u64); // Block 1: No change. - with_env(|e| e.block_number = 1); + system::testing::set_block_number(1); check_new_era(); assert_eq!(sessions_per_era(), 2u64); assert_eq!(last_era_length_change(), 0u64); assert_eq!(current_era(), 0u64); // Block 2: Simple era change. - with_env(|e| e.block_number = 2); + system::testing::set_block_number(2); check_new_era(); assert_eq!(sessions_per_era(), 2u64); assert_eq!(last_era_length_change(), 0u64); assert_eq!(current_era(), 1u64); // Block 3: Schedule an era length change; no visible changes. - with_env(|e| e.block_number = 3); + system::testing::set_block_number(3); set_sessions_per_era(3); check_new_era(); assert_eq!(sessions_per_era(), 2u64); @@ -391,28 +391,28 @@ mod tests { assert_eq!(current_era(), 1u64); // Block 4: Era change kicks in. - with_env(|e| e.block_number = 4); + system::testing::set_block_number(4); check_new_era(); assert_eq!(sessions_per_era(), 3u64); assert_eq!(last_era_length_change(), 4u64); assert_eq!(current_era(), 2u64); // Block 5: No change. - with_env(|e| e.block_number = 5); + system::testing::set_block_number(5); check_new_era(); assert_eq!(sessions_per_era(), 3u64); assert_eq!(last_era_length_change(), 4u64); assert_eq!(current_era(), 2u64); // Block 6: No change. - with_env(|e| e.block_number = 6); + system::testing::set_block_number(6); check_new_era(); assert_eq!(sessions_per_era(), 3u64); assert_eq!(last_era_length_change(), 4u64); assert_eq!(current_era(), 2u64); // Block 7: Era increment. - with_env(|e| e.block_number = 7); + system::testing::set_block_number(7); check_new_era(); assert_eq!(sessions_per_era(), 3u64); assert_eq!(last_era_length_change(), 4u64); diff --git a/polkadot/runtime/src/runtime/system.rs b/polkadot/runtime/src/runtime/system.rs index c7972c949a..935f801924 100644 --- a/polkadot/runtime/src/runtime/system.rs +++ b/polkadot/runtime/src/runtime/system.rs @@ -264,6 +264,15 @@ fn info_expect_equal_hash(given: &Hash, expected: &Hash) { } } +#[cfg(any(feature = "std", test))] +pub mod testing { + use super::*; + + pub fn set_block_number(n: BlockNumber) { + with_env(|e| e.block_number = n); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index 7072339a0712581faa3d0d6c6370673df0ff70de..3b3fb8f78c34f3325307db47c3986ea9cca59203 100644 GIT binary patch delta 5471 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 C?av$l delta 5396 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