mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 05:17:58 +00:00
Move proof generation to the type system level (#8185)
* Start * Finish!!!! * Update client/basic-authorship/src/basic_authorship.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Review comments Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
use std::{pin::Pin, time, sync::Arc};
|
||||
use sc_client_api::backend;
|
||||
use codec::Decode;
|
||||
use sp_consensus::{evaluation, Proposal, RecordProof};
|
||||
use sp_consensus::{evaluation, Proposal, ProofRecording, DisableProofRecording, EnableProofRecording};
|
||||
use sp_core::traits::SpawnNamed;
|
||||
use sp_inherents::InherentData;
|
||||
use log::{error, info, debug, trace, warn};
|
||||
@@ -52,7 +52,7 @@ use sc_proposer_metrics::MetricsLink as PrometheusMetrics;
|
||||
pub const DEFAULT_MAX_BLOCK_SIZE: usize = 4 * 1024 * 1024 + 512;
|
||||
|
||||
/// Proposer factory.
|
||||
pub struct ProposerFactory<A, B, C> {
|
||||
pub struct ProposerFactory<A, B, C, PR> {
|
||||
spawn_handle: Box<dyn SpawnNamed>,
|
||||
/// The client instance.
|
||||
client: Arc<C>,
|
||||
@@ -60,12 +60,15 @@ pub struct ProposerFactory<A, B, C> {
|
||||
transaction_pool: Arc<A>,
|
||||
/// Prometheus Link,
|
||||
metrics: PrometheusMetrics,
|
||||
/// phantom member to pin the `Backend` type.
|
||||
_phantom: PhantomData<B>,
|
||||
/// phantom member to pin the `Backend`/`ProofRecording` type.
|
||||
_phantom: PhantomData<(B, PR)>,
|
||||
max_block_size: usize,
|
||||
}
|
||||
|
||||
impl<A, B, C> ProposerFactory<A, B, C> {
|
||||
impl<A, B, C> ProposerFactory<A, B, C, DisableProofRecording> {
|
||||
/// Create a new proposer factory.
|
||||
///
|
||||
/// Proof recording will be disabled when using proposers built by this instance to build blocks.
|
||||
pub fn new(
|
||||
spawn_handle: impl SpawnNamed + 'static,
|
||||
client: Arc<C>,
|
||||
@@ -81,7 +84,30 @@ impl<A, B, C> ProposerFactory<A, B, C> {
|
||||
max_block_size: DEFAULT_MAX_BLOCK_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C> ProposerFactory<A, B, C, EnableProofRecording> {
|
||||
/// Create a new proposer factory with proof recording enabled.
|
||||
///
|
||||
/// Each proposer created by this instance will record a proof while building a block.
|
||||
pub fn with_proof_recording(
|
||||
spawn_handle: impl SpawnNamed + 'static,
|
||||
client: Arc<C>,
|
||||
transaction_pool: Arc<A>,
|
||||
prometheus: Option<&PrometheusRegistry>,
|
||||
) -> Self {
|
||||
ProposerFactory {
|
||||
spawn_handle: Box::new(spawn_handle),
|
||||
client,
|
||||
transaction_pool,
|
||||
metrics: PrometheusMetrics::new(prometheus),
|
||||
_phantom: PhantomData,
|
||||
max_block_size: DEFAULT_MAX_BLOCK_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C, PR> ProposerFactory<A, B, C, PR> {
|
||||
/// Set the maximum block size in bytes.
|
||||
///
|
||||
/// The default value for the maximum block size is:
|
||||
@@ -91,7 +117,7 @@ impl<A, B, C> ProposerFactory<A, B, C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, Block, C, A> ProposerFactory<A, B, C>
|
||||
impl<B, Block, C, A, PR> ProposerFactory<A, B, C, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
@@ -101,18 +127,18 @@ impl<B, Block, C, A> ProposerFactory<A, B, C>
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
{
|
||||
pub fn init_with_now(
|
||||
fn init_with_now(
|
||||
&mut self,
|
||||
parent_header: &<Block as BlockT>::Header,
|
||||
now: Box<dyn Fn() -> time::Instant + Send + Sync>,
|
||||
) -> Proposer<B, Block, C, A> {
|
||||
) -> Proposer<B, Block, C, A, PR> {
|
||||
let parent_hash = parent_header.hash();
|
||||
|
||||
let id = BlockId::hash(parent_hash);
|
||||
|
||||
info!("🙌 Starting consensus session on top of parent {:?}", parent_hash);
|
||||
|
||||
let proposer = Proposer {
|
||||
let proposer = Proposer::<_, _, _, _, PR> {
|
||||
spawn_handle: self.spawn_handle.clone(),
|
||||
client: self.client.clone(),
|
||||
parent_hash,
|
||||
@@ -129,8 +155,8 @@ impl<B, Block, C, A> ProposerFactory<A, B, C>
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, Block, C> sp_consensus::Environment<Block> for
|
||||
ProposerFactory<A, B, C>
|
||||
impl<A, B, Block, C, PR> sp_consensus::Environment<Block> for
|
||||
ProposerFactory<A, B, C, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
@@ -139,9 +165,10 @@ impl<A, B, Block, C> sp_consensus::Environment<Block> for
|
||||
+ Send + Sync + 'static,
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
{
|
||||
type CreateProposer = future::Ready<Result<Self::Proposer, Self::Error>>;
|
||||
type Proposer = Proposer<B, Block, C, A>;
|
||||
type Proposer = Proposer<B, Block, C, A, PR>;
|
||||
type Error = sp_blockchain::Error;
|
||||
|
||||
fn init(
|
||||
@@ -153,7 +180,7 @@ impl<A, B, Block, C> sp_consensus::Environment<Block> for
|
||||
}
|
||||
|
||||
/// The proposer logic.
|
||||
pub struct Proposer<B, Block: BlockT, C, A: TransactionPool> {
|
||||
pub struct Proposer<B, Block: BlockT, C, A: TransactionPool, PR> {
|
||||
spawn_handle: Box<dyn SpawnNamed>,
|
||||
client: Arc<C>,
|
||||
parent_hash: <Block as BlockT>::Hash,
|
||||
@@ -162,12 +189,12 @@ pub struct Proposer<B, Block: BlockT, C, A: TransactionPool> {
|
||||
transaction_pool: Arc<A>,
|
||||
now: Box<dyn Fn() -> time::Instant + Send + Sync>,
|
||||
metrics: PrometheusMetrics,
|
||||
_phantom: PhantomData<B>,
|
||||
_phantom: PhantomData<(B, PR)>,
|
||||
max_block_size: usize,
|
||||
}
|
||||
|
||||
impl<A, B, Block, C> sp_consensus::Proposer<Block> for
|
||||
Proposer<B, Block, C, A>
|
||||
impl<A, B, Block, C, PR> sp_consensus::Proposer<Block> for
|
||||
Proposer<B, Block, C, A, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block> + 'static,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
@@ -176,19 +203,21 @@ impl<A, B, Block, C> sp_consensus::Proposer<Block> for
|
||||
+ Send + Sync + 'static,
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
{
|
||||
type Transaction = backend::TransactionFor<B, Block>;
|
||||
type Proposal = Pin<Box<dyn Future<
|
||||
Output = Result<Proposal<Block, Self::Transaction>, Self::Error>
|
||||
Output = Result<Proposal<Block, Self::Transaction, PR::Proof>, Self::Error>
|
||||
> + Send>>;
|
||||
type Error = sp_blockchain::Error;
|
||||
type ProofRecording = PR;
|
||||
type Proof = PR::Proof;
|
||||
|
||||
fn propose(
|
||||
self,
|
||||
inherent_data: InherentData,
|
||||
inherent_digests: DigestFor<Block>,
|
||||
max_duration: time::Duration,
|
||||
record_proof: RecordProof,
|
||||
) -> Self::Proposal {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let spawn_handle = self.spawn_handle.clone();
|
||||
@@ -200,7 +229,6 @@ impl<A, B, Block, C> sp_consensus::Proposer<Block> for
|
||||
inherent_data,
|
||||
inherent_digests,
|
||||
deadline,
|
||||
record_proof,
|
||||
).await;
|
||||
if tx.send(res).is_err() {
|
||||
trace!("Could not send block production result to proposer!");
|
||||
@@ -213,7 +241,7 @@ impl<A, B, Block, C> sp_consensus::Proposer<Block> for
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, Block, C> Proposer<B, Block, C, A>
|
||||
impl<A, B, Block, C, PR> Proposer<B, Block, C, A, PR>
|
||||
where
|
||||
A: TransactionPool<Block = Block>,
|
||||
B: backend::Backend<Block> + Send + Sync + 'static,
|
||||
@@ -222,14 +250,14 @@ impl<A, B, Block, C> Proposer<B, Block, C, A>
|
||||
+ Send + Sync + 'static,
|
||||
C::Api: ApiExt<Block, StateBackend = backend::StateBackendFor<B, Block>>
|
||||
+ BlockBuilderApi<Block>,
|
||||
PR: ProofRecording,
|
||||
{
|
||||
async fn propose_with(
|
||||
self,
|
||||
inherent_data: InherentData,
|
||||
inherent_digests: DigestFor<Block>,
|
||||
deadline: time::Instant,
|
||||
record_proof: RecordProof,
|
||||
) -> Result<Proposal<Block, backend::TransactionFor<B, Block>>, sp_blockchain::Error> {
|
||||
) -> Result<Proposal<Block, backend::TransactionFor<B, Block>, PR::Proof>, sp_blockchain::Error> {
|
||||
/// If the block is full we will attempt to push at most
|
||||
/// this number of transactions before quitting for real.
|
||||
/// It allows us to increase block utilization.
|
||||
@@ -238,7 +266,7 @@ impl<A, B, Block, C> Proposer<B, Block, C, A>
|
||||
let mut block_builder = self.client.new_block_at(
|
||||
&self.parent_id,
|
||||
inherent_digests,
|
||||
record_proof,
|
||||
PR::ENABLED,
|
||||
)?;
|
||||
|
||||
for inherent in block_builder.create_inherents(inherent_data)? {
|
||||
@@ -361,6 +389,8 @@ impl<A, B, Block, C> Proposer<B, Block, C, A>
|
||||
error!("Failed to evaluate authored block: {:?}", err);
|
||||
}
|
||||
|
||||
let proof = PR::into_proof(proof)
|
||||
.map_err(|e| sp_blockchain::Error::Application(Box::new(e)))?;
|
||||
Ok(Proposal { block, proof, storage_changes })
|
||||
}
|
||||
}
|
||||
@@ -452,7 +482,7 @@ mod tests {
|
||||
// when
|
||||
let deadline = time::Duration::from_secs(3);
|
||||
let block = futures::executor::block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, RecordProof::No)
|
||||
proposer.propose(Default::default(), Default::default(), deadline)
|
||||
).map(|r| r.block).unwrap();
|
||||
|
||||
// then
|
||||
@@ -497,7 +527,7 @@ mod tests {
|
||||
|
||||
let deadline = time::Duration::from_secs(1);
|
||||
futures::executor::block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, RecordProof::No)
|
||||
proposer.propose(Default::default(), Default::default(), deadline)
|
||||
).map(|r| r.block).unwrap();
|
||||
}
|
||||
|
||||
@@ -543,7 +573,7 @@ mod tests {
|
||||
|
||||
let deadline = time::Duration::from_secs(9);
|
||||
let proposal = futures::executor::block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, RecordProof::No),
|
||||
proposer.propose(Default::default(), Default::default(), deadline),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(proposal.block.extrinsics().len(), 1);
|
||||
@@ -624,7 +654,7 @@ mod tests {
|
||||
// when
|
||||
let deadline = time::Duration::from_secs(9);
|
||||
let block = futures::executor::block_on(
|
||||
proposer.propose(Default::default(), Default::default(), deadline, RecordProof::No)
|
||||
proposer.propose(Default::default(), Default::default(), deadline)
|
||||
).map(|r| r.block).unwrap();
|
||||
|
||||
// then
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
//!
|
||||
//! ```
|
||||
//! # use sc_basic_authorship::ProposerFactory;
|
||||
//! # use sp_consensus::{Environment, Proposer, RecordProof};
|
||||
//! # use sp_consensus::{Environment, Proposer};
|
||||
//! # use sp_runtime::generic::BlockId;
|
||||
//! # use std::{sync::Arc, time::Duration};
|
||||
//! # use substrate_test_runtime_client::{
|
||||
@@ -61,7 +61,6 @@
|
||||
//! Default::default(),
|
||||
//! Default::default(),
|
||||
//! Duration::from_secs(2),
|
||||
//! RecordProof::Yes,
|
||||
//! );
|
||||
//!
|
||||
//! // We wait until the proposition is performed.
|
||||
|
||||
Reference in New Issue
Block a user