mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-08 19:28:01 +00:00
5cb8c0dc1c
* Clear up import/export misunderstandings * Fetch minimum period from runtime * Remove unnecessary comment This variable is already fetched from the runtime in the line below. * Fix bug in factory The `best_block_id` stayed the same, it was always the genesis hash. This resulted in the factory failing after 4096 blocks, since `client/db` discards hashes (in this case the genesis hash) after 4096 blocks from the database. * Fix tense in error message * Improve allocator documentation * Fix bug in allocator Under certain circumstances an invalid pointer was returned: when the `ptr` was calculated as equal to the `max_heap_size`. This is an invalid pointer since there is no access allowed after the heap limit. The way to provoke this was to repeatedly allocate with sizes which were previously not allocated and immediately deallocate right afterwards. What this did was to increment the `bumper` with each allocation, whilst keeping the `total_size` of the heap `0`. If this repeated allocation/deallocation scheme resulted in `max_heap_size == ptr` the `ptr` was still returned. The allocator only checked if the `total_size` was still within the `max_heap_size` limits, and not if the resulting `ptr` was still within the valid heap region. This commit introduces a check to validate if the calculated `ptr` is within the heap. * Add test for zero byte allocation and document behavior * Improve code readability by introducing a const * Fix error message in test * Apply suggestions from code review Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Fix code review suggestions * Replace early return with assertion * Remove test for zero size allocations * Shorten test code * Shorten comment * Make bump() return Result * Add comment for bump() * Remove ambiguous comment * Replace value with const * Use proof for panic message * Fix merge * Add comment regarding minimum allocation size
200 lines
6.8 KiB
Rust
200 lines
6.8 KiB
Rust
// Copyright 2019 Parity Technologies (UK) Ltd.
|
|
// This file is part of Substrate.
|
|
|
|
// Substrate is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Substrate is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//! Simple transaction factory which distributes tokens from a master
|
|
//! account to a specified number of newly created accounts.
|
|
//!
|
|
//! The factory currently only works on an empty database!
|
|
|
|
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
use std::cmp::PartialOrd;
|
|
use std::fmt::Display;
|
|
|
|
use log::info;
|
|
|
|
use client::{Client, block_builder::api::BlockBuilder, runtime_api::ConstructRuntimeApi};
|
|
use consensus_common::{
|
|
BlockOrigin, BlockImportParams, InherentData, ForkChoiceStrategy,
|
|
SelectChain
|
|
};
|
|
use consensus_common::block_import::BlockImport;
|
|
use codec::{Decode, Encode};
|
|
use primitives::{Blake2Hasher, Hasher};
|
|
use sr_primitives::generic::BlockId;
|
|
use sr_primitives::traits::{
|
|
Block as BlockT, Header as HeaderT, ProvideRuntimeApi, SimpleArithmetic,
|
|
One, Zero,
|
|
};
|
|
pub use crate::modes::Mode;
|
|
|
|
pub mod modes;
|
|
mod complex_mode;
|
|
mod simple_modes;
|
|
|
|
pub trait RuntimeAdapter {
|
|
type AccountId: Display;
|
|
type Balance: Display + SimpleArithmetic + From<Self::Number>;
|
|
type Block: BlockT;
|
|
type Index: Copy;
|
|
type Number: Display + PartialOrd + SimpleArithmetic + Zero + One;
|
|
type Phase: Copy;
|
|
type Secret;
|
|
|
|
fn new(mode: Mode, rounds: u64, start_number: u64) -> Self;
|
|
|
|
fn block_no(&self) -> Self::Number;
|
|
fn block_in_round(&self) -> Self::Number;
|
|
fn mode(&self) -> &Mode;
|
|
fn num(&self) -> Self::Number;
|
|
fn rounds(&self) -> Self::Number;
|
|
fn round(&self) -> Self::Number;
|
|
fn start_number(&self) -> Self::Number;
|
|
|
|
fn set_block_in_round(&mut self, val: Self::Number);
|
|
fn set_block_no(&mut self, val: Self::Number);
|
|
fn set_round(&mut self, val: Self::Number);
|
|
|
|
fn transfer_extrinsic(
|
|
&self,
|
|
sender: &Self::AccountId,
|
|
key: &Self::Secret,
|
|
destination: &Self::AccountId,
|
|
amount: &Self::Balance,
|
|
version: u32,
|
|
genesis_hash: &<Self::Block as BlockT>::Hash,
|
|
prior_block_hash: &<Self::Block as BlockT>::Hash,
|
|
) -> <Self::Block as BlockT>::Extrinsic;
|
|
|
|
fn inherent_extrinsics(&self) -> InherentData;
|
|
|
|
fn minimum_balance() -> Self::Balance;
|
|
fn master_account_id() -> Self::AccountId;
|
|
fn master_account_secret() -> Self::Secret;
|
|
fn extract_index(&self, account_id: &Self::AccountId, block_hash: &<Self::Block as BlockT>::Hash) -> Self::Index;
|
|
fn extract_phase(&self, block_hash: <Self::Block as BlockT>::Hash) -> Self::Phase;
|
|
fn gen_random_account_id(seed: &Self::Number) -> Self::AccountId;
|
|
fn gen_random_account_secret(seed: &Self::Number) -> Self::Secret;
|
|
}
|
|
|
|
/// Manufactures transactions. The exact amount depends on
|
|
/// `mode`, `num` and `rounds`.
|
|
pub fn factory<RA, Backend, Exec, Block, RtApi, Sc>(
|
|
mut factory_state: RA,
|
|
client: &Arc<Client<Backend, Exec, Block, RtApi>>,
|
|
select_chain: &Sc,
|
|
) -> cli::error::Result<()>
|
|
where
|
|
Block: BlockT<Hash = <Blake2Hasher as Hasher>::Out>,
|
|
Exec: client::CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
|
|
Backend: client::backend::Backend<Block, Blake2Hasher> + Send,
|
|
Client<Backend, Exec, Block, RtApi>: ProvideRuntimeApi,
|
|
<Client<Backend, Exec, Block, RtApi> as ProvideRuntimeApi>::Api: BlockBuilder<Block>,
|
|
RtApi: ConstructRuntimeApi<Block, Client<Backend, Exec, Block, RtApi>> + Send + Sync,
|
|
Sc: SelectChain<Block>,
|
|
RA: RuntimeAdapter,
|
|
<<RA as RuntimeAdapter>::Block as BlockT>::Hash: From<primitives::H256>,
|
|
{
|
|
if *factory_state.mode() != Mode::MasterToNToM && factory_state.rounds() > RA::Number::one() {
|
|
let msg = "The factory can only be used with rounds set to 1 in this mode.".into();
|
|
return Err(cli::error::Error::Input(msg));
|
|
}
|
|
|
|
let best_header: Result<<Block as BlockT>::Header, cli::error::Error> =
|
|
select_chain.best_chain().map_err(|e| format!("{:?}", e).into());
|
|
let mut best_hash = best_header?.hash();
|
|
let mut best_block_id = BlockId::<Block>::hash(best_hash);
|
|
let version = client.runtime_version_at(&best_block_id)?.spec_version;
|
|
let genesis_hash = client.block_hash(Zero::zero())?
|
|
.expect("Genesis block always exists; qed").into();
|
|
|
|
while let Some(block) = match factory_state.mode() {
|
|
Mode::MasterToNToM => complex_mode::next::<RA, _, _, _, _>(
|
|
&mut factory_state,
|
|
&client,
|
|
version,
|
|
genesis_hash,
|
|
best_hash.into(),
|
|
best_block_id,
|
|
),
|
|
_ => simple_modes::next::<RA, _, _, _, _>(
|
|
&mut factory_state,
|
|
&client,
|
|
version,
|
|
genesis_hash,
|
|
best_hash.into(),
|
|
best_block_id,
|
|
),
|
|
} {
|
|
best_hash = block.header().hash();
|
|
best_block_id = BlockId::<Block>::hash(best_hash);
|
|
import_block(&client, block);
|
|
|
|
info!("Imported block at {}", factory_state.block_no());
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Create a baked block from a transfer extrinsic and timestamp inherent.
|
|
pub fn create_block<RA, Backend, Exec, Block, RtApi>(
|
|
client: &Arc<Client<Backend, Exec, Block, RtApi>>,
|
|
transfer: <RA::Block as BlockT>::Extrinsic,
|
|
inherent_extrinsics: Vec<<Block as BlockT>::Extrinsic>,
|
|
) -> Block
|
|
where
|
|
Block: BlockT<Hash = <Blake2Hasher as Hasher>::Out>,
|
|
Exec: client::CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
|
|
Backend: client::backend::Backend<Block, Blake2Hasher> + Send,
|
|
Client<Backend, Exec, Block, RtApi>: ProvideRuntimeApi,
|
|
RtApi: ConstructRuntimeApi<Block, Client<Backend, Exec, Block, RtApi>> + Send + Sync,
|
|
<Client<Backend, Exec, Block, RtApi> as ProvideRuntimeApi>::Api: BlockBuilder<Block>,
|
|
RA: RuntimeAdapter,
|
|
{
|
|
let mut block = client.new_block(Default::default()).expect("Failed to create new block");
|
|
block.push(
|
|
Decode::decode(&mut &transfer.encode()[..])
|
|
.expect("Failed to decode transfer extrinsic")
|
|
).expect("Failed to push transfer extrinsic into block");
|
|
|
|
for inherent in inherent_extrinsics {
|
|
block.push(inherent).expect("Failed ...");
|
|
}
|
|
|
|
block.bake().expect("Failed to bake block")
|
|
}
|
|
|
|
fn import_block<Backend, Exec, Block, RtApi>(
|
|
client: &Arc<Client<Backend, Exec, Block, RtApi>>,
|
|
block: Block
|
|
) -> () where
|
|
Block: BlockT<Hash = <Blake2Hasher as Hasher>::Out>,
|
|
Exec: client::CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
|
|
Backend: client::backend::Backend<Block, Blake2Hasher> + Send,
|
|
{
|
|
let import = BlockImportParams {
|
|
origin: BlockOrigin::File,
|
|
header: block.header().clone(),
|
|
post_digests: Vec::new(),
|
|
body: Some(block.extrinsics().to_vec()),
|
|
finalized: false,
|
|
justification: None,
|
|
auxiliary: Vec::new(),
|
|
fork_choice: ForkChoiceStrategy::LongestChain,
|
|
};
|
|
(&**client).import_block(import, HashMap::new()).expect("Failed to import block");
|
|
}
|