diff --git a/Cargo.toml b/Cargo.toml index 7346e8df..1bb6562e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,4 +100,3 @@ features = ["all"] bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "master" } bp-invoice = { git = "https://github.com/BP-WG/bp-std.git", branch = "master" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "contract-state2" } -#rgb-core = { path = "../rgb-core" } diff --git a/src/containers/consignment.rs b/src/containers/consignment.rs index 407c8b18..8ca1f078 100644 --- a/src/containers/consignment.rs +++ b/src/containers/consignment.rs @@ -43,9 +43,9 @@ use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize}; use strict_types::TypeSystem; use super::{ - BundledWitness, ContainerVer, ContentId, ContentSigs, IndexedConsignment, Supplement, Terminal, - TerminalDisclose, ASCII_ARMOR_CONSIGNMENT_TYPE, ASCII_ARMOR_CONTRACT, ASCII_ARMOR_IFACE, - ASCII_ARMOR_SCHEMA, ASCII_ARMOR_TERMINAL, ASCII_ARMOR_VERSION, + BundledWitness, ContainerVer, ContentId, ContentSigs, IndexedConsignment, Supplement, + ASCII_ARMOR_CONSIGNMENT_TYPE, ASCII_ARMOR_CONTRACT, ASCII_ARMOR_IFACE, ASCII_ARMOR_SCHEMA, + ASCII_ARMOR_TERMINAL, ASCII_ARMOR_VERSION, }; use crate::interface::{Iface, IfaceImpl}; use crate::persistence::{MemContract, MemContractState}; @@ -185,8 +185,8 @@ pub struct Consignment { /// contract. pub transfer: bool, - /// Set of seals which are history terminals. - pub terminals: SmallOrdMap, + /// Set of secret seals which are history terminals. + pub terminals: SmallOrdMap>, /// Genesis data. pub genesis: Genesis, @@ -246,7 +246,7 @@ impl CommitEncode for Consignment { e.commit_to_set(&LargeOrdSet::from_iter_unsafe( self.extensions.iter().map(Extension::disclose_hash), )); - e.commit_to_set(&SmallOrdSet::from_iter_unsafe(self.terminals_disclose())); + e.commit_to_map(&self.terminals); e.commit_to_set(&SmallOrdSet::from_iter_unsafe(self.attachments.keys().copied())); e.commit_to_set(&TinyOrdSet::from_iter_unsafe( @@ -287,36 +287,27 @@ impl Consignment { #[inline] pub fn schema_id(&self) -> SchemaId { self.schema.schema_id() } - pub fn terminal_secrets(&self) -> impl Iterator)> { - self.terminals - .clone() - .into_iter() - .flat_map(|(id, term)| term.secrets().map(move |secret| (id, secret))) - } - - pub fn terminals_disclose(&self) -> impl Iterator + '_ { - self.terminals.iter().flat_map(|(id, term)| { - term.seals.iter().map(|seal| TerminalDisclose { - bundle_id: *id, - seal: *seal, - }) - }) - } - - #[must_use] - pub fn reveal_bundle_seal(mut self, bundle_id: BundleId, revealed: XChain) -> Self { + pub fn reveal_terminal_seals( + mut self, + f: impl Fn(XChain) -> Result>, E>, + ) -> Result { // We need to clone since ordered set does not allow us to mutate members. let mut bundles = LargeOrdSet::with_capacity(self.bundles.len()); for mut bundled_witness in self.bundles { - for bundle in bundled_witness.anchored_bundles.bundles_mut() { - if bundle.bundle_id() == bundle_id { - bundle.reveal_seal(revealed); + for (bundle_id, secret) in &self.terminals { + if let Some(seal) = f(*secret)? { + for bundle in bundled_witness.anchored_bundles.bundles_mut() { + if bundle.bundle_id() == *bundle_id { + bundle.reveal_seal(seal); + break; + } + } } } bundles.push(bundled_witness).ok(); } self.bundles = bundles; - self + Ok(self) } pub fn into_contract(self) -> Contract { diff --git a/src/containers/mod.rs b/src/containers/mod.rs index d85f0d9f..85ede3c6 100644 --- a/src/containers/mod.rs +++ b/src/containers/mod.rs @@ -53,15 +53,14 @@ pub use kit::{Kit, KitId, ValidKit}; pub use partials::{ Batch, BundleDichotomy, CloseMethodSet, Fascia, TransitionInfo, TransitionInfoError, }; -pub use seal::{BuilderSeal, TerminalSeal, VoutSeal}; +pub use seal::{BuilderSeal, VoutSeal}; pub use suppl::{ AnnotationName, Annotations, ContentRef, SupplId, SupplItem, SupplMap, SupplSub, Supplement, TickerSuppl, VelocityHint, SUPPL_ANNOT_IFACE_CLASS, SUPPL_ANNOT_IFACE_FEATURES, SUPPL_ANNOT_VELOCITY, }; pub use util::{ - ContainerVer, ContentId, ContentSigs, DumbValidator, SigBlob, SigValidator, Terminal, - TerminalDisclose, TrustLevel, + ContainerVer, ContentId, ContentSigs, DumbValidator, SigBlob, SigValidator, TrustLevel, }; pub const ASCII_ARMOR_NAME: &str = "Name"; diff --git a/src/containers/seal.rs b/src/containers/seal.rs index 8c810d86..49dc3079 100644 --- a/src/containers/seal.rs +++ b/src/containers/seal.rs @@ -24,7 +24,6 @@ use bp::seals::txout::{BlindSeal, CloseMethod, SealTxid}; use bp::secp256k1::rand::{thread_rng, RngCore}; use bp::Vout; -use commit_verify::Conceal; use rgb::{GraphSeal, Layer1, SecretSeal, TxoSeal, XChain}; use crate::LIB_NAME_RGB_STD; @@ -108,62 +107,6 @@ impl From for GraphSeal { } } -/// Seal endpoint is a confidential seal which may be linked to the witness -/// transaction, but does not contain information about its id. -/// -/// Seal endpoint can be either a pointer to the output in the witness -/// transaction, plus blinding factor value, or a confidential seal -/// [`SecretSeal`] value pointing some external unknown transaction -/// output -/// -/// Seal endpoint is required in situations where sender assigns state to the -/// witness transaction output on behalf of receiver -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom, dumb = Self::ConcealedUtxo(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum TerminalSeal { - /// External transaction output in concealed form (see [`SecretSeal`]) - #[from] - #[strict_type(tag = 0)] - ConcealedUtxo(SecretSeal), - - /// Seal contained within the witness transaction - #[from] - #[strict_type(tag = 1)] - WitnessVout(VoutSeal), -} - -impl TerminalSeal { - /// Constructs [`TerminalSeal`] for the witness transaction. Uses - /// `thread_rng` to initialize blinding factor. - pub fn new_vout(method: CloseMethod, vout: impl Into) -> TerminalSeal { - TerminalSeal::WitnessVout(VoutSeal::new(method, vout)) - } - - pub fn secret_seal(&self) -> Option { - match self { - TerminalSeal::ConcealedUtxo(seal) => Some(*seal), - TerminalSeal::WitnessVout(_) => None, - } - } -} - -impl Conceal for TerminalSeal { - type Concealed = SecretSeal; - - fn conceal(&self) -> Self::Concealed { - match *self { - TerminalSeal::ConcealedUtxo(hash) => hash, - TerminalSeal::WitnessVout(seal) => GraphSeal::from(seal).conceal(), - } - } -} - /// Seal used by operation builder which can be either revealed or concealed. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)] pub enum BuilderSeal { diff --git a/src/containers/seals.md b/src/containers/seals.md index 0c066771..3136a22f 100644 --- a/src/containers/seals.md +++ b/src/containers/seals.md @@ -14,15 +14,16 @@ Single-use-seals in RGB can have multiple forms because of the confidentiality options and ability to be linked to the witness transaction closing previous seal in RGB state evolution graph. -| **Type name** | **Lib** | **Txid** | **Blinding** | **Private** | **String serialization** | **Use case** | -|------------------|---------| --------- | ------------ |-------------|-----------------------------------------|---------------| -| [`Outpoint`] | BP Core | Required | No | No | `:` | Genesis | -| [`BlindSeal`] | BP Core | Required | Yes | No | `:</~>:#` | Stash | -| [`SecretSeal`] | BP Core | Unknown | Implicit | Yes | `txob:#` | Ext. payments | -| [`ExplicitSeal`] | BP Core | Optional | Yes | No | `:</~>:` | Internal | -| [`VoutSeal`] | RGB Std | Absent | Yes | No | `:~:#` | SealEndpoint | -| [`TerminalSeal`] | RGB Std | Optional | Varies | Can be | `/` | Consignments | +| **Type name** | **Lib** | **Txid** | **Blinding** | **Private** | **String serialization** | **Use case** | +|------------------|---------|----------|--------------|-------------|-----------------------------------------|---------------| +| [`Outpoint`] | BP Core | Required | No | No | `:` | Genesis | +| [`BlindSeal`] | BP Core | Required | Yes | No | `:</~>:#` | Stash | +| [`SecretSeal`] | BP Core | Unknown | Implicit | Yes | `txob:#` | Ext. payments | +| [`ExplicitSeal`] | BP Core | Optional | Yes | No | `:</~>:` | Internal | +| [`VoutSeal`] | RGB Std | Absent | Yes | No | `:~:#` | SealEndpoint | [`Outpoint`]: bp::Outpoint + [`BlindSeal`]: bp::seals::txout::blind::BlindSeal + [`ExplicitSeal`]: bp::seals::txout::ExplicitSeal diff --git a/src/containers/util.rs b/src/containers/util.rs index b53b217c..0e73a450 100644 --- a/src/containers/util.rs +++ b/src/containers/util.rs @@ -21,54 +21,14 @@ use std::collections::{btree_map, BTreeMap}; -use amplify::confinement::{Confined, NonEmptyBlob, SmallOrdSet}; +use amplify::confinement::{Confined, NonEmptyBlob}; use commit_verify::StrictHash; -use rgb::{BundleId, ContractId, Identity, SchemaId, XChain}; +use rgb::{ContractId, Identity, SchemaId}; use strict_encoding::StrictDumb; -use super::{SupplId, TerminalSeal}; +use super::SupplId; use crate::interface::{IfaceId, ImplId}; -use crate::{SecretSeal, LIB_NAME_RGB_STD}; - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct TerminalDisclose { - pub bundle_id: BundleId, - pub seal: XChain, -} - -#[derive(Clone, Eq, PartialEq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Terminal { - pub seals: SmallOrdSet>, -} - -impl Terminal { - pub fn new(seal: XChain) -> Self { - Terminal { - seals: small_bset![seal], - } - } - - pub fn secrets(&self) -> impl Iterator> { - self.seals - .clone() - .into_iter() - .filter_map(|seal| seal.map_ref(TerminalSeal::secret_seal).transpose()) - } -} +use crate::LIB_NAME_RGB_STD; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] #[derive(StrictType, StrictEncode, StrictDecode)] diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index 32f99a46..ace8a820 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -466,15 +466,11 @@ impl Stash

{ &self, mut consignment: Consignment, ) -> Result, StashError

> { - for (bundle_id, secret) in consignment.terminal_secrets() { - if let Some(seal) = self - .provider + consignment = consignment.reveal_terminal_seals(|secret| { + self.provider .seal_secret(secret) - .map_err(StashError::ReadProvider)? - { - consignment = consignment.reveal_bundle_seal(bundle_id, seal); - } - } + .map_err(StashError::ReadProvider) + })?; Ok(consignment) } diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 6bdb663b..9e2ef29e 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -31,7 +31,6 @@ use amplify::Wrapper; use bp::seals::txout::CloseMethod; use bp::Vout; use chrono::Utc; -use commit_verify::Conceal; use invoice::{Amount, Beneficiary, InvoiceState, NonFungible, RgbInvoice}; use rgb::validation::{DbcProof, EAnchor, ResolveWitness, WitnessResolverError}; use rgb::{ @@ -49,9 +48,9 @@ use super::{ }; use crate::containers::{ AnchorSet, AnchoredBundles, Batch, BuilderSeal, BundledWitness, Consignment, ContainerVer, - ContentId, ContentRef, Contract, Fascia, Kit, SealWitness, SupplItem, SupplSub, Terminal, - TerminalSeal, Transfer, TransitionInfo, TransitionInfoError, ValidConsignment, ValidContract, - ValidKit, ValidTransfer, VelocityHint, SUPPL_ANNOT_VELOCITY, + ContentId, ContentRef, Contract, Fascia, Kit, SealWitness, SupplItem, SupplSub, Transfer, + TransitionInfo, TransitionInfoError, ValidConsignment, ValidContract, ValidKit, ValidTransfer, + VelocityHint, SUPPL_ANNOT_VELOCITY, }; use crate::info::{ContractInfo, IfaceInfo, SchemaInfo}; use crate::interface::{ @@ -162,9 +161,6 @@ pub enum ConsignError { /// too many transitions. TooManyBundles, - /// public state at operation output {0} is concealed. - ConcealedPublicState(Opout), - #[from] #[display(inner)] MergeReveal(MergeRevealError), @@ -764,7 +760,7 @@ impl Stock { // 1.3. Collect all state transitions assigning state to the provided outpoints let mut bundled_witnesses = BTreeMap::::new(); let mut transitions = BTreeMap::::new(); - let mut terminals = BTreeMap::::new(); + let mut terminals = BTreeMap::>::new(); for opout in opouts { if opout.op == contract_id { continue; // we skip genesis since it will be present anywhere @@ -774,28 +770,14 @@ impl Stock { transitions.insert(opout.op, transition.clone()); let bundle_id = self.index.bundle_id_for_op(transition.id())?; - // 2. Collect seals from terminal transitions to add to the consignment + // 2. Collect secret seals from terminal transitions to add to the consignment // terminals - for (type_id, typed_assignments) in transition.assignments.iter() { + for typed_assignments in transition.assignments.values() { for index in 0..typed_assignments.len_u16() { let seal = typed_assignments.to_confidential_seals()[index as usize]; if secret_seals.contains(&seal) { - terminals - .entry(bundle_id) - .or_insert(Terminal::new(seal.map(TerminalSeal::from))) - .seals - .push(seal.map(TerminalSeal::from)) - .map_err(|_| ConsignError::TooManyTerminals)?; - } else if opout.no == index && opout.ty == *type_id { - if let Some(seal) = typed_assignments - .revealed_seal_at(index) - .expect("index exists") - { - let seal = seal.map(|s| s.conceal()).map(TerminalSeal::from); - terminals.insert(bundle_id, Terminal::new(seal)); - } else { - return Err(ConsignError::ConcealedPublicState(opout).into()); - } + let res = terminals.insert(bundle_id, seal); + assert_eq!(res, None); } } } @@ -1313,7 +1295,7 @@ mod test { use std::str::FromStr; use baid64::FromBaid64Str; - use commit_verify::{DigestExt, Sha256}; + use commit_verify::{Conceal, DigestExt, Sha256}; use strict_encoding::TypeName; use super::*;