Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Aura: Adds some compatibility mode to support old chains (#12492)
Browse files Browse the repository at this point in the history
* Aura: Adds some compatibility mode to support old chains

In #9132 we changed the way how we get the authorities
from the runtime. Before this mentioned pr we would call `initialize_block` before calling the
authorities runtime function. The problem with this was that when you have a block X that would
switch the authority set, it would already be signed by an authority of the new set. This was wrong,
as a block should only be signed by the current authority set. As this change is a hard fork, this
pr brings back the possibility for users that have a chain running with this old logic to upgrade.

They will need to use:
```
CompatibilityMode::UseInitializeBlock { until: some_block_in_the_future }
```

Using this compatibility mode will make the node behave like the old nodes, aka calling
`initialize_block` before doing the actual runtime call to `authorities`. Then when the given
`until` block is being build/imported the node switches to the new behaviour of not calling
`initialize_block` before. This is a hard fork, so the `until` block should be chosen wisely as a
point where all nodes in the network have upgraded.

* Fixes

* Make docs ready

* Update client/consensus/aura/src/lib.rs

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

* Update client/consensus/aura/src/lib.rs

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

* Update client/consensus/aura/src/lib.rs

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

* FMT

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
  • Loading branch information
bkchr and andresilva authored Oct 28, 2022
1 parent 83ed732 commit 4e1e17c
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 58 deletions.
2 changes: 2 additions & 0 deletions bin/node-template/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ pub fn new_partial(
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
compatibility_mode: Default::default(),
})?;

Ok(sc_service::PartialComponents {
Expand Down Expand Up @@ -280,6 +281,7 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32),
max_block_proposal_slot_portion: None,
telemetry: telemetry.as_ref().map(|x| x.handle()),
compatibility_mode: Default::default(),
},
)?;

Expand Down
84 changes: 42 additions & 42 deletions client/consensus/aura/src/import_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

//! Module implementing the logic for verifying and importing AuRa blocks.

use crate::{aura_err, authorities, find_pre_digest, slot_author, AuthorityId, Error};
use crate::{
aura_err, authorities, find_pre_digest, slot_author, AuthorityId, CompatibilityMode, Error,
};
use codec::{Codec, Decode, Encode};
use log::{debug, info, trace};
use prometheus_endpoint::Registry;
Expand All @@ -31,21 +33,15 @@ use sc_consensus_slots::{check_equivocation, CheckedHeader, InherentDataProvider
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_TRACE};
use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_block_builder::BlockBuilder as BlockBuilderApi;
use sp_blockchain::{
well_known_cache_keys::{self, Id as CacheKeyId},
HeaderBackend,
};
use sp_blockchain::{well_known_cache_keys::Id as CacheKeyId, HeaderBackend};
use sp_consensus::Error as ConsensusError;
use sp_consensus_aura::{
digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi, ConsensusLog,
AURA_ENGINE_ID,
};
use sp_consensus_aura::{digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi};
use sp_consensus_slots::Slot;
use sp_core::{crypto::Pair, ExecutionContext};
use sp_inherents::{CreateInherentDataProviders, InherentDataProvider as _};
use sp_runtime::{
generic::{BlockId, OpaqueDigestItemId},
traits::{Block as BlockT, Header},
generic::BlockId,
traits::{Block as BlockT, Header, NumberFor},
DigestItem,
};
use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc};
Expand Down Expand Up @@ -109,32 +105,35 @@ where
}

/// A verifier for Aura blocks.
pub struct AuraVerifier<C, P, CIDP> {
pub struct AuraVerifier<C, P, CIDP, N> {
client: Arc<C>,
phantom: PhantomData<P>,
create_inherent_data_providers: CIDP,
check_for_equivocation: CheckForEquivocation,
telemetry: Option<TelemetryHandle>,
compatibility_mode: CompatibilityMode<N>,
}

impl<C, P, CIDP> AuraVerifier<C, P, CIDP> {
impl<C, P, CIDP, N> AuraVerifier<C, P, CIDP, N> {
pub(crate) fn new(
client: Arc<C>,
create_inherent_data_providers: CIDP,
check_for_equivocation: CheckForEquivocation,
telemetry: Option<TelemetryHandle>,
compatibility_mode: CompatibilityMode<N>,
) -> Self {
Self {
client,
create_inherent_data_providers,
check_for_equivocation,
telemetry,
compatibility_mode,
phantom: PhantomData,
}
}
}

impl<C, P, CIDP> AuraVerifier<C, P, CIDP>
impl<C, P, CIDP, N> AuraVerifier<C, P, CIDP, N>
where
P: Send + Sync + 'static,
CIDP: Send,
Expand Down Expand Up @@ -172,9 +171,9 @@ where
}

#[async_trait::async_trait]
impl<B: BlockT, C, P, CIDP> Verifier<B> for AuraVerifier<C, P, CIDP>
impl<B: BlockT, C, P, CIDP> Verifier<B> for AuraVerifier<C, P, CIDP, NumberFor<B>>
where
C: ProvideRuntimeApi<B> + Send + Sync + sc_client_api::backend::AuxStore + BlockOf,
C: ProvideRuntimeApi<B> + Send + Sync + sc_client_api::backend::AuxStore,
C::Api: BlockBuilderApi<B> + AuraApi<B, AuthorityId<P>> + ApiExt<B>,
P: Pair + Send + Sync + 'static,
P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + 'static,
Expand All @@ -188,8 +187,13 @@ where
) -> Result<(BlockImportParams<B, ()>, Option<Vec<(CacheKeyId, Vec<u8>)>>), String> {
let hash = block.header.hash();
let parent_hash = *block.header.parent_hash();
let authorities = authorities(self.client.as_ref(), &BlockId::Hash(parent_hash))
.map_err(|e| format!("Could not fetch authorities at {:?}: {}", parent_hash, e))?;
let authorities = authorities(
self.client.as_ref(),
parent_hash,
*block.header.number(),
&self.compatibility_mode,
)
.map_err(|e| format!("Could not fetch authorities at {:?}: {}", parent_hash, e))?;

let create_inherent_data_providers = self
.create_inherent_data_providers
Expand Down Expand Up @@ -259,28 +263,12 @@ where
"pre_header" => ?pre_header,
);

// Look for an authorities-change log.
let maybe_keys = pre_header
.digest()
.logs()
.iter()
.filter_map(|l| {
l.try_to::<ConsensusLog<AuthorityId<P>>>(OpaqueDigestItemId::Consensus(
&AURA_ENGINE_ID,
))
})
.find_map(|l| match l {
ConsensusLog::AuthoritiesChange(a) =>
Some(vec![(well_known_cache_keys::AUTHORITIES, a.encode())]),
_ => None,
});

block.header = pre_header;
block.post_digests.push(seal);
block.fork_choice = Some(ForkChoiceStrategy::LongestChain);
block.post_hash = Some(hash);

Ok((block, maybe_keys))
Ok((block, None))
},
CheckedHeader::Deferred(a, b) => {
debug!(target: "aura", "Checking {:?} failed; {:?}, {:?}.", hash, a, b);
Expand Down Expand Up @@ -323,7 +311,7 @@ impl Default for CheckForEquivocation {
}

/// Parameters of [`import_queue`].
pub struct ImportQueueParams<'a, Block, I, C, S, CIDP> {
pub struct ImportQueueParams<'a, Block: BlockT, I, C, S, CIDP> {
/// The block import to use.
pub block_import: I,
/// The justification import.
Expand All @@ -340,6 +328,10 @@ pub struct ImportQueueParams<'a, Block, I, C, S, CIDP> {
pub check_for_equivocation: CheckForEquivocation,
/// Telemetry instance used to report telemetry metrics.
pub telemetry: Option<TelemetryHandle>,
/// Compatibility mode that should be used.
///
/// If in doubt, use `Default::default()`.
pub compatibility_mode: CompatibilityMode<NumberFor<Block>>,
}

/// Start an import queue for the Aura consensus algorithm.
Expand All @@ -353,6 +345,7 @@ pub fn import_queue<P, Block, I, C, S, CIDP>(
registry,
check_for_equivocation,
telemetry,
compatibility_mode,
}: ImportQueueParams<Block, I, C, S, CIDP>,
) -> Result<DefaultImportQueue<Block, C>, sp_consensus::Error>
where
Expand All @@ -377,18 +370,19 @@ where
CIDP: CreateInherentDataProviders<Block, ()> + Sync + Send + 'static,
CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync,
{
let verifier = build_verifier::<P, _, _>(BuildVerifierParams {
let verifier = build_verifier::<P, _, _, _>(BuildVerifierParams {
client,
create_inherent_data_providers,
check_for_equivocation,
telemetry,
compatibility_mode,
});

Ok(BasicQueue::new(verifier, Box::new(block_import), justification_import, spawner, registry))
}

/// Parameters of [`build_verifier`].
pub struct BuildVerifierParams<C, CIDP> {
pub struct BuildVerifierParams<C, CIDP, N> {
/// The client to interact with the chain.
pub client: Arc<C>,
/// Something that can create the inherent data providers.
Expand All @@ -397,21 +391,27 @@ pub struct BuildVerifierParams<C, CIDP> {
pub check_for_equivocation: CheckForEquivocation,
/// Telemetry instance used to report telemetry metrics.
pub telemetry: Option<TelemetryHandle>,
/// Compatibility mode that should be used.
///
/// If in doubt, use `Default::default()`.
pub compatibility_mode: CompatibilityMode<N>,
}

/// Build the [`AuraVerifier`]
pub fn build_verifier<P, C, CIDP>(
pub fn build_verifier<P, C, CIDP, N>(
BuildVerifierParams {
client,
create_inherent_data_providers,
check_for_equivocation,
telemetry,
}: BuildVerifierParams<C, CIDP>,
) -> AuraVerifier<C, P, CIDP> {
AuraVerifier::<_, P, _>::new(
compatibility_mode,
}: BuildVerifierParams<C, CIDP, N>,
) -> AuraVerifier<C, P, CIDP, N> {
AuraVerifier::<_, P, _, _>::new(
client,
create_inherent_data_providers,
check_for_equivocation,
telemetry,
compatibility_mode,
)
}
Loading

0 comments on commit 4e1e17c

Please sign in to comment.