Rework inherent data client side (#8526)

* Lol

* Yeah

* Moare

* adaasda

* Convert AURA to new pallet macro

* AURA: Switch to `CurrentSlot` instead of `LastTimestamp`

This switches AURA to use `CurrentSlot` instead of `LastTimestamp`.

* Add missing file

* Update frame/aura/src/migrations.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Remove the runtime side provide inherent code

* Use correct weight

* Add TODO

* Remove the Inherent from AURA

* 🤦

* Remove unused stuff

* Update primitives authorship

* Fix babe inherent data provider

* Fix consensus-uncles

* Fix BABE

* Do some further changes to authorship primitives... :D

* More work

* Make it compile the happy path

* Make it async!

* Take hash

* More stuff

* Hacks

* Revert "Hacks"

This reverts commit cfffad88668cfdebf632a59c4fbfada001ef8251.

* Fix

* Make `execute_block` return the final block header

* Move Aura digest stuff

* Make it possible to disable equivocation checking

* Fix fix fix

* Some refactorings

* Comment

* Fixes fixes fixes

* More cleanups

* Some love

* Better love

* Make slot duration being exposed as `Duration` to the outside

* Some slot info love

* Add `build_aura_worker` utility function

* Copy copy copy

* Some stuff

* Start fixing pow

* Fix pow

* Remove some bounds

* More work

* Make grandpa work

* Make slots use `async_trait`

* Introduce `SharedData`

* Add test and fix bugs

* Switch to `SharedData`

* Make grandpa tests working

* More Babe work

* Make grandpa work

* Introduce `SharedData`

* Add test and fix bugs

* Switch to `SharedData`

* Make grandpa tests working

* More Babe work

* Make it async

* Fix fix

* Use `async_trait` in sc-consensus-slots

This makes the code a little bit easier to read and also expresses that
there can always only be one call at a time to `on_slot`.

* Make grandpa tests compile

* More Babe tests work

* Fix network test

* Start fixing service test

* Finish service-test

* Fix sc-consensus-aura

* Fix fix fix

* More fixes

* Make everything compile *yeah*

* Make manual-seal compile

* More fixes

* Start fixing Aura

* Fix Aura tests

* Fix Babe tests

* Make everything compile

* Move code around and switch to async_trait

* Fix Babe

* Docs docs docs

* Move to FRAME

* Fix fix fix

* Make everything compile

* Last cleanups

* Fix integration test

* Change slot usage of the timestamp

* We really need to switch to `impl-trait-for-tuples`

* Update primitives/inherents/src/lib.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Update primitives/inherents/src/lib.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Update primitives/inherents/src/lib.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Some extra logging

* Remove dbg!

* Update primitives/consensus/common/src/import_queue/basic_queue.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
Bastian Köcher
2021-05-03 16:39:25 +02:00
committed by GitHub
parent ef07c3be0d
commit 2675741a09
52 changed files with 1506 additions and 1178 deletions
@@ -24,8 +24,8 @@ use codec::Encode;
use std::{borrow::Cow, sync::{Arc, atomic}, time::SystemTime};
use sc_client_api::AuxStore;
use sc_consensus_babe::{
Config, Epoch, authorship, CompatibleDigestItem, BabeIntermediate,
register_babe_inherent_data_provider, INTERMEDIATE_KEY, find_pre_digest,
Config, Epoch, authorship, CompatibleDigestItem, BabeIntermediate, INTERMEDIATE_KEY,
find_pre_digest,
};
use sc_consensus_epochs::{SharedEpochChanges, descendent_query, ViableEpochDescriptor, EpochHeader};
use sp_keystore::SyncCryptoStorePtr;
@@ -38,12 +38,12 @@ use sp_consensus_babe::{
BabeApi, inherents::BabeInherentData, ConsensusLog, BABE_ENGINE_ID, AuthorityId,
digests::{PreDigest, SecondaryPlainPreDigest, NextEpochDescriptor}, BabeAuthorityWeight,
};
use sp_inherents::{InherentDataProviders, InherentData, ProvideInherentData, InherentIdentifier};
use sp_inherents::{InherentData, InherentDataProvider, InherentIdentifier};
use sp_runtime::{
traits::{DigestItemFor, DigestFor, Block as BlockT, Zero, Header},
generic::{Digest, BlockId},
};
use sp_timestamp::{InherentType, InherentError, INHERENT_IDENTIFIER, TimestampInherentData};
use sp_timestamp::{InherentType, INHERENT_IDENTIFIER, TimestampInherentData};
/// Provides BABE-compatible predigests and BlockImportParams.
/// Intended for use with BABE runtimes.
@@ -73,7 +73,6 @@ impl<B, C> BabeConsensusDataProvider<B, C>
pub fn new(
client: Arc<C>,
keystore: SyncCryptoStorePtr,
provider: &InherentDataProviders,
epoch_changes: SharedEpochChanges<B, Epoch>,
authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
) -> Result<Self, Error> {
@@ -82,10 +81,6 @@ impl<B, C> BabeConsensusDataProvider<B, C>
}
let config = Config::get_or_compute(&*client)?;
let timestamp_provider = SlotTimestampProvider::new(client.clone())?;
provider.register_provider(timestamp_provider)?;
register_babe_inherent_data_provider(provider, config.slot_duration())?;
Ok(Self {
config,
@@ -131,7 +126,8 @@ impl<B, C> ConsensusDataProvider<B> for BabeConsensusDataProvider<B, C>
type Transaction = TransactionFor<C, B>;
fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result<DigestFor<B>, Error> {
let slot = inherents.babe_inherent_data()?;
let slot = inherents.babe_inherent_data()?
.ok_or_else(|| Error::StringError("No babe inherent data".into()))?;
let epoch = self.epoch(parent, slot)?;
// this is a dev node environment, we should always be able to claim a slot.
@@ -194,7 +190,8 @@ impl<B, C> ConsensusDataProvider<B> for BabeConsensusDataProvider<B, C>
params: &mut BlockImportParams<B, Self::Transaction>,
inherents: &InherentData
) -> Result<(), Error> {
let slot = inherents.babe_inherent_data()?;
let slot = inherents.babe_inherent_data()?
.ok_or_else(|| Error::StringError("No babe inherent data".into()))?;
let epoch_changes = self.epoch_changes.shared_data();
let mut epoch_descriptor = epoch_changes
.epoch_descriptor_for_child_of(
@@ -216,7 +213,9 @@ impl<B, C> ConsensusDataProvider<B> for BabeConsensusDataProvider<B, C>
if !has_authority {
log::info!(target: "manual-seal", "authority not found");
let slot = *inherents.timestamp_inherent_data()? / self.config.slot_duration;
let timestamp = inherents.timestamp_inherent_data()?
.ok_or_else(|| Error::StringError("No timestamp inherent data".into()))?;
let slot = *timestamp / self.config.slot_duration;
// manually hard code epoch descriptor
epoch_descriptor = match epoch_descriptor {
ViableEpochDescriptor::Signaled(identifier, _header) => {
@@ -243,14 +242,14 @@ impl<B, C> ConsensusDataProvider<B> for BabeConsensusDataProvider<B, C>
/// Provide duration since unix epoch in millisecond for timestamp inherent.
/// Mocks the timestamp inherent to always produce the timestamp for the next babe slot.
struct SlotTimestampProvider {
pub struct SlotTimestampProvider {
time: atomic::AtomicU64,
slot_duration: u64
}
impl SlotTimestampProvider {
/// create a new mocked time stamp provider.
fn new<B, C>(client: Arc<C>) -> Result<Self, Error>
/// 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>,
@@ -281,11 +280,8 @@ impl SlotTimestampProvider {
}
}
impl ProvideInherentData for SlotTimestampProvider {
fn inherent_identifier(&self) -> &'static InherentIdentifier {
&INHERENT_IDENTIFIER
}
#[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(
@@ -296,7 +292,11 @@ impl ProvideInherentData for SlotTimestampProvider {
Ok(())
}
fn error_to_string(&self, error: &[u8]) -> Option<String> {
InherentError::try_from(&INHERENT_IDENTIFIER, error).map(|e| format!("{:?}", e))
async fn try_handle_error(
&self,
_: &InherentIdentifier,
_: &[u8],
) -> Option<Result<(), sp_inherents::Error>> {
None
}
}
@@ -26,7 +26,7 @@ use sp_consensus::{
import_queue::{Verifier, BasicQueue, CacheKeyId, BoxBlockImport},
};
use sp_blockchain::HeaderBackend;
use sp_inherents::InherentDataProviders;
use sp_inherents::CreateInherentDataProviders;
use sp_runtime::{traits::Block as BlockT, Justifications, ConsensusEngineId};
use sc_client_api::backend::{Backend as ClientBackend, Finalizer};
use sc_transaction_pool::txpool;
@@ -94,7 +94,7 @@ pub fn import_queue<Block, Transaction>(
}
/// Params required to start the instant sealing authorship task.
pub struct ManualSealParams<B: BlockT, BI, E, C: ProvideRuntimeApi<B>, A: txpool::ChainApi, SC, CS> {
pub struct ManualSealParams<B: BlockT, BI, E, C: ProvideRuntimeApi<B>, A: txpool::ChainApi, SC, CS, CIDP> {
/// Block import instance for well. importing blocks.
pub block_import: BI,
@@ -117,12 +117,12 @@ pub struct ManualSealParams<B: BlockT, BI, E, C: ProvideRuntimeApi<B>, A: txpool
/// Digest provider for inclusion in blocks.
pub consensus_data_provider: Option<Box<dyn ConsensusDataProvider<B, Transaction = TransactionFor<C, B>>>>,
/// Provider for inherents to include in blocks.
pub inherent_data_providers: InherentDataProviders,
/// Something that can create the inherent data providers.
pub create_inherent_data_providers: CIDP,
}
/// Params required to start the manual sealing authorship task.
pub struct InstantSealParams<B: BlockT, BI, E, C: ProvideRuntimeApi<B>, A: txpool::ChainApi, SC> {
pub struct InstantSealParams<B: BlockT, BI, E, C: ProvideRuntimeApi<B>, A: txpool::ChainApi, SC, CIDP> {
/// Block import instance for well. importing blocks.
pub block_import: BI,
@@ -141,12 +141,12 @@ pub struct InstantSealParams<B: BlockT, BI, E, C: ProvideRuntimeApi<B>, A: txpoo
/// Digest provider for inclusion in blocks.
pub consensus_data_provider: Option<Box<dyn ConsensusDataProvider<B, Transaction = TransactionFor<C, B>>>>,
/// Provider for inherents to include in blocks.
pub inherent_data_providers: InherentDataProviders,
/// Something that can create the inherent data providers.
pub create_inherent_data_providers: CIDP,
}
/// Creates the background authorship task for the manual seal engine.
pub async fn run_manual_seal<B, BI, CB, E, C, A, SC, CS>(
pub async fn run_manual_seal<B, BI, CB, E, C, A, SC, CS, CIDP>(
ManualSealParams {
mut block_import,
mut env,
@@ -154,10 +154,9 @@ pub async fn run_manual_seal<B, BI, CB, E, C, A, SC, CS>(
pool,
mut commands_stream,
select_chain,
inherent_data_providers,
consensus_data_provider,
..
}: ManualSealParams<B, BI, E, C, A, SC, CS>
create_inherent_data_providers,
}: ManualSealParams<B, BI, E, C, A, SC, CS, CIDP>
)
where
A: txpool::ChainApi<Block=B> + 'static,
@@ -171,6 +170,7 @@ pub async fn run_manual_seal<B, BI, CB, E, C, A, SC, CS>(
CS: Stream<Item=EngineCommand<<B as BlockT>::Hash>> + Unpin + 'static,
SC: SelectChain<B> + 'static,
TransactionFor<C, B>: 'static,
CIDP: CreateInherentDataProviders<B, ()>,
{
while let Some(command) = commands_stream.next().await {
match command {
@@ -189,10 +189,10 @@ pub async fn run_manual_seal<B, BI, CB, E, C, A, SC, CS>(
env: &mut env,
select_chain: &select_chain,
block_import: &mut block_import,
inherent_data_provider: &inherent_data_providers,
consensus_data_provider: consensus_data_provider.as_ref().map(|p| &**p),
pool: pool.clone(),
client: client.clone(),
create_inherent_data_providers: &create_inherent_data_providers,
}
).await;
}
@@ -215,7 +215,7 @@ pub async fn run_manual_seal<B, BI, CB, E, C, A, SC, CS>(
/// runs the background authorship task for the instant seal engine.
/// instant-seal creates a new block for every transaction imported into
/// the transaction pool.
pub async fn run_instant_seal<B, BI, CB, E, C, A, SC>(
pub async fn run_instant_seal<B, BI, CB, E, C, A, SC, CIDP>(
InstantSealParams {
block_import,
env,
@@ -223,9 +223,8 @@ pub async fn run_instant_seal<B, BI, CB, E, C, A, SC>(
pool,
select_chain,
consensus_data_provider,
inherent_data_providers,
..
}: InstantSealParams<B, BI, E, C, A, SC>
create_inherent_data_providers,
}: InstantSealParams<B, BI, E, C, A, SC, CIDP>
)
where
A: txpool::ChainApi<Block=B> + 'static,
@@ -238,6 +237,7 @@ pub async fn run_instant_seal<B, BI, CB, E, C, A, SC>(
E::Proposer: Proposer<B, Transaction = TransactionFor<C, B>>,
SC: SelectChain<B> + 'static,
TransactionFor<C, B>: 'static,
CIDP: CreateInherentDataProviders<B, ()>,
{
// instant-seal creates blocks as soon as transactions are imported
// into the transaction pool.
@@ -261,7 +261,7 @@ pub async fn run_instant_seal<B, BI, CB, E, C, A, SC>(
commands_stream,
select_chain,
consensus_data_provider,
inherent_data_providers,
create_inherent_data_providers,
}
).await
}
@@ -280,7 +280,6 @@ mod tests {
use sp_transaction_pool::{TransactionPool, MaintainedTransactionPool, TransactionSource};
use sp_runtime::generic::BlockId;
use sp_consensus::ImportedAux;
use sp_inherents::InherentDataProviders;
use sc_basic_authorship::ProposerFactory;
use sc_client_api::BlockBackend;
@@ -295,7 +294,6 @@ mod tests {
let builder = TestClientBuilder::new();
let (client, select_chain) = builder.build_with_longest_chain();
let client = Arc::new(client);
let inherent_data_providers = InherentDataProviders::new();
let spawner = sp_core::testing::TaskExecutor::new();
let pool = Arc::new(BasicPool::with_revalidation_type(
Options::default(), true.into(), api(), None, RevalidationType::Full, spawner.clone(),
@@ -330,7 +328,7 @@ mod tests {
pool: pool.pool().clone(),
commands_stream,
select_chain,
inherent_data_providers,
create_inherent_data_providers: |_, _| async { Ok(()) },
consensus_data_provider: None,
}
);
@@ -367,10 +365,14 @@ mod tests {
let builder = TestClientBuilder::new();
let (client, select_chain) = builder.build_with_longest_chain();
let client = Arc::new(client);
let inherent_data_providers = InherentDataProviders::new();
let spawner = sp_core::testing::TaskExecutor::new();
let pool = Arc::new(BasicPool::with_revalidation_type(
Options::default(), true.into(), api(), None, RevalidationType::Full, spawner.clone(),
Options::default(),
true.into(),
api(),
None,
RevalidationType::Full,
spawner.clone(),
));
let env = ProposerFactory::new(
spawner.clone(),
@@ -390,7 +392,7 @@ mod tests {
commands_stream,
select_chain,
consensus_data_provider: None,
inherent_data_providers,
create_inherent_data_providers: |_, _| async { Ok(()) },
}
);
std::thread::spawn(|| {
@@ -442,11 +444,15 @@ mod tests {
let builder = TestClientBuilder::new();
let (client, select_chain) = builder.build_with_longest_chain();
let client = Arc::new(client);
let inherent_data_providers = InherentDataProviders::new();
let pool_api = api();
let spawner = sp_core::testing::TaskExecutor::new();
let pool = Arc::new(BasicPool::with_revalidation_type(
Options::default(), true.into(), pool_api.clone(), None, RevalidationType::Full, spawner.clone(),
Options::default(),
true.into(),
pool_api.clone(),
None,
RevalidationType::Full,
spawner.clone(),
));
let env = ProposerFactory::new(
spawner.clone(),
@@ -466,7 +472,7 @@ mod tests {
commands_stream,
select_chain,
consensus_data_provider: None,
inherent_data_providers,
create_inherent_data_providers: |_, _| async { Ok(()) },
}
);
std::thread::spawn(|| {
@@ -528,7 +534,7 @@ mod tests {
pool_api.add_block(block, true);
pool_api.increment_nonce(Alice.into());
assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Alice, 2)).await.is_ok());
assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Bob, 0)).await.is_ok());
let (tx2, rx2) = futures::channel::oneshot::channel();
assert!(sink.send(EngineCommand::SealNewBlock {
parent_hash: Some(created_block.hash),
@@ -33,14 +33,14 @@ use sp_consensus::{
use sp_blockchain::HeaderBackend;
use std::collections::HashMap;
use std::time::Duration;
use sp_inherents::InherentDataProviders;
use sp_inherents::{CreateInherentDataProviders, InherentDataProvider};
use sp_api::{ProvideRuntimeApi, TransactionFor};
/// max duration for creating a proposal in secs
pub const MAX_PROPOSAL_DURATION: u64 = 10;
/// params for sealing a new block
pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi<B>, E, P: txpool::ChainApi> {
pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi<B>, E, P: txpool::ChainApi, CIDP> {
/// if true, empty blocks(without extrinsics) will be created.
/// otherwise, will return Error::EmptyTransactionPool.
pub create_empty: bool,
@@ -62,12 +62,12 @@ pub struct SealBlockParams<'a, B: BlockT, BI, SC, C: ProvideRuntimeApi<B>, E, P:
pub consensus_data_provider: Option<&'a dyn ConsensusDataProvider<B, Transaction = TransactionFor<C, B>>>,
/// block import object
pub block_import: &'a mut BI,
/// inherent data provider
pub inherent_data_provider: &'a InherentDataProviders,
/// Something that can create the inherent data providers.
pub create_inherent_data_providers: &'a CIDP,
}
/// seals a new block with the given params
pub async fn seal_block<B, BI, SC, C, E, P>(
pub async fn seal_block<B, BI, SC, C, E, P, CIDP>(
SealBlockParams {
create_empty,
finalize,
@@ -77,11 +77,10 @@ pub async fn seal_block<B, BI, SC, C, E, P>(
select_chain,
block_import,
env,
inherent_data_provider,
create_inherent_data_providers,
consensus_data_provider: digest_provider,
mut sender,
..
}: SealBlockParams<'_, B, BI, SC, C, E, P>
}: SealBlockParams<'_, B, BI, SC, C, E, P, CIDP>
)
where
B: BlockT,
@@ -93,6 +92,7 @@ pub async fn seal_block<B, BI, SC, C, E, P>(
P: txpool::ChainApi<Block=B>,
SC: SelectChain<B>,
TransactionFor<C, B>: 'static,
CIDP: CreateInherentDataProviders<B, ()>,
{
let future = async {
if pool.validated_pool().status().ready == 0 && !create_empty {
@@ -109,19 +109,29 @@ pub async fn seal_block<B, BI, SC, C, E, P>(
None => select_chain.best_chain()?
};
let inherent_data_providers =
create_inherent_data_providers
.create_inherent_data_providers(
parent.hash(),
(),
)
.await
.map_err(|e| Error::Other(e))?;
let inherent_data = inherent_data_providers.create_inherent_data()?;
let proposer = env.init(&parent)
.map_err(|err| Error::StringError(format!("{:?}", err))).await?;
let id = inherent_data_provider.create_inherent_data()?;
let inherents_len = id.len();
let inherents_len = inherent_data.len();
let digest = if let Some(digest_provider) = digest_provider {
digest_provider.create_digest(&parent, &id)?
digest_provider.create_digest(&parent, &inherent_data)?
} else {
Default::default()
};
let proposal = proposer.propose(
id.clone(),
inherent_data.clone(),
digest,
Duration::from_secs(MAX_PROPOSAL_DURATION),
None,
@@ -139,7 +149,7 @@ pub async fn seal_block<B, BI, SC, C, E, P>(
params.storage_changes = Some(proposal.storage_changes);
if let Some(digest_provider) = digest_provider {
digest_provider.append_block_import(&parent, &mut params, &id)?;
digest_provider.append_block_import(&parent, &mut params, &inherent_data)?;
}
match block_import.import_block(params, HashMap::new()).await? {