Block production integration benchmark (#6468)

* proposer benchmark

* update cargo.lock
This commit is contained in:
Nikolay Volf
2020-06-30 16:06:16 +03:00
committed by GitHub
parent b832e35c5e
commit 850942ae66
8 changed files with 523 additions and 124 deletions
+127 -82
View File
@@ -152,20 +152,12 @@ impl BlockType {
}
/// Content of the generated block.
#[derive(Clone, Debug)]
pub struct BlockContent {
block_type: BlockType,
size: Option<usize>,
}
impl BlockContent {
fn iter_while(&self, mut f: impl FnMut(usize) -> bool) {
match self.size {
Some(v) => { for i in 0..v { if !f(i) { break; }}}
None => { for i in 0.. { if !f(i) { break; }}}
}
}
}
/// Type of backend database.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum DatabaseType {
@@ -219,6 +211,93 @@ impl CloneableSpawn for TaskExecutor {
}
}
/// Iterator for block content.
pub struct BlockContentIterator<'a> {
iteration: usize,
content: BlockContent,
runtime_version: sc_executor::RuntimeVersion,
genesis_hash: node_primitives::Hash,
keyring: &'a BenchKeyring,
}
impl<'a> BlockContentIterator<'a> {
fn new(content: BlockContent, keyring: &'a BenchKeyring, client: &Client) -> Self {
let runtime_version = client.runtime_version_at(&BlockId::number(0))
.expect("There should be runtime version at 0");
let genesis_hash = client.block_hash(Zero::zero())
.expect("Database error?")
.expect("Genesis block always exists; qed")
.into();
BlockContentIterator {
iteration: 0,
content,
keyring,
runtime_version,
genesis_hash,
}
}
}
impl<'a> Iterator for BlockContentIterator<'a> {
type Item = OpaqueExtrinsic;
fn next(&mut self) -> Option<Self::Item> {
if self.content.size.map(|size| size <= self.iteration).unwrap_or(false) {
return None;
}
let sender = self.keyring.at(self.iteration);
let receiver = get_account_id_from_seed::<sr25519::Public>(
&format!("random-user//{}", self.iteration)
);
let signed = self.keyring.sign(
CheckedExtrinsic {
signed: Some((sender, signed_extra(0, node_runtime::ExistentialDeposit::get() + 1))),
function: match self.content.block_type {
BlockType::RandomTransfersKeepAlive => {
Call::Balances(
BalancesCall::transfer_keep_alive(
pallet_indices::address::Address::Id(receiver),
node_runtime::ExistentialDeposit::get() + 1,
)
)
},
BlockType::RandomTransfersReaping => {
Call::Balances(
BalancesCall::transfer(
pallet_indices::address::Address::Id(receiver),
// Transfer so that ending balance would be 1 less than existential deposit
// so that we kill the sender account.
100*DOLLARS - (node_runtime::ExistentialDeposit::get() - 1),
)
)
},
BlockType::Noop => {
Call::System(
SystemCall::remark(Vec::new())
)
},
},
},
self.runtime_version.spec_version,
self.runtime_version.transaction_version,
self.genesis_hash.into(),
);
let encoded = Encode::encode(&signed);
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..])
.expect("Failed to decode opaque");
self.iteration += 1;
Some(opaque)
}
}
impl BenchDb {
/// New immutable benchmarking database.
///
@@ -288,8 +367,33 @@ impl BenchDb {
(client, backend)
}
/// Generate new block using this database.
pub fn generate_block(&mut self, content: BlockContent) -> Block {
/// Generate list of required inherents.
///
/// Uses already instantiated Client.
pub fn generate_inherents(&mut self, client: &Client) -> Vec<OpaqueExtrinsic> {
let mut inherent_data = InherentData::new();
let timestamp = 1 * MinimumPeriod::get();
inherent_data.put_data(sp_timestamp::INHERENT_IDENTIFIER, &timestamp)
.expect("Put timestamp failed");
inherent_data.put_data(sp_finality_tracker::INHERENT_IDENTIFIER, &0)
.expect("Put finality tracker failed");
client.runtime_api()
.inherent_extrinsics_with_context(
&BlockId::number(0),
ExecutionContext::BlockConstruction,
inherent_data,
).expect("Get inherents failed")
}
/// Iterate over some block content with transaction signed using this database keyring.
pub fn block_content(&self, content: BlockContent, client: &Client) -> BlockContentIterator {
BlockContentIterator::new(content, &self.keyring, client)
}
/// Get cliet for this database operations.
pub fn client(&mut self) -> Client {
let (client, _backend) = Self::bench_client(
self.database_type,
self.directory_guard.path(),
@@ -297,92 +401,33 @@ impl BenchDb {
&self.keyring,
);
let runtime_version = client.runtime_version_at(&BlockId::number(0))
.expect("There should be runtime version at 0");
client
}
let genesis_hash = client.block_hash(Zero::zero())
.expect("Database error?")
.expect("Genesis block always exists; qed")
.into();
/// Generate new block using this database.
pub fn generate_block(&mut self, content: BlockContent) -> Block {
let client = self.client();
let mut block = client
.new_block(Default::default())
.expect("Block creation failed");
let timestamp = 1 * MinimumPeriod::get();
let mut inherent_data = InherentData::new();
inherent_data.put_data(sp_timestamp::INHERENT_IDENTIFIER, &timestamp)
.expect("Put timestamp failed");
inherent_data.put_data(sp_finality_tracker::INHERENT_IDENTIFIER, &0)
.expect("Put finality tracker failed");
for extrinsic in client.runtime_api()
.inherent_extrinsics_with_context(
&BlockId::number(0),
ExecutionContext::BlockConstruction,
inherent_data,
).expect("Get inherents failed")
{
for extrinsic in self.generate_inherents(&client) {
block.push(extrinsic).expect("Push inherent failed");
}
let start = std::time::Instant::now();
content.iter_while(|iteration| {
let sender = self.keyring.at(iteration);
let receiver = get_account_id_from_seed::<sr25519::Public>(
&format!("random-user//{}", iteration)
);
let signed = self.keyring.sign(
CheckedExtrinsic {
signed: Some((sender, signed_extra(0, node_runtime::ExistentialDeposit::get() + 1))),
function: match content.block_type {
BlockType::RandomTransfersKeepAlive => {
Call::Balances(
BalancesCall::transfer_keep_alive(
pallet_indices::address::Address::Id(receiver),
node_runtime::ExistentialDeposit::get() + 1,
)
)
},
BlockType::RandomTransfersReaping => {
Call::Balances(
BalancesCall::transfer(
pallet_indices::address::Address::Id(receiver),
// Transfer so that ending balance would be 1 less than existential deposit
// so that we kill the sender account.
100*DOLLARS - (node_runtime::ExistentialDeposit::get() - 1),
)
)
},
BlockType::Noop => {
Call::System(
SystemCall::remark(Vec::new())
)
},
},
},
runtime_version.spec_version,
runtime_version.transaction_version,
genesis_hash,
);
let encoded = Encode::encode(&signed);
let opaque = OpaqueExtrinsic::decode(&mut &encoded[..])
.expect("Failed to decode opaque");
for opaque in self.block_content(content, &client) {
match block.push(opaque) {
Err(sp_blockchain::Error::ApplyExtrinsicFailed(
sp_blockchain::ApplyExtrinsicFailed::Validity(e)
)) if e.exhausted_resources() => {
return false;
break;
},
Err(err) => panic!("Error pushing transaction: {:?}", err),
Ok(_) => true,
Ok(_) => {},
}
});
};
let block = block.build().expect("Block build failed").block;
@@ -411,7 +456,7 @@ impl BenchDb {
);
BenchContext {
client, backend, db_guard: directory_guard,
client: Arc::new(client), backend, db_guard: directory_guard,
}
}
}
@@ -543,7 +588,7 @@ impl Guard {
/// Benchmarking/test context holding instantiated client and backend references.
pub struct BenchContext {
/// Node client.
pub client: Client,
pub client: Arc<Client>,
/// Node backend.
pub backend: Arc<Backend>,