diff --git a/Cargo.lock b/Cargo.lock index f6826ccd..bb861979 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -599,7 +599,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.1" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#bc626178003ce95cd36ae2d014230e4899602366" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#bdf3d0b04473e4d9a097e26bdfe9dd8b60079997" dependencies = [ "aluvm", "amplify", diff --git a/src/containers/consignment.rs b/src/containers/consignment.rs index 6819e749..161e2c3f 100644 --- a/src/containers/consignment.rs +++ b/src/containers/consignment.rs @@ -28,7 +28,7 @@ use rgb::validation::{AnchoredBundle, ConsignmentApi}; use rgb::{ validation, AssetTag, AssignmentType, AttachId, BundleId, ContractHistory, ContractId, Extension, Genesis, GraphSeal, OpId, OpRef, Operation, Schema, SchemaId, SealDefinition, - SecretSeal, SubSchema, Transition, TransitionBundle, WitnessAnchor, + SecretSeal, SubSchema, Transition, TransitionBundle, }; use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize}; @@ -185,10 +185,9 @@ impl Consignment { for anchored_bundle in &self.bundles { for item in anchored_bundle.bundle.values() { if let Some(transition) = &item.transition { - let txid = anchored_bundle.anchor.txid; - let height = resolver.resolve_height(txid)?; - let ord_txid = WitnessAnchor::new(height, txid); - history.add_transition(transition, ord_txid); + let witness_anchor = resolver.resolve_anchor(&anchored_bundle.anchor)?; + + history.add_transition(transition, witness_anchor); for (id, used) in &mut extension_idx { if *used { continue; @@ -197,11 +196,11 @@ impl Consignment { if input.prev_out.op == *id { *used = true; if let Some(ord) = ordered_extensions.get_mut(id) { - if *ord > ord_txid { - *ord = ord_txid; + if *ord > witness_anchor { + *ord = witness_anchor; } } else { - ordered_extensions.insert(*id, ord_txid); + ordered_extensions.insert(*id, witness_anchor); } } } @@ -210,8 +209,8 @@ impl Consignment { } } for extension in &self.extensions { - if let Some(ord_txid) = ordered_extensions.get(&extension.id()) { - history.add_extension(extension, *ord_txid); + if let Some(witness_anchor) = ordered_extensions.get(&extension.id()) { + history.add_extension(extension, *witness_anchor); } } diff --git a/src/interface/contract.rs b/src/interface/contract.rs index ceb6df0e..8c29a418 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -25,8 +25,8 @@ use std::ops::Deref; use amplify::confinement::{LargeOrdMap, LargeVec, SmallVec}; use bp::Outpoint; use rgb::{ - AssignmentType, AttachId, ContractId, ContractState, FungibleOutput, MediaType, RevealedAttach, - RevealedData, SealWitness, + AssignmentType, AttachId, ContractId, ContractState, FungibleOutput, MediaType, Output, + RevealedAttach, RevealedData, WitnessId, }; use strict_encoding::FieldName; use strict_types::typify::TypedVal; @@ -76,8 +76,8 @@ impl From for AttachedState { #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct FungibleAllocation { - pub owner: Outpoint, - pub witness: SealWitness, + pub owner: Output, + pub witness: Option, pub value: u64, } @@ -88,7 +88,7 @@ impl From for FungibleAllocation { impl From<&FungibleOutput> for FungibleAllocation { fn from(out: &FungibleOutput) -> Self { FungibleAllocation { - owner: out.seal, + owner: out.output, witness: out.witness, value: out.state.value.as_u64(), } @@ -96,52 +96,50 @@ impl From<&FungibleOutput> for FungibleAllocation { } pub trait OutpointFilter { - fn include_outpoint(&self, outpoint: Outpoint) -> bool; + fn include_output(&self, output: Output) -> bool; } pub struct FilterIncludeAll; pub struct FilterExclude(pub T); impl OutpointFilter for &T { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { (*self).include_outpoint(outpoint) } + fn include_output(&self, output: Output) -> bool { (*self).include_output(output) } } impl OutpointFilter for &mut T { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { - self.deref().include_outpoint(outpoint) - } + fn include_output(&self, output: Output) -> bool { self.deref().include_output(output) } } impl OutpointFilter for Option { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { + fn include_output(&self, output: Output) -> bool { self.as_ref() - .map(|filter| filter.include_outpoint(outpoint)) + .map(|filter| filter.include_output(output)) .unwrap_or(true) } } impl OutpointFilter for FilterIncludeAll { - fn include_outpoint(&self, _: Outpoint) -> bool { true } + fn include_output(&self, _: Output) -> bool { true } } impl OutpointFilter for FilterExclude { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { !self.0.include_outpoint(outpoint) } + fn include_output(&self, output: Output) -> bool { !self.0.include_output(output) } } -impl OutpointFilter for &[Outpoint] { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { self.contains(&outpoint) } +impl OutpointFilter for &[Output] { + fn include_output(&self, output: Output) -> bool { self.contains(&output) } } -impl OutpointFilter for Vec { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { self.contains(&outpoint) } +impl OutpointFilter for Vec { + fn include_output(&self, output: Output) -> bool { self.contains(&output) } } -impl OutpointFilter for HashSet { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { self.contains(&outpoint) } +impl OutpointFilter for HashSet { + fn include_output(&self, output: Output) -> bool { self.contains(&output) } } -impl OutpointFilter for BTreeSet { - fn include_outpoint(&self, outpoint: Outpoint) -> bool { self.contains(&outpoint) } +impl OutpointFilter for BTreeSet { + fn include_output(&self, output: Output) -> bool { self.contains(&output) } } /// Contract state is an in-memory structure providing API to read structured @@ -200,7 +198,7 @@ impl ContractIface { .fungibles() .iter() .filter(|outp| outp.opout.ty == type_id) - .filter(|outp| filter.include_outpoint(outp.seal)) + .filter(|outp| filter.include_output(outp.output)) .map(FungibleAllocation::from); Ok(LargeVec::try_from_iter(state).expect("same or smaller collection size")) } diff --git a/src/persistence/inventory.rs b/src/persistence/inventory.rs index b48cd741..0383e0e4 100644 --- a/src/persistence/inventory.rs +++ b/src/persistence/inventory.rs @@ -29,8 +29,8 @@ use bp::Txid; use commit_verify::{mpc, Conceal}; use rgb::{ validation, Anchor, AnchoredBundle, BundleId, ContractId, ExposedSeal, GraphSeal, OpId, - Operation, Opout, SchemaId, SealDefinition, SecretSeal, SubSchema, Transition, - TransitionBundle, + Operation, Opout, Output, SchemaId, SealDefinition, SecretSeal, SubSchema, Transition, + TransitionBundle, WitnessId, }; use strict_encoding::TypeName; @@ -46,7 +46,6 @@ use crate::persistence::hoard::ConsumeError; use crate::persistence::stash::StashInconsistency; use crate::persistence::{Stash, StashError}; use crate::resolvers::ResolveHeight; -use crate::Outpoint; #[derive(Debug, Display, Error, From)] #[display(doc_comments)] @@ -160,6 +159,9 @@ pub enum DataError { /// you'd like to take the risc, call `import_contract_force`. TerminalsUnmined, + /// mismatch between witness seal chain and anchor chain. + ChainMismatch, + #[display(inner)] #[from] Reveal(RevealError), @@ -169,7 +171,7 @@ pub enum DataError { Merge(MergeRevealError), /// outpoint {0} is not part of the contract {1}. - OutpointUnknown(Outpoint, ContractId), + OutpointUnknown(Output, ContractId), #[from] Confinement(confinement::Error), @@ -315,7 +317,7 @@ pub trait Inventory: Deref { &mut self, contract_id: ContractId, bundle: TransitionBundle, - witness_txid: Txid, + witness_id: WitnessId, ) -> Result<(), InventoryError>; /// # Safety @@ -440,9 +442,9 @@ pub trait Inventory: Deref { fn transition(&self, opid: OpId) -> Result<&Transition, InventoryError>; - fn contracts_by_outpoints( + fn contracts_by_outputs( &mut self, - outpoints: impl IntoIterator>, + outputs: impl IntoIterator>, ) -> Result, InventoryError>; fn public_opouts( @@ -450,10 +452,10 @@ pub trait Inventory: Deref { contract_id: ContractId, ) -> Result, InventoryError>; - fn opouts_by_outpoints( + fn opouts_by_outputs( &mut self, contract_id: ContractId, - outpoints: impl IntoIterator>, + outputs: impl IntoIterator>, ) -> Result, InventoryError>; fn opouts_by_terminals( @@ -461,10 +463,10 @@ pub trait Inventory: Deref { terminals: impl IntoIterator, ) -> Result, InventoryError>; - fn state_for_outpoints( + fn state_for_outputs( &mut self, contract_id: ContractId, - outpoints: impl IntoIterator>, + outputs: impl IntoIterator>, ) -> Result, InventoryError>; fn store_seal_secret( @@ -518,11 +520,11 @@ pub trait Inventory: Deref { let (outpoint_seals, terminal_seals) = seals .into_iter() .map(|seal| match seal.into() { - BuilderSeal::Revealed(seal) => (seal.outpoint(), seal.conceal()), + BuilderSeal::Revealed(seal) => (seal.output(), seal.conceal()), BuilderSeal::Concealed(seal) => (None, seal), }) .unzip::<_, _, Vec<_>, Vec<_>>(); - opouts.extend(self.opouts_by_outpoints(contract_id, outpoint_seals.into_iter().flatten())?); + opouts.extend(self.opouts_by_outputs(contract_id, outpoint_seals.into_iter().flatten())?); opouts.extend(self.opouts_by_terminals(terminal_seals.iter().copied())?); // 1.1. Get all public transitions diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 264e9622..df6a80fb 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -24,14 +24,13 @@ use std::convert::Infallible; use std::ops::{Deref, DerefMut}; use amplify::confinement::{MediumOrdMap, MediumOrdSet, TinyOrdMap}; -use amplify::ByteArray; -use bp::Txid; +use commit_verify::Conceal; use rgb::validation::{Status, Validity, Warning}; use rgb::{ validation, Anchor, AnchorId, AnchoredBundle, Assign, AssignmentType, BundleId, ContractHistory, ContractId, ContractState, ExposedState, Extension, Genesis, GenesisSeal, - GraphSeal, OpId, Operation, Opout, SealDefinition, SecretSeal, SubSchema, Transition, - TransitionBundle, TxoSeal, TypedAssigns, WitnessAnchor, + GraphSeal, OpId, Operation, Opout, Output, SealDefinition, SecretSeal, SubSchema, Transition, + TransitionBundle, TypedAssigns, WitnessAnchor, WitnessId, }; use strict_encoding::{StrictDeserialize, StrictSerialize}; @@ -44,7 +43,7 @@ use crate::persistence::{ Hoard, Inventory, InventoryDataError, InventoryError, Stash, StashInconsistency, }; use crate::resolvers::ResolveHeight; -use crate::{Outpoint, LIB_NAME_RGB_STD}; +use crate::LIB_NAME_RGB_STD; #[derive(Clone, Eq, PartialEq, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -56,7 +55,7 @@ pub struct IndexedBundle(ContractId, BundleId); #[strict_type(lib = LIB_NAME_RGB_STD)] pub struct ContractIndex { public_opouts: MediumOrdSet, - outpoint_opouts: MediumOrdMap>, + outpoint_opouts: MediumOrdMap>, } /// Stock is an in-memory inventory (stash, index, contract state) useful for @@ -154,11 +153,7 @@ impl Stock { // clone needed due to borrow checker for (bundle_id, terminal) in consignment.terminals.clone() { for secret in terminal.seals.iter().filter_map(TerminalSeal::secret_seal) { - if let Some(seal) = self - .seal_secrets - .iter() - .find(|s| s.to_concealed_seal() == secret) - { + if let Some(seal) = self.seal_secrets.iter().find(|s| s.conceal() == secret) { consignment.reveal_bundle_seal(bundle_id, *seal); } } @@ -244,7 +239,7 @@ impl Stock { &mut self, id: ContractId, bundle: &TransitionBundle, - witness_txid: Txid, + witness_id: WitnessId, ) -> Result<(), InventoryError<::Error>> { let bundle_id = bundle.bundle_id(); for (opid, item) in bundle.iter() { @@ -255,38 +250,22 @@ impl Stock { match assign { TypedAssigns::Declarative(vec) => { self.index_transition_assignments( - id, - vec, - *opid, - *type_id, - witness_txid, + id, vec, *opid, *type_id, witness_id, )?; } TypedAssigns::Fungible(vec) => { self.index_transition_assignments( - id, - vec, - *opid, - *type_id, - witness_txid, + id, vec, *opid, *type_id, witness_id, )?; } TypedAssigns::Structured(vec) => { self.index_transition_assignments( - id, - vec, - *opid, - *type_id, - witness_txid, + id, vec, *opid, *type_id, witness_id, )?; } TypedAssigns::Attachment(vec) => { self.index_transition_assignments( - id, - vec, - *opid, - *type_id, - witness_txid, + id, vec, *opid, *type_id, witness_id, )?; } } @@ -312,15 +291,15 @@ impl Stock { for (no, a) in vec.iter().enumerate() { let opout = Opout::new(opid, type_id, no as u16); if let Assign::ConfidentialState { seal, .. } | Assign::Revealed { seal, .. } = a { - let outpoint = seal.outpoint_or(seal.txid); - match index.outpoint_opouts.get_mut(&outpoint) { + let output = seal.output().expect("genesis seals always have outpoint"); + match index.outpoint_opouts.get_mut(&output) { Some(opouts) => { opouts.push(opout)?; } None => { index .outpoint_opouts - .insert(outpoint, confined_bset!(opout))?; + .insert(output, confined_bset!(opout))?; } } } @@ -337,7 +316,7 @@ impl Stock { vec: &[Assign], opid: OpId, type_id: AssignmentType, - witness_txid: Txid, + witness_id: WitnessId, ) -> Result<(), InventoryError<::Error>> { let index = self .contract_index @@ -347,15 +326,17 @@ impl Stock { for (no, a) in vec.iter().enumerate() { let opout = Opout::new(opid, type_id, no as u16); if let Assign::ConfidentialState { seal, .. } | Assign::Revealed { seal, .. } = a { - let outpoint = seal.outpoint_or(witness_txid); - match index.outpoint_opouts.get_mut(&outpoint) { + let output = seal + .output_or_witness(witness_id) + .map_err(|_| DataError::ChainMismatch)?; + match index.outpoint_opouts.get_mut(&output) { Some(opouts) => { opouts.push(opout)?; } None => { index .outpoint_opouts - .insert(outpoint, confined_bset!(opout))?; + .insert(output, confined_bset!(opout))?; } } } @@ -503,16 +484,16 @@ impl Inventory for Stock { &mut self, contract_id: ContractId, bundle: TransitionBundle, - witness_txid: Txid, + witness_id: WitnessId, ) -> Result<(), InventoryError<::Error>> { - self.index_bundle(contract_id, &bundle, witness_txid)?; + self.index_bundle(contract_id, &bundle, witness_id)?; let history = self .history .get_mut(&contract_id) .ok_or(InventoryInconsistency::StateAbsent(contract_id))?; for item in bundle.values() { if let Some(transition) = &item.transition { - let ord_txid = WitnessAnchor::from_mempool(witness_txid); + let ord_txid = WitnessAnchor::from_mempool(witness_id); history.add_transition(transition, ord_txid); } } @@ -591,17 +572,17 @@ impl Inventory for Stock { Ok(AnchoredBundle { anchor, bundle }) } - fn contracts_by_outpoints( + fn contracts_by_outputs( &mut self, - outpoints: impl IntoIterator>, + outputs: impl IntoIterator>, ) -> Result, InventoryError> { - let outpoints = outpoints + let outputs = outputs .into_iter() .map(|o| o.into()) .collect::>(); let mut selected = BTreeSet::new(); for (contract_id, index) in &self.contract_index { - for outpoint in &outpoints { + for outpoint in &outputs { if index.outpoint_opouts.contains_key(outpoint) { selected.insert(*contract_id); } @@ -621,21 +602,21 @@ impl Inventory for Stock { Ok(index.public_opouts.to_inner()) } - fn opouts_by_outpoints( + fn opouts_by_outputs( &mut self, contract_id: ContractId, - outpoints: impl IntoIterator>, + outputs: impl IntoIterator>, ) -> Result, InventoryError> { let index = self .contract_index .get(&contract_id) .ok_or(StashInconsistency::ContractAbsent(contract_id))?; let mut opouts = BTreeSet::new(); - for outpoint in outpoints.into_iter().map(|o| o.into()) { + for output in outputs.into_iter().map(|o| o.into()) { let set = index .outpoint_opouts - .get(&outpoint) - .ok_or(DataError::OutpointUnknown(outpoint, contract_id))?; + .get(&output) + .ok_or(DataError::OutpointUnknown(output, contract_id))?; opouts.extend(set) } Ok(opouts) @@ -654,12 +635,12 @@ impl Inventory for Stock { .collect()) } - fn state_for_outpoints( + fn state_for_outputs( &mut self, contract_id: ContractId, - outpoints: impl IntoIterator>, + outputs: impl IntoIterator>, ) -> Result, InventoryError> { - let outpoints = outpoints + let outputs = outputs .into_iter() .map(|o| o.into()) .collect::>(); @@ -672,25 +653,25 @@ impl Inventory for Stock { let mut res = BTreeMap::new(); for output in history.fungibles() { - if outpoints.contains(&output.seal) { + if outputs.contains(&output.output) { res.insert(output.opout, TypedState::Amount(output.state.value.as_u64())); } } for output in history.data() { - if outpoints.contains(&output.seal) { + if outputs.contains(&output.output) { res.insert(output.opout, TypedState::Data(output.state.clone())); } } for output in history.rights() { - if outpoints.contains(&output.seal) { + if outputs.contains(&output.output) { res.insert(output.opout, TypedState::Void); } } for output in history.attach() { - if outpoints.contains(&output.seal) { + if outputs.contains(&output.output) { res.insert(output.opout, TypedState::Attachment(output.state.clone().into())); } } diff --git a/src/resolvers.rs b/src/resolvers.rs index d237ede2..20de0b22 100644 --- a/src/resolvers.rs +++ b/src/resolvers.rs @@ -19,13 +19,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use rgb::{ExposedSeal, SealDefinition, WitnessOrd}; +use rgb::{Anchor, WitnessAnchor}; pub trait ResolveHeight { type Error: std::error::Error; - fn resolve_height( - &mut self, - seal_definition: SealDefinition, - ) -> Result; + fn resolve_anchor(&mut self, anchor: &Anchor) -> Result; }