Skip to content

Commit

Permalink
Stash/controller model for staking (paritytech#1782)
Browse files Browse the repository at this point in the history
* First steps to stash/controller separation

* More drafting

* More drafting

* Finish draft.

* Optimisation

* Remove accidental commit

* Make it build.

* Fix linked map for traits.

* Fix Option<_> variant.

*  Improve naming a tad

* Rebuild runtime

* Builds!

* First test.

* Bump RT version

* Minor fix

* Update Mock

* adds the correct reward testcase (+staking eras which was already ok)

* fixes the basic staking testcase to work properly (along with a small fix in the module)

* New logic to avoid controller transferring stash.

* Fix some build issues.

* adding some comments to tests

* Fix impls.

* adds a few more lines to explain the test case

* More fixes.

* gets the basic test up and running again

* Fix rest of build

* Rebuild wasm

* Fix docs.

* fix staking test with new chnages

* updating some tests, pending questions

* More working tests

* adds double staking test

* Docs

* remove invalid slashing test

* Payee stuff.

* Fix build

* Docs

* Fix test

* Fix a couple of tests

* Layout plan for finishing tests before Pragmen

* Add some working tests

* re-build staking and reward tests

* Add more tests

* fix offline grace test

* Nominator should have payee checked for cleanup

* adds more nomination tets

* adds validator prefs tests

* Fix and clean up some TODOs

* Fix a couple of issues

* Fix tests

* noting warnings from tests

* final fix of local tests

* Fix slot_stake bug

* Half baked test

* Add logic to limit `unstake_threshold` set in storage

* Make sure to check before writing!

Almost forgot this one

* Move a couple of comments

* fix last broken slot_stake test

* Ignore broken test
  • Loading branch information
gavofyork authored and MTDK1 committed Apr 12, 2019
1 parent 79e3d06 commit bb19494
Show file tree
Hide file tree
Showing 24 changed files with 1,852 additions and 891 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions core/network-libp2p/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ fn two_nodes_transfer_lots_of_packets() {
}

#[test]
#[ignore]
// TODO: remove ignore once this test it fixed. #1777
fn many_nodes_connectivity() {
// Creates many nodes, then make sure that they are all connected to each other.
// Note: if you increase this number, keep in mind that there's a limit to the number of
Expand Down
61 changes: 5 additions & 56 deletions core/sr-primitives/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ use substrate_primitives;
use substrate_primitives::Blake2Hasher;
use crate::codec::{Codec, Encode, HasCompact};
pub use integer_sqrt::IntegerSquareRoot;
pub use num_traits::{Zero, One, Bounded};
pub use num_traits::ops::checked::{
CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedShl, CheckedShr,
pub use num_traits::{
Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
CheckedShl, CheckedShr, Saturating
};
use rstd::ops::{
Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign,
Expand Down Expand Up @@ -126,59 +126,6 @@ pub trait BlockNumberToHash {
}
}

/// Charge bytes fee trait
pub trait ChargeBytesFee<AccountId> {
/// Charge fees from `transactor` for an extrinsic (transaction) of encoded length
/// `encoded_len` bytes. Return Ok iff the payment was successful.
fn charge_base_bytes_fee(transactor: &AccountId, encoded_len: usize) -> Result<(), &'static str>;
}

/// Charge fee trait
pub trait ChargeFee<AccountId>: ChargeBytesFee<AccountId> {
/// The type of fee amount.
type Amount;

/// Charge `amount` of fees from `transactor`. Return Ok iff the payment was successful.
fn charge_fee(transactor: &AccountId, amount: Self::Amount) -> Result<(), &'static str>;

/// Refund `amount` of previous charged fees from `transactor`. Return Ok iff the refund was successful.
fn refund_fee(transactor: &AccountId, amount: Self::Amount) -> Result<(), &'static str>;
}

/// Transfer fungible asset trait
pub trait TransferAsset<AccountId> {
/// The type of asset amount.
type Amount;

/// Transfer asset from `from` account to `to` account with `amount` of asset.
fn transfer(from: &AccountId, to: &AccountId, amount: Self::Amount) -> Result<(), &'static str>;

/// Remove asset from `who` account by deducing `amount` in the account balances.
fn remove_from(who: &AccountId, amount: Self::Amount) -> Result<(), &'static str>;

/// Add asset to `who` account by increasing `amount` in the account balances.
fn add_to(who: &AccountId, amount: Self::Amount) -> Result<(), &'static str>;
}

impl<T> ChargeBytesFee<T> for () {
fn charge_base_bytes_fee(_: &T, _: usize) -> Result<(), &'static str> { Ok(()) }
}

impl<T> ChargeFee<T> for () {
type Amount = ();

fn charge_fee(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) }
fn refund_fee(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) }
}

impl<T> TransferAsset<T> for () {
type Amount = ();

fn transfer(_: &T, _: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) }
fn remove_from(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) }
fn add_to(_: &T, _: Self::Amount) -> Result<(), &'static str> { Ok(()) }
}

/// Extensible conversion trait. Generic over both source and destination types.
pub trait Convert<A, B> {
/// Make conversion.
Expand Down Expand Up @@ -236,6 +183,7 @@ pub trait SimpleArithmetic:
CheckedSub +
CheckedMul +
CheckedDiv +
Saturating +
PartialOrd<Self> + Ord +
HasCompact
{}
Expand All @@ -253,6 +201,7 @@ impl<T:
CheckedSub +
CheckedMul +
CheckedDiv +
Saturating +
PartialOrd<Self> + Ord +
HasCompact
> SimpleArithmetic for T {}
Expand Down
Binary file not shown.
1 change: 1 addition & 0 deletions node-template/runtime/wasm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 73 additions & 35 deletions node/cli/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

//! Substrate chain configurations.
use primitives::{Ed25519AuthorityId, ed25519};
use primitives::{Ed25519AuthorityId as AuthorityId, ed25519};
use node_primitives::AccountId;
use node_runtime::{ConsensusConfig, CouncilSeatsConfig, CouncilVotingConfig, DemocracyConfig,
SessionConfig, StakingConfig, TimestampConfig, BalancesConfig, TreasuryConfig,
Expand All @@ -39,14 +39,26 @@ pub fn dried_danta_config() -> Result<ChainSpec, String> {
}

fn staging_testnet_config_genesis() -> GenesisConfig {
let initial_authorities = vec![
// stash, controller, session-key
let initial_authorities: Vec<(AccountId, AccountId, AuthorityId)> = vec![(
hex!["fbecf7767fc63a6f9fa8094bbc5751d7269cd8e619cfdd9edfbe1fbc716b173e"].into(), // 5Hm2GcbuUct7sWX8d56zRktxr9D9Lw5hTFjSUhUoVHwFNmYW TODO: change once we switch to sr25519
hex!["6ed35e632190b9c795f019030e6c5cff1508655db28c83577e0a4366c9bd5773"].into(), // 5Ea1uyGz6H5WHZhWvPDxxLXWyiUkzWDwx54Hcn8LJ5dbFawH TODO: change once we switch to sr25519
hex!["82c39b31a2b79a90f8e66e7a77fdb85a4ed5517f2ae39f6a80565e8ecae85cf5"].into(),
),(
hex!["30b76ef977b84a575992ef52f561db315221123c68074269d3d51ce211c4a3dc"].into(), // 5DAaeTwVuyUmTyLBR5vKEDWeDJ75nhLutDuCJH58it7EHDM2 TODO: change once we switch to sr25519
hex!["a270edf24cb2a472b0e913fc43bfd4da0ef337cc715eaf94073d5198f7659f0c"].into(), // 5FjhAKgzpuzt1dYWE7H7Jb1sEHSuG5hcyZdPtfX829gmFVXh TODO: change once we switch to sr25519
hex!["4de37a07567ebcbf8c64568428a835269a566723687058e017b6d69db00a77e7"].into(),
),(
hex!["7b9e79c1bfc71ad0c4389565c01e79269dc512cb9bd856489671662481355417"].into(), // 5ErnpkRUbmM3WdbQwnVwfZeYs3iKmggEQceyB9db9ft18dSn TODO: change once we switch to sr25519
hex!["9ffec660c4d328306cf5e38faf4b132fb5c9f38287af95d9b25629fc29de3945"].into(), // 5FgV9vxNpdCXMUmHCLQcsN4mUUUG6ZpFuvAMrm5X4BUnFhie TODO: change once we switch to sr25519
hex!["063d7787ebca768b7445dfebe7d62cbb1625ff4dba288ea34488da266dd6dca5"].into(),
),(
hex!["7e58b096b95c4b3b271f27fedd9f2c51edd48b9d37046240e601180c9dcc8c27"].into(), // 5EvNEhYYd4b9giczuCo2o8bfLZoKW9jnTeUukfL1NWsAAeEx TODO: change once we switch to sr25519
hex!["36dfc933bb0848d8addf16a961369b2e122633a5819a19e43c8142381a1280e3"].into(), // 5DJevPKpz4EEvmSpK7W6KemS3i5JYPq5FEuEewgRY2cZCxNg TODO: change once we switch to sr25519
hex!["8101764f45778d4980dadaceee6e8af2517d3ab91ac9bec9cd1714fa5994081c"].into(),
];
let endowed_accounts = vec![
hex!["f295940fa750df68a686fcf4abd4111c8a9c5a5a5a83c4c8639c451a94a7adfd"].into(),
)];
let endowed_accounts: Vec<AccountId> = vec![
hex!["f295940fa750df68a686fcf4abd4111c8a9c5a5a5a83c4c8639c451a94a7adfd"].into(), // 5HYmsxGRAmZMjyZYmf7uGPL2YDQGHEt6NjGrfUuxNEgeGBRN TODO: change once we switch to sr25519
];
const MILLICENTS: u128 = 1_000_000_000;
const CENTS: u128 = 1_000 * MILLICENTS; // assume this is worth about a cent.
Expand All @@ -57,29 +69,37 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
const HOURS: u64 = MINUTES * 60;
const DAYS: u64 = HOURS * 24;

const ENDOWMENT: u128 = 10_000_000 * DOLLARS;
const STASH: u128 = 100 * DOLLARS;

GenesisConfig {
consensus: Some(ConsensusConfig {
code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(), // FIXME change once we have #1252
authorities: initial_authorities.clone(),
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
}),
system: None,
balances: Some(BalancesConfig {
balances: endowed_accounts.iter().map(|&k| (k, 10_000_000 * DOLLARS)).collect(),
balances: endowed_accounts.iter()
.map(|&k| (k, ENDOWMENT))
.chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
.collect(),
existential_deposit: 1 * DOLLARS,
transfer_fee: 1 * CENTS,
creation_fee: 1 * CENTS,
vesting: vec![],
}),
indices: Some(IndicesConfig {
ids: endowed_accounts.clone(),
ids: endowed_accounts.iter().cloned()
.chain(initial_authorities.iter().map(|x| x.0.clone()))
.collect::<Vec<_>>(),
}),
session: Some(SessionConfig {
validators: initial_authorities.iter().cloned().map(Into::into).collect(),
validators: initial_authorities.iter().map(|x| x.1.into()).collect(),
session_length: 5 * MINUTES,
keys: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect::<Vec<_>>(),
}),
staking: Some(StakingConfig {
current_era: 0,
intentions: initial_authorities.iter().cloned().map(Into::into).collect(),
offline_slash: Perbill::from_billionths(1_000_000),
session_reward: Perbill::from_billionths(2_065),
current_offline_slash: 0,
Expand All @@ -89,7 +109,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
bonding_duration: 60 * MINUTES,
offline_slash_grace: 4,
minimum_validator_count: 4,
invulnerables: initial_authorities.iter().cloned().map(Into::into).collect(),
stakers: initial_authorities.iter().map(|x| (x.0.into(), x.1.into(), STASH)).collect(),
invulnerables: initial_authorities.iter().map(|x| x.1.into()).collect(),
}),
democracy: Some(DemocracyConfig {
launch_period: 10 * MINUTES, // 1 day per public referendum
Expand Down Expand Up @@ -137,7 +158,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
key: endowed_accounts[0].clone(),
}),
grandpa: Some(GrandpaConfig {
authorities: initial_authorities.clone().into_iter().map(|k| (k, 1)).collect(),
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
}),
fees: Some(FeesConfig {
transaction_base_fee: 1 * CENTS,
Expand All @@ -162,52 +183,68 @@ pub fn staging_testnet_config() -> ChainSpec {
}

/// Helper function to generate AuthorityID from seed
pub fn get_authority_id_from_seed(seed: &str) -> Ed25519AuthorityId {
pub fn get_account_id_from_seed(seed: &str) -> AccountId {
let padded_seed = pad_seed(seed);
// NOTE from ed25519 impl:
// prefer pkcs#8 unless security doesn't matter -- this is used primarily for tests.
ed25519::Pair::from_seed(&padded_seed).public().0.into()
}

/// Helper function to generate stash, controller and session key from seed
pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, AuthorityId) {
let padded_seed = pad_seed(seed);
// NOTE from ed25519 impl:
// prefer pkcs#8 unless security doesn't matter -- this is used primarily for tests.
(
get_account_id_from_seed(&format!("{}-stash", seed)),
get_account_id_from_seed(seed),
ed25519::Pair::from_seed(&padded_seed).public().0.into()
)
}

/// Helper function to create GenesisConfig for testing
pub fn testnet_genesis(
initial_authorities: Vec<Ed25519AuthorityId>,
initial_authorities: Vec<(AccountId, AccountId, AuthorityId)>,
root_key: AccountId,
endowed_accounts: Option<Vec<Ed25519AuthorityId>>,
endowed_accounts: Option<Vec<AccountId>>,
) -> GenesisConfig {
let endowed_accounts = endowed_accounts.unwrap_or_else(|| {
let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
vec![
get_authority_id_from_seed("Alice"),
get_authority_id_from_seed("Bob"),
get_authority_id_from_seed("Charlie"),
get_authority_id_from_seed("Dave"),
get_authority_id_from_seed("Eve"),
get_authority_id_from_seed("Ferdie"),
get_account_id_from_seed("Alice"),
get_account_id_from_seed("Bob"),
get_account_id_from_seed("Charlie"),
get_account_id_from_seed("Dave"),
get_account_id_from_seed("Eve"),
get_account_id_from_seed("Ferdie"),
]
});

const STASH: u128 = 1 << 20;
const ENDOWMENT: u128 = 1 << 20;

GenesisConfig {
consensus: Some(ConsensusConfig {
code: include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm").to_vec(),
authorities: initial_authorities.clone(),
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
}),
system: None,
indices: Some(IndicesConfig {
ids: endowed_accounts.iter().map(|x| x.0.into()).collect(),
ids: endowed_accounts.clone(),
}),
balances: Some(BalancesConfig {
existential_deposit: 500,
transfer_fee: 0,
creation_fee: 0,
balances: endowed_accounts.iter().map(|&k| (k.into(), (1 << 60))).collect(),
balances: endowed_accounts.iter().map(|&k| (k.into(), ENDOWMENT)).collect(),
vesting: vec![],
}),
session: Some(SessionConfig {
validators: initial_authorities.iter().cloned().map(Into::into).collect(),
validators: initial_authorities.iter().map(|x| x.1.into()).collect(),
session_length: 10,
keys: initial_authorities.iter().map(|x| (x.1.clone(), x.2.clone())).collect::<Vec<_>>(),
}),
staking: Some(StakingConfig {
current_era: 0,
intentions: initial_authorities.iter().cloned().map(Into::into).collect(),
minimum_validator_count: 1,
validator_count: 2,
sessions_per_era: 5,
Expand All @@ -217,7 +254,8 @@ pub fn testnet_genesis(
current_offline_slash: 0,
current_session_reward: 0,
offline_slash_grace: 0,
invulnerables: initial_authorities.iter().cloned().map(Into::into).collect(),
stakers: initial_authorities.iter().map(|x| (x.0.into(), x.1.into(), STASH)).collect(),
invulnerables: initial_authorities.iter().map(|x| x.1.into()).collect(),
}),
democracy: Some(DemocracyConfig {
launch_period: 9,
Expand All @@ -228,7 +266,7 @@ pub fn testnet_genesis(
}),
council_seats: Some(CouncilSeatsConfig {
active_council: endowed_accounts.iter()
.filter(|a| initial_authorities.iter().find(|&b| a.0 == b.0).is_none())
.filter(|&endowed| initial_authorities.iter().find(|&(_, controller, _)| controller == endowed).is_none())
.map(|a| (a.clone().into(), 1000000)).collect(),
candidacy_bond: 10,
voter_bond: 2,
Expand Down Expand Up @@ -267,7 +305,7 @@ pub fn testnet_genesis(
key: root_key,
}),
grandpa: Some(GrandpaConfig {
authorities: initial_authorities.clone().into_iter().map(|k| (k, 1)).collect(),
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
}),
fees: Some(FeesConfig {
transaction_base_fee: 1,
Expand All @@ -279,9 +317,9 @@ pub fn testnet_genesis(
fn development_config_genesis() -> GenesisConfig {
testnet_genesis(
vec![
get_authority_id_from_seed("Alice"),
get_authority_keys_from_seed("Alice"),
],
get_authority_id_from_seed("Alice").into(),
get_account_id_from_seed("Alice").into(),
None,
)
}
Expand All @@ -294,10 +332,10 @@ pub fn development_config() -> ChainSpec {
fn local_testnet_genesis() -> GenesisConfig {
testnet_genesis(
vec![
get_authority_id_from_seed("Alice"),
get_authority_id_from_seed("Bob"),
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
],
get_authority_id_from_seed("Alice").into(),
get_account_id_from_seed("Alice").into(),
None,
)
}
Expand Down
Loading

0 comments on commit bb19494

Please sign in to comment.