mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 09:21:05 +00:00
Adds AuraConsensusDataProvider (#10503)
* adds support for parachains to test-runner * adds file header * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * proper docs, remove unused _client * fixes * Update client/consensus/manual-seal/src/consensus/timestamp.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update client/consensus/manual-seal/src/consensus/timestamp.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * pr fixes Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
@@ -490,24 +490,34 @@ fn aura_err<B: BlockT>(error: Error<B>) -> Error<B> {
|
||||
error
|
||||
}
|
||||
|
||||
/// Aura Errors
|
||||
#[derive(derive_more::Display, Debug)]
|
||||
enum Error<B: BlockT> {
|
||||
pub enum Error<B: BlockT> {
|
||||
/// Multiple Aura pre-runtime headers
|
||||
#[display(fmt = "Multiple Aura pre-runtime headers")]
|
||||
MultipleHeaders,
|
||||
/// No Aura pre-runtime digest found
|
||||
#[display(fmt = "No Aura pre-runtime digest found")]
|
||||
NoDigestFound,
|
||||
/// Header is unsealed
|
||||
#[display(fmt = "Header {:?} is unsealed", _0)]
|
||||
HeaderUnsealed(B::Hash),
|
||||
/// Header has a bad seal
|
||||
#[display(fmt = "Header {:?} has a bad seal", _0)]
|
||||
HeaderBadSeal(B::Hash),
|
||||
/// Slot Author not found
|
||||
#[display(fmt = "Slot Author not found")]
|
||||
SlotAuthorNotFound,
|
||||
/// Bad signature
|
||||
#[display(fmt = "Bad signature on {:?}", _0)]
|
||||
BadSignature(B::Hash),
|
||||
/// Client Error
|
||||
Client(sp_blockchain::Error),
|
||||
/// Unknown inherent error for identifier
|
||||
#[display(fmt = "Unknown inherent error for identifier: {}", "String::from_utf8_lossy(_0)")]
|
||||
UnknownInherentError(sp_inherents::InherentIdentifier),
|
||||
#[display(fmt = "Inherent error: {}", _0)]
|
||||
/// Inherents Error
|
||||
Inherent(sp_inherents::Error),
|
||||
}
|
||||
|
||||
@@ -517,7 +527,8 @@ impl<B: BlockT> std::convert::From<Error<B>> for String {
|
||||
}
|
||||
}
|
||||
|
||||
fn find_pre_digest<B: BlockT, Signature: Codec>(header: &B::Header) -> Result<Slot, Error<B>> {
|
||||
/// Get pre-digests from the header
|
||||
pub fn find_pre_digest<B: BlockT, Signature: Codec>(header: &B::Header) -> Result<Slot, Error<B>> {
|
||||
if header.number().is_zero() {
|
||||
return Ok(0.into())
|
||||
}
|
||||
|
||||
@@ -27,8 +27,10 @@ async-trait = "0.1.50"
|
||||
sc-client-api = { path = "../../api", version = "4.0.0-dev" }
|
||||
sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" }
|
||||
sc-consensus-babe = { path = "../../consensus/babe", version = "0.10.0-dev" }
|
||||
sc-consensus-aura = { path = "../../consensus/aura", version = "0.10.0-dev" }
|
||||
sc-consensus-epochs = { path = "../../consensus/epochs", version = "0.10.0-dev" }
|
||||
sp-consensus-babe = { path = "../../../primitives/consensus/babe", version = "0.10.0-dev" }
|
||||
sp-consensus-aura = { path = "../../../primitives/consensus/aura", version = "0.10.0-dev" }
|
||||
|
||||
sc-transaction-pool = { path = "../../transaction-pool", version = "4.0.0-dev" }
|
||||
sp-blockchain = { path = "../../../primitives/blockchain", version = "4.0.0-dev" }
|
||||
|
||||
@@ -23,7 +23,9 @@ use sc_consensus::BlockImportParams;
|
||||
use sp_inherents::InherentData;
|
||||
use sp_runtime::{traits::Block as BlockT, Digest};
|
||||
|
||||
pub mod aura;
|
||||
pub mod babe;
|
||||
pub mod timestamp;
|
||||
|
||||
/// Consensus data provider, manual seal uses this trait object for authoring blocks valid
|
||||
/// for any runtime.
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program 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.
|
||||
|
||||
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Aura consensus data provider, This allows manual seal author blocks that are valid for
|
||||
//! runtimes that expect the aura-specific digests.
|
||||
|
||||
use crate::{ConsensusDataProvider, Error};
|
||||
use sc_client_api::{AuxStore, UsageProvider};
|
||||
use sc_consensus::BlockImportParams;
|
||||
use sc_consensus_aura::slot_duration;
|
||||
use sp_api::{ProvideRuntimeApi, TransactionFor};
|
||||
use sp_blockchain::{HeaderBackend, HeaderMetadata};
|
||||
use sp_consensus_aura::{
|
||||
digests::CompatibleDigestItem,
|
||||
sr25519::{AuthorityId, AuthoritySignature},
|
||||
AuraApi,
|
||||
};
|
||||
use sp_inherents::InherentData;
|
||||
use sp_runtime::{traits::Block as BlockT, Digest, DigestItem};
|
||||
use sp_timestamp::TimestampInherentData;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
|
||||
/// Consensus data provider for Aura.
|
||||
pub struct AuraConsensusDataProvider<B, C> {
|
||||
// slot duration in milliseconds
|
||||
slot_duration: u64,
|
||||
// phantom data for required generics
|
||||
_phantom: PhantomData<(B, C)>,
|
||||
}
|
||||
|
||||
impl<B, C> AuraConsensusDataProvider<B, C>
|
||||
where
|
||||
B: BlockT,
|
||||
C: AuxStore + ProvideRuntimeApi<B> + UsageProvider<B>,
|
||||
C::Api: AuraApi<B, AuthorityId>,
|
||||
{
|
||||
/// Creates a new instance of the [`AuraConsensusDataProvider`], requires that `client`
|
||||
/// implements [`sp_consensus_aura::AuraApi`]
|
||||
pub fn new(client: Arc<C>) -> Self {
|
||||
let slot_duration =
|
||||
(*slot_duration(&*client).expect("slot_duration is always present; qed.")).get();
|
||||
|
||||
Self { slot_duration, _phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, C> ConsensusDataProvider<B> for AuraConsensusDataProvider<B, C>
|
||||
where
|
||||
B: BlockT,
|
||||
C: AuxStore
|
||||
+ HeaderBackend<B>
|
||||
+ HeaderMetadata<B, Error = sp_blockchain::Error>
|
||||
+ UsageProvider<B>
|
||||
+ ProvideRuntimeApi<B>,
|
||||
C::Api: AuraApi<B, AuthorityId>,
|
||||
{
|
||||
type Transaction = TransactionFor<C, B>;
|
||||
|
||||
fn create_digest(
|
||||
&self,
|
||||
_parent: &B::Header,
|
||||
inherents: &InherentData,
|
||||
) -> Result<Digest, Error> {
|
||||
let time_stamp =
|
||||
*inherents.timestamp_inherent_data()?.expect("Timestamp is always present; qed");
|
||||
// we always calculate the new slot number based on the current time-stamp and the slot
|
||||
// duration.
|
||||
let digest_item = <DigestItem as CompatibleDigestItem<AuthoritySignature>>::aura_pre_digest(
|
||||
(time_stamp / self.slot_duration).into(),
|
||||
);
|
||||
Ok(Digest { logs: vec![digest_item] })
|
||||
}
|
||||
|
||||
fn append_block_import(
|
||||
&self,
|
||||
_parent: &B::Header,
|
||||
_params: &mut BlockImportParams<B, Self::Transaction>,
|
||||
_inherents: &InherentData,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! BABE consensus data provider
|
||||
//! BABE consensus data provider, This allows manual seal author blocks that are valid for runtimes
|
||||
//! that expect babe-specific digests.
|
||||
|
||||
use super::ConsensusDataProvider;
|
||||
use crate::Error;
|
||||
@@ -30,11 +31,7 @@ use sc_consensus_epochs::{
|
||||
descendent_query, EpochHeader, SharedEpochChanges, ViableEpochDescriptor,
|
||||
};
|
||||
use sp_keystore::SyncCryptoStorePtr;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
sync::{atomic, Arc},
|
||||
time::SystemTime,
|
||||
};
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
use sc_consensus::{BlockImportParams, ForkChoiceStrategy, Verifier};
|
||||
use sp_api::{ProvideRuntimeApi, TransactionFor};
|
||||
@@ -46,13 +43,13 @@ use sp_consensus_babe::{
|
||||
AuthorityId, BabeApi, BabeAuthorityWeight, ConsensusLog, BABE_ENGINE_ID,
|
||||
};
|
||||
use sp_consensus_slots::Slot;
|
||||
use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier};
|
||||
use sp_inherents::InherentData;
|
||||
use sp_runtime::{
|
||||
generic::{BlockId, Digest},
|
||||
traits::{Block as BlockT, Header, Zero},
|
||||
traits::{Block as BlockT, Header},
|
||||
DigestItem,
|
||||
};
|
||||
use sp_timestamp::{InherentType, TimestampInherentData, INHERENT_IDENTIFIER};
|
||||
use sp_timestamp::TimestampInherentData;
|
||||
|
||||
/// Provides BABE-compatible predigests and BlockImportParams.
|
||||
/// Intended for use with BABE runtimes.
|
||||
@@ -311,67 +308,3 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide duration since unix epoch in millisecond for timestamp inherent.
|
||||
/// Mocks the timestamp inherent to always produce the timestamp for the next babe slot.
|
||||
pub struct SlotTimestampProvider {
|
||||
time: atomic::AtomicU64,
|
||||
slot_duration: u64,
|
||||
}
|
||||
|
||||
impl SlotTimestampProvider {
|
||||
/// Create a new mocked time stamp provider.
|
||||
pub fn new<B, C>(client: Arc<C>) -> Result<Self, Error>
|
||||
where
|
||||
B: BlockT,
|
||||
C: AuxStore + HeaderBackend<B> + ProvideRuntimeApi<B> + UsageProvider<B>,
|
||||
C::Api: BabeApi<B>,
|
||||
{
|
||||
let slot_duration = Config::get(&*client)?.slot_duration;
|
||||
let info = client.info();
|
||||
|
||||
// looks like this isn't the first block, rehydrate the fake time.
|
||||
// otherwise we'd be producing blocks for older slots.
|
||||
let time = if info.best_number != Zero::zero() {
|
||||
let header = client.header(BlockId::Hash(info.best_hash))?.unwrap();
|
||||
let slot = find_pre_digest::<B>(&header).unwrap().slot();
|
||||
// add the slot duration so there's no collision of slots
|
||||
(*slot * slot_duration) + slot_duration
|
||||
} else {
|
||||
// this is the first block, use the correct time.
|
||||
let now = SystemTime::now();
|
||||
now.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map_err(|err| Error::StringError(format!("{}", err)))?
|
||||
.as_millis() as u64
|
||||
};
|
||||
|
||||
Ok(Self { time: atomic::AtomicU64::new(time), slot_duration })
|
||||
}
|
||||
|
||||
/// Get the current slot number
|
||||
pub fn slot(&self) -> u64 {
|
||||
self.time.load(atomic::Ordering::SeqCst) / self.slot_duration
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InherentDataProvider for SlotTimestampProvider {
|
||||
fn provide_inherent_data(
|
||||
&self,
|
||||
inherent_data: &mut InherentData,
|
||||
) -> Result<(), sp_inherents::Error> {
|
||||
// we update the time here.
|
||||
let duration: InherentType =
|
||||
self.time.fetch_add(self.slot_duration, atomic::Ordering::SeqCst).into();
|
||||
inherent_data.put_data(INHERENT_IDENTIFIER, &duration)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn try_handle_error(
|
||||
&self,
|
||||
_: &InherentIdentifier,
|
||||
_: &[u8],
|
||||
) -> Option<Result<(), sp_inherents::Error>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program 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.
|
||||
|
||||
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Mocked timestamp inherent, allows for manual seal to create blocks for runtimes
|
||||
//! that expect this inherent.
|
||||
|
||||
use crate::Error;
|
||||
use sc_client_api::{AuxStore, UsageProvider};
|
||||
use sc_consensus_aura::slot_duration;
|
||||
use sc_consensus_babe::Config;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus_aura::{
|
||||
sr25519::{AuthorityId, AuthoritySignature},
|
||||
AuraApi,
|
||||
};
|
||||
use sp_consensus_babe::BabeApi;
|
||||
use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Zero},
|
||||
};
|
||||
use sp_timestamp::{InherentType, INHERENT_IDENTIFIER};
|
||||
use std::{
|
||||
sync::{atomic, Arc},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
/// Provide duration since unix epoch in millisecond for timestamp inherent.
|
||||
/// Mocks the timestamp inherent to always produce a valid timestamp for the next slot.
|
||||
///
|
||||
/// This works by either fetching the `slot_number` from the most recent header and dividing
|
||||
/// that value by `slot_duration` in order to fork chains that expect this inherent.
|
||||
///
|
||||
/// It produces timestamp inherents that are increaed by `slot_duraation` whenever
|
||||
/// `provide_inherent_data` is called.
|
||||
pub struct SlotTimestampProvider {
|
||||
// holds the unix millisecnd timestamp for the most recent block
|
||||
unix_millis: atomic::AtomicU64,
|
||||
// configured slot_duration in the runtime
|
||||
slot_duration: u64,
|
||||
}
|
||||
|
||||
impl SlotTimestampProvider {
|
||||
/// Create a new mocked time stamp provider, for babe.
|
||||
pub fn new_babe<B, C>(client: Arc<C>) -> Result<Self, Error>
|
||||
where
|
||||
B: BlockT,
|
||||
C: AuxStore + HeaderBackend<B> + ProvideRuntimeApi<B> + UsageProvider<B>,
|
||||
C::Api: BabeApi<B>,
|
||||
{
|
||||
let slot_duration = Config::get(&*client)?.slot_duration;
|
||||
|
||||
let time = Self::with_header(&client, slot_duration, |header| {
|
||||
let slot_number = *sc_consensus_babe::find_pre_digest::<B>(&header)
|
||||
.map_err(|err| format!("{}", err))?
|
||||
.slot();
|
||||
Ok(slot_number)
|
||||
})?;
|
||||
|
||||
Ok(Self { unix_millis: atomic::AtomicU64::new(time), slot_duration })
|
||||
}
|
||||
|
||||
/// Create a new mocked time stamp provider, for aura
|
||||
pub fn new_aura<B, C>(client: Arc<C>) -> Result<Self, Error>
|
||||
where
|
||||
B: BlockT,
|
||||
C: AuxStore + HeaderBackend<B> + ProvideRuntimeApi<B> + UsageProvider<B>,
|
||||
C::Api: AuraApi<B, AuthorityId>,
|
||||
{
|
||||
let slot_duration = (*slot_duration(&*client)?).get();
|
||||
|
||||
let time = Self::with_header(&client, slot_duration, |header| {
|
||||
let slot_number = *sc_consensus_aura::find_pre_digest::<B, AuthoritySignature>(&header)
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
Ok(slot_number)
|
||||
})?;
|
||||
|
||||
Ok(Self { unix_millis: atomic::AtomicU64::new(time), slot_duration })
|
||||
}
|
||||
|
||||
fn with_header<F, C, B>(client: &Arc<C>, slot_duration: u64, func: F) -> Result<u64, Error>
|
||||
where
|
||||
B: BlockT,
|
||||
C: AuxStore + HeaderBackend<B> + UsageProvider<B>,
|
||||
F: Fn(B::Header) -> Result<u64, Error>,
|
||||
{
|
||||
let info = client.info();
|
||||
|
||||
// looks like this isn't the first block, rehydrate the fake time.
|
||||
// otherwise we'd be producing blocks for older slots.
|
||||
let time = if info.best_number != Zero::zero() {
|
||||
let header = client
|
||||
.header(BlockId::Hash(info.best_hash))?
|
||||
.ok_or_else(|| "best header not found in the db!".to_string())?;
|
||||
let slot = func(header)?;
|
||||
// add the slot duration so there's no collision of slots
|
||||
(slot * slot_duration) + slot_duration
|
||||
} else {
|
||||
// this is the first block, use the correct time.
|
||||
let now = SystemTime::now();
|
||||
now.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map_err(|err| Error::StringError(format!("{}", err)))?
|
||||
.as_millis() as u64
|
||||
};
|
||||
|
||||
Ok(time)
|
||||
}
|
||||
|
||||
/// Get the current slot number
|
||||
pub fn slot(&self) -> u64 {
|
||||
self.unix_millis.load(atomic::Ordering::SeqCst) / self.slot_duration
|
||||
}
|
||||
|
||||
/// Gets the current time stamp.
|
||||
pub fn timestamp(&self) -> sp_timestamp::Timestamp {
|
||||
sp_timestamp::Timestamp::new(self.unix_millis.load(atomic::Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InherentDataProvider for SlotTimestampProvider {
|
||||
fn provide_inherent_data(
|
||||
&self,
|
||||
inherent_data: &mut InherentData,
|
||||
) -> Result<(), sp_inherents::Error> {
|
||||
// we update the time here.
|
||||
let new_time: InherentType =
|
||||
self.unix_millis.fetch_add(self.slot_duration, atomic::Ordering::SeqCst).into();
|
||||
inherent_data.put_data(INHERENT_IDENTIFIER, &new_time)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn try_handle_error(
|
||||
&self,
|
||||
_: &InherentIdentifier,
|
||||
_: &[u8],
|
||||
) -> Option<Result<(), sp_inherents::Error>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,6 @@ pub enum Error {
|
||||
BlockNotFound(String),
|
||||
/// Some string error
|
||||
#[display(fmt = "{}", _0)]
|
||||
#[from(ignore)]
|
||||
StringError(String),
|
||||
/// send error
|
||||
#[display(fmt = "Consensus process is terminating")]
|
||||
|
||||
Reference in New Issue
Block a user