Skip to content

Commit

Permalink
containers: refactor Consignment terminals to contain only secret seals
Browse files Browse the repository at this point in the history
terminals were used before in RGB Core. With change of the validation algorithm they are used just in standard library to resolve secret seal. This change remove unnecessary data from the terminals structure.
  • Loading branch information
dr-orlovsky committed Aug 1, 2024
1 parent 5b11666 commit bc2ec1c
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 176 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
47 changes: 19 additions & 28 deletions src/containers/consignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -185,8 +185,8 @@ pub struct Consignment<const TRANSFER: bool> {
/// contract.
pub transfer: bool,

/// Set of seals which are history terminals.
pub terminals: SmallOrdMap<BundleId, Terminal>,
/// Set of secret seals which are history terminals.
pub terminals: SmallOrdMap<BundleId, XChain<SecretSeal>>,

/// Genesis data.
pub genesis: Genesis,
Expand Down Expand Up @@ -246,7 +246,7 @@ impl<const TRANSFER: bool> CommitEncode for Consignment<TRANSFER> {
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(
Expand Down Expand Up @@ -287,36 +287,27 @@ impl<const TRANSFER: bool> Consignment<TRANSFER> {
#[inline]
pub fn schema_id(&self) -> SchemaId { self.schema.schema_id() }

pub fn terminal_secrets(&self) -> impl Iterator<Item = (BundleId, XChain<SecretSeal>)> {
self.terminals
.clone()
.into_iter()
.flat_map(|(id, term)| term.secrets().map(move |secret| (id, secret)))
}

pub fn terminals_disclose(&self) -> impl Iterator<Item = TerminalDisclose> + '_ {
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<GraphSeal>) -> Self {
pub fn reveal_terminal_seals<E>(
mut self,
f: impl Fn(XChain<SecretSeal>) -> Result<Option<XChain<GraphSeal>>, E>,
) -> Result<Self, E> {
// 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 {
Expand Down
5 changes: 2 additions & 3 deletions src/containers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
57 changes: 0 additions & 57 deletions src/containers/seal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -108,62 +107,6 @@ impl From<VoutSeal> 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<Vout>) -> TerminalSeal {
TerminalSeal::WitnessVout(VoutSeal::new(method, vout))
}

pub fn secret_seal(&self) -> Option<SecretSeal> {
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<Seal: TxoSeal + Ord> {
Expand Down
17 changes: 9 additions & 8 deletions src/containers/seals.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 | `<txid>:<vout>` | Genesis |
| [`BlindSeal`] | BP Core | Required | Yes | No | `<method>:<<txid>/~>:<vout>#<blinding>` | Stash |
| [`SecretSeal`] | BP Core | Unknown | Implicit | Yes | `txob:<baid64>#<checksum>` | Ext. payments |
| [`ExplicitSeal`] | BP Core | Optional | Yes | No | `<method>:<<txid>/~>:<vout>` | Internal |
| [`VoutSeal`] | RGB Std | Absent | Yes | No | `<method>:~:<vout>#<blinding>` | SealEndpoint |
| [`TerminalSeal`] | RGB Std | Optional | Varies | Can be | `<ConcealedSeal>/<VoutSeal>` | Consignments |
| **Type name** | **Lib** | **Txid** | **Blinding** | **Private** | **String serialization** | **Use case** |
|------------------|---------|----------|--------------|-------------|-----------------------------------------|---------------|
| [`Outpoint`] | BP Core | Required | No | No | `<txid>:<vout>` | Genesis |
| [`BlindSeal`] | BP Core | Required | Yes | No | `<method>:<<txid>/~>:<vout>#<blinding>` | Stash |
| [`SecretSeal`] | BP Core | Unknown | Implicit | Yes | `txob:<baid64>#<checksum>` | Ext. payments |
| [`ExplicitSeal`] | BP Core | Optional | Yes | No | `<method>:<<txid>/~>:<vout>` | Internal |
| [`VoutSeal`] | RGB Std | Absent | Yes | No | `<method>:~:<vout>#<blinding>` | SealEndpoint |

[`Outpoint`]: bp::Outpoint

[`BlindSeal`]: bp::seals::txout::blind::BlindSeal

[`ExplicitSeal`]: bp::seals::txout::ExplicitSeal
48 changes: 4 additions & 44 deletions src/containers/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TerminalSeal>,
}

#[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<XChain<TerminalSeal>>,
}

impl Terminal {
pub fn new(seal: XChain<TerminalSeal>) -> Self {
Terminal {
seals: small_bset![seal],
}
}

pub fn secrets(&self) -> impl Iterator<Item = XChain<SecretSeal>> {
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)]
Expand Down
12 changes: 4 additions & 8 deletions src/persistence/stash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,15 +466,11 @@ impl<P: StashProvider> Stash<P> {
&self,
mut consignment: Consignment<TRANSFER>,
) -> Result<Consignment<TRANSFER>, StashError<P>> {
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)
}

Expand Down
36 changes: 9 additions & 27 deletions src/persistence/stock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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::{
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -764,7 +760,7 @@ impl<S: StashProvider, H: StateProvider, P: IndexProvider> Stock<S, H, P> {
// 1.3. Collect all state transitions assigning state to the provided outpoints
let mut bundled_witnesses = BTreeMap::<BundleId, BundledWitness>::new();
let mut transitions = BTreeMap::<OpId, Transition>::new();
let mut terminals = BTreeMap::<BundleId, Terminal>::new();
let mut terminals = BTreeMap::<BundleId, XChain<SecretSeal>>::new();
for opout in opouts {
if opout.op == contract_id {
continue; // we skip genesis since it will be present anywhere
Expand All @@ -774,28 +770,14 @@ impl<S: StashProvider, H: StateProvider, P: IndexProvider> Stock<S, H, P> {
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);
}
}
}
Expand Down Expand Up @@ -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::*;
Expand Down

0 comments on commit bc2ec1c

Please sign in to comment.