Commit b3f026f1 authored by Gav Wood's avatar Gav Wood Committed by asynchronous rob
Browse files

Make Polkadot use the Substrate traity libraries (#105)

* Initial stuff.

* Various fixes.

* Fix tests.

* Fix another test

* Fix another test.

* Docs in polkadot runtime.

* Fix up ser/de tests.

* Update god keys

* Syntax

* Fix

* Merge remote-tracking branch 'origin/master' into gav-merge-runtime

* Permissions on init.sh

* Port-over the whitespace from @rphmeier

* Rename

* Merge branch 'master' into gav-merge-runtime

* Fix typo.

* Fix grumbles.

* Make more idiomatic.

* Move `Ed25519Signature` out of traits.
parent 7d65a0ed
......@@ -8,7 +8,10 @@ error-chain = "0.11"
polkadot-executor = { path = "../executor" }
polkadot-runtime = { path = "../runtime" }
polkadot-primitives = { path = "../primitives" }
substrate-codec = { path = "../../substrate/codec" }
substrate-runtime-io = { path = "../../substrate/runtime-io" }
substrate-client = { path = "../../substrate/client" }
substrate-primitives = { path = "../../substrate/primitives" }
substrate-executor = { path = "../../substrate/executor" }
substrate-state-machine = { path = "../../substrate/state-machine" }
......
......@@ -18,10 +18,13 @@
//! runtime.
extern crate polkadot_executor;
extern crate polkadot_runtime;
extern crate polkadot_runtime as runtime;
extern crate polkadot_primitives as primitives;
extern crate substrate_codec as codec;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_client as client;
extern crate substrate_executor as substrate_executor;
extern crate substrate_primitives;
extern crate substrate_state_machine as state_machine;
#[macro_use]
......@@ -32,14 +35,12 @@ extern crate substrate_keyring as keyring;
use client::backend::Backend;
use client::Client;
use polkadot_runtime::runtime;
use polkadot_executor::Executor as LocalDispatch;
use substrate_executor::{NativeExecutionDispatch, NativeExecutor};
use state_machine::OverlayedChanges;
use primitives::{AccountId, SessionKey, Timestamp, TxOrder};
use primitives::block::{Id as BlockId, Block, Header, Body};
use primitives::transaction::UncheckedTransaction;
use primitives::{AccountId, BlockId, Index, SessionKey, Timestamp};
use primitives::parachain::DutyRoster;
use runtime::{Block, Header, UncheckedExtrinsic, Extrinsic, Call, TimestampCall};
error_chain! {
errors {
......@@ -53,15 +54,15 @@ error_chain! {
description("Unknown block")
display("Unknown block")
}
/// Attempted to push an inherent transaction manually.
PushedInherentTransaction(tx: UncheckedTransaction) {
description("Attempted to push an inherent transaction to a block."),
display("Pushed inherent transaction to a block: {:?}", tx),
/// Attempted to push an inherent extrinsic manually.
PushedInherentTransaction(xt: UncheckedExtrinsic) {
description("Attempted to push an inherent extrinsic to a block."),
display("Pushed inherent extrinsic to a block: {:?}", xt),
}
/// Badly-formed transaction.
BadlyFormedTransaction(tx: UncheckedTransaction) {
description("Attempted to push a badly-formed transaction to a block."),
display("Pushed badly-formed transaction to a block: {:?}", tx),
/// Badly-formed extrinsic.
BadlyFormedTransaction(xt: UncheckedExtrinsic) {
description("Attempted to push a badly-formed extrinsic to a block."),
display("Pushed badly-formed extrinsic to a block: {:?}", xt),
}
/// Some other error.
// TODO: allow to be specified as associated type of PolkadotApi
......@@ -87,8 +88,8 @@ impl From<client::error::Error> for Error {
/// A builder for blocks.
pub trait BlockBuilder: Sized {
/// Push a non-inherent transaction.
fn push_transaction(&mut self, transaction: UncheckedTransaction) -> Result<()>;
/// Push a non-inherent extrinsic.
fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()>;
/// Finalise the block.
fn bake(self) -> Block;
......@@ -127,8 +128,8 @@ pub trait PolkadotApi {
/// Get the timestamp registered at a block.
fn timestamp(&self, at: &Self::CheckedBlockId) -> Result<Timestamp>;
/// Get the nonce of an account at a block.
fn nonce(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<TxOrder>;
/// Get the index of an account at a block.
fn index(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<Index>;
/// Evaluate a block and see if it gives an error.
......@@ -179,27 +180,27 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
}
fn session_keys(&self, at: &CheckedId) -> Result<Vec<SessionKey>> {
with_runtime!(self, at, ::runtime::consensus::authorities)
with_runtime!(self, at, ::runtime::Consensus::authorities)
}
fn validators(&self, at: &CheckedId) -> Result<Vec<AccountId>> {
with_runtime!(self, at, ::runtime::session::validators)
with_runtime!(self, at, ::runtime::Session::validators)
}
fn duty_roster(&self, at: &CheckedId) -> Result<DutyRoster> {
with_runtime!(self, at, ::runtime::parachains::calculate_duty_roster)
with_runtime!(self, at, ::runtime::Parachains::calculate_duty_roster)
}
fn timestamp(&self, at: &CheckedId) -> Result<Timestamp> {
with_runtime!(self, at, ::runtime::timestamp::get)
with_runtime!(self, at, ::runtime::Timestamp::now)
}
fn evaluate_block(&self, at: &CheckedId, block: Block) -> Result<()> {
with_runtime!(self, at, || ::runtime::system::internal::execute_block(block))
with_runtime!(self, at, || ::runtime::Executive::execute_block(block))
}
fn nonce(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<TxOrder> {
with_runtime!(self, at, || ::runtime::system::nonce(account))
fn index(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<Index> {
with_runtime!(self, at, || ::runtime::System::account_index(account))
}
fn build_block(&self, parent: &CheckedId, timestamp: Timestamp) -> Result<Self::BlockBuilder> {
......@@ -208,14 +209,20 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
parent_hash: self.block_hash_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))?,
number: self.block_number_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))? + 1,
state_root: Default::default(),
transaction_root: Default::default(),
extrinsics_root: Default::default(),
digest: Default::default(),
};
let body = Body {
timestamp: timestamp,
transactions: Vec::new(),
};
let extrinsics = vec![
UncheckedExtrinsic {
extrinsic: Extrinsic {
signed: Default::default(),
index: Default::default(),
function: Call::Timestamp(TimestampCall::set(timestamp)),
},
signature: Default::default(),
}
];
let mut builder = ClientBlockBuilder {
parent: *parent,
......@@ -223,11 +230,13 @@ impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>>
state: self.state_at(parent)?,
header,
timestamp,
transactions: Vec::new(),
extrinsics: extrinsics.clone(),
};
for inherent in body.inherent_transactions() {
builder.execute_transaction(inherent)?;
builder.initialise_block()?;
for inherent in extrinsics {
builder.apply_extrinsic(inherent)?;
}
Ok(builder)
......@@ -242,34 +251,53 @@ pub struct ClientBlockBuilder<S> {
state: S,
header: Header,
timestamp: Timestamp,
transactions: Vec<UncheckedTransaction>,
extrinsics: Vec<UncheckedExtrinsic>,
}
impl<S: state_machine::Backend> ClientBlockBuilder<S>
where S::Error: Into<client::error::Error>
{
// executes a transaction, inherent or otherwise, without appending to the list
fn execute_transaction(&mut self, transaction: UncheckedTransaction) -> Result<()> {
if !transaction.is_well_formed() {
bail!(ErrorKind::BadlyFormedTransaction(transaction));
// executes a extrinsic, inherent or otherwise, without appending to the list
fn initialise_block(&mut self) -> Result<()> {
let mut ext = state_machine::Ext {
overlay: &mut self.changes,
backend: &self.state,
};
let h = self.header.clone();
let result = ::substrate_executor::with_native_environment(
&mut ext,
|| runtime::Executive::initialise_block(&h),
).map_err(Into::into);
match result {
Ok(_) => {
ext.overlay.commit_prospective();
Ok(())
}
Err(e) => {
ext.overlay.discard_prospective();
Err(e)
}
}
}
// executes a extrinsic, inherent or otherwise, without appending to the list
fn apply_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()> {
let mut ext = state_machine::Ext {
overlay: &mut self.changes,
backend: &self.state,
};
// TODO: avoid clone
let header = self.header.clone();
let result = ::substrate_executor::with_native_environment(
&mut ext,
move || runtime::system::internal::execute_transaction(transaction, header),
move || runtime::Executive::apply_extrinsic(extrinsic),
).map_err(Into::into);
match result {
Ok(header) => {
Ok(_) => {
ext.overlay.commit_prospective();
self.header = header;
Ok(())
}
Err(e) => {
......@@ -283,12 +311,13 @@ impl<S: state_machine::Backend> ClientBlockBuilder<S>
impl<S: state_machine::Backend> BlockBuilder for ClientBlockBuilder<S>
where S::Error: Into<client::error::Error>
{
fn push_transaction(&mut self, transaction: UncheckedTransaction) -> Result<()> {
if transaction.transaction.function.is_inherent() {
bail!(ErrorKind::PushedInherentTransaction(transaction));
fn push_extrinsic(&mut self, extrinsic: UncheckedExtrinsic) -> Result<()> {
// Check that this is not an "inherent" extrinsic.
if extrinsic.signature == Default::default() {
bail!(ErrorKind::PushedInherentTransaction(extrinsic));
} else {
self.execute_transaction(transaction.clone())?;
self.transactions.push(transaction);
self.apply_extrinsic(extrinsic.clone())?;
self.extrinsics.push(extrinsic);
Ok(())
}
}
......@@ -299,18 +328,14 @@ impl<S: state_machine::Backend> BlockBuilder for ClientBlockBuilder<S>
backend: &self.state,
};
let old_header = self.header;
let final_header = ::substrate_executor::with_native_environment(
&mut ext,
move || runtime::system::internal::finalise_block(old_header)
).expect("all inherent transactions pushed; all other transactions executed correctly; qed");
move || runtime::Executive::finalise_block()
).expect("all inherent extrinsics pushed; all other extrinsics executed correctly; qed");
Block {
header: final_header,
body: Body {
timestamp: self.timestamp,
transactions: self.transactions,
}
extrinsics: self.extrinsics,
}
}
}
......@@ -318,10 +343,12 @@ impl<S: state_machine::Backend> BlockBuilder for ClientBlockBuilder<S>
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::with_externalities;
use keyring::Keyring;
use codec::Slicable;
use client::in_mem::Backend as InMemory;
use polkadot_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig};
use substrate_executor::NativeExecutionDispatch;
use keyring::Keyring;
use runtime::{GenesisConfig, ConsensusConfig, SessionConfig, BuildExternalities};
fn validators() -> Vec<AccountId> {
vec![
......@@ -331,20 +358,31 @@ mod tests {
}
fn client() -> Client<InMemory, NativeExecutor<LocalDispatch>> {
let genesis_config = GenesisConfig {
consensus: Some(ConsensusConfig {
code: LocalDispatch::native_equivalent().to_vec(),
authorities: validators(),
}),
system: None,
session: Some(SessionConfig {
validators: validators(),
session_length: 100,
}),
council: Some(Default::default()),
democracy: Some(Default::default()),
parachains: Some(Default::default()),
staking: Some(Default::default()),
};
::client::new_in_mem(
LocalDispatch::new(),
|| {
let config = GenesisConfig::new_simple(validators(), 100);
// override code entry.
let mut storage = config.genesis_map();
storage.insert(b":code".to_vec(), LocalDispatch::native_equivalent().to_vec());
let block = ::client::genesis::construct_genesis_block(
&config.genesis_map()
let mut storage = genesis_config.build_externalities();
let block = ::client::genesis::construct_genesis_block(&storage);
with_externalities(&mut storage, ||
// TODO: use api.rs to dispatch instead
runtime::System::initialise_genesis_state(&block.header)
);
storage.extend(additional_storage_with_genesis(&block));
(block.header, storage.into_iter().collect())
(substrate_primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
}
).unwrap()
}
......
......@@ -13,6 +13,7 @@ log = "0.4"
polkadot-api = { path = "../api" }
polkadot-collator = { path = "../collator" }
polkadot-primitives = { path = "../primitives" }
polkadot-runtime = { path = "../runtime" }
polkadot-statement-table = { path = "../statement-table" }
polkadot-transaction-pool = { path = "../transaction-pool" }
substrate-bft = { path = "../../substrate/bft" }
......
......@@ -38,6 +38,7 @@ extern crate polkadot_collator as collator;
extern crate polkadot_statement_table as table;
extern crate polkadot_primitives;
extern crate polkadot_transaction_pool as transaction_pool;
extern crate polkadot_runtime;
extern crate substrate_bft as bft;
extern crate substrate_codec as codec;
extern crate substrate_primitives as primitives;
......@@ -62,11 +63,11 @@ use table::generic::Statement as GenericStatement;
use runtime_support::Hashable;
use polkadot_api::{PolkadotApi, BlockBuilder};
use polkadot_primitives::{Hash, Timestamp};
use polkadot_primitives::block::Block as PolkadotBlock;
use polkadot_primitives::parachain::{Id as ParaId, DutyRoster, BlockData, Extrinsic, CandidateReceipt};
use polkadot_runtime::Block as PolkadotGenericBlock;
use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId, Number as BlockNumber};
use primitives::AuthorityId;
use transaction_pool::{Ready, TransactionPool};
use transaction_pool::{Ready, TransactionPool, PolkadotBlock};
use futures::prelude::*;
use futures::future;
......@@ -152,7 +153,7 @@ impl TableContext {
}
fn sign_statement(&self, statement: table::Statement) -> table::SignedStatement {
let signature = sign_table_statement(&statement, &self.key, &self.parent_hash);
let signature = sign_table_statement(&statement, &self.key, &self.parent_hash).into();
let local_id = self.key.public().0;
table::SignedStatement {
......@@ -552,7 +553,7 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
if pending_size + pending.encoded_size() >= MAX_TRANSACTIONS_SIZE { break }
match block_builder.push_transaction(pending.as_transaction().clone()) {
match block_builder.push_extrinsic(pending.as_transaction().clone()) {
Ok(()) => {
pending_size += pending.encoded_size();
}
......@@ -582,23 +583,23 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior)>) {
use bft::generic::Misbehavior as GenericMisbehavior;
use primitives::bft::{MisbehaviorKind, MisbehaviorReport};
use polkadot_primitives::transaction::{Function, Transaction, UncheckedTransaction};
use polkadot_runtime::{Call, Extrinsic, UncheckedExtrinsic, ConsensusCall};
let local_id = self.local_key.public().0;
let mut pool = self.transaction_pool.lock();
let mut next_nonce = {
let mut next_index = {
let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client);
let cur_nonce = pool.pending(readiness_evaluator)
.filter(|tx| tx.as_transaction().transaction.signed == local_id)
let cur_index = pool.pending(readiness_evaluator)
.filter(|tx| tx.as_ref().as_ref().signed == local_id)
.last()
.map(|tx| Ok(tx.as_transaction().transaction.nonce))
.unwrap_or_else(|| self.client.nonce(&self.parent_id, local_id));
.map(|tx| Ok(tx.as_ref().as_ref().index))
.unwrap_or_else(|| self.client.index(&self.parent_id, local_id));
match cur_nonce {
Ok(cur_nonce) => cur_nonce + 1,
match cur_index {
Ok(cur_index) => cur_index + 1,
Err(e) => {
warn!(target: "consensus", "Error computing next transaction nonce: {}", e);
warn!(target: "consensus", "Error computing next transaction index: {}", e);
return;
}
}
......@@ -618,23 +619,18 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
=> MisbehaviorKind::BftDoubleCommit(round as u32, (h1, s1.signature), (h2, s2.signature)),
}
};
let tx = Transaction {
let extrinsic = Extrinsic {
signed: local_id,
nonce: next_nonce,
function: Function::ReportMisbehavior(report),
index: next_index,
function: Call::Consensus(ConsensusCall::report_misbehavior(report)),
};
next_nonce += 1;
next_index += 1;
let message = tx.encode();
let signature = self.local_key.sign(&message);
let tx = UncheckedTransaction {
transaction: tx,
signature,
};
let signature = self.local_key.sign(&extrinsic.encode()).into();
let uxt = UncheckedExtrinsic { extrinsic, signature };
pool.import(tx).expect("locally signed transaction is valid; qed");
pool.import(uxt).expect("locally signed extrinsic is valid; qed");
}
}
}
......@@ -649,10 +645,11 @@ fn evaluate_proposal<C: PolkadotApi>(
const MAX_TIMESTAMP_DRIFT: Timestamp = 4;
let encoded = Slicable::encode(proposal);
let proposal = PolkadotBlock::decode(&mut &encoded[..])
let proposal = PolkadotGenericBlock::decode(&mut &encoded[..])
.and_then(|b| PolkadotBlock::from(b).ok())
.ok_or_else(|| ErrorKind::ProposalNotForPolkadot)?;
let transactions_size = proposal.body.transactions.iter().fold(0, |a, tx| {
let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| {
a + Slicable::encode(tx).len()
});
......@@ -668,7 +665,7 @@ fn evaluate_proposal<C: PolkadotApi>(
// a) we assume the parent is valid.
// b) the runtime checks that `proposal.parent_hash` == `block_hash(proposal.number - 1)`
let block_timestamp = proposal.body.timestamp;
let block_timestamp = proposal.timestamp();
// TODO: just defer using `tokio_timer` to delay prepare vote.
if block_timestamp > now + MAX_TIMESTAMP_DRIFT {
......@@ -676,6 +673,6 @@ fn evaluate_proposal<C: PolkadotApi>(
}
// execute the block.
client.evaluate_block(parent_id, proposal)?;
client.evaluate_block(parent_id, proposal.into())?;
Ok(true)
}
......@@ -27,282 +27,4 @@ extern crate polkadot_primitives as polkadot_primitives;
extern crate ed25519;
extern crate triehash;
#[cfg(test)] extern crate substrate_keyring as keyring;
#[cfg(test)] extern crate substrate_runtime_support as runtime_support;
#[cfg(test)] #[macro_use] extern crate hex_literal;
native_executor_instance!(pub Executor, polkadot_runtime::api::dispatch, include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm"));
#[cfg(test)]
mod tests {
use runtime_io;
use super::Executor;
use substrate_executor::WasmExecutor;
use codec::{KeyedVec, Slicable, Joiner};
use keyring::Keyring;
use runtime_support::Hashable;
use polkadot_runtime::runtime::staking::balance;
use state_machine::{CodeExecutor, TestExternalities};
use primitives::twox_128;
use polkadot_primitives::{
Hash, Header, Body, BlockNumber, Block, Digest, Transaction,
UncheckedTransaction, Function, InherentFunction,
};
use ed25519::{Public, Pair};
const BLOATY_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm");
const COMPACT_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm");
// TODO: move into own crate.
macro_rules! map {
($( $name:expr => $value:expr ),*) => (
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
)
}
fn new_test_ext() -> TestExternalities {
let one = Keyring::One.to_raw_public();
let two = Keyring::Two.to_raw_public();
let three = [3u8; 32];
map![
twox_128(&0u64.to_keyed_vec(b"sys:old:")).to_vec() => [69u8; 32].encode(),
twox_128(b"gov:apr").to_vec() => vec![].and(&667u32),
twox_128(b"ses:len").to_vec() => vec![].and(&2u64),
twox_128(b"ses:val:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"ses:val:")).to_vec() => three.to_vec(),
twox_128(b"sta:wil:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"sta:wil:")).to_vec() => one.to_vec(),
twox_128(&1u32.to_keyed_vec(b"sta:wil:")).to_vec() => two.to_vec(),
twox_128(&2u32.to_keyed_vec(b"sta:wil:")).to_vec() => three.to_vec(),
twox_128(b"sta:spe").to_vec() => vec![].and(&2u64),
twox_128(b"sta:vac").to_vec() => vec![].and(&3u64),
twox_128(b"sta:era").to_vec() => vec![].and(&0u64),
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
]
}
fn set_timestamp(timestamp: u64) -> UncheckedTransaction {
UncheckedTransaction::inherent(InherentFunction::TimestampSet(timestamp))
}
fn tx() -> UncheckedTransaction {
let transaction = Transaction {
signed: Keyring::One.to_raw_public(),
nonce: 0,
function: Function::StakingTransfer(Keyring::Two.to_raw_public(), 69),
};
let signature = Keyring::from_raw_public(transaction.signed).unwrap()
.sign(&transaction.encode());
UncheckedTransaction { transaction, signature }
}
fn execute_tx_on<C>(executor: C, ext: &mut TestExternalities, code: &[u8], tx: UncheckedTransaction, header: Header)
-> Result<Vec<u8>, C::Error>
where C: CodeExecutor
{
let next_header = executor.call(ext, code, "execute_transaction", &vec![].and(&header).and(&set_timestamp(100_000))).unwrap();
let next_input = next_header.and(&tx);
executor.call(ext, code, "execute_transaction", &next_input[..])
}
fn construct_block(number: BlockNumber, parent_hash: Hash, state_root: Hash, timestamp: u64, txs: Vec<Transaction>) -> (Vec<u8>, Hash) {
use triehash::ordered_trie_root;
let transactions = txs.into_iter().map(|transaction| {
let signature = Pair::from(Keyring::from_public(Public::from_raw(transaction.signed)).unwrap())
.sign(&transaction.encode());
UncheckedTransaction { transaction, signature }
}).collect();
let header = Header {
parent_hash,
number,
state_root,
transaction_root: Default::default(),
digest: Digest { logs: vec![], },
};
let mut block = Block {
header,
body: Body { timestamp, transactions },
};
let transaction_root = ordered_trie_root(block.all_transactions().map(|tx| Slicable::encode(&tx))).0.into();
block.header.transaction_root = transaction_root;
let hash = block.header.blake2_256();
(block.encode(), hash.into())
}
fn block1() -> (Vec<u8>, Hash) {
construct_block(
1,
[69u8; 32].into(),
hex!("3df569d47a0d7f4a448486f04fba4eea3e9dfca001319c609f88b3a67b0dd1ea").into(),
100_000,
vec![
Transaction {
signed: Keyring::One.to_raw_public(),
nonce: 0,
function: Function::StakingTransfer(Keyring::Two.to_raw_public(), 69),
}
]
)
}
fn block2() -> (Vec<u8>, Hash) {
construct_block(
2,