2121// limitations under the License.
2222
2323use std:: cmp:: Ordering ;
24- use std:: ops:: Deref ;
2524
26- use bp:: dbc;
27- use bp:: dbc:: anchor:: MergeError ;
25+ use bp:: dbc:: opret:: OpretProof ;
26+ use bp:: dbc:: tapret:: TapretProof ;
27+ use bp:: dbc:: Anchor ;
28+ use bp:: Txid ;
2829use commit_verify:: mpc;
2930use strict_encoding:: StrictDumb ;
3031
31- use crate :: { TransitionBundle , WitnessId , WitnessOrd , LIB_NAME_RGB } ;
32+ use crate :: { BundleId , ContractId , TransitionBundle , WitnessId , WitnessOrd , LIB_NAME_RGB } ;
3233
3334#[ derive( Clone , Eq , PartialEq , Debug ) ]
3435#[ derive( StrictType , StrictDumb , StrictEncode , StrictDecode ) ]
@@ -39,10 +40,15 @@ use crate::{TransitionBundle, WitnessId, WitnessOrd, LIB_NAME_RGB};
3940 serde( crate = "serde_crate" , rename_all = "camelCase" )
4041) ]
4142pub struct AnchoredBundle {
42- pub anchor : Anchor ,
43+ pub anchor : XAnchor ,
4344 pub bundle : TransitionBundle ,
4445}
4546
47+ impl AnchoredBundle {
48+ #[ inline]
49+ pub fn bundle_id ( & self ) -> BundleId { self . bundle . bundle_id ( ) }
50+ }
51+
4652#[ derive( Clone , Eq , PartialEq , Debug ) ]
4753#[ derive( StrictType , StrictDumb , StrictEncode , StrictDecode ) ]
4854#[ strict_type( lib = LIB_NAME_RGB , tags = custom, dumb = Self :: Bitcoin ( strict_dumb!( ) ) ) ]
@@ -51,65 +57,212 @@ pub struct AnchoredBundle {
5157 derive( Serialize , Deserialize ) ,
5258 serde( crate = "serde_crate" , rename_all = "camelCase" )
5359) ]
54- pub enum Anchor < P : mpc:: Proof + StrictDumb = mpc:: MerkleProof > {
60+ pub enum XAnchor < P : mpc:: Proof + StrictDumb = mpc:: MerkleProof > {
5561 #[ strict_type( tag = 0x00 ) ]
56- Bitcoin ( dbc :: Anchor < P > ) ,
62+ Bitcoin ( AnchorSet < P > ) ,
5763
5864 #[ strict_type( tag = 0x01 ) ]
59- Liquid ( dbc :: Anchor < P > ) ,
65+ Liquid ( AnchorSet < P > ) ,
6066}
6167
62- impl < P : mpc:: Proof + StrictDumb > Deref for Anchor < P > {
63- type Target = dbc:: Anchor < P > ;
64-
68+ impl < P : mpc:: Proof + StrictDumb > XAnchor < P > {
6569 #[ inline]
66- fn deref ( & self ) -> & Self :: Target {
70+ pub fn layer1 ( & self ) -> Layer1 {
6771 match self {
68- Anchor :: Bitcoin ( anchor) | Anchor :: Liquid ( anchor) => anchor,
72+ XAnchor :: Bitcoin ( _) => Layer1 :: Bitcoin ,
73+ XAnchor :: Liquid ( _) => Layer1 :: Liquid ,
6974 }
7075 }
71- }
7276
73- impl < P : mpc:: Proof + StrictDumb > Anchor < P > {
7477 #[ inline]
75- pub fn layer1 ( & self ) -> Layer1 {
78+ pub fn witness_id ( & self ) -> WitnessId {
7679 match self {
77- Anchor :: Bitcoin ( _ ) => Layer1 :: Bitcoin ,
78- Anchor :: Liquid ( _ ) => Layer1 :: Liquid ,
80+ XAnchor :: Bitcoin ( anchor ) => WitnessId :: Bitcoin ( anchor . txid_unchecked ( ) ) ,
81+ XAnchor :: Liquid ( anchor ) => WitnessId :: Liquid ( anchor . txid_unchecked ( ) ) ,
7982 }
8083 }
8184
82- #[ inline]
83- pub fn witness_id ( & self ) -> WitnessId {
85+ fn map < Q : mpc:: Proof + StrictDumb , E > (
86+ self ,
87+ f : impl FnOnce ( AnchorSet < P > ) -> Result < AnchorSet < Q > , E > ,
88+ ) -> Result < XAnchor < Q > , E > {
8489 match self {
85- Anchor :: Bitcoin ( anchor) => WitnessId :: Bitcoin ( anchor. txid ) ,
86- Anchor :: Liquid ( anchor) => WitnessId :: Liquid ( anchor. txid ) ,
90+ XAnchor :: Bitcoin ( anchor) => f ( anchor) . map ( XAnchor :: Bitcoin ) ,
91+ XAnchor :: Liquid ( anchor) => f ( anchor) . map ( XAnchor :: Liquid ) ,
8792 }
8893 }
94+ }
8995
90- pub fn map < Q : mpc:: Proof + StrictDumb , E > (
91- self ,
92- f : impl FnOnce ( dbc:: Anchor < P > ) -> Result < dbc:: Anchor < Q > , E > ,
93- ) -> Result < Anchor < Q > , E > {
96+ impl XAnchor < mpc:: MerkleBlock > {
97+ pub fn known_bundle_ids ( & self ) -> impl Iterator < Item = ( BundleId , ContractId ) > + ' _ {
9498 match self {
95- Anchor :: Bitcoin ( anchor) => f ( anchor) . map ( Anchor :: Bitcoin ) ,
96- Anchor :: Liquid ( anchor) => f ( anchor) . map ( Anchor :: Liquid ) ,
99+ XAnchor :: Bitcoin ( anchor) | XAnchor :: Liquid ( anchor) => anchor. known_bundle_ids ( ) ,
97100 }
98101 }
102+
103+ pub fn to_merkle_proof (
104+ & self ,
105+ contract_id : ContractId ,
106+ ) -> Result < XAnchor < mpc:: MerkleProof > , mpc:: LeafNotKnown > {
107+ self . clone ( ) . into_merkle_proof ( contract_id)
108+ }
109+
110+ pub fn into_merkle_proof (
111+ self ,
112+ contract_id : ContractId ,
113+ ) -> Result < XAnchor < mpc:: MerkleProof > , mpc:: LeafNotKnown > {
114+ self . map ( |a| a. into_merkle_proof ( contract_id) )
115+ }
116+ }
117+
118+ impl XAnchor < mpc:: MerkleProof > {
119+ pub fn to_merkle_block (
120+ & self ,
121+ contract_id : ContractId ,
122+ bundle_id : BundleId ,
123+ ) -> Result < XAnchor < mpc:: MerkleBlock > , mpc:: InvalidProof > {
124+ self . clone ( ) . into_merkle_block ( contract_id, bundle_id)
125+ }
126+
127+ pub fn into_merkle_block (
128+ self ,
129+ contract_id : ContractId ,
130+ bundle_id : BundleId ,
131+ ) -> Result < XAnchor < mpc:: MerkleBlock > , mpc:: InvalidProof > {
132+ self . map ( |a| a. into_merkle_block ( contract_id, bundle_id) )
133+ }
99134}
100135
101- impl Anchor < mpc:: MerkleBlock > {
102- pub fn merge_reveal ( self , other : Self ) -> Result < Self , MergeError > {
103- match ( self , other) {
104- ( Anchor :: Bitcoin ( anchor) , Anchor :: Bitcoin ( other) ) => {
105- anchor. merge_reveal ( other) . map ( Anchor :: Bitcoin )
106- }
107- ( Anchor :: Liquid ( anchor) , Anchor :: Liquid ( other) ) => {
108- anchor. merge_reveal ( other) . map ( Anchor :: Liquid )
109- }
110- _ => Err ( MergeError :: ProofMismatch ) ,
136+ #[ derive( Clone , Eq , PartialEq , Debug ) ]
137+ #[ derive( StrictType , StrictDumb , StrictEncode , StrictDecode ) ]
138+ #[ strict_type( lib = LIB_NAME_RGB , tags = custom, dumb = Self :: Tapret ( strict_dumb!( ) ) ) ]
139+ #[ cfg_attr(
140+ feature = "serde" ,
141+ derive( Serialize , Deserialize ) ,
142+ serde( crate = "serde_crate" , rename_all = "camelCase" )
143+ ) ]
144+ pub enum AnchorSet < P : mpc:: Proof + StrictDumb = mpc:: MerkleProof > {
145+ #[ strict_type( tag = 0x01 ) ]
146+ Tapret ( Anchor < P , TapretProof > ) ,
147+ #[ strict_type( tag = 0x02 ) ]
148+ Opret ( Anchor < P , OpretProof > ) ,
149+ #[ strict_type( tag = 0x03 ) ]
150+ Dual {
151+ tapret : Anchor < P , TapretProof > ,
152+ opret : Anchor < P , OpretProof > ,
153+ } ,
154+ }
155+
156+ impl < P : mpc:: Proof + StrictDumb > AnchorSet < P > {
157+ pub fn txid ( & self ) -> Option < Txid > {
158+ match self {
159+ AnchorSet :: Tapret ( a) => Some ( a. txid ) ,
160+ AnchorSet :: Opret ( a) => Some ( a. txid ) ,
161+ AnchorSet :: Dual { tapret, opret } if tapret. txid == opret. txid => Some ( tapret. txid ) ,
162+ _ => None ,
163+ }
164+ }
165+
166+ pub ( crate ) fn txid_unchecked ( & self ) -> Txid {
167+ match self {
168+ AnchorSet :: Tapret ( a) => a. txid ,
169+ AnchorSet :: Opret ( a) => a. txid ,
170+ AnchorSet :: Dual { tapret, .. } => tapret. txid ,
171+ }
172+ }
173+
174+ pub fn from_split (
175+ tapret : Option < Anchor < P , TapretProof > > ,
176+ opret : Option < Anchor < P , OpretProof > > ,
177+ ) -> Option < Self > {
178+ Some ( match ( tapret, opret) {
179+ ( Some ( tapret) , Some ( opret) ) => Self :: Dual { tapret, opret } ,
180+ ( Some ( tapret) , None ) => Self :: Tapret ( tapret) ,
181+ ( None , Some ( opret) ) => Self :: Opret ( opret) ,
182+ ( None , None ) => return None ,
183+ } )
184+ }
185+
186+ #[ allow( clippy:: type_complexity) ]
187+ pub fn as_split ( & self ) -> ( Option < & Anchor < P , TapretProof > > , Option < & Anchor < P , OpretProof > > ) {
188+ match self {
189+ AnchorSet :: Tapret ( tapret) => ( Some ( tapret) , None ) ,
190+ AnchorSet :: Opret ( opret) => ( None , Some ( opret) ) ,
191+ AnchorSet :: Dual { tapret, opret } => ( Some ( tapret) , Some ( opret) ) ,
192+ }
193+ }
194+
195+ #[ allow( clippy:: type_complexity) ]
196+ pub fn into_split ( self ) -> ( Option < Anchor < P , TapretProof > > , Option < Anchor < P , OpretProof > > ) {
197+ match self {
198+ AnchorSet :: Tapret ( tapret) => ( Some ( tapret) , None ) ,
199+ AnchorSet :: Opret ( opret) => ( None , Some ( opret) ) ,
200+ AnchorSet :: Dual { tapret, opret } => ( Some ( tapret) , Some ( opret) ) ,
111201 }
112202 }
203+
204+ pub fn mpc_proofs ( & self ) -> impl Iterator < Item = & P > {
205+ let ( t, o) = self . as_split ( ) ;
206+ t. map ( |a| & a. mpc_proof )
207+ . into_iter ( )
208+ . chain ( o. map ( |a| & a. mpc_proof ) )
209+ }
210+ }
211+
212+ impl AnchorSet < mpc:: MerkleProof > {
213+ pub fn to_merkle_block (
214+ & self ,
215+ contract_id : ContractId ,
216+ bundle_id : BundleId ,
217+ ) -> Result < AnchorSet < mpc:: MerkleBlock > , mpc:: InvalidProof > {
218+ self . clone ( ) . into_merkle_block ( contract_id, bundle_id)
219+ }
220+
221+ pub fn into_merkle_block (
222+ self ,
223+ contract_id : ContractId ,
224+ bundle_id : BundleId ,
225+ ) -> Result < AnchorSet < mpc:: MerkleBlock > , mpc:: InvalidProof > {
226+ let ( tapret, opret) = self . into_split ( ) ;
227+ let tapret = tapret
228+ . map ( |t| t. into_merkle_block ( contract_id, bundle_id) )
229+ . transpose ( ) ?;
230+ let opret = opret
231+ . map ( |o| o. into_merkle_block ( contract_id, bundle_id) )
232+ . transpose ( ) ?;
233+ Ok ( AnchorSet :: from_split ( tapret, opret) . expect ( "one must be non-None" ) )
234+ }
235+ }
236+
237+ impl AnchorSet < mpc:: MerkleBlock > {
238+ pub fn known_bundle_ids ( & self ) -> impl Iterator < Item = ( BundleId , ContractId ) > + ' _ {
239+ self . mpc_proofs ( ) . flat_map ( |p| {
240+ p. to_known_message_map ( )
241+ . into_iter ( )
242+ . map ( |( p, m) | ( m. into ( ) , p. into ( ) ) )
243+ } )
244+ }
245+
246+ pub fn to_merkle_proof (
247+ & self ,
248+ contract_id : ContractId ,
249+ ) -> Result < AnchorSet < mpc:: MerkleProof > , mpc:: LeafNotKnown > {
250+ self . clone ( ) . into_merkle_proof ( contract_id)
251+ }
252+
253+ pub fn into_merkle_proof (
254+ self ,
255+ contract_id : ContractId ,
256+ ) -> Result < AnchorSet < mpc:: MerkleProof > , mpc:: LeafNotKnown > {
257+ let ( tapret, opret) = self . into_split ( ) ;
258+ let tapret = tapret
259+ . map ( |t| t. into_merkle_proof ( contract_id) )
260+ . transpose ( ) ?;
261+ let opret = opret
262+ . map ( |o| o. into_merkle_proof ( contract_id) )
263+ . transpose ( ) ?;
264+ Ok ( AnchorSet :: from_split ( tapret, opret) . expect ( "one must be non-None" ) )
265+ }
113266}
114267
115268/// Txid and height information ordered according to the RGB consensus rules.
0 commit comments