1+ use futures:: future:: pending;
12use sc_client_api:: AuxStore ;
23use sc_client_api:: BlockOf ;
34use sc_client_api:: UsageProvider ;
@@ -8,17 +9,23 @@ use sc_consensus::{BasicQueue, DefaultImportQueue};
89use sc_consensus_aura:: AuraVerifier ;
910use sc_consensus_aura:: CheckForEquivocation ;
1011use sc_consensus_aura:: ImportQueueParams ;
12+ use sc_consensus_babe:: CompatibleDigestItem as _;
1113use sc_consensus_slots:: InherentDataProviderExt ;
1214use sc_telemetry:: TelemetryHandle ;
1315use sp_api:: ApiExt ;
1416use sp_api:: ProvideRuntimeApi ;
1517use sp_block_builder:: BlockBuilder as BlockBuilderApi ;
1618use sp_blockchain:: HeaderBackend ;
19+ use sp_blockchain:: HeaderMetadata ;
1720use sp_consensus:: error:: Error as ConsensusError ;
1821use sp_consensus_aura:: AuraApi ;
19- use sp_consensus_aura:: sr25519:: AuthorityId ;
20- use sp_consensus_aura:: sr25519:: AuthorityPair ;
22+ use sp_consensus_aura:: sr25519:: AuthorityId as AuraAuthorityId ;
23+ use sp_consensus_aura:: sr25519:: AuthorityPair as AuraAuthorityPair ;
24+ use sp_consensus_babe:: AuthorityId as BabeAuthorityId ;
25+ use sp_consensus_babe:: AuthorityPair as BabeAuthorityPair ;
2126use sp_consensus_babe:: BABE_ENGINE_ID ;
27+ use sp_core:: Pair ;
28+ use sp_core:: crypto:: Ss58Codec ;
2229use sp_inherents:: CreateInherentDataProviders ;
2330use sp_runtime:: Digest ;
2431use sp_runtime:: DigestItem ;
@@ -34,11 +41,19 @@ use std::sync::Arc;
3441/// blacklist the offending node and refuse to connect with them until they
3542/// are restarted
3643struct AuraWrappedVerifier < B , C , CIDP , N > {
37- inner : AuraVerifier < C , AuthorityPair , CIDP , N > ,
44+ inner : AuraVerifier < C , AuraAuthorityPair , CIDP , N > ,
45+ client : Arc < C > ,
3846 _phantom : std:: marker:: PhantomData < B > ,
3947}
4048
41- impl < B : BlockT , C , CIDP , N > AuraWrappedVerifier < B , C , CIDP , N > {
49+ impl < B : BlockT , C , CIDP , N > AuraWrappedVerifier < B , C , CIDP , N >
50+ where
51+ CIDP : CreateInherentDataProviders < B , ( ) > + Send + Sync ,
52+ CIDP :: InherentDataProviders : InherentDataProviderExt + Send + Sync ,
53+ C : ProvideRuntimeApi < B > + Send + Sync + sc_client_api:: backend:: AuxStore ,
54+ C :: Api : BlockBuilderApi < B > + AuraApi < B , AuraAuthorityId > + ApiExt < B > ,
55+ C : HeaderBackend < B > + HeaderMetadata < B > ,
56+ {
4257 pub fn new (
4358 client : Arc < C > ,
4459 create_inherent_data_providers : CIDP ,
@@ -47,44 +62,102 @@ impl<B: BlockT, C, CIDP, N> AuraWrappedVerifier<B, C, CIDP, N> {
4762 compatibility_mode : sc_consensus_aura:: CompatibilityMode < N > ,
4863 ) -> Self {
4964 let verifier_params = sc_consensus_aura:: BuildVerifierParams :: < C , CIDP , _ > {
50- client,
65+ client : client . clone ( ) ,
5166 create_inherent_data_providers,
5267 telemetry,
5368 check_for_equivocation,
5469 compatibility_mode,
5570 } ;
5671 let verifier =
57- sc_consensus_aura:: build_verifier :: < AuthorityPair , C , CIDP , N > ( verifier_params) ;
72+ sc_consensus_aura:: build_verifier :: < AuraAuthorityPair , C , CIDP , N > ( verifier_params) ;
5873
5974 AuraWrappedVerifier {
6075 inner : verifier,
76+ client,
6177 _phantom : std:: marker:: PhantomData ,
6278 }
6379 }
80+
81+ /// When a Babe block is encountered in Aura mode, we need to check it is legitimate
82+ /// before switching to the Babe service.
83+ ///
84+ /// We can't use a full [`BabeVerifier`] because we don't have a Babe link running, however we
85+ /// can check that the block author is one of the authorities from the last verified Aura block.
86+ ///
87+ /// The Babe block will be verified in full after the node spins back up as a Babe service.
88+ async fn check_babe_block ( & self , block : BlockImportParams < B > ) -> Result < ( ) , String > {
89+ log:: info!(
90+ "Checking Babe block {:?} is legitimate" ,
91+ block. post_header( ) . hash( )
92+ ) ;
93+ let mut header = block. header . clone ( ) ;
94+ let seal = header
95+ . digest_mut ( )
96+ . pop ( )
97+ . ok_or_else ( || "Header Unsealed" . to_string ( ) ) ?;
98+ let sig = seal
99+ . as_babe_seal ( )
100+ . ok_or_else ( || "Header bad seal" . to_string ( ) ) ?;
101+
102+ let authorities = self . get_last_aura_authorities ( block. header ) ?;
103+ if let Some ( a) = authorities. into_iter ( ) . find ( |a| {
104+ let babe_key = BabeAuthorityId :: from ( a. clone ( ) . into_inner ( ) ) ;
105+ BabeAuthorityPair :: verify ( & sig, header. hash ( ) , & babe_key)
106+ } ) {
107+ log:: info!(
108+ "Babe block has a valid signature by author: {}" ,
109+ a. to_ss58check( )
110+ ) ;
111+ Ok ( ( ) )
112+ } else {
113+ Err ( "Babe block has a bad signature. Rejecting." . to_string ( ) )
114+ }
115+ }
116+
117+ /// Given the hash of the first Babe block mined, get the Aura authorities that existed prior to
118+ /// the runtime upgrade.
119+ ///
120+ /// Note: We need get the Aura authorities from grandparent rather than the parent,
121+ /// because the runtime upgrade clearing the Aura authorities occurs in the parent.
122+ fn get_last_aura_authorities (
123+ & self ,
124+ first_babe_block_header : B :: Header ,
125+ ) -> Result < Vec < AuraAuthorityId > , String > {
126+ let parent_header = self
127+ . client
128+ . header ( * first_babe_block_header. parent_hash ( ) )
129+ . map_err ( |e| format ! ( "Failed to get parent header: {}" , e) ) ?
130+ . ok_or ( "Parent header not found" . to_string ( ) ) ?;
131+ let grandparent_hash = parent_header. parent_hash ( ) ;
132+
133+ let runtime_api = self . client . runtime_api ( ) ;
134+ let authorities = runtime_api
135+ . authorities ( * grandparent_hash)
136+ . map_err ( |e| format ! ( "Failed to get Aura authorities: {}" , e) ) ?;
137+
138+ Ok ( authorities)
139+ }
64140}
65141
66142#[ async_trait:: async_trait]
67143impl < B : BlockT , C , CIDP > Verifier < B > for AuraWrappedVerifier < B , C , CIDP , NumberFor < B > >
68144where
69145 C : ProvideRuntimeApi < B > + Send + Sync + sc_client_api:: backend:: AuxStore ,
70- C :: Api : BlockBuilderApi < B > + AuraApi < B , AuthorityId > + ApiExt < B > ,
146+ C :: Api : BlockBuilderApi < B > + AuraApi < B , AuraAuthorityId > + ApiExt < B > ,
147+ C : HeaderBackend < B > + HeaderMetadata < B > ,
71148 CIDP : CreateInherentDataProviders < B , ( ) > + Send + Sync ,
72149 CIDP :: InherentDataProviders : InherentDataProviderExt + Send + Sync ,
73150{
74151 async fn verify ( & self , block : BlockImportParams < B > ) -> Result < BlockImportParams < B > , String > {
75152 let number: NumberFor < B > = * block. post_header ( ) . number ( ) ;
76153 log:: debug!( "Verifying block: {:?}" , number) ;
77154 if is_babe_digest ( block. header . digest ( ) ) {
78- // TODO: Use a BabeVerifier to verify Babe blocks. This will
79- // prevent rapid validation failure and subsequent re-fetching
80- // of the same block from peers, which triggers the peers to
81- // blacklist the offending node and refuse to connect with them until they
82- // are restarted.
83- //
84- // Unfortunately, BabeVerifier construction logic is NOT public outside of
85- // its crate in vanilla Polkadot SDK, so we are unable to use it until we
86- // migrate to our Polkadot SDK fork.
87- self . inner . verify ( block) . await
155+ self . check_babe_block ( block) . await ?;
156+ log:: debug!(
157+ "Detected Babe block! Verifier cannot continue, upgrade must be triggered elsewhere..."
158+ ) ;
159+ pending :: < ( ) > ( ) . await ;
160+ unreachable ! ( "Should not reach here, pending forever." ) ;
88161 } else {
89162 self . inner . verify ( block) . await
90163 }
@@ -97,15 +170,16 @@ pub fn import_queue<B, I, C, S, CIDP>(
97170) -> Result < DefaultImportQueue < B > , sp_consensus:: Error >
98171where
99172 B : BlockT ,
100- C :: Api : BlockBuilderApi < B > + AuraApi < B , AuthorityId > + ApiExt < B > ,
173+ C :: Api : BlockBuilderApi < B > + AuraApi < B , AuraAuthorityId > + ApiExt < B > ,
101174 C : ' static
102175 + ProvideRuntimeApi < B >
103176 + BlockOf
104177 + Send
105178 + Sync
106179 + AuxStore
107180 + UsageProvider < B >
108- + HeaderBackend < B > ,
181+ + HeaderBackend < B >
182+ + HeaderMetadata < B > ,
109183 I : BlockImport < B , Error = ConsensusError > + Send + Sync + ' static ,
110184 S : sp_core:: traits:: SpawnEssentialNamed ,
111185 CIDP : CreateInherentDataProviders < B , ( ) > + Sync + Send + ' static ,
0 commit comments