diff --git a/src/persistence/index.rs b/src/persistence/index.rs index b6b71207..b07b831c 100644 --- a/src/persistence/index.rs +++ b/src/persistence/index.rs @@ -335,7 +335,7 @@ impl Index

{ pub(super) fn bundle_info( &self, bundle_id: BundleId, - ) -> Result<(XWitnessId, ContractId), IndexError

> { + ) -> Result<(impl Iterator + '_, ContractId), IndexError

> { Ok(self.provider.bundle_info(bundle_id)?) } } @@ -392,7 +392,7 @@ pub trait IndexReadProvider { fn bundle_info( &self, bundle_id: BundleId, - ) -> Result<(XWitnessId, ContractId), IndexReadError>; + ) -> Result<(impl Iterator, ContractId), IndexReadError>; } pub trait IndexWriteProvider: StoreTransaction { diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index 013feddd..b5fd0528 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -580,7 +580,7 @@ impl StateReadProvider for MemState { let ord = self .witnesses .get(&witness_id) - .ok_or(StateInconsistency::AbsentWitness)?; + .ok_or(StateInconsistency::AbsentWitness(witness_id))?; Ok(ord.is_valid()) } } @@ -1205,7 +1205,7 @@ pub struct MemIndex { op_bundle_index: MediumOrdMap, bundle_contract_index: MediumOrdMap, - bundle_witness_index: MediumOrdMap, + bundle_witness_index: MediumOrdMap>, contract_index: TinyOrdMap, terminal_index: MediumOrdMap, TinyOrdSet>, } @@ -1339,7 +1339,7 @@ impl IndexReadProvider for MemIndex { fn bundle_info( &self, bundle_id: BundleId, - ) -> Result<(XWitnessId, ContractId), IndexReadError> { + ) -> Result<(impl Iterator, ContractId), IndexReadError> { let witness_id = self .bundle_witness_index .get(&bundle_id) @@ -1348,7 +1348,7 @@ impl IndexReadProvider for MemIndex { .bundle_contract_index .get(&bundle_id) .ok_or(IndexInconsistency::BundleContractUnknown(bundle_id))?; - Ok((*witness_id, *contract_id)) + Ok((witness_id.iter().cloned(), *contract_id)) } } @@ -1382,7 +1382,10 @@ impl IndexWriteProvider for MemIndex { } .into()); } - self.bundle_witness_index.insert(bundle_id, witness_id)?; + self.bundle_witness_index + .entry(bundle_id)? + .or_default() + .push(witness_id)?; let present2 = self .bundle_contract_index .insert(bundle_id, contract_id)? diff --git a/src/persistence/state.rs b/src/persistence/state.rs index 6431037a..ce8e1d57 100644 --- a/src/persistence/state.rs +++ b/src/persistence/state.rs @@ -19,6 +19,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::borrow::Borrow; use std::collections::BTreeMap; use std::error::Error; use std::fmt::Debug; @@ -51,6 +52,10 @@ pub enum StateError { #[display(doc_comments)] Resolver(XWitnessId, WitnessResolverError), + /// valid (non-archived) witness is absent in the list of witnesses for a + /// state transition bundle. + AbsentValidWitness, + /// {0} /// /// It may happen due to RGB standard library bug, or indicate internal @@ -65,11 +70,8 @@ pub enum StateError { pub enum StateInconsistency { /// contract state {0} is not known. UnknownContract(ContractId), - /// a witness is absent in the list of witnesses for a state transition bundle. - AbsentWitness, - /// valid (non-archived) witness is absent in the list of witnesses for a - /// state transition bundle. - AbsentValidWitness, + /// a witness {0} is absent from the state data. + AbsentWitness(XWitnessId), } #[derive(Clone, Eq, PartialEq, Debug, Hash)] @@ -135,10 +137,21 @@ impl State

{ .map_err(StateError::ReadProvider) } - pub fn is_valid_witness(&self, witness_id: XWitnessId) -> Result> { - self.provider - .is_valid_witness(witness_id) - .map_err(StateError::ReadProvider) + pub fn select_valid_witness( + &self, + witness_ids: impl IntoIterator>, + ) -> Result> { + for witness_id in witness_ids { + let witness_id = *witness_id.borrow(); + if self + .provider + .is_valid_witness(witness_id) + .map_err(StateError::ReadProvider)? + { + return Ok(witness_id); + } + } + Err(StateError::AbsentValidWitness) } pub fn update_from_bundle( diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 5add193e..9bad430e 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -108,6 +108,10 @@ pub enum StockError< #[from] StashData(StashDataError), + /// valid (non-archived) witness is absent in the list of witnesses for a + /// state transition bundle. + AbsentValidWitness, + /// witness {0} can't be resolved: {1} WitnessUnresolved(XWitnessId, WitnessResolverError), } @@ -134,6 +138,7 @@ impl From Self::StateWrite(err), StateError::Inconsistency(e) => Self::StateInconsistency(e), StateError::Resolver(id, e) => Self::WitnessUnresolved(id, e), + StateError::AbsentValidWitness => Self::AbsentValidWitness, } } } @@ -314,6 +319,7 @@ macro_rules! stock_err_conv { StockError::IndexWrite(e) => StockError::IndexWrite(e), StockError::StateRead(e) => StockError::StateRead(e), StockError::StateWrite(e) => StockError::StateWrite(e), + StockError::AbsentValidWitness => StockError::AbsentValidWitness, StockError::StashData(e) => StockError::StashData(e), StockError::StashInconsistency(e) => StockError::StashInconsistency(e), StockError::StateInconsistency(e) => StockError::StateInconsistency(e), @@ -846,7 +852,8 @@ impl Stock { let mut bundles = BTreeMap::::new(); for anchored_bundle in anchored_bundles.into_values() { - let witness_id = self.index.bundle_info(anchored_bundle.bundle_id())?.0; + let witness_ids = self.index.bundle_info(anchored_bundle.bundle_id())?.0; + let witness_id = self.state.select_valid_witness(witness_ids)?; let pub_witness = self.stash.witness(witness_id)?.public.clone(); let wb = match bundles.remove(&witness_id) { Some(bundle) => bundle.into_double(anchored_bundle)?, @@ -1349,12 +1356,10 @@ impl Stock { } fn client_bundle(&self, bundle_id: BundleId) -> Result> { - let (witness_id, contract_id) = self.index.bundle_info(bundle_id)?; + let (witness_ids, contract_id) = self.index.bundle_info(bundle_id)?; let bundle = self.stash.bundle(bundle_id)?.clone(); - if !self.state.is_valid_witness(witness_id)? { - return Err(StateInconsistency::AbsentValidWitness.into()); - } + let witness_id = self.state.select_valid_witness(witness_ids)?; let witness = self.stash.witness(witness_id)?; let (merkle_block, dbc) = match (bundle.close_method, &witness.anchors) { ( diff --git a/src/stl/stl.rs b/src/stl/stl.rs index bc18c9cf..959cf478 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:t8loV$Vb-Z8hGMSi-pC9dCUe-Lpy$rm8-CGtTeJa-6ll2sCk#guest-infant-crash"; + "stl:hHEaUT1x-VjyiUK0-v$pgYr0-xQwdM5m-S3UaY23-nj7!2vM#orbit-virgo-basil"; /// 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 c82a2097..22529f61 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:t8loV$Vb-Z8hGMSi-pC9dCUe-Lpy$rm8-CGtTeJa-6ll2sCk#guest-infant-crash +Id: stl:hHEaUT1x-VjyiUK0-v$pgYr0-xQwdM5m-S3UaY23-nj7!2vM#orbit-virgo-basil Name: RGBStorage Dependencies: RGBCommit#harvest-person-orion, @@ -11,7 +11,7 @@ Dependencies: RGBLogic#rapid-baboon-satire, Std#ralph-blue-lucky, Bitcoin#signal-color-cipher -Check-SHA256: 74c61ee061f186917d794a71630d15cbd6c223f15ba043b722b7556123ee98ad +Check-SHA256: 21288028263f43cb6a61761336c6ffb69b6e948258d2077d35c0264ad5b8e685 3Q|WxQ*>`~VP|CtAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{j2~tNwLvL+uX>=wP0_2znD++Ak !AD4^=04ZLvBczwX;cPMM?zC{WJT(uU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*$Y#2 @@ -176,47 +176,48 @@ t!&=b=EbQ4dy}<28ig(gSpg+?&9*`C2(3=%09avzwZKZf-~wC#0000000030|Nj600000JVs&n0Y-K}l Zgg^CV{}PwWMy~&3IZTkC#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i;{(leIk>g)RqK0VQ|Mwn6X+ txo3vSYd;;z)HQ~0$c(hS0}9Zh)e@2rNlD$O59e#ogQsB77jP l+h5j^*S;D0000000030|Nj600000IVs&n0Y-LwzbZ%vHb4hMwWq1Gz0w7l>toMja192_( -UwD?W=?zm*&IhOn$k(lG-qz;DsRMhHwLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O12rNlD$O59e -#ogQsB77jPl+h5j^*S;EEYxz&xd)D|X2*0_E|OYH;h*YvvIyS{G&S`ex{XQ}0000000000 -{{R30000004RmF4ZE0>{Y)NipWq1Gz0w7l>toMja192_(UwD?W=?zm*&IhOn$k(lG-qz;DsoRQL8iEuM -btv-qj6g$b#7A9pc!|f`I$jaRzSe2A1ON#FAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jlMuXs -u{2tXFT+?;?hj39&>gq>HOrf1lB-q;n)I5N0000000000{{R30000000000000000|Ns90000002u)>e -Q*>c-Xa)@kb7N>_ZDDj_015&iS0}9Zh)e@H4o{!1*GOa*TS*HAD4^=04ZLvBczwX;eGPz<~n@;VY|KA!vt$qMEp^75#kD_Tqj3Tz6$0d#2P+C};lr6VNhMM> -59zuEq~<=?!m-5UiD^_h#~MC<5IE1bzMOP@>#x3$o4Af`kVHyQ&~TYCSRqgV00000000300000000007 -XJu|>b7gY?3IZTkC#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i^eNEJ-@Z0;0Ob-P{Wzd?2rs)M&&= -&l*}G;Jw22Ix+$vS0}9Zh)e@H4o{!1*GOa*TS*H -4!*u&n59zuEq~<=? -!m-5UiD^`0J=2M>OG#EL&$!Mwbxg)RqK0VQ|M -wn6X+txo3vSYd;;z)HQ~0$c(hS0}9Zh)e@toMja192_(UwD?W -=?zm*&IhOn$k(lG-qz;Dsg=m)dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#R4E#C#?5~OapN(_Fs6G -vFQy{P|gRa2*}s1Y~I%9#i>)L^XdU9;lkvmMR*4bh)jz;q`~Q5Z+&x=I0QQSl+6GD0000000960|Nj60 -000ShX>@L7b8}^L015&iS0}9Zh)e@H4o{!1*GOa*TS*H;u!nFdemP_$e?^hl+JkM;eY!XR2mk;;0000000000|Ns90 -000000000000000|Nj60000003v*>-a%FT=WnpY{00{yhS0}9Zh)e@Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HLtfv$so3kRF1PV2}fOp_vjQ6FdFHId|toMja192_(UwD?W=?zm*&IhOn$k(lG-qz;DskZ2Vh8!q$B6|*YuiTY;OURW8 -#d%1{rxIXtTaY^?oB}2l0_2znD++Ak!AD4^=04ZLvBczwX;h-%S=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&o -6$0d#2P+C};lr6VNhMM>59zuEq~<=?!m-5UiD^{g)D=(>(T2L(qY0=?N -CKUqYmH4o{!1*GOa*TS*HeQ*>c;Wd;HXcWHEPWpi_7a{vkgAXg`>_lQgbaV_>=c$Ts04O39g2dD_h -*R5>c*5<{jiECIT&Bl;lSX#$ms8AQN7m&qYg8B7tjqC|5&qz6Q-tazCB3Um~mr!r)9aR2}S000000RR90{{R30010DnZgg^C -V{~%>3IZTkC#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i^eNEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G -;Jw22Ix+!vno`+&e1Pj6a?JDUs8A->-qfH?0iRw!WuNN`7KQr&0000000030000000000 +UwD?W=?zm*&IhOn$k(lG-qz;DsRMhHwLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O1_lQgb +aV_>=c$Ts04O39g2dD_h*R5>c*5<{jiECIT&Bl;lSX#$ms8AQN7m&qYtoMja192_(UwD?W=?zm*&IhOn +$k(lG-qz;DshUXjT +-wZT0^&Yy7N)`YB000000093000000000eiWpZt4ZeeUmZe(S6015&iS0}9Zh)e@^xB4~9n`Dx!RtcK)nwJ0o00000009300000000000 +0000000960{{R30000P0Wo=V*VRL8(4G42%Xk~3-bYTDr0w7l>toMja192_(UwD?W=?zm*&IhOn$k(lG +-qz;DsgzRF+XJhss8OG%_CC-Q>(otsF+cqN0Qy}ddQ=3E5CSF@0_2znD++Ak!AD4^=04ZL +vBczwX;jj8FLmd)8^C0+InTyb%?WTG%$DZ$m;bAR)ya#VGE@Kn000000093000000000JQW?^Gxa{vkg +CKUqYmH4o{!1*GOa*TS*Hp#+${pKVqYC +0wxs#KG(vr#N>%-R5`~QK7J55&$qsubbafuzL1-^j%|=cN>I>nnK4)) +Pyhe`000000RI300000000(DfZe??2a{vkgAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jp9m~T +I>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0w7l>toMja192_(UwD?W=?zm*&IhOn$k(lG-qz;DsqC`m +cE6dyPJT+tk%Iz|R3_dTDo~ZL;TN>NvAD4^=04ZLvBczwX;cQ7t+(1Z!Y#S=r-tc=NPf>PeW=$`IKP*ssSB}HE2RJl0wxs#KG(vr#N>%-RAW8UiLgsaRw~c9&Ny{YCK_TCaeS`x+X~XLW@}|UwEzGB00000 +0RI300000000000000000RI300000000&}qZe(m_a{vkgAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c +*5<{j1ACLTJsO2B2U!6ncg?mz@CdC==Kxq?gSEg)z2E{|0w7l>toMja192_(UwD?W=?zm*&IhOn$k(lG +-qz;DsjrQf(E(H_nGEpD*KTAo3`$}tLz4xH6U7V?G +015&iS0}9Zh)e@_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jQ>XLl0V(0al>0fVsbCfs) +I{K8&0000000000|NsC00000033q99Ze??GWpe-u0w7l>toMja192_(UwD?W=?zm*&IhOn$k(lG-qz;D +sflY?CC$c=UszhlV5m?Ru@{iVU*wrVdeH+Q@FPbX@d73l0_2znD++Ak!AD4^=04ZLvBczw +X;jBwX*pITEeW==xua`S>RI02$<40II2sv4aet}zMj!wH0000000960|Nj60000YNbaY{3Xl-R~baMa- +0w7l>toMja192_(UwD?W=?zm*&IhOn$k(lG-qz;Dsf2M2lPpg3!?y@aX^XIja4CK{WF&t@k=WXUZP9(Y +H~bW>$vY;yn!0w7l>toMja192_( +UwD?W=?zm*&IhOn$k(lG-qz;DsgJwD=tr7PH4o{!1*GOa*TS*Hr6F_xjAC6(~TLj#*ewiHWCDKG(vr#N>%-RN~YXP!Z9Fy4s@&s7y*h +O1UlNfirx{z*_V4e8lMKAp#~90_2znD++Ak!AD4^=04ZLvBczwX;g+75G-hCV9w&(UffE` +hM!G~aLQ!~gAR@AcC9KZUqt`_000000096000000000P0Wo=V*VRU5%0tt6%bZ%vHb7gY?3IZTkC#?5~ +OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i@yFSS8KIkY89@$6%;X7qJ(R#b4x^L3+^xAn+qc8}R~*|CjUw +a13d{WJ1%*`n^wC{{=S47&=@>>ouDKt(|c83nQ8ri$WPp5w@a4b3LR7M69fMnD+{F6rHCsWOZ=>00000 +00030|Ns9000009V{dMBa$#e1a{vkgAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jp9m~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 b017c408..ede9ff69 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 7f2a9a8b..d3a44b8b 100644 --- a/stl/RGBStorage@0.11.0.sty +++ b/stl/RGBStorage@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:t8loV$Vb-Z8hGMSi-pC9dCUe-Lpy$rm8-CGtTeJa-6ll2sCk#guest-infant-crash + Id: stl:hHEaUT1x-VjyiUK0-v$pgYr0-xQwdM5m-S3UaY23-nj7!2vM#orbit-virgo-basil Name: RGBStorage Version: 0.11.0 Description: RGB storage library @@ -231,10 +231,10 @@ data MemContractState : schemaId RGBCommit.SchemaId @mnemonic(gilbert-torpedo-digital) data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.DataState}, limit U24 -@mnemonic(dialog-parody-ralph) +@mnemonic(savage-joshua-clone) data MemIndex : opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit.BundleId} , bundleContractIndex {RGBCommit.BundleId -> ^ ..0xffffff RGBCommit.ContractId} - , bundleWitnessIndex {RGBCommit.BundleId -> ^ ..0xffffff RGBCommit.XChainTxid} + , bundleWitnessIndex {RGBCommit.BundleId -> ^ ..0xffffff {RGBCommit.XChainTxid ^ ..0xff}} , contractIndex {RGBCommit.ContractId -> ^ ..0xff ContractIndex} , terminalIndex {RGBCommit.XChainSecretSeal -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xff}}