mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 01:07:57 +00:00
927e13c13a
* Adding script for rename, could be applicable for nodes on top of it, too * add stderr and gitlab ci features * apply script * fix now minor details in expected stderr * Update the Cargo.lock * fix name: sc-transaction -> sc-tracing * fix rename in script, too
180 lines
5.0 KiB
Rust
180 lines
5.0 KiB
Rust
// Copyright 2017-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/>.
|
|
|
|
//! Substrate block builder
|
|
//!
|
|
//! This crate provides the [`BlockBuilder`] utility and the corresponding runtime api
|
|
//! [`BlockBuilder`](api::BlockBuilder).Error
|
|
//!
|
|
//! The block builder utility is used in the node as an abstraction over the runtime api to
|
|
//! initialize a block, to push extrinsics and to finalize a block.
|
|
|
|
#![warn(missing_docs)]
|
|
|
|
use codec::Encode;
|
|
|
|
use sp_runtime::{
|
|
generic::BlockId,
|
|
traits::{
|
|
Header as HeaderT, Hash, Block as BlockT, HashFor, ProvideRuntimeApi, ApiRef, DigestFor,
|
|
NumberFor, One,
|
|
}
|
|
};
|
|
use sp_blockchain::{ApplyExtrinsicFailed, Error};
|
|
use primitives::ExecutionContext;
|
|
use state_machine::StorageProof;
|
|
use sp_api::{Core, ApiExt, ApiErrorFor};
|
|
|
|
pub use runtime_api::BlockBuilder as BlockBuilderApi;
|
|
|
|
|
|
/// Utility for building new (valid) blocks from a stream of extrinsics.
|
|
pub struct BlockBuilder<'a, Block: BlockT, A: ProvideRuntimeApi> {
|
|
header: Block::Header,
|
|
extrinsics: Vec<Block::Extrinsic>,
|
|
api: ApiRef<'a, A::Api>,
|
|
block_id: BlockId<Block>,
|
|
}
|
|
|
|
impl<'a, Block, A> BlockBuilder<'a, Block, A>
|
|
where
|
|
Block: BlockT,
|
|
A: ProvideRuntimeApi + 'a,
|
|
A::Api: BlockBuilderApi<Block>,
|
|
ApiErrorFor<A, Block>: From<Error>,
|
|
{
|
|
/// Create a new instance of builder based on the given `parent_hash` and `parent_number`.
|
|
///
|
|
/// While proof recording is enabled, all accessed trie nodes are saved.
|
|
/// These recorded trie nodes can be used by a third party to prove the
|
|
/// output of this block builder without having access to the full storage.
|
|
pub fn new(
|
|
api: &'a A,
|
|
parent_hash: Block::Hash,
|
|
parent_number: NumberFor<Block>,
|
|
proof_recording: bool,
|
|
inherent_digests: DigestFor<Block>,
|
|
) -> Result<Self, ApiErrorFor<A, Block>> {
|
|
let header = <<Block as BlockT>::Header as HeaderT>::new(
|
|
parent_number + One::one(),
|
|
Default::default(),
|
|
Default::default(),
|
|
parent_hash,
|
|
inherent_digests,
|
|
);
|
|
|
|
let mut api = api.runtime_api();
|
|
|
|
if proof_recording {
|
|
api.record_proof();
|
|
}
|
|
|
|
let block_id = BlockId::Hash(parent_hash);
|
|
|
|
api.initialize_block_with_context(
|
|
&block_id, ExecutionContext::BlockConstruction, &header,
|
|
)?;
|
|
|
|
Ok(Self {
|
|
header,
|
|
extrinsics: Vec::new(),
|
|
api,
|
|
block_id,
|
|
})
|
|
}
|
|
|
|
/// Push onto the block's list of extrinsics.
|
|
///
|
|
/// This will ensure the extrinsic can be validly executed (by executing it);
|
|
pub fn push(&mut self, xt: <Block as BlockT>::Extrinsic) -> Result<(), ApiErrorFor<A, Block>> {
|
|
let block_id = &self.block_id;
|
|
let extrinsics = &mut self.extrinsics;
|
|
|
|
if self
|
|
.api
|
|
.has_api_with::<dyn BlockBuilderApi<Block, Error = ApiErrorFor<A, Block>>, _>(
|
|
block_id,
|
|
|version| version < 4,
|
|
)?
|
|
{
|
|
// Run compatibility fallback for v3.
|
|
self.api.map_api_result(|api| {
|
|
#[allow(deprecated)]
|
|
match api.apply_extrinsic_before_version_4_with_context(
|
|
block_id,
|
|
ExecutionContext::BlockConstruction,
|
|
xt.clone(),
|
|
)? {
|
|
Ok(_) => {
|
|
extrinsics.push(xt);
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(ApplyExtrinsicFailed::from(e).into())?,
|
|
}
|
|
})
|
|
} else {
|
|
self.api.map_api_result(|api| {
|
|
match api.apply_extrinsic_with_context(
|
|
block_id,
|
|
ExecutionContext::BlockConstruction,
|
|
xt.clone(),
|
|
)? {
|
|
Ok(_) => {
|
|
extrinsics.push(xt);
|
|
Ok(())
|
|
}
|
|
Err(tx_validity) => Err(ApplyExtrinsicFailed::Validity(tx_validity).into())?,
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Consume the builder to return a valid `Block` containing all pushed extrinsics.
|
|
pub fn bake(mut self) -> Result<Block, ApiErrorFor<A, Block>> {
|
|
self.bake_impl()?;
|
|
Ok(<Block as BlockT>::new(self.header, self.extrinsics))
|
|
}
|
|
|
|
fn bake_impl(&mut self) -> Result<(), ApiErrorFor<A, Block>> {
|
|
self.header = self.api.finalize_block_with_context(
|
|
&self.block_id, ExecutionContext::BlockConstruction
|
|
)?;
|
|
|
|
debug_assert_eq!(
|
|
self.header.extrinsics_root().clone(),
|
|
HashFor::<Block>::ordered_trie_root(
|
|
self.extrinsics.iter().map(Encode::encode).collect(),
|
|
),
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Consume the builder to return a valid `Block` containing all pushed extrinsics
|
|
/// and the generated proof.
|
|
///
|
|
/// The proof will be `Some(_)`, if proof recording was enabled while creating
|
|
/// the block builder.
|
|
pub fn bake_and_extract_proof(mut self)
|
|
-> Result<(Block, Option<StorageProof>), ApiErrorFor<A, Block>>
|
|
{
|
|
self.bake_impl()?;
|
|
|
|
let proof = self.api.extract_proof();
|
|
Ok((<Block as BlockT>::new(self.header, self.extrinsics), proof))
|
|
}
|
|
}
|