Merkle Mountain Range pallet improvements#7891
Conversation
|
Did you consider moving frame/merkle-mountain-range/mmr/lib.rs to primitive (+ Instance and Config traits)? |
I'd rather keep the primitives as minimal as possible, right now it's:
I guess your idea would be to provide stateless proof verification in the primitives crate as well? It should be possible even without |
| pub fn from_leaf<T: FullLeaf>(leaf: T) -> Self { | ||
| let encoded_leaf = leaf.using_encoded(|d| d.to_vec(), true); | ||
| // OpaqueLeaf must be SCALE-compatible with `Vec<u8>`. | ||
| // Simply using raw encoded bytes don't work, cause we don't know the | ||
| // length of the expected data. | ||
| let encoded_vec = codec::Encode::encode(&encoded_leaf); | ||
| OpaqueLeaf(encoded_vec) | ||
| } | ||
| } | ||
|
|
||
| impl FullLeaf for OpaqueLeaf { | ||
| fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F, _compact: bool) -> R { | ||
| f(&self.0) |
There was a problem hiding this comment.
this type encoding/decoding is bit confusing to me.
The encoding is identity but the decoding is not.
e.g. encode(decode(encode(OpaqueLeaf(something))) != encode(OpaqueLeaf(something))
I think it would make more sense to have a manual implementation of Decode.
Or to change to something like this:
| pub fn from_leaf<T: FullLeaf>(leaf: T) -> Self { | |
| let encoded_leaf = leaf.using_encoded(|d| d.to_vec(), true); | |
| // OpaqueLeaf must be SCALE-compatible with `Vec<u8>`. | |
| // Simply using raw encoded bytes don't work, cause we don't know the | |
| // length of the expected data. | |
| let encoded_vec = codec::Encode::encode(&encoded_leaf); | |
| OpaqueLeaf(encoded_vec) | |
| } | |
| } | |
| impl FullLeaf for OpaqueLeaf { | |
| fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F, _compact: bool) -> R { | |
| f(&self.0) | |
| pub fn from_leaf<T: FullLeaf>(leaf: T) -> Self { | |
| let encoded_leaf = leaf.using_encoded(|d| d.to_vec(), true); | |
| OpaqueLeaf(encoded_leaf) | |
| } | |
| } | |
| impl FullLeaf for OpaqueLeaf { | |
| fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F, _compact: bool) -> R { | |
| f(&self.0.encode()) |
There was a problem hiding this comment.
I was writing an elaborate answer why this is correct, just to learn that it's all wrong :) Thanks for being persistent with this.
So my initialy motivation was to have OpaqueLeaf be Vec<u8> SCALE-compatible, but pretend to be the "unwraped" (no length prefix) encoding for MMR struct. I've realised that this is not really needed, and I can relax the FullLeaf requirement and have OpaqueLeaf be completely independent from SCALE.
Please see the updated version now. The runtime API just accepts a raw Vec<u8>, and we just wrap this into OpaqueLeaf to get custom FullLeaf implementation (the default one (blanket impl for codec::Encode) would re-encode the vec, which is what I wanted to avoid).
Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
gui1117
left a comment
There was a problem hiding this comment.
looks good to me, does it need an audit ?
|
|
||
| fn verify_proof_stateless( | ||
| root: mmr::Hash, | ||
| leaf: Vec<u8>, |
There was a problem hiding this comment.
by curiosity: am I correct saying that user could also give the hash instead of the encoded leaf here ?
There was a problem hiding this comment.
So the leaf has to be encoded in it's compact form, so depending on the types used in the pallet it either has to be the hash (if it's wrapped in Compact) or the full leaf. I don't think passing a hash here would work in case your MMR leaf is configured without Compact (i.e. the "compact" encoding and regular encoding is the same).
The MMR code was not audited yet, it will be though as a part of a bigger bridge project when we stabilise the code a bit more. |
|
bot merge |
|
Trying merge. |
Follow up on #7312
This PR adds runtime APIs to make it easy to generate and verify MMR proofs if pallet is included in the runtime.
Additionally it adds a
verify_leaf_proofstandalone function, which allows stateless verification of MMR proofs that are coming from differently configured pallets (i.e. other chains). This functionality is exposed in the runtime api as well for convenience.Since the exact layout of the leaf type is most likely unknown, we use
OpaqueLeafstructure, which maintains scale-compatibility with the type the proof originates from.