mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 12:31:03 +00:00
local testnet for substrate node (#70)
This commit is contained in:
committed by
Bastian Köcher
parent
37b8bc51aa
commit
04c9da81da
@@ -15,8 +15,8 @@
|
|||||||
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use bridge_node_runtime::{
|
use bridge_node_runtime::{
|
||||||
AccountId, AuraConfig, BalancesConfig, BridgeEthPoAConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
|
AccountId, AuraConfig, BalancesConfig, BridgeEthPoAConfig, GenesisConfig, GrandpaConfig, SessionConfig,
|
||||||
SystemConfig, WASM_BINARY,
|
SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
|
||||||
};
|
};
|
||||||
use grandpa_primitives::AuthorityId as GrandpaId;
|
use grandpa_primitives::AuthorityId as GrandpaId;
|
||||||
use sc_service;
|
use sc_service;
|
||||||
@@ -34,6 +34,8 @@ pub type ChainSpec = sc_service::ChainSpec<GenesisConfig>;
|
|||||||
pub enum Alternative {
|
pub enum Alternative {
|
||||||
/// Whatever the current runtime is, with just Alice as an auth.
|
/// Whatever the current runtime is, with just Alice as an auth.
|
||||||
Development,
|
Development,
|
||||||
|
/// Whatever the current runtime is, with simple Alice/Bob/Charlie/Dave/Eve auths.
|
||||||
|
LocalTestnet,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate a crypto pair from seed
|
/// Helper function to generate a crypto pair from seed
|
||||||
@@ -54,8 +56,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate an authority key for Aura
|
/// Helper function to generate an authority key for Aura
|
||||||
pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
|
pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, GrandpaId) {
|
||||||
(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
|
(
|
||||||
|
get_account_id_from_seed::<sr25519::Public>(s),
|
||||||
|
get_from_seed::<AuraId>(s),
|
||||||
|
get_from_seed::<GrandpaId>(s),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Alternative {
|
impl Alternative {
|
||||||
@@ -84,19 +90,60 @@ impl Alternative {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
|
Alternative::LocalTestnet => ChainSpec::from_genesis(
|
||||||
|
"Local Testnet",
|
||||||
|
"local_testnet",
|
||||||
|
|| {
|
||||||
|
testnet_genesis(
|
||||||
|
vec![
|
||||||
|
get_authority_keys_from_seed("Alice"),
|
||||||
|
get_authority_keys_from_seed("Bob"),
|
||||||
|
get_authority_keys_from_seed("Charlie"),
|
||||||
|
get_authority_keys_from_seed("Dave"),
|
||||||
|
get_authority_keys_from_seed("Eve"),
|
||||||
|
],
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
|
vec![
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Bob"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Charlie"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Dave"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Eve"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
|
||||||
|
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from(s: &str) -> Option<Self> {
|
pub(crate) fn from(s: &str) -> Option<Self> {
|
||||||
match s {
|
match s {
|
||||||
"" | "dev" => Some(Alternative::Development),
|
"" | "dev" => Some(Alternative::Development),
|
||||||
|
"local" => Some(Alternative::LocalTestnet),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn session_keys(aura: AuraId, grandpa: GrandpaId) -> SessionKeys {
|
||||||
|
SessionKeys { aura, grandpa }
|
||||||
|
}
|
||||||
|
|
||||||
fn testnet_genesis(
|
fn testnet_genesis(
|
||||||
initial_authorities: Vec<(AuraId, GrandpaId)>,
|
initial_authorities: Vec<(AccountId, AuraId, GrandpaId)>,
|
||||||
root_key: AccountId,
|
root_key: AccountId,
|
||||||
endowed_accounts: Vec<AccountId>,
|
endowed_accounts: Vec<AccountId>,
|
||||||
_enable_println: bool,
|
_enable_println: bool,
|
||||||
@@ -110,13 +157,19 @@ fn testnet_genesis(
|
|||||||
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
||||||
}),
|
}),
|
||||||
pallet_aura: Some(AuraConfig {
|
pallet_aura: Some(AuraConfig {
|
||||||
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
|
authorities: Vec::new(),
|
||||||
}),
|
}),
|
||||||
pallet_bridge_eth_poa: load_kovan_config(),
|
pallet_bridge_eth_poa: load_kovan_config(),
|
||||||
pallet_grandpa: Some(GrandpaConfig {
|
pallet_grandpa: Some(GrandpaConfig {
|
||||||
authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(),
|
authorities: Vec::new(),
|
||||||
}),
|
}),
|
||||||
pallet_sudo: Some(SudoConfig { key: root_key }),
|
pallet_sudo: Some(SudoConfig { key: root_key }),
|
||||||
|
pallet_session: Some(SessionConfig {
|
||||||
|
keys: initial_authorities
|
||||||
|
.iter()
|
||||||
|
.map(|x| (x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone())))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ default-features = false
|
|||||||
rev = "2afecf81ee19b8a6edb364b419190ea47c4a4a31"
|
rev = "2afecf81ee19b8a6edb364b419190ea47c4a4a31"
|
||||||
git = "https://github.com/paritytech/substrate/"
|
git = "https://github.com/paritytech/substrate/"
|
||||||
|
|
||||||
|
[dependencies.pallet-session]
|
||||||
|
version = "2.0.0-alpha.2"
|
||||||
|
default-features = false
|
||||||
|
rev = "2afecf81ee19b8a6edb364b419190ea47c4a4a31"
|
||||||
|
git = "https://github.com/paritytech/substrate/"
|
||||||
|
|
||||||
[dependencies.frame-system]
|
[dependencies.frame-system]
|
||||||
version = "2.0.0-alpha.2"
|
version = "2.0.0-alpha.2"
|
||||||
default-features = false
|
default-features = false
|
||||||
@@ -149,6 +155,12 @@ default-features = false
|
|||||||
rev = "2afecf81ee19b8a6edb364b419190ea47c4a4a31"
|
rev = "2afecf81ee19b8a6edb364b419190ea47c4a4a31"
|
||||||
git = "https://github.com/paritytech/substrate/"
|
git = "https://github.com/paritytech/substrate/"
|
||||||
|
|
||||||
|
[dependencies.sp-staking]
|
||||||
|
version = "2.0.0-alpha.2"
|
||||||
|
default-features = false
|
||||||
|
rev = "2afecf81ee19b8a6edb364b419190ea47c4a4a31"
|
||||||
|
git = "https://github.com/paritytech/substrate/"
|
||||||
|
|
||||||
[dependencies.sp-std]
|
[dependencies.sp-std]
|
||||||
version = "2.0.0-alpha.2"
|
version = "2.0.0-alpha.2"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|||||||
@@ -24,12 +24,15 @@
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||||
|
|
||||||
|
use codec::{Decode, Encode};
|
||||||
use pallet_grandpa::fg_primitives;
|
use pallet_grandpa::fg_primitives;
|
||||||
use pallet_grandpa::AuthorityList as GrandpaAuthorityList;
|
use pallet_grandpa::AuthorityList as GrandpaAuthorityList;
|
||||||
use sp_api::impl_runtime_apis;
|
use sp_api::impl_runtime_apis;
|
||||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
use sp_core::OpaqueMetadata;
|
use sp_core::OpaqueMetadata;
|
||||||
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, ConvertInto, IdentifyAccount, IdentityLookup, Verify};
|
use sp_runtime::traits::{
|
||||||
|
BlakeTwo256, Block as BlockT, ConvertInto, IdentifyAccount, IdentityLookup, OpaqueKeys, Verify,
|
||||||
|
};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys, transaction_validity::TransactionValidity, ApplyExtrinsicResult,
|
create_runtime_str, generic, impl_opaque_keys, transaction_validity::TransactionValidity, ApplyExtrinsicResult,
|
||||||
MultiSignature,
|
MultiSignature,
|
||||||
@@ -89,12 +92,12 @@ pub mod opaque {
|
|||||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||||
/// Opaque block identifier type.
|
/// Opaque block identifier type.
|
||||||
pub type BlockId = generic::BlockId<Block>;
|
pub type BlockId = generic::BlockId<Block>;
|
||||||
|
}
|
||||||
|
|
||||||
impl_opaque_keys! {
|
impl_opaque_keys! {
|
||||||
pub struct SessionKeys {
|
pub struct SessionKeys {
|
||||||
pub aura: Aura,
|
pub aura: Aura,
|
||||||
pub grandpa: Grandpa,
|
pub grandpa: Grandpa,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +236,72 @@ impl pallet_sudo::Trait for Runtime {
|
|||||||
type Call = Call;
|
type Call = Call;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
pub const Period: BlockNumber = 4;
|
||||||
|
pub const Offset: BlockNumber = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl pallet_session::Trait for Runtime {
|
||||||
|
type Event = Event;
|
||||||
|
type ValidatorId = <Self as frame_system::Trait>::AccountId;
|
||||||
|
type ValidatorIdOf = ();
|
||||||
|
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
|
||||||
|
type SessionManager = ShiftSessionManager;
|
||||||
|
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
|
||||||
|
type Keys = SessionKeys;
|
||||||
|
type DisabledValidatorsThreshold = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ShiftSessionManager;
|
||||||
|
|
||||||
|
impl ShiftSessionManager {
|
||||||
|
/// Select validators for session.
|
||||||
|
fn select_validators(
|
||||||
|
session_index: sp_staking::SessionIndex,
|
||||||
|
available_validators: &[AccountId],
|
||||||
|
) -> Vec<AccountId> {
|
||||||
|
let available_validators_count = available_validators.len();
|
||||||
|
let count = sp_std::cmp::max(1, 2 * available_validators_count / 3);
|
||||||
|
let offset = session_index as usize % available_validators_count;
|
||||||
|
let end = offset + count;
|
||||||
|
let session_validators = match end.overflowing_sub(available_validators_count) {
|
||||||
|
(wrapped_end, false) if wrapped_end != 0 => available_validators[offset..]
|
||||||
|
.iter()
|
||||||
|
.chain(available_validators[..wrapped_end].iter())
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
_ => available_validators[offset..end].to_vec(),
|
||||||
|
};
|
||||||
|
|
||||||
|
session_validators
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl pallet_session::SessionManager<AccountId> for ShiftSessionManager {
|
||||||
|
fn end_session(_: sp_staking::SessionIndex) {}
|
||||||
|
fn new_session(session_index: sp_staking::SessionIndex) -> Option<Vec<AccountId>> {
|
||||||
|
// can't access genesis config here :/
|
||||||
|
if session_index == 0 || session_index == 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the idea that on first call (i.e. when session 1 ends) we're reading current
|
||||||
|
// set of validators from session module (they are initial validators) and save
|
||||||
|
// in our 'local storage'.
|
||||||
|
// then for every session we select (deterministically) 2/3 of these initial
|
||||||
|
// validators to serve validators of new session
|
||||||
|
let available_validators = sp_io::storage::get(b":available_validators")
|
||||||
|
.and_then(|validators| Decode::decode(&mut &validators[..]).ok())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let validators = <pallet_session::Module<Runtime>>::validators();
|
||||||
|
sp_io::storage::set(b":available_validators", &validators.encode());
|
||||||
|
validators
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(Self::select_validators(session_index, &available_validators))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
construct_runtime!(
|
construct_runtime!(
|
||||||
pub enum Runtime where
|
pub enum Runtime where
|
||||||
Block = Block,
|
Block = Block,
|
||||||
@@ -247,6 +316,7 @@ construct_runtime!(
|
|||||||
Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},
|
Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},
|
||||||
TransactionPayment: pallet_transaction_payment::{Module, Storage},
|
TransactionPayment: pallet_transaction_payment::{Module, Storage},
|
||||||
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
|
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
|
||||||
|
Session: pallet_session::{Module, Call, Storage, Event, Config<T>},
|
||||||
BridgeEthPoA: pallet_bridge_eth_poa::{Module, Call, Config, Storage, ValidateUnsigned},
|
BridgeEthPoA: pallet_bridge_eth_poa::{Module, Call, Config, Storage, ValidateUnsigned},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -374,13 +444,13 @@ impl_runtime_apis! {
|
|||||||
|
|
||||||
impl sp_session::SessionKeys<Block> for Runtime {
|
impl sp_session::SessionKeys<Block> for Runtime {
|
||||||
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
|
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
|
||||||
opaque::SessionKeys::generate(seed)
|
SessionKeys::generate(seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_session_keys(
|
fn decode_session_keys(
|
||||||
encoded: Vec<u8>,
|
encoded: Vec<u8>,
|
||||||
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
||||||
opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
|
SessionKeys::decode_into_raw_public_keys(&encoded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,3 +460,48 @@ impl_runtime_apis! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shift_session_manager_works() {
|
||||||
|
let acc1 = AccountId::from([1u8; 32]);
|
||||||
|
let acc2 = AccountId::from([2u8; 32]);
|
||||||
|
let acc3 = AccountId::from([3u8; 32]);
|
||||||
|
let acc4 = AccountId::from([4u8; 32]);
|
||||||
|
let acc5 = AccountId::from([5u8; 32]);
|
||||||
|
let all_accs = vec![acc1.clone(), acc2.clone(), acc3.clone(), acc4.clone(), acc5.clone()];
|
||||||
|
|
||||||
|
// at least 1 validator is selected
|
||||||
|
assert_eq!(
|
||||||
|
ShiftSessionManager::select_validators(0, &[acc1.clone()]),
|
||||||
|
vec![acc1.clone()],
|
||||||
|
);
|
||||||
|
|
||||||
|
// at session#0, shift is also 0
|
||||||
|
assert_eq!(
|
||||||
|
ShiftSessionManager::select_validators(0, &all_accs),
|
||||||
|
vec![acc1.clone(), acc2.clone(), acc3.clone()],
|
||||||
|
);
|
||||||
|
|
||||||
|
// at session#1, shift is also 1
|
||||||
|
assert_eq!(
|
||||||
|
ShiftSessionManager::select_validators(1, &all_accs),
|
||||||
|
vec![acc2.clone(), acc3.clone(), acc4.clone()],
|
||||||
|
);
|
||||||
|
|
||||||
|
// at session#3, we're wrapping
|
||||||
|
assert_eq!(
|
||||||
|
ShiftSessionManager::select_validators(3, &all_accs),
|
||||||
|
vec![acc4, acc5, acc1.clone()],
|
||||||
|
);
|
||||||
|
|
||||||
|
// at session#5, we're starting from the beginning again
|
||||||
|
assert_eq!(
|
||||||
|
ShiftSessionManager::select_validators(5, &all_accs),
|
||||||
|
vec![acc1, acc2, acc3],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user