|
33 | 33 | //! |
34 | 34 | //! and thanks to versioning can be easily updated in the future. |
35 | 35 |
|
36 | | -use sp_runtime::traits::{Convert, Member}; |
| 36 | +use sp_runtime::traits::{Convert, Header, Member}; |
37 | 37 | use sp_std::prelude::*; |
38 | 38 |
|
39 | 39 | use codec::Decode; |
40 | | -use pallet_mmr::{LeafDataProvider, ParentNumberAndHash}; |
| 40 | +use pallet_mmr::{primitives::AncestryProof, LeafDataProvider, ParentNumberAndHash}; |
41 | 41 | use sp_consensus_beefy::{ |
| 42 | + known_payloads, |
42 | 43 | mmr::{BeefyAuthoritySet, BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion}, |
43 | | - ValidatorSet as BeefyValidatorSet, |
| 44 | + AncestryHelper, Commitment, ConsensusLog, ValidatorSet as BeefyValidatorSet, |
44 | 45 | }; |
45 | 46 |
|
46 | 47 | use frame_support::{crypto::ecdsa::ECDSAExt, traits::Get}; |
47 | | -use frame_system::pallet_prelude::BlockNumberFor; |
| 48 | +use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor}; |
48 | 49 |
|
49 | 50 | pub use pallet::*; |
| 51 | +use sp_runtime::generic::OpaqueDigestItemId; |
50 | 52 |
|
51 | 53 | #[cfg(test)] |
52 | 54 | mod mock; |
@@ -172,6 +174,75 @@ where |
172 | 174 | } |
173 | 175 | } |
174 | 176 |
|
| 177 | +impl<T: Config> AncestryHelper<HeaderFor<T>> for Pallet<T> |
| 178 | +where |
| 179 | + T: pallet_mmr::Config<Hashing = sp_consensus_beefy::MmrHashing>, |
| 180 | +{ |
| 181 | + type Proof = AncestryProof<MerkleRootOf<T>>; |
| 182 | + type ValidationContext = MerkleRootOf<T>; |
| 183 | + |
| 184 | + fn extract_validation_context(header: HeaderFor<T>) -> Option<Self::ValidationContext> { |
| 185 | + // Check if the provided header is canonical. |
| 186 | + let expected_hash = frame_system::Pallet::<T>::block_hash(header.number()); |
| 187 | + if expected_hash != header.hash() { |
| 188 | + return None; |
| 189 | + } |
| 190 | + |
| 191 | + // Extract the MMR root from the header digest |
| 192 | + header.digest().convert_first(|l| { |
| 193 | + l.try_to(OpaqueDigestItemId::Consensus(&sp_consensus_beefy::BEEFY_ENGINE_ID)) |
| 194 | + .and_then(|log: ConsensusLog<<T as pallet_beefy::Config>::BeefyId>| match log { |
| 195 | + ConsensusLog::MmrRoot(mmr_root) => Some(mmr_root), |
| 196 | + _ => None, |
| 197 | + }) |
| 198 | + }) |
| 199 | + } |
| 200 | + |
| 201 | + fn is_non_canonical( |
| 202 | + commitment: &Commitment<BlockNumberFor<T>>, |
| 203 | + proof: Self::Proof, |
| 204 | + context: Self::ValidationContext, |
| 205 | + ) -> bool { |
| 206 | + let commitment_leaf_count = |
| 207 | + match pallet_mmr::Pallet::<T>::block_num_to_leaf_count(commitment.block_number) { |
| 208 | + Ok(commitment_leaf_count) => commitment_leaf_count, |
| 209 | + Err(_) => { |
| 210 | + // We can't prove that the commitment is non-canonical if the |
| 211 | + // `commitment.block_number` is invalid. |
| 212 | + return false |
| 213 | + }, |
| 214 | + }; |
| 215 | + if commitment_leaf_count != proof.prev_leaf_count { |
| 216 | + // Can't prove that the commitment is non-canonical if the `commitment.block_number` |
| 217 | + // doesn't match the ancestry proof. |
| 218 | + return false; |
| 219 | + } |
| 220 | + |
| 221 | + let canonical_mmr_root = context; |
| 222 | + let canonical_prev_root = |
| 223 | + match pallet_mmr::Pallet::<T>::verify_ancestry_proof(canonical_mmr_root, proof) { |
| 224 | + Ok(canonical_prev_root) => canonical_prev_root, |
| 225 | + Err(_) => { |
| 226 | + // Can't prove that the commitment is non-canonical if the proof |
| 227 | + // is invalid. |
| 228 | + return false |
| 229 | + }, |
| 230 | + }; |
| 231 | + |
| 232 | + let commitment_root = |
| 233 | + match commitment.payload.get_decoded::<MerkleRootOf<T>>(&known_payloads::MMR_ROOT_ID) { |
| 234 | + Some(commitment_root) => commitment_root, |
| 235 | + None => { |
| 236 | + // If the commitment doesn't contain any MMR root, while the proof is valid, |
| 237 | + // the commitment is invalid |
| 238 | + return true |
| 239 | + }, |
| 240 | + }; |
| 241 | + |
| 242 | + canonical_prev_root != commitment_root |
| 243 | + } |
| 244 | +} |
| 245 | + |
175 | 246 | impl<T: Config> Pallet<T> { |
176 | 247 | /// Return the currently active BEEFY authority set proof. |
177 | 248 | pub fn authority_set_proof() -> BeefyAuthoritySet<MerkleRootOf<T>> { |
|
0 commit comments