mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 15:51:12 +00:00
make SelectChain async (#9128)
* make SelectChain async * make JustificationImport async
This commit is contained in:
Generated
+2
@@ -7208,6 +7208,7 @@ dependencies = [
|
||||
name = "sc-consensus"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"parking_lot 0.11.1",
|
||||
"sc-client-api",
|
||||
"sp-blockchain",
|
||||
@@ -8707,6 +8708,7 @@ name = "sp-api-test"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"futures 0.3.15",
|
||||
"log",
|
||||
"parity-scale-codec",
|
||||
"rustversion",
|
||||
|
||||
@@ -93,11 +93,14 @@ impl<B: BlockT, C, SC> BabeRpcHandler<B, C, SC> {
|
||||
}
|
||||
|
||||
impl<B, C, SC> BabeApi for BabeRpcHandler<B, C, SC>
|
||||
where
|
||||
B: BlockT,
|
||||
C: ProvideRuntimeApi<B> + HeaderBackend<B> + HeaderMetadata<B, Error=BlockChainError> + 'static,
|
||||
C::Api: BabeRuntimeApi<B>,
|
||||
SC: SelectChain<B> + Clone + 'static,
|
||||
where
|
||||
B: BlockT,
|
||||
C: ProvideRuntimeApi<B>
|
||||
+ HeaderBackend<B>
|
||||
+ HeaderMetadata<B, Error = BlockChainError>
|
||||
+ 'static,
|
||||
C::Api: BabeRuntimeApi<B>,
|
||||
SC: SelectChain<B> + Clone + 'static,
|
||||
{
|
||||
fn epoch_authorship(&self) -> FutureResult<HashMap<AuthorityId, EpochAuthorship>> {
|
||||
if let Err(err) = self.deny_unsafe.check_if_safe() {
|
||||
@@ -118,28 +121,33 @@ impl<B, C, SC> BabeApi for BabeRpcHandler<B, C, SC>
|
||||
self.select_chain.clone(),
|
||||
);
|
||||
let future = async move {
|
||||
let header = select_chain.best_chain().map_err(Error::Consensus)?;
|
||||
let epoch_start = client.runtime_api()
|
||||
let header = select_chain.best_chain().map_err(Error::Consensus).await?;
|
||||
let epoch_start = client
|
||||
.runtime_api()
|
||||
.current_epoch_start(&BlockId::Hash(header.hash()))
|
||||
.map_err(|err| {
|
||||
Error::StringError(format!("{:?}", err))
|
||||
})?;
|
||||
.map_err(|err| Error::StringError(format!("{:?}", err)))?;
|
||||
let epoch = epoch_data(
|
||||
&shared_epoch,
|
||||
&client,
|
||||
&babe_config,
|
||||
*epoch_start,
|
||||
&select_chain,
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
let (epoch_start, epoch_end) = (epoch.start_slot(), epoch.end_slot());
|
||||
|
||||
let mut claims: HashMap<AuthorityId, EpochAuthorship> = HashMap::new();
|
||||
|
||||
let keys = {
|
||||
epoch.authorities.iter()
|
||||
epoch
|
||||
.authorities
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, a)| {
|
||||
if SyncCryptoStore::has_keys(&*keystore, &[(a.0.to_raw_vec(), AuthorityId::ID)]) {
|
||||
if SyncCryptoStore::has_keys(
|
||||
&*keystore,
|
||||
&[(a.0.to_raw_vec(), AuthorityId::ID)],
|
||||
) {
|
||||
Some((a.0.clone(), i))
|
||||
} else {
|
||||
None
|
||||
@@ -167,7 +175,8 @@ impl<B, C, SC> BabeApi for BabeRpcHandler<B, C, SC>
|
||||
}
|
||||
|
||||
Ok(claims)
|
||||
}.boxed();
|
||||
}
|
||||
.boxed();
|
||||
|
||||
Box::new(future.compat())
|
||||
}
|
||||
@@ -203,20 +212,20 @@ impl From<Error> for jsonrpc_core::Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// fetches the epoch data for a given slot.
|
||||
fn epoch_data<B, C, SC>(
|
||||
/// Fetches the epoch data for a given slot.
|
||||
async fn epoch_data<B, C, SC>(
|
||||
epoch_changes: &SharedEpochChanges<B, Epoch>,
|
||||
client: &Arc<C>,
|
||||
babe_config: &Config,
|
||||
slot: u64,
|
||||
select_chain: &SC,
|
||||
) -> Result<Epoch, Error>
|
||||
where
|
||||
B: BlockT,
|
||||
C: HeaderBackend<B> + HeaderMetadata<B, Error=BlockChainError> + 'static,
|
||||
SC: SelectChain<B>,
|
||||
where
|
||||
B: BlockT,
|
||||
C: HeaderBackend<B> + HeaderMetadata<B, Error = BlockChainError> + 'static,
|
||||
SC: SelectChain<B>,
|
||||
{
|
||||
let parent = select_chain.best_chain()?;
|
||||
let parent = select_chain.best_chain().await?;
|
||||
epoch_changes.shared_data().epoch_data_for_child_of(
|
||||
descendent_query(&**client),
|
||||
&parent.hash(),
|
||||
|
||||
@@ -989,7 +989,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_and_report_equivocation(
|
||||
async fn check_and_report_equivocation(
|
||||
&self,
|
||||
slot_now: Slot,
|
||||
slot: Slot,
|
||||
@@ -1024,6 +1024,7 @@ where
|
||||
let best_id = self
|
||||
.select_chain
|
||||
.best_chain()
|
||||
.await
|
||||
.map(|h| BlockId::Hash(h.hash()))
|
||||
.map_err(|e| Error::Client(e.into()))?;
|
||||
|
||||
@@ -1070,13 +1071,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
type BlockVerificationResult<Block> = Result<
|
||||
(
|
||||
BlockImportParams<Block, ()>,
|
||||
Option<Vec<(CacheKeyId, Vec<u8>)>>,
|
||||
),
|
||||
String,
|
||||
>;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<Block, Client, SelectChain, CAW, CIDP> Verifier<Block>
|
||||
for BabeVerifier<Block, Client, SelectChain, CAW, CIDP>
|
||||
where
|
||||
Block: BlockT,
|
||||
Client: HeaderMetadata<Block, Error = sp_blockchain::Error> + HeaderBackend<Block> + ProvideRuntimeApi<Block>
|
||||
+ Send + Sync + AuxStore + ProvideCache<Block>,
|
||||
Client: HeaderMetadata<Block, Error = sp_blockchain::Error>
|
||||
+ HeaderBackend<Block>
|
||||
+ ProvideRuntimeApi<Block>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ AuxStore
|
||||
+ ProvideCache<Block>,
|
||||
Client::Api: BlockBuilderApi<Block> + BabeApi<Block>,
|
||||
SelectChain: sp_consensus::SelectChain<Block>,
|
||||
CAW: CanAuthorWith<Block> + Send + Sync,
|
||||
@@ -1089,7 +1103,7 @@ where
|
||||
header: Block::Header,
|
||||
justifications: Option<Justifications>,
|
||||
mut body: Option<Vec<Block::Extrinsic>>,
|
||||
) -> Result<(BlockImportParams<Block, ()>, Option<Vec<(CacheKeyId, Vec<u8>)>>), String> {
|
||||
) -> BlockVerificationResult<Block> {
|
||||
trace!(
|
||||
target: "babe",
|
||||
"Verifying origin: {:?} header: {:?} justification(s): {:?} body: {:?}",
|
||||
@@ -1158,7 +1172,7 @@ where
|
||||
&header,
|
||||
&verified_info.author,
|
||||
&origin,
|
||||
) {
|
||||
).await {
|
||||
warn!(target: "babe", "Error checking/reporting BABE equivocation: {:?}", err);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ readme = "README.md"
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
sc-client-api = { version = "3.0.0", path = "../../api" }
|
||||
sp-blockchain = { version = "3.0.0", path = "../../../primitives/blockchain" }
|
||||
sp-runtime = { version = "3.0.0", path = "../../../primitives/runtime" }
|
||||
|
||||
@@ -46,15 +46,15 @@ impl<B, Block> Clone for LongestChain<B, Block> {
|
||||
}
|
||||
|
||||
impl<B, Block> LongestChain<B, Block>
|
||||
where
|
||||
B: backend::Backend<Block>,
|
||||
Block: BlockT,
|
||||
where
|
||||
B: backend::Backend<Block>,
|
||||
Block: BlockT,
|
||||
{
|
||||
/// Instantiate a new LongestChain for Backend B
|
||||
pub fn new(backend: Arc<B>) -> Self {
|
||||
LongestChain {
|
||||
backend,
|
||||
_phantom: Default::default()
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,30 +75,30 @@ impl<B, Block> LongestChain<B, Block>
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<B, Block> SelectChain<Block> for LongestChain<B, Block>
|
||||
where
|
||||
B: backend::Backend<Block>,
|
||||
Block: BlockT,
|
||||
where
|
||||
B: backend::Backend<Block>,
|
||||
Block: BlockT,
|
||||
{
|
||||
|
||||
fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, ConsensusError> {
|
||||
LongestChain::leaves(self)
|
||||
.map_err(|e| ConsensusError::ChainLookup(e.to_string()).into())
|
||||
async fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, ConsensusError> {
|
||||
LongestChain::leaves(self).map_err(|e| ConsensusError::ChainLookup(e.to_string()).into())
|
||||
}
|
||||
|
||||
fn best_chain(&self) -> Result<<Block as BlockT>::Header, ConsensusError>
|
||||
{
|
||||
async fn best_chain(&self) -> Result<<Block as BlockT>::Header, ConsensusError> {
|
||||
LongestChain::best_block_header(&self)
|
||||
.map_err(|e| ConsensusError::ChainLookup(e.to_string()).into())
|
||||
}
|
||||
|
||||
fn finality_target(
|
||||
async fn finality_target(
|
||||
&self,
|
||||
target_hash: Block::Hash,
|
||||
maybe_max_number: Option<NumberFor<Block>>
|
||||
maybe_max_number: Option<NumberFor<Block>>,
|
||||
) -> Result<Option<Block::Hash>, ConsensusError> {
|
||||
let import_lock = self.backend.get_import_lock();
|
||||
self.backend.blockchain().best_containing(target_hash, maybe_max_number, import_lock)
|
||||
self.backend
|
||||
.blockchain()
|
||||
.best_containing(target_hash, maybe_max_number, import_lock)
|
||||
.map_err(|e| ConsensusError::ChainLookup(e.to_string()).into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,45 +80,47 @@ pub async fn seal_block<B, BI, SC, C, E, P, CIDP>(
|
||||
create_inherent_data_providers,
|
||||
consensus_data_provider: digest_provider,
|
||||
mut sender,
|
||||
}: SealBlockParams<'_, B, BI, SC, C, E, P, CIDP>
|
||||
)
|
||||
where
|
||||
B: BlockT,
|
||||
BI: BlockImport<B, Error = sp_consensus::Error, Transaction = sp_api::TransactionFor<C, B>>
|
||||
+ Send + Sync + 'static,
|
||||
C: HeaderBackend<B> + ProvideRuntimeApi<B>,
|
||||
E: Environment<B>,
|
||||
E::Proposer: Proposer<B, Transaction = TransactionFor<C, B>>,
|
||||
P: txpool::ChainApi<Block=B>,
|
||||
SC: SelectChain<B>,
|
||||
TransactionFor<C, B>: 'static,
|
||||
CIDP: CreateInherentDataProviders<B, ()>,
|
||||
}: SealBlockParams<'_, B, BI, SC, C, E, P, CIDP>,
|
||||
) where
|
||||
B: BlockT,
|
||||
BI: BlockImport<B, Error = sp_consensus::Error, Transaction = sp_api::TransactionFor<C, B>>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
C: HeaderBackend<B> + ProvideRuntimeApi<B>,
|
||||
E: Environment<B>,
|
||||
E::Proposer: Proposer<B, Transaction = TransactionFor<C, B>>,
|
||||
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 {
|
||||
return Err(Error::EmptyTransactionPool)
|
||||
return Err(Error::EmptyTransactionPool);
|
||||
}
|
||||
|
||||
// get the header to build this new block on.
|
||||
// use the parent_hash supplied via `EngineCommand`
|
||||
// or fetch the best_block.
|
||||
let parent = match parent_hash {
|
||||
Some(hash) => {
|
||||
client.header(BlockId::Hash(hash))?.ok_or_else(|| Error::BlockNotFound(format!("{}", hash)))?
|
||||
}
|
||||
None => select_chain.best_chain()?
|
||||
Some(hash) => client
|
||||
.header(BlockId::Hash(hash))?
|
||||
.ok_or_else(|| Error::BlockNotFound(format!("{}", hash)))?,
|
||||
None => select_chain.best_chain().await?,
|
||||
};
|
||||
|
||||
let inherent_data_providers =
|
||||
create_inherent_data_providers
|
||||
.create_inherent_data_providers(parent.hash(), ())
|
||||
.await
|
||||
.map_err(|e| Error::Other(e))?;
|
||||
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 proposer = env
|
||||
.init(&parent)
|
||||
.map_err(|err| Error::StringError(format!("{:?}", err)))
|
||||
.await?;
|
||||
let inherents_len = inherent_data.len();
|
||||
|
||||
let digest = if let Some(digest_provider) = digest_provider {
|
||||
|
||||
@@ -341,7 +341,10 @@ where
|
||||
mut block: BlockImportParams<B, Self::Transaction>,
|
||||
new_cache: HashMap<CacheKeyId, Vec<u8>>,
|
||||
) -> Result<ImportResult, Self::Error> {
|
||||
let best_header = self.select_chain.best_chain()
|
||||
let best_header = self
|
||||
.select_chain
|
||||
.best_chain()
|
||||
.await
|
||||
.map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))?;
|
||||
let best_hash = best_header.hash();
|
||||
|
||||
@@ -543,7 +546,8 @@ pub fn start_mining_worker<Block, C, S, Algorithm, E, SO, L, CIDP, CAW>(
|
||||
) -> (
|
||||
Arc<Mutex<MiningWorker<Block, Algorithm, C, L, <E::Proposer as Proposer<Block>>::Proof>>>,
|
||||
impl Future<Output = ()>,
|
||||
) where
|
||||
)
|
||||
where
|
||||
Block: BlockT,
|
||||
C: ProvideRuntimeApi<Block> + BlockchainEvents<Block> + 'static,
|
||||
S: SelectChain<Block> + 'static,
|
||||
@@ -578,7 +582,7 @@ pub fn start_mining_worker<Block, C, S, Algorithm, E, SO, L, CIDP, CAW>(
|
||||
return;
|
||||
}
|
||||
|
||||
let best_header = match select_chain.best_chain() {
|
||||
let best_header = match select_chain.best_chain().await {
|
||||
Ok(x) => x,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
@@ -588,7 +592,7 @@ pub fn start_mining_worker<Block, C, S, Algorithm, E, SO, L, CIDP, CAW>(
|
||||
err
|
||||
);
|
||||
return;
|
||||
},
|
||||
}
|
||||
};
|
||||
let best_hash = best_header.hash();
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ where
|
||||
|
||||
let ends_at = Instant::now() + ends_in;
|
||||
|
||||
let chain_head = match self.client.best_chain() {
|
||||
let chain_head = match self.client.best_chain().await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
|
||||
@@ -34,12 +34,12 @@ use parking_lot::RwLock;
|
||||
use prometheus_endpoint::{register, Counter, Gauge, PrometheusError, U64};
|
||||
|
||||
use sc_client_api::{
|
||||
backend::{apply_aux, Backend},
|
||||
backend::{apply_aux, Backend as BackendT},
|
||||
utils::is_descendent_of,
|
||||
};
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
|
||||
use sp_blockchain::HeaderMetadata;
|
||||
use sp_consensus::SelectChain;
|
||||
use sp_consensus::SelectChain as SelectChainT;
|
||||
use sp_finality_grandpa::{
|
||||
AuthorityId, AuthoritySignature, Equivocation, EquivocationProof, GrandpaApi, RoundNumber,
|
||||
SetId, GRANDPA_ENGINE_ID,
|
||||
@@ -54,7 +54,7 @@ use crate::{
|
||||
local_authority_id,
|
||||
notification::GrandpaJustificationSender,
|
||||
until_imported::UntilVoteTargetImported,
|
||||
voting_rule::VotingRule,
|
||||
voting_rule::VotingRule as VotingRuleT,
|
||||
ClientForGrandpa, CommandOrError, Commit, Config, Error, NewAuthoritySet, Precommit, Prevote,
|
||||
PrimaryPropose, SignedMessage, VoterCommand,
|
||||
};
|
||||
@@ -478,11 +478,11 @@ impl<BE, Block: BlockT, C, N: NetworkT<Block>, SC, VR> Environment<BE, Block, C,
|
||||
impl<BE, Block, C, N, SC, VR> Environment<BE, Block, C, N, SC, VR>
|
||||
where
|
||||
Block: BlockT,
|
||||
BE: Backend<Block>,
|
||||
BE: BackendT<Block>,
|
||||
C: ClientForGrandpa<Block, BE>,
|
||||
C::Api: GrandpaApi<Block>,
|
||||
N: NetworkT<Block>,
|
||||
SC: SelectChain<Block>,
|
||||
SC: SelectChainT<Block>,
|
||||
{
|
||||
/// Report the given equivocation to the GRANDPA runtime module. This method
|
||||
/// generates a session membership proof of the offender and then submits an
|
||||
@@ -503,9 +503,12 @@ where
|
||||
|
||||
let is_descendent_of = is_descendent_of(&*self.client, None);
|
||||
|
||||
let best_header = self.select_chain
|
||||
.best_chain()
|
||||
.map_err(|e| Error::Blockchain(e.to_string()))?;
|
||||
// TODO: add proper async support here
|
||||
let best_header = futures::executor::block_on(
|
||||
self.select_chain
|
||||
.best_chain()
|
||||
.map_err(|e| Error::Blockchain(e.to_string())),
|
||||
)?;
|
||||
|
||||
let authority_set = self.authority_set.inner();
|
||||
|
||||
@@ -581,11 +584,11 @@ impl<BE, Block, C, N, SC, VR> finality_grandpa::Chain<Block::Hash, NumberFor<Blo
|
||||
for Environment<BE, Block, C, N, SC, VR>
|
||||
where
|
||||
Block: BlockT,
|
||||
BE: Backend<Block>,
|
||||
BE: BackendT<Block>,
|
||||
C: ClientForGrandpa<Block, BE>,
|
||||
N: NetworkT<Block>,
|
||||
SC: SelectChain<Block>,
|
||||
VR: VotingRule<Block, C>,
|
||||
SC: SelectChainT<Block>,
|
||||
VR: VotingRuleT<Block, C>,
|
||||
NumberFor<Block>: BlockNumberOps,
|
||||
{
|
||||
fn ancestry(
|
||||
@@ -637,12 +640,12 @@ impl<B, Block, C, N, SC, VR> voter::Environment<Block::Hash, NumberFor<Block>>
|
||||
for Environment<B, Block, C, N, SC, VR>
|
||||
where
|
||||
Block: BlockT,
|
||||
B: Backend<Block>,
|
||||
B: BackendT<Block>,
|
||||
C: ClientForGrandpa<Block, B> + 'static,
|
||||
C::Api: GrandpaApi<Block>,
|
||||
N: NetworkT<Block>,
|
||||
SC: SelectChain<Block>,
|
||||
VR: VotingRule<Block, C>,
|
||||
SC: SelectChainT<Block> + 'static,
|
||||
VR: VotingRuleT<Block, C> + Clone + 'static,
|
||||
NumberFor<Block>: BlockNumberOps,
|
||||
{
|
||||
type Timer = Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>>;
|
||||
@@ -684,116 +687,25 @@ where
|
||||
type Error = CommandOrError<Block::Hash, NumberFor<Block>>;
|
||||
|
||||
fn best_chain_containing(&self, block: Block::Hash) -> Self::BestChain {
|
||||
let find_best_chain = || {
|
||||
let client = self.client.clone();
|
||||
let authority_set = self.authority_set.clone();
|
||||
let select_chain = self.select_chain.clone();
|
||||
let voting_rule = self.voting_rule.clone();
|
||||
let set_id = self.set_id;
|
||||
|
||||
Box::pin(async move {
|
||||
// NOTE: when we finalize an authority set change through the sync protocol the voter is
|
||||
// signaled asynchronously. therefore the voter could still vote in the next round
|
||||
// before activating the new set. the `authority_set` is updated immediately thus we
|
||||
// restrict the voter based on that.
|
||||
if self.set_id != self.authority_set.set_id() {
|
||||
return None;
|
||||
// before activating the new set. the `authority_set` is updated immediately thus
|
||||
// we restrict the voter based on that.
|
||||
if set_id != authority_set.set_id() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let base_header = match self.client.header(BlockId::Hash(block)).ok()? {
|
||||
Some(h) => h,
|
||||
None => {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find base block", block);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// we refuse to vote beyond the current limit number where transitions are scheduled to
|
||||
// occur.
|
||||
// once blocks are finalized that make that transition irrelevant or activate it,
|
||||
// we will proceed onwards. most of the time there will be no pending transition.
|
||||
// the limit, if any, is guaranteed to be higher than or equal to the given base number.
|
||||
let limit = self.authority_set.current_limit(*base_header.number());
|
||||
debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit);
|
||||
|
||||
match self.select_chain.finality_target(block, None) {
|
||||
Ok(Some(best_hash)) => {
|
||||
let best_header = self
|
||||
.client
|
||||
.header(BlockId::Hash(best_hash))
|
||||
.ok()?
|
||||
.expect("Header known to exist after `finality_target` call; qed");
|
||||
|
||||
// check if our vote is currently being limited due to a pending change
|
||||
let limit = limit.filter(|limit| limit < best_header.number());
|
||||
|
||||
if let Some(target_number) = limit {
|
||||
let mut target_header = best_header.clone();
|
||||
|
||||
// walk backwards until we find the target block
|
||||
loop {
|
||||
if *target_header.number() < target_number {
|
||||
unreachable!(
|
||||
"we are traversing backwards from a known block; \
|
||||
blocks are stored contiguously; \
|
||||
qed"
|
||||
);
|
||||
}
|
||||
|
||||
if *target_header.number() == target_number {
|
||||
break;
|
||||
}
|
||||
|
||||
target_header = self
|
||||
.client
|
||||
.header(BlockId::Hash(*target_header.parent_hash()))
|
||||
.ok()?
|
||||
.expect("Header known to exist after `finality_target` call; qed");
|
||||
}
|
||||
|
||||
Some((base_header, best_header, target_header))
|
||||
} else {
|
||||
// otherwise just use the given best as the target
|
||||
Some((base_header, best_header.clone(), best_header))
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block);
|
||||
None
|
||||
}
|
||||
Err(e) => {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some((base_header, best_header, target_header)) = find_best_chain() {
|
||||
// restrict vote according to the given voting rule, if the
|
||||
// voting rule doesn't restrict the vote then we keep the
|
||||
// previous target.
|
||||
//
|
||||
// note that we pass the original `best_header`, i.e. before the
|
||||
// authority set limit filter, which can be considered a
|
||||
// mandatory/implicit voting rule.
|
||||
//
|
||||
// we also make sure that the restricted vote is higher than the
|
||||
// round base (i.e. last finalized), otherwise the value
|
||||
// returned by the given voting rule is ignored and the original
|
||||
// target is used instead.
|
||||
let rule_fut = self.voting_rule.restrict_vote(
|
||||
self.client.clone(),
|
||||
&base_header,
|
||||
&best_header,
|
||||
&target_header,
|
||||
);
|
||||
|
||||
Box::pin(async move {
|
||||
Ok(rule_fut
|
||||
.await
|
||||
.filter(|(_, restricted_number)| {
|
||||
// we can only restrict votes within the interval [base, target]
|
||||
restricted_number >= base_header.number()
|
||||
&& restricted_number < target_header.number()
|
||||
})
|
||||
.or_else(|| Some((target_header.hash(), *target_header.number()))))
|
||||
})
|
||||
} else {
|
||||
Box::pin(future::ok(None))
|
||||
}
|
||||
best_chain_containing(block, client, authority_set, select_chain, voting_rule)
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
})
|
||||
}
|
||||
|
||||
fn round_data(
|
||||
@@ -1227,6 +1139,111 @@ impl<Block: BlockT> From<GrandpaJustification<Block>> for JustificationOrCommit<
|
||||
}
|
||||
}
|
||||
|
||||
async fn best_chain_containing<Block, Backend, Client, SelectChain, VotingRule>(
|
||||
block: Block::Hash,
|
||||
client: Arc<Client>,
|
||||
authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
|
||||
select_chain: SelectChain,
|
||||
voting_rule: VotingRule,
|
||||
) -> Result<Option<(Block::Hash, NumberFor<Block>)>, Error>
|
||||
where
|
||||
Backend: BackendT<Block>,
|
||||
Block: BlockT,
|
||||
Client: ClientForGrandpa<Block, Backend>,
|
||||
SelectChain: SelectChainT<Block> + 'static,
|
||||
VotingRule: VotingRuleT<Block, Client>,
|
||||
{
|
||||
let base_header = match client.header(BlockId::Hash(block))? {
|
||||
Some(h) => h,
|
||||
None => {
|
||||
debug!(target: "afg",
|
||||
"Encountered error finding best chain containing {:?}: couldn't find base block",
|
||||
block,
|
||||
);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
// we refuse to vote beyond the current limit number where transitions are scheduled to occur.
|
||||
// once blocks are finalized that make that transition irrelevant or activate it, we will
|
||||
// proceed onwards. most of the time there will be no pending transition. the limit, if any, is
|
||||
// guaranteed to be higher than or equal to the given base number.
|
||||
let limit = authority_set.current_limit(*base_header.number());
|
||||
debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit);
|
||||
|
||||
let result = match select_chain.finality_target(block, None).await {
|
||||
Ok(Some(best_hash)) => {
|
||||
let best_header = client
|
||||
.header(BlockId::Hash(best_hash))?
|
||||
.expect("Header known to exist after `finality_target` call; qed");
|
||||
|
||||
// check if our vote is currently being limited due to a pending change
|
||||
let limit = limit.filter(|limit| limit < best_header.number());
|
||||
|
||||
let (base_header, best_header, target_header) = if let Some(target_number) = limit {
|
||||
let mut target_header = best_header.clone();
|
||||
|
||||
// walk backwards until we find the target block
|
||||
loop {
|
||||
if *target_header.number() < target_number {
|
||||
unreachable!(
|
||||
"we are traversing backwards from a known block; \
|
||||
blocks are stored contiguously; \
|
||||
qed"
|
||||
);
|
||||
}
|
||||
|
||||
if *target_header.number() == target_number {
|
||||
break;
|
||||
}
|
||||
|
||||
target_header = client
|
||||
.header(BlockId::Hash(*target_header.parent_hash()))?
|
||||
.expect("Header known to exist after `finality_target` call; qed");
|
||||
}
|
||||
|
||||
(base_header, best_header, target_header)
|
||||
} else {
|
||||
// otherwise just use the given best as the target
|
||||
(base_header, best_header.clone(), best_header)
|
||||
};
|
||||
|
||||
// restrict vote according to the given voting rule, if the
|
||||
// voting rule doesn't restrict the vote then we keep the
|
||||
// previous target.
|
||||
//
|
||||
// note that we pass the original `best_header`, i.e. before the
|
||||
// authority set limit filter, which can be considered a
|
||||
// mandatory/implicit voting rule.
|
||||
//
|
||||
// we also make sure that the restricted vote is higher than the
|
||||
// round base (i.e. last finalized), otherwise the value
|
||||
// returned by the given voting rule is ignored and the original
|
||||
// target is used instead.
|
||||
voting_rule
|
||||
.restrict_vote(client.clone(), &base_header, &best_header, &target_header)
|
||||
.await
|
||||
.filter(|(_, restricted_number)| {
|
||||
// we can only restrict votes within the interval [base, target]
|
||||
restricted_number >= base_header.number() &&
|
||||
restricted_number < target_header.number()
|
||||
})
|
||||
.or_else(|| Some((target_header.hash(), *target_header.number())))
|
||||
}
|
||||
Ok(None) => {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block);
|
||||
None
|
||||
}
|
||||
Err(e) => {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Finalize the given block and apply any authority set changes. If an
|
||||
/// authority set change is enacted then a justification is created (if not
|
||||
/// given) and stored with the block when finalizing it.
|
||||
@@ -1244,7 +1261,7 @@ pub(crate) fn finalize_block<BE, Block, Client>(
|
||||
) -> Result<(), CommandOrError<Block::Hash, NumberFor<Block>>>
|
||||
where
|
||||
Block: BlockT,
|
||||
BE: Backend<Block>,
|
||||
BE: BackendT<Block>,
|
||||
Client: ClientForGrandpa<Block, BE>,
|
||||
{
|
||||
// NOTE: lock must be held through writing to DB to avoid race. this lock
|
||||
|
||||
@@ -81,6 +81,7 @@ impl<Backend, Block: BlockT, Client, SC: Clone> Clone
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<BE, Block: BlockT, Client, SC> JustificationImport<Block>
|
||||
for GrandpaBlockImport<BE, Block, Client, SC>
|
||||
where
|
||||
@@ -92,22 +93,30 @@ where
|
||||
{
|
||||
type Error = ConsensusError;
|
||||
|
||||
fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor<Block>)> {
|
||||
async fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor<Block>)> {
|
||||
let mut out = Vec::new();
|
||||
let chain_info = self.inner.info();
|
||||
|
||||
// request justifications for all pending changes for which change blocks have already been imported
|
||||
let authorities = self.authority_set.inner();
|
||||
for pending_change in authorities.pending_changes() {
|
||||
let pending_changes: Vec<_> = self
|
||||
.authority_set
|
||||
.inner()
|
||||
.pending_changes()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
for pending_change in pending_changes {
|
||||
if pending_change.delay_kind == DelayKind::Finalized &&
|
||||
pending_change.effective_number() > chain_info.finalized_number &&
|
||||
pending_change.effective_number() <= chain_info.best_number
|
||||
{
|
||||
let effective_block_hash = if !pending_change.delay.is_zero() {
|
||||
self.select_chain.finality_target(
|
||||
pending_change.canon_hash,
|
||||
Some(pending_change.effective_number()),
|
||||
)
|
||||
self.select_chain
|
||||
.finality_target(
|
||||
pending_change.canon_hash,
|
||||
Some(pending_change.effective_number()),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
Ok(Some(pending_change.canon_hash))
|
||||
};
|
||||
@@ -125,7 +134,7 @@ where
|
||||
out
|
||||
}
|
||||
|
||||
fn import_justification(
|
||||
async fn import_justification(
|
||||
&mut self,
|
||||
hash: Block::Hash,
|
||||
number: NumberFor<Block>,
|
||||
|
||||
@@ -1075,10 +1075,15 @@ impl TestNetFactory for TestNet {
|
||||
|
||||
pub struct ForceFinalized(PeersClient);
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl JustificationImport<Block> for ForceFinalized {
|
||||
type Error = ConsensusError;
|
||||
|
||||
fn import_justification(
|
||||
async fn on_start(&mut self) -> Vec<(H256, NumberFor<Block>)> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
async fn import_justification(
|
||||
&mut self,
|
||||
hash: H256,
|
||||
_number: NumberFor<Block>,
|
||||
|
||||
@@ -561,13 +561,14 @@ mod tests {
|
||||
client.clone(),
|
||||
);
|
||||
let source = sp_runtime::transaction_validity::TransactionSource::External;
|
||||
let best = longest_chain.best_chain().unwrap();
|
||||
let best = block_on(longest_chain.best_chain()).unwrap();
|
||||
let transaction = Transfer {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: Default::default(),
|
||||
}.into_signed_tx();
|
||||
}
|
||||
.into_signed_tx();
|
||||
block_on(pool.submit_one(
|
||||
&BlockId::hash(best.hash()), source, transaction.clone()),
|
||||
).unwrap();
|
||||
|
||||
@@ -337,7 +337,6 @@ fn construct_genesis_with_bad_transaction_should_panic() {
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn client_initializes_from_genesis_ok() {
|
||||
let client = substrate_test_runtime_client::new();
|
||||
@@ -450,7 +449,9 @@ fn best_containing_with_genesis_block() {
|
||||
|
||||
assert_eq!(
|
||||
genesis_hash.clone(),
|
||||
longest_chain_select.finality_target(genesis_hash.clone(), None).unwrap().unwrap()
|
||||
block_on(longest_chain_select.finality_target(genesis_hash.clone(), None))
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -461,11 +462,17 @@ fn best_containing_with_hash_not_found() {
|
||||
|
||||
let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
|
||||
|
||||
let uninserted_block = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
let uninserted_block = client
|
||||
.new_block(Default::default())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
|
||||
assert_eq!(
|
||||
None,
|
||||
longest_chain_select.finality_target(uninserted_block.hash().clone(), None).unwrap()
|
||||
block_on(longest_chain_select.finality_target(uninserted_block.hash().clone(), None))
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -624,18 +631,43 @@ fn best_containing_on_longest_chain_with_single_chain_3_blocks() {
|
||||
let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
|
||||
|
||||
// G -> A1
|
||||
let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
let a1 = client
|
||||
.new_block(Default::default())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
let a2 = client
|
||||
.new_block(Default::default())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
|
||||
assert_eq!(a2.hash(), longest_chain_select.finality_target(genesis_hash, None).unwrap().unwrap());
|
||||
assert_eq!(a2.hash(), longest_chain_select.finality_target(a1.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(a2.hash(), longest_chain_select.finality_target(a2.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(
|
||||
a2.hash(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a2.hash(),
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a2.hash(),
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -715,19 +747,19 @@ fn best_containing_on_longest_chain_with_multiple_forks() {
|
||||
).unwrap().build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap();
|
||||
|
||||
// // B2 -> C3
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(b2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
// B2 -> C3
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
})
|
||||
.unwrap();
|
||||
let c3 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap();
|
||||
|
||||
@@ -750,7 +782,7 @@ fn best_containing_on_longest_chain_with_multiple_forks() {
|
||||
assert_eq!(client.chain_info().best_hash, a5.hash());
|
||||
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
let leaves = longest_chain_select.leaves().unwrap();
|
||||
let leaves = block_on(longest_chain_select.leaves()).unwrap();
|
||||
|
||||
assert!(leaves.contains(&a5.hash()));
|
||||
assert!(leaves.contains(&b4.hash()));
|
||||
@@ -759,208 +791,422 @@ fn best_containing_on_longest_chain_with_multiple_forks() {
|
||||
assert_eq!(leaves.len(), 4);
|
||||
|
||||
// search without restriction
|
||||
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
genesis_hash, None).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a1.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a2.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a3.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a4.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a5.hash(), None).unwrap().unwrap());
|
||||
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b2.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b3.hash(), None).unwrap().unwrap());
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b4.hash(), None).unwrap().unwrap());
|
||||
|
||||
assert_eq!(c3.hash(), longest_chain_select.finality_target(
|
||||
c3.hash(), None).unwrap().unwrap());
|
||||
|
||||
assert_eq!(d2.hash(), longest_chain_select.finality_target(
|
||||
d2.hash(), None).unwrap().unwrap());
|
||||
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a3.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a4.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a5.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b2.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b3.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b4.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
c3.hash(),
|
||||
block_on(longest_chain_select.finality_target(c3.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
d2.hash(),
|
||||
block_on(longest_chain_select.finality_target(d2.hash(), None))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// search only blocks with number <= 5. equivalent to without restriction for this scenario
|
||||
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
genesis_hash, Some(5)).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a1.hash(), Some(5)).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a2.hash(), Some(5)).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a3.hash(), Some(5)).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a4.hash(), Some(5)).unwrap().unwrap());
|
||||
assert_eq!(a5.hash(), longest_chain_select.finality_target(
|
||||
a5.hash(), Some(5)).unwrap().unwrap());
|
||||
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b2.hash(), Some(5)).unwrap().unwrap());
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b3.hash(), Some(5)).unwrap().unwrap());
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b4.hash(), Some(5)).unwrap().unwrap());
|
||||
|
||||
assert_eq!(c3.hash(), longest_chain_select.finality_target(
|
||||
c3.hash(), Some(5)).unwrap().unwrap());
|
||||
|
||||
assert_eq!(d2.hash(), longest_chain_select.finality_target(
|
||||
d2.hash(), Some(5)).unwrap().unwrap());
|
||||
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a3.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a4.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a5.hash(),
|
||||
block_on(longest_chain_select.finality_target(a5.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b2.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b3.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b4.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
c3.hash(),
|
||||
block_on(longest_chain_select.finality_target(c3.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
d2.hash(),
|
||||
block_on(longest_chain_select.finality_target(d2.hash(), Some(5)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// search only blocks with number <= 4
|
||||
|
||||
assert_eq!(a4.hash(), longest_chain_select.finality_target(
|
||||
genesis_hash, Some(4)).unwrap().unwrap());
|
||||
assert_eq!(a4.hash(), longest_chain_select.finality_target(
|
||||
a1.hash(), Some(4)).unwrap().unwrap());
|
||||
assert_eq!(a4.hash(), longest_chain_select.finality_target(
|
||||
a2.hash(), Some(4)).unwrap().unwrap());
|
||||
assert_eq!(a4.hash(), longest_chain_select.finality_target(
|
||||
a3.hash(), Some(4)).unwrap().unwrap());
|
||||
assert_eq!(a4.hash(), longest_chain_select.finality_target(
|
||||
a4.hash(), Some(4)).unwrap().unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a5.hash(), Some(4)).unwrap());
|
||||
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b2.hash(), Some(4)).unwrap().unwrap());
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b3.hash(), Some(4)).unwrap().unwrap());
|
||||
assert_eq!(b4.hash(), longest_chain_select.finality_target(
|
||||
b4.hash(), Some(4)).unwrap().unwrap());
|
||||
|
||||
assert_eq!(c3.hash(), longest_chain_select.finality_target(
|
||||
c3.hash(), Some(4)).unwrap().unwrap());
|
||||
|
||||
assert_eq!(d2.hash(), longest_chain_select.finality_target(
|
||||
d2.hash(), Some(4)).unwrap().unwrap());
|
||||
|
||||
|
||||
// search only blocks with number <= 3
|
||||
|
||||
assert_eq!(a3.hash(), longest_chain_select.finality_target(
|
||||
genesis_hash, Some(3)).unwrap().unwrap());
|
||||
assert_eq!(a3.hash(), longest_chain_select.finality_target(
|
||||
a1.hash(), Some(3)).unwrap().unwrap());
|
||||
assert_eq!(a3.hash(), longest_chain_select.finality_target(
|
||||
a2.hash(), Some(3)).unwrap().unwrap());
|
||||
assert_eq!(a3.hash(), longest_chain_select.finality_target(
|
||||
a3.hash(), Some(3)).unwrap().unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a4.hash(), Some(3)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a5.hash(), Some(3)).unwrap());
|
||||
|
||||
assert_eq!(b3.hash(), longest_chain_select.finality_target(
|
||||
b2.hash(), Some(3)).unwrap().unwrap());
|
||||
assert_eq!(b3.hash(), longest_chain_select.finality_target(
|
||||
b3.hash(), Some(3)).unwrap().unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b4.hash(), Some(3)).unwrap());
|
||||
|
||||
assert_eq!(c3.hash(), longest_chain_select.finality_target(
|
||||
c3.hash(), Some(3)).unwrap().unwrap());
|
||||
|
||||
assert_eq!(d2.hash(), longest_chain_select.finality_target(
|
||||
d2.hash(), Some(3)).unwrap().unwrap());
|
||||
|
||||
|
||||
// search only blocks with number <= 2
|
||||
|
||||
assert_eq!(a2.hash(), longest_chain_select.finality_target(
|
||||
genesis_hash, Some(2)).unwrap().unwrap());
|
||||
assert_eq!(a2.hash(), longest_chain_select.finality_target(
|
||||
a1.hash(), Some(2)).unwrap().unwrap());
|
||||
assert_eq!(a2.hash(), longest_chain_select.finality_target(
|
||||
a2.hash(), Some(2)).unwrap().unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a3.hash(), Some(2)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a4.hash(), Some(2)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a5.hash(), Some(2)).unwrap());
|
||||
|
||||
assert_eq!(b2.hash(), longest_chain_select.finality_target(
|
||||
b2.hash(), Some(2)).unwrap().unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b3.hash(), Some(2)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b4.hash(), Some(2)).unwrap());
|
||||
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
c3.hash(), Some(2)).unwrap());
|
||||
|
||||
assert_eq!(d2.hash(), longest_chain_select.finality_target(
|
||||
d2.hash(), Some(2)).unwrap().unwrap());
|
||||
|
||||
|
||||
// search only blocks with number <= 1
|
||||
|
||||
assert_eq!(a1.hash(), longest_chain_select.finality_target(
|
||||
genesis_hash, Some(1)).unwrap().unwrap());
|
||||
assert_eq!(a1.hash(), longest_chain_select.finality_target(
|
||||
a1.hash(), Some(1)).unwrap().unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a2.hash(), Some(1)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a3.hash(), Some(1)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a4.hash(), Some(1)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a5.hash(), Some(1)).unwrap());
|
||||
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b2.hash(), Some(1)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b3.hash(), Some(1)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b4.hash(), Some(1)).unwrap());
|
||||
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
c3.hash(), Some(1)).unwrap());
|
||||
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
d2.hash(), Some(1)).unwrap());
|
||||
|
||||
// search only blocks with number <= 0
|
||||
|
||||
assert_eq!(genesis_hash, longest_chain_select.finality_target(
|
||||
genesis_hash, Some(0)).unwrap().unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a1.hash(), Some(0)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a2.hash(), Some(0)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a3.hash(), Some(0)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a4.hash(), Some(0)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
a5.hash(), Some(0)).unwrap());
|
||||
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b2.hash(), Some(0)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b3.hash(), Some(0)).unwrap());
|
||||
assert_eq!(None, longest_chain_select.finality_target(
|
||||
b4.hash(), Some(0)).unwrap());
|
||||
|
||||
assert_eq!(
|
||||
a4.hash(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a4.hash(),
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a4.hash(),
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a4.hash(),
|
||||
block_on(longest_chain_select.finality_target(a3.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a4.hash(),
|
||||
block_on(longest_chain_select.finality_target(a4.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
longest_chain_select.finality_target(c3.hash().clone(), Some(0)).unwrap(),
|
||||
block_on(longest_chain_select.finality_target(a5.hash(), Some(4))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b2.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b3.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b4.hash(),
|
||||
block_on(longest_chain_select.finality_target(b4.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
c3.hash(),
|
||||
block_on(longest_chain_select.finality_target(c3.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
d2.hash(),
|
||||
block_on(longest_chain_select.finality_target(d2.hash(), Some(4)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// search only blocks with number <= 3
|
||||
assert_eq!(
|
||||
a3.hash(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a3.hash(),
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a3.hash(),
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a3.hash(),
|
||||
block_on(longest_chain_select.finality_target(a3.hash(), Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a4.hash(), Some(3))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a5.hash(), Some(3))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b3.hash(),
|
||||
block_on(longest_chain_select.finality_target(b2.hash(), Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b3.hash(),
|
||||
block_on(longest_chain_select.finality_target(b3.hash(), Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b4.hash(), Some(3))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
c3.hash(),
|
||||
block_on(longest_chain_select.finality_target(c3.hash(), Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
d2.hash(),
|
||||
block_on(longest_chain_select.finality_target(d2.hash(), Some(3)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// search only blocks with number <= 2
|
||||
assert_eq!(
|
||||
a2.hash(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, Some(2)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a2.hash(),
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), Some(2)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a2.hash(),
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), Some(2)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a3.hash(), Some(2))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a4.hash(), Some(2))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a5.hash(), Some(2))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
b2.hash(),
|
||||
block_on(longest_chain_select.finality_target(b2.hash(), Some(2)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b3.hash(), Some(2))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b4.hash(), Some(2))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(c3.hash(), Some(2))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
d2.hash(),
|
||||
block_on(longest_chain_select.finality_target(d2.hash(), Some(2)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// search only blocks with number <= 1
|
||||
assert_eq!(
|
||||
a1.hash(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, Some(1)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
a1.hash(),
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), Some(1)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), Some(1))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a3.hash(), Some(1))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a4.hash(), Some(1))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a5.hash(), Some(1))).unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
None,
|
||||
longest_chain_select.finality_target(d2.hash().clone(), Some(0)).unwrap(),
|
||||
block_on(longest_chain_select.finality_target(b2.hash(), Some(1))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b3.hash(), Some(1))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b4.hash(), Some(1))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(c3.hash(), Some(1))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(d2.hash(), Some(1))).unwrap()
|
||||
);
|
||||
|
||||
// search only blocks with number <= 0
|
||||
assert_eq!(
|
||||
genesis_hash,
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, Some(0)))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a1.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a2.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a3.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a4.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(a5.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b2.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b3.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(b4.hash(), Some(0))).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(c3.hash().clone(), Some(0))).unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
block_on(longest_chain_select.finality_target(d2.hash().clone(), Some(0))).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -972,18 +1218,30 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() {
|
||||
let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain();
|
||||
|
||||
// G -> A1
|
||||
let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
let a1 = client
|
||||
.new_block(Default::default())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
let a2 = client
|
||||
.new_block(Default::default())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
|
||||
assert_eq!(
|
||||
a2.hash(),
|
||||
longest_chain_select.finality_target(genesis_hash, Some(10)).unwrap().unwrap(),
|
||||
block_on(longest_chain_select.finality_target(genesis_hash, Some(10)))
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1181,7 +1439,7 @@ fn finalizing_diverged_block_should_trigger_reorg() {
|
||||
|
||||
// `SelectChain` should report B2 as best block though
|
||||
assert_eq!(
|
||||
select_chain.best_chain().unwrap().hash(),
|
||||
block_on(select_chain.best_chain()).unwrap().hash(),
|
||||
b2.hash(),
|
||||
);
|
||||
|
||||
|
||||
@@ -27,9 +27,10 @@ rustversion = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.0"
|
||||
substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" }
|
||||
sp-core = { version = "3.0.0", path = "../../core" }
|
||||
futures = "0.3.9"
|
||||
log = "0.4.14"
|
||||
sp-core = { version = "3.0.0", path = "../../core" }
|
||||
substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" }
|
||||
|
||||
[[bench]]
|
||||
name = "bench"
|
||||
|
||||
@@ -160,10 +160,15 @@ fn record_proof_works() {
|
||||
.build_with_longest_chain();
|
||||
|
||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
||||
let storage_root = longest_chain.best_chain().unwrap().state_root().clone();
|
||||
let storage_root = futures::executor::block_on(longest_chain.best_chain())
|
||||
.unwrap()
|
||||
.state_root()
|
||||
.clone();
|
||||
|
||||
let runtime_code = sp_core::traits::RuntimeCode {
|
||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(client.code_at(&block_id).unwrap().into()),
|
||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(
|
||||
client.code_at(&block_id).unwrap().into(),
|
||||
),
|
||||
hash: vec![1],
|
||||
heap_pages: None,
|
||||
};
|
||||
|
||||
@@ -363,15 +363,16 @@ impl<B: BlockT, T, E: std::error::Error + Send + 'static, Transaction> BlockImpo
|
||||
}
|
||||
|
||||
/// Justification import trait
|
||||
#[async_trait::async_trait]
|
||||
pub trait JustificationImport<B: BlockT> {
|
||||
type Error: std::error::Error + Send + 'static;
|
||||
|
||||
/// Called by the import queue when it is started. Returns a list of justifications to request
|
||||
/// from the network.
|
||||
fn on_start(&mut self) -> Vec<(B::Hash, NumberFor<B>)> { Vec::new() }
|
||||
async fn on_start(&mut self) -> Vec<(B::Hash, NumberFor<B>)>;
|
||||
|
||||
/// Import a Block justification and finalize the given block.
|
||||
fn import_justification(
|
||||
async fn import_justification(
|
||||
&mut self,
|
||||
hash: B::Hash,
|
||||
number: NumberFor<B>,
|
||||
|
||||
@@ -220,16 +220,16 @@ impl<B: BlockT> BlockImportWorker<B> {
|
||||
metrics,
|
||||
};
|
||||
|
||||
// Let's initialize `justification_import`
|
||||
if let Some(justification_import) = worker.justification_import.as_mut() {
|
||||
for (hash, number) in justification_import.on_start() {
|
||||
worker.result_sender.request_justification(&hash, number);
|
||||
}
|
||||
}
|
||||
|
||||
let delay_between_blocks = Duration::default();
|
||||
|
||||
let future = async move {
|
||||
// Let's initialize `justification_import`
|
||||
if let Some(justification_import) = worker.justification_import.as_mut() {
|
||||
for (hash, number) in justification_import.on_start().await {
|
||||
worker.result_sender.request_justification(&hash, number);
|
||||
}
|
||||
}
|
||||
|
||||
let block_import_process = block_import_process(
|
||||
block_import,
|
||||
verifier,
|
||||
@@ -254,15 +254,18 @@ impl<B: BlockT> BlockImportWorker<B> {
|
||||
// Make sure to first process all justifications
|
||||
while let Poll::Ready(justification) = futures::poll!(justification_port.next()) {
|
||||
match justification {
|
||||
Some(ImportJustification(who, hash, number, justification)) =>
|
||||
worker.import_justification(who, hash, number, justification),
|
||||
Some(ImportJustification(who, hash, number, justification)) => {
|
||||
worker
|
||||
.import_justification(who, hash, number, justification)
|
||||
.await
|
||||
}
|
||||
None => {
|
||||
log::debug!(
|
||||
target: "block-import",
|
||||
"Stopping block import because justification channel was closed!",
|
||||
);
|
||||
return
|
||||
},
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +281,7 @@ impl<B: BlockT> BlockImportWorker<B> {
|
||||
(future, justification_sender, block_import_sender)
|
||||
}
|
||||
|
||||
fn import_justification(
|
||||
async fn import_justification(
|
||||
&mut self,
|
||||
who: Origin,
|
||||
hash: B::Hash,
|
||||
@@ -286,8 +289,11 @@ impl<B: BlockT> BlockImportWorker<B> {
|
||||
justification: Justification,
|
||||
) {
|
||||
let started = wasm_timer::Instant::now();
|
||||
let success = self.justification_import.as_mut().map(|justification_import| {
|
||||
justification_import.import_justification(hash, number, justification)
|
||||
|
||||
let success = match self.justification_import.as_mut() {
|
||||
Some(justification_import) => justification_import
|
||||
.import_justification(hash, number, justification)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
debug!(
|
||||
target: "sync",
|
||||
@@ -298,14 +304,19 @@ impl<B: BlockT> BlockImportWorker<B> {
|
||||
who,
|
||||
);
|
||||
e
|
||||
}).is_ok()
|
||||
}).unwrap_or(false);
|
||||
})
|
||||
.is_ok(),
|
||||
None => false,
|
||||
};
|
||||
|
||||
if let Some(metrics) = self.metrics.as_ref() {
|
||||
metrics.justification_import_time.observe(started.elapsed().as_secs_f64());
|
||||
metrics
|
||||
.justification_import_time
|
||||
.observe(started.elapsed().as_secs_f64());
|
||||
}
|
||||
|
||||
self.result_sender.justification_imported(who, &hash, number, success);
|
||||
self.result_sender
|
||||
.justification_imported(who, &hash, number, success);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,10 +483,15 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl JustificationImport<Block> for () {
|
||||
type Error = crate::Error;
|
||||
|
||||
fn import_justification(
|
||||
async fn on_start(&mut self) -> Vec<(Hash, BlockNumber)> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
async fn import_justification(
|
||||
&mut self,
|
||||
_hash: Hash,
|
||||
_number: BlockNumber,
|
||||
|
||||
@@ -33,23 +33,24 @@ use sp_runtime::traits::{Block as BlockT, NumberFor};
|
||||
/// some implementations.
|
||||
///
|
||||
/// Non-deterministically finalizing chains may only use the `_authoring` functions.
|
||||
#[async_trait::async_trait]
|
||||
pub trait SelectChain<Block: BlockT>: Sync + Send + Clone {
|
||||
|
||||
/// Get all leaves of the chain: block hashes that have no children currently.
|
||||
/// Get all leaves of the chain, i.e. block hashes that have no children currently.
|
||||
/// Leaves that can never be finalized will not be returned.
|
||||
fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, Error>;
|
||||
async fn leaves(&self) -> Result<Vec<<Block as BlockT>::Hash>, Error>;
|
||||
|
||||
/// Among those `leaves` deterministically pick one chain as the generally
|
||||
/// best chain to author new blocks upon and probably finalize.
|
||||
fn best_chain(&self) -> Result<<Block as BlockT>::Header, Error>;
|
||||
/// best chain to author new blocks upon and probably (but not necessarily)
|
||||
/// finalize.
|
||||
async fn best_chain(&self) -> Result<<Block as BlockT>::Header, Error>;
|
||||
|
||||
/// Get the best descendent of `target_hash` that we should attempt to
|
||||
/// finalize next, if any. It is valid to return the given `target_hash`
|
||||
/// itself if no better descendent exists.
|
||||
fn finality_target(
|
||||
async fn finality_target(
|
||||
&self,
|
||||
target_hash: <Block as BlockT>::Hash,
|
||||
_maybe_max_number: Option<NumberFor<Block>>
|
||||
_maybe_max_number: Option<NumberFor<Block>>,
|
||||
) -> Result<Option<<Block as BlockT>::Hash>, Error> {
|
||||
Ok(Some(target_hash))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user