mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-10 17:11:03 +00:00
Introduce module structure over comments.
This commit is contained in:
@@ -38,14 +38,14 @@ use primitives::{Block, UncheckedTransaction};
|
||||
/// Execute a block, with `input` being the canonical serialisation of the block. Returns the
|
||||
/// empty vector.
|
||||
pub fn execute_block(input: &[u8]) -> Vec<u8> {
|
||||
runtime::system::execute_block(Block::from_slice(input).unwrap());
|
||||
runtime::system::internal::execute_block(Block::from_slice(input).unwrap());
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Execute a given, serialised, transaction. Returns the empty vector.
|
||||
pub fn execute_transaction(input: &[u8]) -> Vec<u8> {
|
||||
let utx = UncheckedTransaction::from_slice(input).unwrap();
|
||||
runtime::system::execute_transaction(&utx);
|
||||
runtime::system::internal::execute_transaction(&utx);
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,15 @@ use runtime::{staking, session, timestamp, governance};
|
||||
/// Public functions that can be dispatched to.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "with-std", derive(PartialEq, Debug))]
|
||||
#[repr(u8)]
|
||||
pub enum Function {
|
||||
StakingStake,
|
||||
StakingUnstake,
|
||||
StakingTransfer,
|
||||
SessionSetKey,
|
||||
TimestampSet,
|
||||
GovernancePropose,
|
||||
GovernanceApprove,
|
||||
StakingStake = 0,
|
||||
StakingUnstake = 1,
|
||||
StakingTransfer = 2,
|
||||
SessionSetKey = 3,
|
||||
TimestampSet = 4,
|
||||
GovernancePropose = 5,
|
||||
GovernanceApprove = 6,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
@@ -55,31 +56,31 @@ impl Function {
|
||||
let mut params = StreamReader::new(data);
|
||||
match *self {
|
||||
Function::StakingStake => {
|
||||
staking::stake(transactor);
|
||||
staking::public::stake(transactor);
|
||||
}
|
||||
Function::StakingUnstake => {
|
||||
staking::unstake(transactor);
|
||||
staking::public::unstake(transactor);
|
||||
}
|
||||
Function::StakingTransfer => {
|
||||
let dest = params.read().unwrap();
|
||||
let value = params.read().unwrap();
|
||||
staking::transfer(transactor, &dest, value);
|
||||
staking::public::transfer(transactor, &dest, value);
|
||||
}
|
||||
Function::SessionSetKey => {
|
||||
let session = params.read().unwrap();
|
||||
session::set_key(transactor, &session);
|
||||
session::public::set_key(transactor, &session);
|
||||
}
|
||||
Function::TimestampSet => {
|
||||
let t = params.read().unwrap();
|
||||
timestamp::set(t);
|
||||
timestamp::public::set(t);
|
||||
}
|
||||
Function::GovernancePropose => {
|
||||
let proposal = params.read().unwrap();
|
||||
governance::propose(transactor, &proposal);
|
||||
governance::public::propose(transactor, &proposal);
|
||||
}
|
||||
Function::GovernanceApprove => {
|
||||
let era_index = params.read().unwrap();
|
||||
governance::approve(transactor, era_index);
|
||||
governance::public::approve(transactor, era_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,14 @@ use runtime::{system, governance, staking, session};
|
||||
/// Internal functions that can be dispatched to.
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "with-std", derive(PartialEq, Debug))]
|
||||
#[repr(u8)]
|
||||
pub enum InternalFunction {
|
||||
SystemSetCode,
|
||||
StakingSetSessionsPerEra,
|
||||
StakingSetBondingDuration,
|
||||
StakingSetValidatorCount,
|
||||
GovernanceSetApprovalPpmRequired,
|
||||
SessionSetLength,
|
||||
SystemSetCode = 0,
|
||||
StakingSetSessionsPerEra = 1,
|
||||
StakingSetBondingDuration = 2,
|
||||
StakingSetValidatorCount = 3,
|
||||
GovernanceSetApprovalPpmRequired = 4,
|
||||
SessionSetLength = 5,
|
||||
}
|
||||
|
||||
impl InternalFunction {
|
||||
@@ -85,27 +86,27 @@ impl Proposal {
|
||||
match self.function {
|
||||
InternalFunction::SystemSetCode => {
|
||||
let code: Vec<u8> = params.read().unwrap();
|
||||
system::set_code(&code);
|
||||
system::privileged::set_code(&code);
|
||||
}
|
||||
InternalFunction::StakingSetSessionsPerEra => {
|
||||
let value = params.read().unwrap();
|
||||
staking::set_sessions_per_era(value);
|
||||
staking::privileged::set_sessions_per_era(value);
|
||||
}
|
||||
InternalFunction::StakingSetBondingDuration => {
|
||||
let value = params.read().unwrap();
|
||||
staking::set_bonding_duration(value);
|
||||
staking::privileged::set_bonding_duration(value);
|
||||
}
|
||||
InternalFunction::StakingSetValidatorCount => {
|
||||
let value = params.read().unwrap();
|
||||
staking::set_validator_count(value);
|
||||
staking::privileged::set_validator_count(value);
|
||||
}
|
||||
InternalFunction::GovernanceSetApprovalPpmRequired => {
|
||||
let value = params.read().unwrap();
|
||||
governance::set_approval_ppm_required(value);
|
||||
governance::privileged::set_approval_ppm_required(value);
|
||||
}
|
||||
InternalFunction::SessionSetLength => {
|
||||
let value = params.read().unwrap();
|
||||
session::set_length(value);
|
||||
session::privileged::set_length(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,7 +115,7 @@ impl Proposal {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use statichex::StaticHexInto;
|
||||
use support::StaticHexInto;
|
||||
|
||||
#[test]
|
||||
fn slicing_should_work() {
|
||||
|
||||
@@ -31,14 +31,18 @@ pub fn authorities() -> Vec<SessionKey> {
|
||||
AuthorityStorageVec::items()
|
||||
}
|
||||
|
||||
/// Set the current set of authorities' session keys.
|
||||
///
|
||||
/// Called by `next_session` only.
|
||||
pub fn set_authorities(authorities: &[SessionKey]) {
|
||||
AuthorityStorageVec::set_items(authorities);
|
||||
}
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
/// Set a single authority by index.
|
||||
pub fn set_authority(index: u32, key: &SessionKey) {
|
||||
AuthorityStorageVec::set_item(index, key);
|
||||
/// Set the current set of authorities' session keys.
|
||||
///
|
||||
/// Called by `next_session` only.
|
||||
pub fn set_authorities(authorities: &[SessionKey]) {
|
||||
AuthorityStorageVec::set_items(authorities);
|
||||
}
|
||||
|
||||
/// Set a single authority by index.
|
||||
pub fn set_authority(index: u32, key: &SessionKey) {
|
||||
AuthorityStorageVec::set_item(index, key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,48 +31,6 @@ use support::{Storable, StorageVec, kill};
|
||||
use primitives::{AccountID, Hash, BlockNumber, Proposal};
|
||||
use runtime::{staking, system, session};
|
||||
|
||||
// TRANSACTION API
|
||||
|
||||
/// Propose a sensitive action to be taken. Any action that is enactable by `Proposal` is valid.
|
||||
/// Proposal is by the `transactor` and will automatically count as an approval. Transactor must
|
||||
/// be a current validator. It is illegal to propose when there is already a proposal in effect.
|
||||
pub fn propose(validator: &AccountID, proposal: &Proposal) {
|
||||
if Proposal::lookup(b"gov:pro").is_some() {
|
||||
panic!("there may only be one proposal per era.");
|
||||
}
|
||||
proposal.store(b"gov:pro");
|
||||
approve(validator, staking::current_era());
|
||||
}
|
||||
|
||||
/// Approve the current era's proposal. Transactor must be a validator. This may not be done more
|
||||
/// than once for any validator in an era.
|
||||
pub fn approve(validator: &AccountID, era_index: BlockNumber) {
|
||||
if era_index != staking::current_era() {
|
||||
panic!("approval vote applied on non-current era.")
|
||||
}
|
||||
if Proposal::lookup(b"gov:pro").is_none() {
|
||||
panic!("there must be a proposal in order to approve.");
|
||||
}
|
||||
if session::validators().into_iter().position(|v| &v == validator).is_none() {
|
||||
panic!("transactor must be a validator to approve.");
|
||||
}
|
||||
let key = validator.to_keyed_vec(b"gov:app:");
|
||||
if bool::lookup(&key).is_some() {
|
||||
panic!("transactor may not approve a proposal twice in one era.");
|
||||
}
|
||||
true.store(&key);
|
||||
}
|
||||
|
||||
/// Set the proportion of validators that must approve for a proposal to be enacted at the end of
|
||||
/// its era. The value, `ppm`, is measured as a fraction of 1000 rounded down to the nearest whole
|
||||
/// validator. `1000` would require the approval of all validators; `667` would require two-thirds
|
||||
/// (or there abouts) of validators.
|
||||
pub fn set_approval_ppm_required(ppm: u32) {
|
||||
ppm.store(b"gov:apr");
|
||||
}
|
||||
|
||||
// INSPECTION API
|
||||
|
||||
/// The proportion of validators required for a propsal to be approved measured as the number out
|
||||
/// of 1000.
|
||||
pub fn approval_ppm_required() -> u32 {
|
||||
@@ -84,20 +42,68 @@ pub fn approvals_required() -> u32 {
|
||||
approval_ppm_required() * session::validator_count() as u32 / 1000
|
||||
}
|
||||
|
||||
// PUBLIC API
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
/// Current era is ending; we should finish up any proposals.
|
||||
pub fn end_of_an_era() {
|
||||
// tally up votes for the current proposal, if any. enact if there are sufficient approvals.
|
||||
if let Some(proposal) = Proposal::lookup(b"gov:pro") {
|
||||
kill(b"gov:pro");
|
||||
let approvals_required = approvals_required();
|
||||
let approved = session::validators().into_iter()
|
||||
.filter_map(|v| bool::take(&v.to_keyed_vec(b"gov:app:")))
|
||||
.take(approvals_required as usize)
|
||||
.count() as u32;
|
||||
if approved == approvals_required {
|
||||
proposal.enact();
|
||||
/// Propose a sensitive action to be taken. Any action that is enactable by `Proposal` is valid.
|
||||
/// Proposal is by the `transactor` and will automatically count as an approval. Transactor must
|
||||
/// be a current validator. It is illegal to propose when there is already a proposal in effect.
|
||||
pub fn propose(validator: &AccountID, proposal: &Proposal) {
|
||||
if Proposal::lookup(b"gov:pro").is_some() {
|
||||
panic!("there may only be one proposal per era.");
|
||||
}
|
||||
proposal.store(b"gov:pro");
|
||||
approve(validator, staking::current_era());
|
||||
}
|
||||
|
||||
/// Approve the current era's proposal. Transactor must be a validator. This may not be done more
|
||||
/// than once for any validator in an era.
|
||||
pub fn approve(validator: &AccountID, era_index: BlockNumber) {
|
||||
if era_index != staking::current_era() {
|
||||
panic!("approval vote applied on non-current era.")
|
||||
}
|
||||
if Proposal::lookup(b"gov:pro").is_none() {
|
||||
panic!("there must be a proposal in order to approve.");
|
||||
}
|
||||
if session::validators().into_iter().position(|v| &v == validator).is_none() {
|
||||
panic!("transactor must be a validator to approve.");
|
||||
}
|
||||
let key = validator.to_keyed_vec(b"gov:app:");
|
||||
if bool::lookup(&key).is_some() {
|
||||
panic!("transactor may not approve a proposal twice in one era.");
|
||||
}
|
||||
true.store(&key);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Set the proportion of validators that must approve for a proposal to be enacted at the end of
|
||||
/// its era. The value, `ppm`, is measured as a fraction of 1000 rounded down to the nearest whole
|
||||
/// validator. `1000` would require the approval of all validators; `667` would require two-thirds
|
||||
/// (or there abouts) of validators.
|
||||
pub fn set_approval_ppm_required(ppm: u32) {
|
||||
ppm.store(b"gov:apr");
|
||||
}
|
||||
}
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
/// Current era is ending; we should finish up any proposals.
|
||||
pub fn end_of_an_era() {
|
||||
// tally up votes for the current proposal, if any. enact if there are sufficient approvals.
|
||||
if let Some(proposal) = Proposal::lookup(b"gov:pro") {
|
||||
kill(b"gov:pro");
|
||||
let approvals_required = approvals_required();
|
||||
let approved = session::validators().into_iter()
|
||||
.filter_map(|v| bool::take(&v.to_keyed_vec(b"gov:app:")))
|
||||
.take(approvals_required as usize)
|
||||
.count() as u32;
|
||||
if approved == approvals_required {
|
||||
proposal.enact();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,13 +112,10 @@ pub fn end_of_an_era() {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use keyedvec::KeyedVec;
|
||||
use joiner::Joiner;
|
||||
use testing::{one, two, TestExternalities};
|
||||
use primitives::AccountID;
|
||||
use proposal::InternalFunction;
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use support::{one, two, TestExternalities, with_env};
|
||||
use primitives::{AccountID, InternalFunction};
|
||||
use runtime::{staking, session};
|
||||
use environment::with_env;
|
||||
|
||||
fn new_test_ext() -> TestExternalities {
|
||||
let one = one();
|
||||
@@ -152,12 +155,12 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Approve it. Era length changes.
|
||||
with_env(|e| e.block_number = 1);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
approve(&two, 1);
|
||||
staking::check_new_era();
|
||||
public::approve(&two, 1);
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 2);
|
||||
});
|
||||
}
|
||||
@@ -178,21 +181,21 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Fail it.
|
||||
with_env(|e| e.block_number = 1);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
staking::check_new_era();
|
||||
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);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
approve(&two, 2);
|
||||
staking::check_new_era();
|
||||
public::approve(&two, 2);
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 2);
|
||||
});
|
||||
}
|
||||
@@ -213,11 +216,11 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Will have only 1 vote. No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
staking::check_new_era();
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 1);
|
||||
});
|
||||
}
|
||||
@@ -239,12 +242,12 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Will have only 1 vote. No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
approve(&two, 0);
|
||||
staking::check_new_era();
|
||||
public::approve(&two, 0);
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 1);
|
||||
});
|
||||
}
|
||||
@@ -266,13 +269,13 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Will have only 1 vote. No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
approve(&two, 1);
|
||||
approve(&two, 1);
|
||||
staking::check_new_era();
|
||||
public::approve(&two, 1);
|
||||
public::approve(&two, 1);
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 1);
|
||||
});
|
||||
}
|
||||
@@ -294,15 +297,15 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Will have only 1 vote. No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
propose(&two, &Proposal {
|
||||
public::propose(&two, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
staking::check_new_era();
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 1);
|
||||
});
|
||||
}
|
||||
@@ -324,8 +327,8 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Will have only 1 vote. No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
approve(&two, 1);
|
||||
staking::check_new_era();
|
||||
public::approve(&two, 1);
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 1);
|
||||
});
|
||||
}
|
||||
@@ -348,12 +351,12 @@ mod tests {
|
||||
|
||||
// Block 1: Make proposal. Will have only 1 vote. No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
propose(&one, &Proposal {
|
||||
public::propose(&one, &Proposal {
|
||||
function: InternalFunction::StakingSetSessionsPerEra,
|
||||
input_data: vec![].join(&2u64),
|
||||
});
|
||||
approve(&four, 1);
|
||||
staking::check_new_era();
|
||||
public::approve(&four, 1);
|
||||
staking::internal::check_new_era();
|
||||
assert_eq!(staking::era_length(), 1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,50 +23,6 @@ use support::{kill, Storable, StorageVec};
|
||||
use primitives::{AccountID, SessionKey, BlockNumber};
|
||||
use runtime::{system, staking, consensus};
|
||||
|
||||
struct ValidatorStorageVec {}
|
||||
impl StorageVec for ValidatorStorageVec {
|
||||
type Item = AccountID;
|
||||
const PREFIX: &'static[u8] = b"ses:val:";
|
||||
}
|
||||
|
||||
// TRANSACTION API (available to all transactors)
|
||||
|
||||
/// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next
|
||||
/// session.
|
||||
pub fn set_key(validator: &AccountID, key: &SessionKey) {
|
||||
// set new value for next session
|
||||
key.store(&validator.to_keyed_vec(b"ses:nxt:"));
|
||||
}
|
||||
// PRIVILEGED API (available to proposals)
|
||||
|
||||
/// Set a new era length. Won't kick in until the next era change (at current length).
|
||||
pub fn set_length(new: BlockNumber) {
|
||||
new.store(b"ses:nln");
|
||||
}
|
||||
|
||||
// INTERNAL API (available to other runtime modules)
|
||||
|
||||
/// Set the current set of validators.
|
||||
///
|
||||
/// Called by staking::next_era() only. `next_session` should be called after this in order to
|
||||
/// update the session keys to the next validator set.
|
||||
pub fn set_validators(new: &[AccountID]) {
|
||||
ValidatorStorageVec::set_items(new);
|
||||
consensus::set_authorities(new);
|
||||
}
|
||||
|
||||
/// Hook to be called after transaction processing.
|
||||
pub fn check_rotate_session() {
|
||||
// do this last, after the staking system has had chance to switch out the authorities for the
|
||||
// new set.
|
||||
// check block number and call next_session if necessary.
|
||||
if (system::block_number() - last_length_change()) % length() == 0 {
|
||||
rotate_session();
|
||||
}
|
||||
}
|
||||
|
||||
// Inspection API
|
||||
|
||||
/// Get the current set of authorities. These are the session keys.
|
||||
pub fn validators() -> Vec<AccountID> {
|
||||
ValidatorStorageVec::items()
|
||||
@@ -92,7 +48,56 @@ pub fn last_length_change() -> BlockNumber {
|
||||
Storable::lookup_default(b"ses:llc")
|
||||
}
|
||||
|
||||
// PRIVATE (not available for use externally)
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
/// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next
|
||||
/// session.
|
||||
pub fn set_key(validator: &AccountID, key: &SessionKey) {
|
||||
// set new value for next session
|
||||
key.store(&validator.to_keyed_vec(b"ses:nxt:"));
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Set a new era length. Won't kick in until the next era change (at current length).
|
||||
pub fn set_length(new: BlockNumber) {
|
||||
new.store(b"ses:nln");
|
||||
}
|
||||
}
|
||||
|
||||
// INTERNAL API (available to other runtime modules)
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
/// Set the current set of validators.
|
||||
///
|
||||
/// Called by staking::next_era() only. `next_session` should be called after this in order to
|
||||
/// update the session keys to the next validator set.
|
||||
pub fn set_validators(new: &[AccountID]) {
|
||||
ValidatorStorageVec::set_items(new);
|
||||
consensus::internal::set_authorities(new);
|
||||
}
|
||||
|
||||
/// Hook to be called after transaction processing.
|
||||
pub fn check_rotate_session() {
|
||||
// do this last, after the staking system has had chance to switch out the authorities for the
|
||||
// new set.
|
||||
// check block number and call next_session if necessary.
|
||||
if (system::block_number() - last_length_change()) % length() == 0 {
|
||||
rotate_session();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ValidatorStorageVec {}
|
||||
impl StorageVec for ValidatorStorageVec {
|
||||
type Item = AccountID;
|
||||
const PREFIX: &'static[u8] = b"ses:val:";
|
||||
}
|
||||
|
||||
/// Move onto next session: register the new authority set.
|
||||
fn rotate_session() {
|
||||
@@ -110,7 +115,7 @@ fn rotate_session() {
|
||||
validators().iter().enumerate().for_each(|(i, v)| {
|
||||
let k = v.to_keyed_vec(b"ses:nxt:");
|
||||
if let Some(n) = Storable::lookup(&k) {
|
||||
consensus::set_authority(i as u32, &n);
|
||||
consensus::internal::set_authority(i as u32, &n);
|
||||
kill(&k);
|
||||
}
|
||||
});
|
||||
@@ -118,13 +123,15 @@ fn rotate_session() {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::public::*;
|
||||
use super::privileged::*;
|
||||
use super::internal::*;
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use keyedvec::KeyedVec;
|
||||
use joiner::Joiner;
|
||||
use testing::{one, two, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use support::{one, two, TestExternalities, with_env};
|
||||
use primitives::AccountID;
|
||||
use runtime::{consensus, session};
|
||||
use environment::with_env;
|
||||
|
||||
fn simple_setup() -> TestExternalities {
|
||||
TestExternalities { storage: map![
|
||||
@@ -145,8 +152,8 @@ mod tests {
|
||||
let mut t = simple_setup();
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
assert_eq!(session::length(), 2u64);
|
||||
assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]);
|
||||
assert_eq!(length(), 2u64);
|
||||
assert_eq!(validators(), vec![[10u8; 32], [20u8; 32]]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -156,48 +163,48 @@ mod tests {
|
||||
with_externalities(&mut t, || {
|
||||
// Block 1: Change to length 3; no visible change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
session::set_length(3);
|
||||
session::check_rotate_session();
|
||||
assert_eq!(session::length(), 2);
|
||||
assert_eq!(session::current_index(), 0);
|
||||
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);
|
||||
session::set_length(3);
|
||||
session::check_rotate_session();
|
||||
assert_eq!(session::length(), 3);
|
||||
assert_eq!(session::current_index(), 1);
|
||||
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);
|
||||
session::check_rotate_session();
|
||||
assert_eq!(session::length(), 3);
|
||||
assert_eq!(session::current_index(), 1);
|
||||
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);
|
||||
session::set_length(2);
|
||||
session::check_rotate_session();
|
||||
assert_eq!(session::length(), 3);
|
||||
assert_eq!(session::current_index(), 1);
|
||||
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);
|
||||
session::check_rotate_session();
|
||||
assert_eq!(session::length(), 2);
|
||||
assert_eq!(session::current_index(), 2);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 2);
|
||||
assert_eq!(current_index(), 2);
|
||||
|
||||
// Block 6: No change.
|
||||
with_env(|e| e.block_number = 6);
|
||||
session::check_rotate_session();
|
||||
assert_eq!(session::length(), 2);
|
||||
assert_eq!(session::current_index(), 2);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 2);
|
||||
assert_eq!(current_index(), 2);
|
||||
|
||||
// Block 7: Next index.
|
||||
with_env(|e| e.block_number = 7);
|
||||
session::check_rotate_session();
|
||||
assert_eq!(session::length(), 2);
|
||||
assert_eq!(session::current_index(), 3);
|
||||
check_rotate_session();
|
||||
assert_eq!(length(), 2);
|
||||
assert_eq!(current_index(), 3);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -207,25 +214,25 @@ mod tests {
|
||||
with_externalities(&mut t, || {
|
||||
// Block 1: No change
|
||||
with_env(|e| e.block_number = 1);
|
||||
session::check_rotate_session();
|
||||
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);
|
||||
session::check_rotate_session();
|
||||
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);
|
||||
session::set_key(&[20; 32], &[22; 32]);
|
||||
set_key(&[20; 32], &[22; 32]);
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
|
||||
session::check_rotate_session();
|
||||
check_rotate_session();
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]);
|
||||
|
||||
// Block 4: Session rollover, authority 2 changes.
|
||||
with_env(|e| e.block_number = 4);
|
||||
session::check_rotate_session();
|
||||
check_rotate_session();
|
||||
assert_eq!(consensus::authorities(), vec![[11u8; 32], [22u8; 32]]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,88 +29,6 @@ pub type Balance = u64;
|
||||
/// The amount of bonding period left in an account. Measured in eras.
|
||||
pub type Bondage = u64;
|
||||
|
||||
struct IntentionStorageVec {}
|
||||
impl StorageVec for IntentionStorageVec {
|
||||
type Item = AccountID;
|
||||
const PREFIX: &'static[u8] = b"sta:wil:";
|
||||
}
|
||||
|
||||
// Each identity's stake may be in one of three bondage states, given by an integer:
|
||||
// - n | n <= current_era(): inactive: free to be transferred.
|
||||
// - ~0: active: currently representing a validator.
|
||||
// - n | n > current_era(): deactivating: recently representing a validator and not yet
|
||||
// ready for transfer.
|
||||
|
||||
// TRANSACTION API
|
||||
|
||||
/// Transfer some unlocked staking balance to another staker.
|
||||
pub fn transfer(transactor: &AccountID, dest: &AccountID, value: Balance) {
|
||||
let from_key = transactor.to_keyed_vec(b"sta:bal:");
|
||||
let from_balance = Balance::lookup_default(&from_key);
|
||||
assert!(from_balance >= value);
|
||||
let to_key = dest.to_keyed_vec(b"sta:bal:");
|
||||
let to_balance: Balance = Storable::lookup_default(&to_key);
|
||||
assert!(bondage(transactor) <= bondage(dest));
|
||||
assert!(to_balance + value > to_balance); // no overflow
|
||||
(from_balance - value).store(&from_key);
|
||||
(to_balance + value).store(&to_key);
|
||||
}
|
||||
|
||||
/// Declare the desire to stake for the transactor.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
pub fn stake(transactor: &AccountID) {
|
||||
let mut intentions = IntentionStorageVec::items();
|
||||
// can't be in the list twice.
|
||||
assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked.");
|
||||
intentions.push(transactor.clone());
|
||||
IntentionStorageVec::set_items(&intentions);
|
||||
u64::max_value().store(&transactor.to_keyed_vec(b"sta:bon:"));
|
||||
}
|
||||
|
||||
/// Retract the desire to stake for the transactor.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
pub fn unstake(transactor: &AccountID) {
|
||||
let mut intentions = IntentionStorageVec::items();
|
||||
if let Some(position) = intentions.iter().position(|t| t == transactor) {
|
||||
intentions.swap_remove(position);
|
||||
} else {
|
||||
panic!("Cannot unstake if not already staked.");
|
||||
}
|
||||
IntentionStorageVec::set_items(&intentions);
|
||||
(current_era() + bonding_duration()).store(&transactor.to_keyed_vec(b"sta:bon:"));
|
||||
}
|
||||
|
||||
// PRIVILEDGED API
|
||||
|
||||
/// Set the number of sessions in an era.
|
||||
pub fn set_sessions_per_era(new: BlockNumber) {
|
||||
new.store(b"sta:nse");
|
||||
}
|
||||
|
||||
/// The length of the bonding duration in eras.
|
||||
pub fn set_bonding_duration(new: BlockNumber) {
|
||||
new.store(b"sta:loc");
|
||||
}
|
||||
|
||||
/// The length of a staking era in sessions.
|
||||
pub fn set_validator_count(new: usize) {
|
||||
(new as u32).store(b"sta:vac");
|
||||
}
|
||||
|
||||
// INTERNAL API
|
||||
|
||||
/// Hook to be called after to transaction processing.
|
||||
pub fn check_new_era() {
|
||||
// check block number and call new_era if necessary.
|
||||
if (system::block_number() - last_era_length_change()) % era_length() == 0 {
|
||||
new_era();
|
||||
}
|
||||
}
|
||||
|
||||
// INSPECTION API
|
||||
|
||||
/// The length of the bonding duration in eras.
|
||||
pub fn bonding_duration() -> BlockNumber {
|
||||
Storable::lookup_default(b"sta:loc")
|
||||
@@ -151,7 +69,91 @@ pub fn bondage(who: &AccountID) -> Bondage {
|
||||
Storable::lookup_default(&who.to_keyed_vec(b"sta:bon:"))
|
||||
}
|
||||
|
||||
// PRIVATE
|
||||
// Each identity's stake may be in one of three bondage states, given by an integer:
|
||||
// - n | n <= current_era(): inactive: free to be transferred.
|
||||
// - ~0: active: currently representing a validator.
|
||||
// - n | n > current_era(): deactivating: recently representing a validator and not yet
|
||||
// ready for transfer.
|
||||
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
/// Transfer some unlocked staking balance to another staker.
|
||||
pub fn transfer(transactor: &AccountID, dest: &AccountID, value: Balance) {
|
||||
let from_key = transactor.to_keyed_vec(b"sta:bal:");
|
||||
let from_balance = Balance::lookup_default(&from_key);
|
||||
assert!(from_balance >= value);
|
||||
let to_key = dest.to_keyed_vec(b"sta:bal:");
|
||||
let to_balance: Balance = Storable::lookup_default(&to_key);
|
||||
assert!(bondage(transactor) <= bondage(dest));
|
||||
assert!(to_balance + value > to_balance); // no overflow
|
||||
(from_balance - value).store(&from_key);
|
||||
(to_balance + value).store(&to_key);
|
||||
}
|
||||
|
||||
/// Declare the desire to stake for the transactor.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
pub fn stake(transactor: &AccountID) {
|
||||
let mut intentions = IntentionStorageVec::items();
|
||||
// can't be in the list twice.
|
||||
assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked.");
|
||||
intentions.push(transactor.clone());
|
||||
IntentionStorageVec::set_items(&intentions);
|
||||
u64::max_value().store(&transactor.to_keyed_vec(b"sta:bon:"));
|
||||
}
|
||||
|
||||
/// Retract the desire to stake for the transactor.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
pub fn unstake(transactor: &AccountID) {
|
||||
let mut intentions = IntentionStorageVec::items();
|
||||
if let Some(position) = intentions.iter().position(|t| t == transactor) {
|
||||
intentions.swap_remove(position);
|
||||
} else {
|
||||
panic!("Cannot unstake if not already staked.");
|
||||
}
|
||||
IntentionStorageVec::set_items(&intentions);
|
||||
(current_era() + bonding_duration()).store(&transactor.to_keyed_vec(b"sta:bon:"));
|
||||
}
|
||||
}
|
||||
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Set the number of sessions in an era.
|
||||
pub fn set_sessions_per_era(new: BlockNumber) {
|
||||
new.store(b"sta:nse");
|
||||
}
|
||||
|
||||
/// The length of the bonding duration in eras.
|
||||
pub fn set_bonding_duration(new: BlockNumber) {
|
||||
new.store(b"sta:loc");
|
||||
}
|
||||
|
||||
/// The length of a staking era in sessions.
|
||||
pub fn set_validator_count(new: usize) {
|
||||
(new as u32).store(b"sta:vac");
|
||||
}
|
||||
}
|
||||
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
/// Hook to be called after to transaction processing.
|
||||
pub fn check_new_era() {
|
||||
// check block number and call new_era if necessary.
|
||||
if (system::block_number() - last_era_length_change()) % era_length() == 0 {
|
||||
new_era();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IntentionStorageVec {}
|
||||
impl StorageVec for IntentionStorageVec {
|
||||
type Item = AccountID;
|
||||
const PREFIX: &'static[u8] = b"sta:wil:";
|
||||
}
|
||||
|
||||
/// The era has changed - enact new staking set.
|
||||
///
|
||||
@@ -159,7 +161,7 @@ pub fn bondage(who: &AccountID) -> Bondage {
|
||||
/// get a chance to set their session keys.
|
||||
fn new_era() {
|
||||
// Inform governance module that it's the end of an era
|
||||
governance::end_of_an_era();
|
||||
governance::internal::end_of_an_era();
|
||||
|
||||
// Increment current era.
|
||||
(current_era() + 1).store(b"sta:era");
|
||||
@@ -172,7 +174,7 @@ fn new_era() {
|
||||
}
|
||||
|
||||
// evaluate desired staking amounts and nominations and optimise to find the best
|
||||
// combination of validators, then use session::set_validators().
|
||||
// combination of validators, then use session::internal::set_validators().
|
||||
// for now, this just orders would-be stakers by their balances and chooses the top-most
|
||||
// validator_count() of them.
|
||||
let mut intentions = IntentionStorageVec::items()
|
||||
@@ -180,7 +182,7 @@ fn new_era() {
|
||||
.map(|v| (balance(&v), v))
|
||||
.collect::<Vec<_>>();
|
||||
intentions.sort_unstable_by(|&(b1, _), &(b2, _)| b2.cmp(&b1));
|
||||
session::set_validators(
|
||||
session::internal::set_validators(
|
||||
&intentions.into_iter()
|
||||
.map(|(_, v)| v)
|
||||
.take(validator_count())
|
||||
@@ -190,13 +192,16 @@ fn new_era() {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::internal::*;
|
||||
use super::public::*;
|
||||
use super::privileged::*;
|
||||
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use keyedvec::KeyedVec;
|
||||
use joiner::Joiner;
|
||||
use testing::{one, two, TestExternalities};
|
||||
use codec::{KeyedVec, Joiner};
|
||||
use support::{one, two, TestExternalities, with_env};
|
||||
use primitives::AccountID;
|
||||
use runtime::{staking, session};
|
||||
use environment::with_env;
|
||||
|
||||
#[test]
|
||||
fn staking_should_work() {
|
||||
@@ -220,54 +225,54 @@ mod tests {
|
||||
], };
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(staking::era_length(), 2u64);
|
||||
assert_eq!(staking::validator_count(), 2usize);
|
||||
assert_eq!(staking::bonding_duration(), 3u64);
|
||||
assert_eq!(era_length(), 2u64);
|
||||
assert_eq!(validator_count(), 2usize);
|
||||
assert_eq!(bonding_duration(), 3u64);
|
||||
assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]);
|
||||
|
||||
// Block 1: Add three validators. No obvious change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
staking::stake(&one);
|
||||
staking::stake(&two);
|
||||
staking::stake(&four);
|
||||
staking::check_new_era();
|
||||
stake(&one);
|
||||
stake(&two);
|
||||
stake(&four);
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]);
|
||||
|
||||
// Block 2: New validator set now.
|
||||
with_env(|e| e.block_number = 2);
|
||||
staking::check_new_era();
|
||||
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);
|
||||
staking::stake(&three);
|
||||
staking::unstake(&four);
|
||||
staking::check_new_era();
|
||||
stake(&three);
|
||||
unstake(&four);
|
||||
check_new_era();
|
||||
|
||||
// Block 4: New era - validators change.
|
||||
with_env(|e| e.block_number = 4);
|
||||
staking::check_new_era();
|
||||
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);
|
||||
staking::transfer(&four, &one, 40);
|
||||
staking::check_new_era();
|
||||
transfer(&four, &one, 40);
|
||||
check_new_era();
|
||||
|
||||
// Block 6: Lowest now validator.
|
||||
with_env(|e| e.block_number = 6);
|
||||
staking::check_new_era();
|
||||
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);
|
||||
staking::unstake(&three);
|
||||
staking::check_new_era();
|
||||
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);
|
||||
staking::check_new_era();
|
||||
check_new_era();
|
||||
assert_eq!(session::validators(), vec![one.clone(), two.clone()]);
|
||||
});
|
||||
}
|
||||
@@ -279,60 +284,60 @@ mod tests {
|
||||
twox_128(b"sta:spe").to_vec() => vec![].join(&2u64)
|
||||
], };
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(staking::era_length(), 2u64);
|
||||
assert_eq!(staking::sessions_per_era(), 2u64);
|
||||
assert_eq!(staking::last_era_length_change(), 0u64);
|
||||
assert_eq!(staking::current_era(), 0u64);
|
||||
assert_eq!(era_length(), 2u64);
|
||||
assert_eq!(sessions_per_era(), 2u64);
|
||||
assert_eq!(last_era_length_change(), 0u64);
|
||||
assert_eq!(current_era(), 0u64);
|
||||
|
||||
// Block 1: No change.
|
||||
with_env(|e| e.block_number = 1);
|
||||
staking::check_new_era();
|
||||
assert_eq!(staking::sessions_per_era(), 2u64);
|
||||
assert_eq!(staking::last_era_length_change(), 0u64);
|
||||
assert_eq!(staking::current_era(), 0u64);
|
||||
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);
|
||||
staking::check_new_era();
|
||||
assert_eq!(staking::sessions_per_era(), 2u64);
|
||||
assert_eq!(staking::last_era_length_change(), 0u64);
|
||||
assert_eq!(staking::current_era(), 1u64);
|
||||
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);
|
||||
staking::set_sessions_per_era(3);
|
||||
staking::check_new_era();
|
||||
assert_eq!(staking::sessions_per_era(), 2u64);
|
||||
assert_eq!(staking::last_era_length_change(), 0u64);
|
||||
assert_eq!(staking::current_era(), 1u64);
|
||||
set_sessions_per_era(3);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 2u64);
|
||||
assert_eq!(last_era_length_change(), 0u64);
|
||||
assert_eq!(current_era(), 1u64);
|
||||
|
||||
// Block 4: Era change kicks in.
|
||||
with_env(|e| e.block_number = 4);
|
||||
staking::check_new_era();
|
||||
assert_eq!(staking::sessions_per_era(), 3u64);
|
||||
assert_eq!(staking::last_era_length_change(), 4u64);
|
||||
assert_eq!(staking::current_era(), 2u64);
|
||||
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);
|
||||
staking::check_new_era();
|
||||
assert_eq!(staking::sessions_per_era(), 3u64);
|
||||
assert_eq!(staking::last_era_length_change(), 4u64);
|
||||
assert_eq!(staking::current_era(), 2u64);
|
||||
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);
|
||||
staking::check_new_era();
|
||||
assert_eq!(staking::sessions_per_era(), 3u64);
|
||||
assert_eq!(staking::last_era_length_change(), 4u64);
|
||||
assert_eq!(staking::current_era(), 2u64);
|
||||
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);
|
||||
staking::check_new_era();
|
||||
assert_eq!(staking::sessions_per_era(), 3u64);
|
||||
assert_eq!(staking::last_era_length_change(), 4u64);
|
||||
assert_eq!(staking::current_era(), 3u64);
|
||||
check_new_era();
|
||||
assert_eq!(sessions_per_era(), 3u64);
|
||||
assert_eq!(last_era_length_change(), 4u64);
|
||||
assert_eq!(current_era(), 3u64);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -346,8 +351,8 @@ mod tests {
|
||||
], };
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(staking::balance(&one), 42);
|
||||
assert_eq!(staking::balance(&two), 0);
|
||||
assert_eq!(balance(&one), 42);
|
||||
assert_eq!(balance(&two), 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -361,9 +366,9 @@ mod tests {
|
||||
], };
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
staking::transfer(&one, &two, 69);
|
||||
assert_eq!(staking::balance(&one), 42);
|
||||
assert_eq!(staking::balance(&two), 69);
|
||||
transfer(&one, &two, 69);
|
||||
assert_eq!(balance(&one), 42);
|
||||
assert_eq!(balance(&two), 69);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -378,8 +383,8 @@ mod tests {
|
||||
], };
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
staking::stake(&one);
|
||||
staking::transfer(&one, &two, 69);
|
||||
stake(&one);
|
||||
transfer(&one, &two, 69);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,75 +34,83 @@ pub fn block_hash(number: BlockNumber) -> Hash {
|
||||
Storable::lookup_default(&number.to_keyed_vec(b"sys:old:"))
|
||||
}
|
||||
|
||||
/// Deposits a log and ensures it matches the blocks log data.
|
||||
pub fn deposit_log(log: &[u8]) {
|
||||
with_env(|e| {
|
||||
assert_eq!(log, &e.digest.logs[e.next_log_index][..]);
|
||||
e.next_log_index += 1;
|
||||
});
|
||||
pub mod privileged {
|
||||
use super::*;
|
||||
|
||||
/// Set the new code.
|
||||
pub fn set_code(new: &[u8]) {
|
||||
new.store(b":code");
|
||||
}
|
||||
}
|
||||
|
||||
/// Actually execute all transitioning for `block`.
|
||||
pub fn execute_block(mut block: Block) {
|
||||
// populate environment from header.
|
||||
with_env(|e| {
|
||||
e.block_number = block.header.number;
|
||||
mem::swap(&mut e.digest, &mut block.header.digest);
|
||||
e.next_log_index = 0;
|
||||
});
|
||||
pub mod internal {
|
||||
use super::*;
|
||||
|
||||
let ref header = block.header;
|
||||
/// Deposits a log and ensures it matches the blocks log data.
|
||||
pub fn deposit_log(log: &[u8]) {
|
||||
with_env(|e| {
|
||||
assert_eq!(log, &e.digest.logs[e.next_log_index][..]);
|
||||
e.next_log_index += 1;
|
||||
});
|
||||
}
|
||||
|
||||
// check parent_hash is correct.
|
||||
assert!(
|
||||
header.number > 0 && block_hash(header.number - 1) == header.parent_hash,
|
||||
"Parent hash should be valid."
|
||||
);
|
||||
/// Actually execute all transitioning for `block`.
|
||||
pub fn execute_block(mut block: Block) {
|
||||
// populate environment from header.
|
||||
with_env(|e| {
|
||||
e.block_number = block.header.number;
|
||||
mem::swap(&mut e.digest, &mut block.header.digest);
|
||||
e.next_log_index = 0;
|
||||
});
|
||||
|
||||
// TODO: check transaction trie root represents the transactions.
|
||||
// this requires non-trivial changes to the externals API or compiling trie rooting into wasm
|
||||
// so will wait until a little later.
|
||||
let ref header = block.header;
|
||||
|
||||
// store the header hash in storage.
|
||||
let header_hash_key = header.number.to_keyed_vec(b"sys:old:");
|
||||
header.blake2_256().store(&header_hash_key);
|
||||
// check parent_hash is correct.
|
||||
assert!(
|
||||
header.number > 0 && block_hash(header.number - 1) == header.parent_hash,
|
||||
"Parent hash should be valid."
|
||||
);
|
||||
|
||||
// execute transactions
|
||||
block.transactions.iter().for_each(execute_transaction);
|
||||
// TODO: check transaction trie root represents the transactions.
|
||||
// this requires non-trivial changes to the externals API or compiling trie rooting into wasm
|
||||
// so will wait until a little later.
|
||||
|
||||
staking::check_new_era();
|
||||
session::check_rotate_session();
|
||||
// store the header hash in storage.
|
||||
let header_hash_key = header.number.to_keyed_vec(b"sys:old:");
|
||||
header.blake2_256().store(&header_hash_key);
|
||||
|
||||
// any final checks
|
||||
final_checks(&block);
|
||||
// execute transactions
|
||||
block.transactions.iter().for_each(execute_transaction);
|
||||
|
||||
// TODO: check storage root.
|
||||
// this requires non-trivial changes to the externals API or compiling trie rooting into wasm
|
||||
// so will wait until a little later.
|
||||
}
|
||||
staking::internal::check_new_era();
|
||||
session::internal::check_rotate_session();
|
||||
|
||||
/// Execute a given transaction.
|
||||
pub fn execute_transaction(utx: &UncheckedTransaction) {
|
||||
// Verify the signature is good.
|
||||
assert!(utx.ed25519_verify(), "All transactions should be properly signed");
|
||||
// any final checks
|
||||
final_checks(&block);
|
||||
|
||||
let ref tx = utx.transaction;
|
||||
// TODO: check storage root.
|
||||
// this requires non-trivial changes to the externals API or compiling trie rooting into wasm
|
||||
// so will wait until a little later.
|
||||
}
|
||||
|
||||
// check nonce
|
||||
let nonce_key = tx.signed.to_keyed_vec(b"sys:non:");
|
||||
let expected_nonce: TxOrder = Storable::lookup_default(&nonce_key);
|
||||
assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce");
|
||||
/// Execute a given transaction.
|
||||
pub fn execute_transaction(utx: &UncheckedTransaction) {
|
||||
// Verify the signature is good.
|
||||
assert!(utx.ed25519_verify(), "All transactions should be properly signed");
|
||||
|
||||
// increment nonce in storage
|
||||
(expected_nonce + 1).store(&nonce_key);
|
||||
let ref tx = utx.transaction;
|
||||
|
||||
// decode parameters and dispatch
|
||||
tx.function.dispatch(&tx.signed, &tx.input_data);
|
||||
}
|
||||
// check nonce
|
||||
let nonce_key = tx.signed.to_keyed_vec(b"sys:non:");
|
||||
let expected_nonce: TxOrder = Storable::lookup_default(&nonce_key);
|
||||
assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce");
|
||||
|
||||
/// Set the new code.
|
||||
pub fn set_code(new: &[u8]) {
|
||||
new.store(b":code");
|
||||
// increment nonce in storage
|
||||
(expected_nonce + 1).store(&nonce_key);
|
||||
|
||||
// decode parameters and dispatch
|
||||
tx.function.dispatch(&tx.signed, &tx.input_data);
|
||||
}
|
||||
}
|
||||
|
||||
fn final_checks(_block: &Block) {
|
||||
@@ -113,15 +121,14 @@ fn final_checks(_block: &Block) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use joiner::Joiner;
|
||||
use function::Function;
|
||||
use keyedvec::KeyedVec;
|
||||
use slicable::Slicable;
|
||||
use super::*;
|
||||
use super::internal::*;
|
||||
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use primitives::{UncheckedTransaction, Transaction};
|
||||
use statichex::StaticHexInto;
|
||||
use runtime::{system, staking};
|
||||
use testing::{TestExternalities, HexDisplay, one, two};
|
||||
use codec::{Joiner, KeyedVec, Slicable};
|
||||
use support::{StaticHexInto, TestExternalities, HexDisplay, one, two};
|
||||
use primitives::{UncheckedTransaction, Transaction, Function};
|
||||
use runtime::staking;
|
||||
|
||||
#[test]
|
||||
fn staking_balance_transfer_dispatch_works() {
|
||||
@@ -147,7 +154,7 @@ mod tests {
|
||||
println!("tx is {}", HexDisplay::from(&tx.transaction.to_vec()));
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
system::execute_transaction(&tx);
|
||||
execute_transaction(&tx);
|
||||
assert_eq!(staking::balance(&one), 42);
|
||||
assert_eq!(staking::balance(&two), 69);
|
||||
});
|
||||
|
||||
@@ -26,18 +26,24 @@ pub fn get() -> Timestamp {
|
||||
Storable::lookup_default(b"tim:val")
|
||||
}
|
||||
|
||||
/// Set the current time.
|
||||
pub fn set(now: Timestamp) {
|
||||
now.store(b"tim:val")
|
||||
pub mod public {
|
||||
use super::*;
|
||||
|
||||
/// Set the current time.
|
||||
pub fn set(now: Timestamp) {
|
||||
now.store(b"tim:val")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use joiner::Joiner;
|
||||
use keyedvec::KeyedVec;
|
||||
use super::*;
|
||||
use super::public::*;
|
||||
|
||||
use runtime_std::{with_externalities, twox_128};
|
||||
use runtime::timestamp;
|
||||
use testing::TestExternalities;
|
||||
use codec::{Joiner, KeyedVec};
|
||||
use support::TestExternalities;
|
||||
|
||||
#[test]
|
||||
fn timestamp_works() {
|
||||
@@ -46,9 +52,9 @@ mod tests {
|
||||
], };
|
||||
|
||||
with_externalities(&mut t, || {
|
||||
assert_eq!(timestamp::get(), 42);
|
||||
timestamp::set(69);
|
||||
assert_eq!(timestamp::get(), 69);
|
||||
assert_eq!(get(), 42);
|
||||
set(69);
|
||||
assert_eq!(get(), 69);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ mod tests {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use runtime_std::with_externalities;
|
||||
use testing::{TestExternalities, HexDisplay};
|
||||
use support::{TestExternalities, HexDisplay};
|
||||
use runtime_std::{storage, twox_128};
|
||||
|
||||
#[test]
|
||||
@@ -180,7 +180,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn proposals_can_be_stored() {
|
||||
use proposal::{Proposal, InternalFunction};
|
||||
use primitives::{Proposal, InternalFunction};
|
||||
let mut t = TestExternalities { storage: HashMap::new(), };
|
||||
with_externalities(&mut t, || {
|
||||
let x = Proposal { function: InternalFunction::StakingSetSessionsPerEra, input_data: b"Hello world".to_vec() };
|
||||
|
||||
Reference in New Issue
Block a user