mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-06 18:28:03 +00:00
Move create_inherents into the block-builder (#6553)
* Move `create_inherents` into the block-builder This moves the `create_inherents` call into the block-builder. This has the advantage that `create_inherents` will be able to reuse the same context that will be used when applying the extrinsics and we also save one call to `on_initialize`. To make sure that `create_inherents` does not modify any state, we execute it in a transaction that is rolled-back after doing the runtime call. * Feedback and build fix * Update primitives/runtime/src/lib.rs Co-authored-by: Sergei Shulepov <sergei@parity.io> * Update client/block-builder/src/lib.rs Co-authored-by: Sergei Shulepov <sergei@parity.io>
This commit is contained in:
Generated
+1
@@ -5994,6 +5994,7 @@ dependencies = [
|
||||
"sp-blockchain",
|
||||
"sp-consensus",
|
||||
"sp-core",
|
||||
"sp-inherents",
|
||||
"sp-runtime",
|
||||
"sp-state-machine",
|
||||
"sp-trie",
|
||||
|
||||
@@ -26,7 +26,6 @@ use codec::Decode;
|
||||
use sp_consensus::{evaluation, Proposal, RecordProof};
|
||||
use sp_inherents::InherentData;
|
||||
use log::{error, info, debug, trace, warn};
|
||||
use sp_core::ExecutionContext;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Hash as HashT, Header as HeaderT, DigestFor, BlakeTwo256},
|
||||
@@ -200,15 +199,7 @@ impl<A, B, Block, C> Proposer<B, Block, C, A>
|
||||
record_proof,
|
||||
)?;
|
||||
|
||||
// We don't check the API versions any further here since the dispatch compatibility
|
||||
// check should be enough.
|
||||
for inherent in self.client.runtime_api()
|
||||
.inherent_extrinsics_with_context(
|
||||
&self.parent_id,
|
||||
ExecutionContext::BlockConstruction,
|
||||
inherent_data
|
||||
)?
|
||||
{
|
||||
for inherent in block_builder.create_inherents(inherent_data)? {
|
||||
match block_builder.push(inherent) {
|
||||
Err(ApplyExtrinsicFailed(Validity(e))) if e.exhausted_resources() =>
|
||||
warn!("⚠️ Dropping non-mandatory inherent from overweight block."),
|
||||
|
||||
@@ -20,6 +20,7 @@ sp-consensus = { version = "0.8.0-rc4", path = "../../primitives/consensus/commo
|
||||
sp-blockchain = { version = "2.0.0-rc4", path = "../../primitives/blockchain" }
|
||||
sp-core = { version = "2.0.0-rc4", path = "../../primitives/core" }
|
||||
sp-block-builder = { version = "2.0.0-rc4", path = "../../primitives/block-builder" }
|
||||
sp-inherents = { version = "2.0.0-rc4", path = "../../primitives/inherents" }
|
||||
sc-client-api = { version = "2.0.0-rc4", path = "../api" }
|
||||
codec = { package = "parity-scale-codec", version = "1.3.1", features = ["derive"] }
|
||||
|
||||
|
||||
@@ -34,7 +34,10 @@ use sp_runtime::{
|
||||
};
|
||||
use sp_blockchain::{ApplyExtrinsicFailed, Error};
|
||||
use sp_core::ExecutionContext;
|
||||
use sp_api::{Core, ApiExt, ApiErrorFor, ApiRef, ProvideRuntimeApi, StorageChanges, StorageProof};
|
||||
use sp_api::{
|
||||
Core, ApiExt, ApiErrorFor, ApiRef, ProvideRuntimeApi, StorageChanges, StorageProof,
|
||||
TransactionOutcome,
|
||||
};
|
||||
use sp_consensus::RecordProof;
|
||||
|
||||
pub use sp_block_builder::BlockBuilder as BlockBuilderApi;
|
||||
@@ -156,17 +159,22 @@ where
|
||||
let block_id = &self.block_id;
|
||||
let extrinsics = &mut self.extrinsics;
|
||||
|
||||
self.api.map_api_result(|api| {
|
||||
self.api.execute_in_transaction(|api| {
|
||||
match api.apply_extrinsic_with_context(
|
||||
block_id,
|
||||
ExecutionContext::BlockConstruction,
|
||||
xt.clone(),
|
||||
)? {
|
||||
Ok(_) => {
|
||||
) {
|
||||
Ok(Ok(_)) => {
|
||||
extrinsics.push(xt);
|
||||
Ok(())
|
||||
TransactionOutcome::Commit(Ok(()))
|
||||
}
|
||||
Err(tx_validity) => Err(ApplyExtrinsicFailed::Validity(tx_validity).into()),
|
||||
Ok(Err(tx_validity)) => {
|
||||
TransactionOutcome::Rollback(
|
||||
Err(ApplyExtrinsicFailed::Validity(tx_validity).into()),
|
||||
)
|
||||
},
|
||||
Err(e) => TransactionOutcome::Rollback(Err(e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -212,6 +220,25 @@ where
|
||||
proof,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create the inherents for the block.
|
||||
///
|
||||
/// Returns the inherents created by the runtime or an error if something failed.
|
||||
pub fn create_inherents(
|
||||
&mut self,
|
||||
inherent_data: sp_inherents::InherentData,
|
||||
) -> Result<Vec<Block::Extrinsic>, ApiErrorFor<A, Block>> {
|
||||
let block_id = self.block_id;
|
||||
self.api.execute_in_transaction(move |api| {
|
||||
// `create_inherents` should not change any state, to ensure this we always rollback
|
||||
// the transaction.
|
||||
TransactionOutcome::Rollback(api.inherent_extrinsics_with_context(
|
||||
&block_id,
|
||||
ExecutionContext::BlockConstruction,
|
||||
inherent_data
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -21,6 +21,7 @@ use sp_std::{prelude::*, marker::PhantomData};
|
||||
use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode};
|
||||
use crate::hash::{Twox128, StorageHasher};
|
||||
use sp_runtime::generic::{Digest, DigestItem};
|
||||
pub use sp_runtime::TransactionOutcome;
|
||||
|
||||
pub mod unhashed;
|
||||
pub mod hashed;
|
||||
@@ -29,14 +30,6 @@ pub mod child;
|
||||
pub mod generator;
|
||||
pub mod migration;
|
||||
|
||||
/// Describes whether a storage transaction should be committed or rolled back.
|
||||
pub enum TransactionOutcome<T> {
|
||||
/// Transaction should be committed.
|
||||
Commit(T),
|
||||
/// Transaction should be rolled back.
|
||||
Rollback(T),
|
||||
}
|
||||
|
||||
/// Execute the supplied function in a new storage transaction.
|
||||
///
|
||||
/// All changes to storage performed by the supplied function are discarded if the returned
|
||||
|
||||
@@ -253,18 +253,18 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
{
|
||||
type StateBackend = C::StateBackend;
|
||||
|
||||
fn map_api_result<F: FnOnce(&Self) -> std::result::Result<R, E>, R, E>(
|
||||
fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
|
||||
&self,
|
||||
map_call: F,
|
||||
) -> std::result::Result<R, E> where Self: Sized {
|
||||
call: F,
|
||||
) -> R where Self: Sized {
|
||||
self.changes.borrow_mut().start_transaction();
|
||||
*self.commit_on_success.borrow_mut() = false;
|
||||
let res = map_call(self);
|
||||
let res = call(self);
|
||||
*self.commit_on_success.borrow_mut() = true;
|
||||
|
||||
self.commit_on_ok(&res);
|
||||
self.commit_or_rollback(matches!(res, #crate_::TransactionOutcome::Commit(_)));
|
||||
|
||||
res
|
||||
res.into_inner()
|
||||
}
|
||||
|
||||
fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
|
||||
@@ -380,21 +380,21 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
|
||||
&self.recorder,
|
||||
);
|
||||
|
||||
self.commit_on_ok(&res);
|
||||
self.commit_or_rollback(res.is_ok());
|
||||
res
|
||||
}
|
||||
|
||||
fn commit_on_ok<R, E>(&self, res: &std::result::Result<R, E>) {
|
||||
fn commit_or_rollback(&self, commit: bool) {
|
||||
let proof = "\
|
||||
We only close a transaction when we opened one ourself.
|
||||
Other parts of the runtime that make use of transactions (state-machine)
|
||||
also balance their transactions. The runtime cannot close client initiated
|
||||
transactions. qed";
|
||||
if *self.commit_on_success.borrow() {
|
||||
if res.is_err() {
|
||||
self.changes.borrow_mut().rollback_transaction().expect(proof);
|
||||
} else {
|
||||
if commit {
|
||||
self.changes.borrow_mut().commit_transaction().expect(proof);
|
||||
} else {
|
||||
self.changes.borrow_mut().rollback_transaction().expect(proof);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,11 +73,11 @@ fn implement_common_api_traits(
|
||||
impl #crate_::ApiExt<#block_type> for #self_ty {
|
||||
type StateBackend = #crate_::InMemoryBackend<#crate_::HashFor<#block_type>>;
|
||||
|
||||
fn map_api_result<F: FnOnce(&Self) -> std::result::Result<R, E>, R, E>(
|
||||
fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
|
||||
&self,
|
||||
map_call: F,
|
||||
) -> std::result::Result<R, E> where Self: Sized {
|
||||
map_call(self)
|
||||
call: F,
|
||||
) -> R where Self: Sized {
|
||||
call(self).into_inner()
|
||||
}
|
||||
|
||||
fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
|
||||
|
||||
@@ -58,7 +58,7 @@ pub use sp_runtime::{
|
||||
Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, HashFor, NumberFor,
|
||||
Header as HeaderT, Hash as HashT,
|
||||
},
|
||||
generic::BlockId, transaction_validity::TransactionValidity, RuntimeString,
|
||||
generic::BlockId, transaction_validity::TransactionValidity, RuntimeString, TransactionOutcome,
|
||||
};
|
||||
#[doc(hidden)]
|
||||
pub use sp_core::{offchain, ExecutionContext};
|
||||
@@ -356,15 +356,15 @@ pub trait ApiExt<Block: BlockT>: ApiErrorExt {
|
||||
/// The state backend that is used to store the block states.
|
||||
type StateBackend: StateBackend<HashFor<Block>>;
|
||||
|
||||
/// The given closure will be called with api instance. Inside the closure any api call is
|
||||
/// allowed. After doing the api call, the closure is allowed to map the `Result` to a
|
||||
/// different `Result` type. This can be important, as the internal data structure that keeps
|
||||
/// track of modifications to the storage, discards changes when the `Result` is an `Err`.
|
||||
/// On `Ok`, the structure commits the changes to an internal buffer.
|
||||
fn map_api_result<F: FnOnce(&Self) -> result::Result<R, E>, R, E>(
|
||||
/// Execute the given closure inside a new transaction.
|
||||
///
|
||||
/// Depending on the outcome of the closure, the transaction is committed or rolled-back.
|
||||
///
|
||||
/// The internal result of the closure is returned afterwards.
|
||||
fn execute_in_transaction<F: FnOnce(&Self) -> TransactionOutcome<R>, R>(
|
||||
&self,
|
||||
map_call: F,
|
||||
) -> result::Result<R, E> where Self: Sized;
|
||||
call: F,
|
||||
) -> R where Self: Sized;
|
||||
|
||||
/// Checks if the given api is implemented and versions match.
|
||||
fn has_api<A: RuntimeApiInfo + ?Sized>(
|
||||
|
||||
@@ -801,6 +801,23 @@ impl Drop for SignatureBatching {
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes on what should happen with a storage transaction.
|
||||
pub enum TransactionOutcome<R> {
|
||||
/// Commit the transaction.
|
||||
Commit(R),
|
||||
/// Rollback the transaction.
|
||||
Rollback(R),
|
||||
}
|
||||
|
||||
impl<R> TransactionOutcome<R> {
|
||||
/// Convert into the inner type.
|
||||
pub fn into_inner(self) -> R {
|
||||
match self {
|
||||
Self::Commit(r) => r,
|
||||
Self::Rollback(r) => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
Reference in New Issue
Block a user