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

Commit 658c389

Browse files
seunlanlegebkchr
authored andcommitted
manual seal is now consensus agnostic (#7010)
* manual seal is now consensus agnostic * pr grumbles
1 parent f8189fc commit 658c389

File tree

10 files changed

+439
-88
lines changed

10 files changed

+439
-88
lines changed

Cargo.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/consensus/babe/src/aux_schema.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn load_decode<B, T>(backend: &B, key: &[u8]) -> ClientResult<Option<T>>
5151
}
5252

5353
/// Load or initialize persistent epoch change data from backend.
54-
pub(crate) fn load_epoch_changes<Block: BlockT, B: AuxStore>(
54+
pub fn load_epoch_changes<Block: BlockT, B: AuxStore>(
5555
backend: &B,
5656
config: &BabeGenesisConfiguration,
5757
) -> ClientResult<SharedEpochChanges<Block, Epoch>> {

client/consensus/babe/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,10 @@ use schnorrkel::SignatureError;
126126
use codec::{Encode, Decode};
127127
use sp_api::ApiExt;
128128

129-
mod aux_schema;
130129
mod verification;
131130
mod migration;
131+
132+
pub mod aux_schema;
132133
pub mod authorship;
133134
#[cfg(test)]
134135
mod tests;
@@ -1051,7 +1052,7 @@ where
10511052
}
10521053

10531054
/// Register the babe inherent data provider, if not registered already.
1054-
fn register_babe_inherent_data_provider(
1055+
pub fn register_babe_inherent_data_provider(
10551056
inherent_data_providers: &InherentDataProviders,
10561057
slot_duration: u64,
10571058
) -> Result<(), sp_consensus::Error> {

client/consensus/manual-seal/Cargo.toml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,28 @@ parking_lot = "0.10.0"
2222
serde = { version = "1.0", features=["derive"] }
2323
assert_matches = "1.3.0"
2424

25-
sc-client-api = { path = "../../../client/api", version = "2.0.0-rc6" }
26-
sc-transaction-pool = { path = "../../transaction-pool", version = "2.0.0-rc6" }
27-
sp-blockchain = { path = "../../../primitives/blockchain", version = "2.0.0-rc6" }
28-
sp-consensus = { package = "sp-consensus", path = "../../../primitives/consensus/common", version = "0.8.0-rc6" }
29-
sp-inherents = { path = "../../../primitives/inherents", version = "2.0.0-rc6" }
30-
sp-runtime = { path = "../../../primitives/runtime", version = "2.0.0-rc6" }
31-
sp-core = { path = "../../../primitives/core", version = "2.0.0-rc6" }
32-
sp-transaction-pool = { path = "../../../primitives/transaction-pool", version = "2.0.0-rc6" }
33-
prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-rc6" }
25+
sc-client-api = { path = "../../api", version = "2.0.0-rc5" }
26+
sc-consensus-babe = { path = "../../consensus/babe", version = "0.8.0-rc5" }
27+
sc-consensus-epochs = { path = "../../consensus/epochs", version = "0.8.0-rc5" }
28+
sp-consensus-babe = { path = "../../../primitives/consensus/babe", version = "0.8.0-rc5" }
29+
sc-keystore = { path = "../../keystore", version = "2.0.0-rc5" }
30+
31+
sc-transaction-pool = { path = "../../transaction-pool", version = "2.0.0-rc5" }
32+
sp-blockchain = { path = "../../../primitives/blockchain", version = "2.0.0-rc5" }
33+
sp-consensus = { package = "sp-consensus", path = "../../../primitives/consensus/common", version = "0.8.0-rc5" }
34+
sp-inherents = { path = "../../../primitives/inherents", version = "2.0.0-rc5" }
35+
sp-runtime = { path = "../../../primitives/runtime", version = "2.0.0-rc5" }
36+
sp-core = { path = "../../../primitives/core", version = "2.0.0-rc5" }
37+
sp-api = { path = "../../../primitives/api", version = "2.0.0-rc5" }
38+
sp-transaction-pool = { path = "../../../primitives/transaction-pool", version = "2.0.0-rc5" }
39+
sp-timestamp = { path = "../../../primitives/timestamp", version = "2.0.0-rc6" }
40+
41+
prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-rc5" }
3442

3543
[dev-dependencies]
44+
tokio = { version = "0.2", features = ["rt-core", "macros"] }
3645
sc-basic-authorship = { path = "../../basic-authorship", version = "0.8.0-rc6" }
3746
substrate-test-runtime-client = { path = "../../../test-utils/runtime/client", version = "2.0.0-rc6" }
3847
substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool", version = "2.0.0-rc6" }
39-
tokio = { version = "0.2", features = ["rt-core", "macros"] }
4048
env_logger = "0.7.0"
4149
tempfile = "3.1.0"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5+
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
16+
// You should have received a copy of the GNU General Public License
17+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+
//! Extensions for manual seal to produce blocks valid for any runtime.
20+
use super::Error;
21+
22+
use sp_runtime::traits::{Block as BlockT, DigestFor};
23+
use sp_inherents::InherentData;
24+
use sp_consensus::BlockImportParams;
25+
26+
pub mod babe;
27+
28+
/// Consensus data provider, manual seal uses this trait object for authoring blocks valid
29+
/// for any runtime.
30+
pub trait ConsensusDataProvider<B: BlockT>: Send + Sync {
31+
/// Block import transaction type
32+
type Transaction;
33+
34+
/// Attempt to create a consensus digest.
35+
fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result<DigestFor<B>, Error>;
36+
37+
/// set up the neccessary import params.
38+
fn append_block_import(
39+
&self,
40+
parent: &B::Header,
41+
params: &mut BlockImportParams<B, Self::Transaction>,
42+
inherents: &InherentData
43+
) -> Result<(), Error>;
44+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5+
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
16+
// You should have received a copy of the GNU General Public License
17+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+
//! BABE consensus data provider
20+
21+
use super::ConsensusDataProvider;
22+
use crate::Error;
23+
24+
use std::{
25+
any::Any,
26+
borrow::Cow,
27+
sync::{Arc, atomic},
28+
time::SystemTime,
29+
};
30+
use sc_client_api::AuxStore;
31+
use sc_consensus_babe::{
32+
Config, Epoch, authorship, CompatibleDigestItem, BabeIntermediate,
33+
register_babe_inherent_data_provider, INTERMEDIATE_KEY,
34+
};
35+
use sc_consensus_epochs::{SharedEpochChanges, descendent_query};
36+
use sc_keystore::KeyStorePtr;
37+
38+
use sp_api::{ProvideRuntimeApi, TransactionFor};
39+
use sp_blockchain::{HeaderBackend, HeaderMetadata};
40+
use sp_consensus::BlockImportParams;
41+
use sp_consensus_babe::{BabeApi, inherents::BabeInherentData};
42+
use sp_inherents::{InherentDataProviders, InherentData, ProvideInherentData, InherentIdentifier};
43+
use sp_runtime::{
44+
traits::{DigestItemFor, DigestFor, Block as BlockT, Header as _},
45+
generic::Digest,
46+
};
47+
use sp_timestamp::{InherentType, InherentError, INHERENT_IDENTIFIER};
48+
49+
/// Provides BABE-compatible predigests and BlockImportParams.
50+
/// Intended for use with BABE runtimes.
51+
pub struct BabeConsensusDataProvider<B: BlockT, C> {
52+
/// shared reference to keystore
53+
keystore: KeyStorePtr,
54+
55+
/// Shared reference to the client.
56+
client: Arc<C>,
57+
58+
/// Shared epoch changes
59+
epoch_changes: SharedEpochChanges<B, Epoch>,
60+
61+
/// BABE config, gotten from the runtime.
62+
config: Config,
63+
}
64+
65+
impl<B, C> BabeConsensusDataProvider<B, C>
66+
where
67+
B: BlockT,
68+
C: AuxStore + ProvideRuntimeApi<B>,
69+
C::Api: BabeApi<B, Error = sp_blockchain::Error>,
70+
{
71+
pub fn new(
72+
client: Arc<C>,
73+
keystore: KeyStorePtr,
74+
provider: &InherentDataProviders,
75+
epoch_changes: SharedEpochChanges<B, Epoch>,
76+
) -> Result<Self, Error> {
77+
let config = Config::get_or_compute(&*client)?;
78+
let timestamp_provider = SlotTimestampProvider::new(config.slot_duration)?;
79+
80+
provider.register_provider(timestamp_provider)?;
81+
register_babe_inherent_data_provider(provider, config.slot_duration)?;
82+
83+
Ok(Self {
84+
config,
85+
client,
86+
keystore,
87+
epoch_changes,
88+
})
89+
}
90+
}
91+
92+
impl<B, C> ConsensusDataProvider<B> for BabeConsensusDataProvider<B, C>
93+
where
94+
B: BlockT,
95+
C: AuxStore + HeaderBackend<B> + HeaderMetadata<B, Error = sp_blockchain::Error> + ProvideRuntimeApi<B>,
96+
C::Api: BabeApi<B, Error = sp_blockchain::Error>,
97+
{
98+
type Transaction = TransactionFor<C, B>;
99+
100+
fn create_digest(&self, parent: &B::Header, inherents: &InherentData) -> Result<DigestFor<B>, Error> {
101+
let slot_number = inherents.babe_inherent_data()?;
102+
103+
let epoch_changes = self.epoch_changes.lock();
104+
let epoch_descriptor = epoch_changes
105+
.epoch_descriptor_for_child_of(
106+
descendent_query(&*self.client),
107+
&parent.hash(),
108+
parent.number().clone(),
109+
slot_number,
110+
)
111+
.map_err(|e| Error::StringError(format!("failed to fetch epoch_descriptor: {}", e)))?
112+
.ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet)?;
113+
114+
let epoch = epoch_changes
115+
.viable_epoch(
116+
&epoch_descriptor,
117+
|slot| Epoch::genesis(&self.config, slot),
118+
)
119+
.ok_or_else(|| {
120+
log::info!(target: "babe", "create_digest: no viable_epoch :(");
121+
sp_consensus::Error::InvalidAuthoritiesSet
122+
})?;
123+
124+
// this is a dev node environment, we should always be able to claim a slot.
125+
let (predigest, _) = authorship::claim_slot(slot_number, epoch.as_ref(), &self.keystore)
126+
.ok_or_else(|| Error::StringError("failed to claim slot for authorship".into()))?;
127+
128+
Ok(Digest {
129+
logs: vec![
130+
<DigestItemFor<B> as CompatibleDigestItem>::babe_pre_digest(predigest),
131+
],
132+
})
133+
}
134+
135+
fn append_block_import(
136+
&self,
137+
parent: &B::Header,
138+
params: &mut BlockImportParams<B, Self::Transaction>,
139+
inherents: &InherentData
140+
) -> Result<(), Error> {
141+
let slot_number = inherents.babe_inherent_data()?;
142+
143+
let epoch_descriptor = self.epoch_changes.lock()
144+
.epoch_descriptor_for_child_of(
145+
descendent_query(&*self.client),
146+
&parent.hash(),
147+
parent.number().clone(),
148+
slot_number,
149+
)
150+
.map_err(|e| Error::StringError(format!("failed to fetch epoch data: {}", e)))?
151+
.ok_or_else(|| sp_consensus::Error::InvalidAuthoritiesSet)?;
152+
153+
params.intermediates.insert(
154+
Cow::from(INTERMEDIATE_KEY),
155+
Box::new(BabeIntermediate::<B> { epoch_descriptor }) as Box<dyn Any>,
156+
);
157+
158+
Ok(())
159+
}
160+
}
161+
162+
/// Provide duration since unix epoch in millisecond for timestamp inherent.
163+
/// Mocks the timestamp inherent to always produce the timestamp for the next babe slot.
164+
struct SlotTimestampProvider {
165+
time: atomic::AtomicU64,
166+
slot_duration: u64
167+
}
168+
169+
impl SlotTimestampProvider {
170+
/// create a new mocked time stamp provider.
171+
fn new(slot_duration: u64) -> Result<Self, Error> {
172+
let now = SystemTime::now();
173+
let duration = now.duration_since(SystemTime::UNIX_EPOCH)
174+
.map_err(|err| Error::StringError(format!("{}", err)))?;
175+
Ok(Self {
176+
time: atomic::AtomicU64::new(duration.as_millis() as u64),
177+
slot_duration,
178+
})
179+
}
180+
}
181+
182+
impl ProvideInherentData for SlotTimestampProvider {
183+
fn inherent_identifier(&self) -> &'static InherentIdentifier {
184+
&INHERENT_IDENTIFIER
185+
}
186+
187+
fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), sp_inherents::Error> {
188+
// we update the time here.
189+
let duration: InherentType = self.time.fetch_add(self.slot_duration, atomic::Ordering::SeqCst);
190+
inherent_data.put_data(INHERENT_IDENTIFIER, &duration)?;
191+
Ok(())
192+
}
193+
194+
fn error_to_string(&self, error: &[u8]) -> Option<String> {
195+
InherentError::try_from(&INHERENT_IDENTIFIER, error).map(|e| format!("{:?}", e))
196+
}
197+
}

client/consensus/manual-seal/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
//! A manual sealing engine: the engine listens for rpc calls to seal blocks and create forks.
2020
//! This is suitable for a testing environment.
21+
2122
use sp_consensus::{Error as ConsensusError, ImportResult};
2223
use sp_blockchain::Error as BlockchainError;
2324
use sp_inherents::Error as InherentsError;

0 commit comments

Comments
 (0)