diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index 09dc944d..7656b741 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -1212,7 +1212,7 @@ pub struct MemIndex { bundle_contract_index: MediumOrdMap, bundle_witness_index: MediumOrdMap>, contract_index: TinyOrdMap, - terminal_index: MediumOrdMap, Opout>, + terminal_index: MediumOrdMap, TinyOrdSet>, } impl StrictSerialize for MemIndex {} @@ -1329,7 +1329,8 @@ impl IndexReadProvider for MemIndex { .terminal_index .iter() .filter(|(seal, _)| terminals.contains(*seal)) - .map(|(_, opout)| *opout) + .flat_map(|(_, opout)| opout.iter()) + .copied() .collect()) } @@ -1432,9 +1433,9 @@ impl IndexWriteProvider for MemIndex { .get_mut(&contract_id) .ok_or(IndexInconsistency::ContractAbsent(contract_id))?; - for (no, a) in vec.iter().enumerate() { + for (no, assign) in vec.iter().enumerate() { let opout = Opout::new(opid, type_id, no as u16); - if let Assign::ConfidentialState { seal, .. } | Assign::Revealed { seal, .. } = a { + if let Assign::ConfidentialState { seal, .. } | Assign::Revealed { seal, .. } = assign { let output = seal .to_output_seal() .expect("genesis seals always have outpoint"); @@ -1447,11 +1448,10 @@ impl IndexWriteProvider for MemIndex { } } } - if let Assign::Confidential { seal, .. } | Assign::ConfidentialSeal { seal, .. } = a { - self.terminal_index.insert(*seal, opout)?; - } } - Ok(()) + + // We need two cycles due to the borrow checker + self.extend_terminals(vec, opid, type_id) } fn index_transition_assignments( @@ -1486,10 +1486,44 @@ impl IndexWriteProvider for MemIndex { } } } + } + + // We need two cycles due to the borrow checker + self.extend_terminals(vec, opid, type_id) + } +} + +impl MemIndex { + fn extend_terminals( + &mut self, + vec: &[Assign], + opid: OpId, + type_id: AssignmentType, + ) -> Result<(), IndexWriteError> { + for (no, assign) in vec.iter().enumerate() { + let opout = Opout::new(opid, type_id, no as u16); if let Assign::Confidential { seal, .. } | Assign::ConfidentialSeal { seal, .. } = assign { - self.terminal_index.insert(*seal, opout)?; + self.add_terminal(*seal, opout)?; + } + } + Ok(()) + } + + fn add_terminal( + &mut self, + seal: XChain, + opout: Opout, + ) -> Result<(), IndexWriteError> { + match self + .terminal_index + .remove(&seal) + .expect("can have zero elements") + { + Some(mut existing_opouts) => existing_opouts.push(opout)?, + None => { + self.terminal_index.insert(seal, tiny_bset![opout])?; } } Ok(()) diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index deda9605..c751d7fc 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -28,6 +28,7 @@ use amplify::confinement; use amplify::confinement::{Confined, MediumBlob, TinyOrdMap}; use bp::dbc::anchor::MergeError; use bp::dbc::tapret::TapretCommitment; +use bp::seals::txout::CloseMethod; use commit_verify::mpc; use nonasync::persistence::{CloneNoPersistence, Persisting}; use rgb::validation::Scripts; @@ -118,6 +119,9 @@ pub enum StashInconsistency { /// information about witness {0} is absent. WitnessAbsent(XWitnessId), + /// witness {0} for the bundle {1} misses contract {2} information in {3} anchor. + WitnessMissesContract(XWitnessId, BundleId, ContractId, CloseMethod), + /// bundle {0} is absent. BundleAbsent(BundleId), diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 051e31c1..4e48e5cb 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -1352,24 +1352,46 @@ impl Stock { AnchorSet::Opret(opret) => (None, Some(opret)), AnchorSet::Double { tapret, opret } => (Some(tapret), Some(opret)), }; - let mut anchor = None; - if let Some(a) = tapret { - if let Ok(a) = a.to_merkle_proof(contract_id) { - anchor = Some(EAnchor::new(a.mpc_proof, DbcProof::Tapret(a.dbc_proof))); - } - } - if anchor.is_none() { - if let Some(a) = opret { - if let Ok(a) = a.to_merkle_proof(contract_id) { - anchor = Some(EAnchor::new(a.mpc_proof, DbcProof::Opret(a.dbc_proof))); - } + let Ok(tapret) = tapret.map(|a| a.to_merkle_proof(contract_id)).transpose() else { + return Err(StashInconsistency::WitnessMissesContract( + witness_id, + bundle_id, + contract_id, + CloseMethod::TapretFirst, + ) + .into()); + }; + let Ok(opret) = opret.map(|a| a.to_merkle_proof(contract_id)).transpose() else { + return Err(StashInconsistency::WitnessMissesContract( + witness_id, + bundle_id, + contract_id, + CloseMethod::OpretFirst, + ) + .into()); + }; + let anchored_bundles = match (opret, tapret) { + (Some(opret), Some(tapret)) => AnchoredBundles::Double { + tapret_anchor: tapret, + tapret_bundle: bundle.clone(), + opret_anchor: opret, + opret_bundle: bundle, + }, + (Some(opret), None) => AnchoredBundles::with( + EAnchor::new(opret.mpc_proof, DbcProof::Opret(opret.dbc_proof)), + bundle, + ), + (None, Some(tapret)) => AnchoredBundles::with( + EAnchor::new(tapret.mpc_proof, DbcProof::Tapret(tapret.dbc_proof)), + bundle, + ), + (None, None) => { + return Err( + StashInconsistency::BundleMissedInAnchors(bundle_id, contract_id).into() + ); } - } - let Some(anchor) = anchor else { - return Err(StashInconsistency::BundleMissedInAnchors(bundle_id, contract_id).into()); }; - let anchored_bundles = AnchoredBundles::with(anchor, bundle); // TODO: Conceal all transitions except the one we need Ok(BundledWitness { diff --git a/src/stl/stl.rs b/src/stl/stl.rs index 8fb3a73f..f7a69de9 100644 --- a/src/stl/stl.rs +++ b/src/stl/stl.rs @@ -41,7 +41,7 @@ use crate::LIB_NAME_RGB_STD; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. pub const LIB_ID_RGB_STORAGE: &str = - "stl:ieoE!c74-z5Us1Cc-j6$RdoB-BWAdWBF-jwE9Vu7-sFCnYdI#lopez-alert-slow"; + "stl:ZVab0Axk-3hHvPBw-PVgbKK9-OjbajRO-sbN53sE-De3$HdM#cabinet-emerald-brush"; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. diff --git a/stl/RGBStorage@0.11.0.sta b/stl/RGBStorage@0.11.0.sta index 8ae654db..b6378c9d 100644 --- a/stl/RGBStorage@0.11.0.sta +++ b/stl/RGBStorage@0.11.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:ieoE!c74-z5Us1Cc-j6$RdoB-BWAdWBF-jwE9Vu7-sFCnYdI#lopez-alert-slow +Id: stl:ZVab0Axk-3hHvPBw-PVgbKK9-OjbajRO-sbN53sE-De3$HdM#cabinet-emerald-brush Name: RGBStorage Dependencies: RGBStd#picnic-reverse-convert, @@ -11,7 +11,7 @@ Dependencies: BPCore#totem-holiday-helena, Std#ralph-blue-lucky, Bitcoin#signal-color-cipher -Check-SHA256: e92b99ae1abe013f0fae063ec109b931cfd4d7bc645988b39dd559495485266b +Check-SHA256: eb80a555081e5cd6c487489afaa6035c7871cc544a4e7098144d9f2b9455724e 3Q|WxQ*>`~VP|CtF%(Tiw}_hL!Gmq7aiBy4V-l87!ykk~3_hpwOT62w22w{tQ*>lS>Z4!V_T!KNI`QJ| h6;Zj^jB$MPK+?7Lu3>C`4HI)Q*?4^V{}w`aAk91a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjH @@ -181,42 +181,43 @@ J@XWBBi(Rv?4579E{O-(Y+vWlpwilmiECIT&Bl;lSX#$ms8AQN7m&qYUXjT -wZT0^&Yy7N)`YB000000093000000000eiWpZt4ZeeUmZe(S6015(R#MKE+xj;HS^AvC+-Eea3oo~4= -i3iziU+2)E(%OvMidq_i6cBYN^7xEELu$lFU37Sf$J;ty5yrmOX|)6bWW?18O}RiiJ@XWBBi(Rv?4579 -E{O-(Y+vWlpwilmlMuXsu{2tXFT+?;?hj39&>gq>HOrf1lB-q;n)I5N0000000000|Ns90000002u)>e -Q*>c-Xa)@kb7N>_ZDDj_015(R#MKE+xj;HS^AvC+-Eea3oo~4=i3iziU+2)E(%OuaQq$W5tE;F{pQrXd -&=l*`O?@#x{Qdy?T_k!`1dtE{F%(Tiw}_hL!Gmq7aiBy4V-l87!ykk~3_hpwOT62w(swU)=eHZcWUx8U -##PM;a30K-=Jl8VtAf?Zi=Hx60000000000{{R300000025DwtV`Xyy3IZ_{O+>edn&iQQZK-jfL<3_I -mQceVghC8Hr}9g@+p9auz<~n@;VY|KA!vt$qMEp^75#kD_Tqj3T;6ir08h??ZVgKepCphN>> -5|&WIAA~{-KBw|ayxXfe#~MC<5IE1bzMOP@>#x3$o4Af`kVHyQ&~TYCSRqgV00000000300000000007 -XJu|>b7gY?3Ib%r)d@|xKsr716mTQmaB}ROZ@Dgs2ia_2=g^?i+KitFEJ-@Z0;0Ob-P{Wzd?2rs)M&&= -&l*}G;Jw22Ix+%e#MKE+xj;HS^AvC+-Eea3oo~4=i3iziU+2)E(%OvdvgUTbnZZteO3IOg0+3WD-We)T -m9OC!w7#?l6>4!*u&n>5|&WIAA~{- -KBw|ayxXf|J=2M>OG#EL&$!Mwbxg)RqK0VQ|M -wn6X+txo3vSYd;;z)HQ~0$c)Q#MKE+xj;HS^AvC+-Eea3oo~4=i3iziU+2)E(%Ou#jhE2@R4ADY@XOb3 -WHJm&VktwD1&R~J8Qi15W{8Ub0000000030|Ns900000AWq5RDZgXjGZgT(%0%XM12~D{`Iz96ga3kGt -a_pUNxh{zZ*=%3u(4f-VjFrgddLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#R6o+)d@|xKsr716mTQm -aB}ROZ@Dgs2ia_2=g^?i+Kf}D^XdU9;lkvmMR*4bh)jz;q`~Q5Z+&x=I0QQSl+6GD0000000960|Nj60 -000ShX>@L7b8}^L015(R#MKE+xj;HS^AvC+-Eea3oo~4=i3iziU+2)E(%OuPYgi@C#*klFTE}3hP#3Wm -ki}o*nL&Ed10e7tM;q}1F%(Tiw}_hL!Gmq7aiBy4V-l87!ykk~3_hpwOT62wUNH8E>xBrIwS50cCx~Y4 ->vpbO6eBrP2Wxp8;c>|H0000000000|NsC0000003t@D0VPj}*Wo~qH015(R#MKE+xj;HS^AvC+-Eea3 -oo~4=i3iziU+2)E(%OuKaSf9!PV~dK2uo>;u!nFdemP_$e?^hl+JkM;eY!XR2mk;;0000000000|Ns90 -000000000000000|Nj60000003v*>-a%FT=WnpY{00{zQ#MKE+xj;HS^AvC+-Eea3oo~4=i3iziU+2)E -(%OuVyTa&4noi_R;$3lnz4{Zl)X|Z&ZIQtMA_g1big7gn0000000030|Nj600000Aba`-PQ+acAWo-gQ ->Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HLtfv$so3kRF1PV2}fOp_vjQ6FdFHId|edn&iQQZK-jfL<3_ImQceVghC8Hr}9g@+pD7BS=7<6%^jtx5=^cXz--x^ -3Rg~O2_Ny!Q1}E;1fT!_000000096000000000DRX<~B#3IbwqHGd)HR2XhQO_4{AcS-HH^7AVzASV -8M4NYxyCjU1gEwF5PXV6FZDLo1#Vec_~kix7WfVQ#Sd|CM9$^_0000000030{{R3000004b7^OD015&z -6ir08h??ZVgKepCphN>>5|&WIAA~{-KBw|ayxXhd)D=(>(T2L(qY0=?N -F%(Tiw}_hL!Gmq7aiBy4V-l87!ykk~3_hpwOT62wh8PemXlG!~;@e)_O3H?xO^a~KWeI~0jp}x-Dk@(^ -0000000000|Nj60000002u)>eQ*>c;Wd;HXcWHEPWpi_7a{vkgWW?18O}RiiJ@XWBBi(Rv?4579E{O-( -Y+vWlpwilmiECIT&Bl;lSX#$ms8AQN7m&qYg8B7tjqC|5&qz6Q-tazCB3Um~mr!r)9aR2}S000000RR90{{R30010DnZgg^C -V{~%>3Ib%r)d@|xKsr716mTQmaB}ROZ@Dgs2ia_2=g^?i+KitFEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G -;Jw22Ix+!vno`+&e1Pj6a?JDUs8A->-qfH?0iRw!WuNN`7KQr&0000000030000000000 +i3iziU+2)E(%OvMidq_i6cBYN^7xEELu$lFU37Sf$J;ty5yrmOX|)6Z2?Auq)d@|xKsr716mTQmaB}RO +Z@Dgs2ia_2=g^?i+KiJBynwMZT8l5kSW@l}O=!>^xB4~9n`Dx!RtcK)nwJ0o00000009300000000000 +0000000960{{R30000P0Wo=V*VRL8(4G42%Xk~3-bYTDr0%XM12~D{`Iz96ga3kGta_pUNxh{zZ*=%3u +(4f-VjFeK-+XJhss8OG%_CC-Q>(otsF+cqN0Qy}ddQ=3E5CSn2O+>edn&iQQZK-jfL<3_ImQceVghC8H +r}9g@+pE%dFLmd)8^C0+InTyb%?WTG%$DZ$m;bAR)ya#VGE@Kn000000093000000000JQW?^Gxa{vkg +F%(Tiw}_hL!Gmq7aiBy4V-l87!ykk~3_hpwOT62wJIcU;0|?p#+${pKVqYC +0x=X#M7M~VI>nnK4)) +Pyhe`000000RI300000000(DfZe??2a{vkgWW?18O}RiiJ@XWBBi(Rv?4579E{O-(Y+vWlpwilmp9m~T +I>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0%XM12~D{`Iz96ga3kGta_pUNxh{zZ*=%3u(4f-VjO?=J +cE6dyPJT+tk%Iz|R3_dTDo~ZL;TN>Nvedn&iQQ +ZK-jfL<3_ImQceVghC8Hr}9g@+p7kct+(1Z!Y#S=r-tc=NPf>PeW=$`IKP*ssSB}HE2RJl0x=X#M7M~V +V?G +015(R#MKE+xj;HS^AvC+-Eea3oo~4=i3iziU+2)E(%Oub$mV(;bz)!CmQ_M(k?Vd!kfCo{nDM?)_qK{8 +68FUdWW?18O}RiiJ@XWBBi(Rv?4579E{O-(Y+vWlpwilmQ>XLl0V(0al>0fVsbCfs) +I{K8&0000000000|NsC00000033q99Ze??GWpe-u0%XM12~D{`Iz96ga3kGta_pUNxh{zZ*=%3u(4f-V +jEQSlCC$c=UszhlV5m?Ru@{iVU*wrVdeH+Q@FPbX@d7avO+>edn&iQQZK-jfL<3_ImQceVghC8Hr}9g@ ++pAtM_K53+2$;2e|4Ao^X6@^Cu3Qu&Ia3E~c^u(!$n*dJ0000000960|Nj60000YNbaY{3Xl-R~baMa- +0%XM12~D{`Iz96ga3kGta_pUNxh{zZ*=%3u(4f-VjD&FwlPpg3!?y@aX^XIja4CK{WF&t@k=WXUZP9(Y +H~bW>$vY;yn!0%XM12~D{`Iz96g +a3kGta_pUNxh{zZ*=%3u(4f-VjE}p*=tr7Pr6F_xjAC6(~TLj#*ewiHWCDedn&iQQZK-jfL<3_ImQceVghC8Hr}9g@+pC5c5G-hCV9w&(UffE` +hM!G~aLQ!~gAR@AcC9KZUqt`_000000096000000000P0Wo=V*VRU5%0tt6%bZ%vHb7gY?3Ib%r)d@|x +Ksr716mTQmaB}ROZ@Dgs2ia_2=g^?i+Kh>7SS8KIkY89@$6%;X7qJ(R#b4x^L3+^xAn+qc8}R~eDia2b +(>AB29AOeYx#=(k!8In=XQlLX14LMLVywUR3nQ8ri$WPp5w@a4b3LR7M69fMnD+{F6rHCsWOZ=>00000 +00030|Ns9000009V{dMBa$#e1a{vkgWW?18O}RiiJ@XWBBi(Rv?4579E{O-(Y+vWlpwilmp9m~TI>-W| +y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0d|^F*?W9|>m72;^XjNjCf456piKdvUO#1@>k1Zy`v3p{00000 +0RI300000000 -----END STRICT TYPE LIB----- diff --git a/stl/RGBStorage@0.11.0.stl b/stl/RGBStorage@0.11.0.stl index 9e05119f..4bb0d0e9 100644 Binary files a/stl/RGBStorage@0.11.0.stl and b/stl/RGBStorage@0.11.0.stl differ diff --git a/stl/RGBStorage@0.11.0.sty b/stl/RGBStorage@0.11.0.sty index f83e0249..f0d72b14 100644 --- a/stl/RGBStorage@0.11.0.sty +++ b/stl/RGBStorage@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:ieoE!c74-z5Us1Cc-j6$RdoB-BWAdWBF-jwE9Vu7-sFCnYdI#lopez-alert-slow + Id: stl:ZVab0Axk-3hHvPBw-PVgbKK9-OjbajRO-sbN53sE-De3$HdM#cabinet-emerald-brush Name: RGBStorage Version: 0.11.0 Description: RGB storage library @@ -231,12 +231,12 @@ data MemContractState : schemaId RGBCommit.SchemaId @mnemonic(gilbert-torpedo-digital) data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.DataState}, limit U24 -@mnemonic(origin-flame-actor) +@mnemonic(savage-joshua-clone) data MemIndex : opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit.BundleId} , bundleContractIndex {RGBCommit.BundleId -> ^ ..0xffffff RGBCommit.ContractId} , bundleWitnessIndex {RGBCommit.BundleId -> ^ ..0xffffff {RGBCommit.XChainTxid ^ ..0xff}} , contractIndex {RGBCommit.ContractId -> ^ ..0xff ContractIndex} - , terminalIndex {RGBCommit.XChainSecretSeal -> ^ ..0xffffff RGBCommit.Opout} + , terminalIndex {RGBCommit.XChainSecretSeal -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xff}} @mnemonic(ultra-sweden-limbo) data MemStash : schemata {RGBCommit.SchemaId -> ^ ..0xff RGBStd.SchemaIfaces}