Skip to content

Commit

Permalink
Merge branch 'single-commit' into v0.11
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Apr 11, 2024
2 parents e555dc6 + 2cf0676 commit 6aa7885
Show file tree
Hide file tree
Showing 14 changed files with 649 additions and 686 deletions.
224 changes: 114 additions & 110 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/bin/rgbcore-stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ Bundles vesper lexicon=types+commitments
.unwrap();
let layout = TransitionBundle::commitment_layout();
writeln!(file, "{layout}").unwrap();
let tt = sys.type_tree("RGB.AnchorSet").unwrap();
let tt = sys.type_tree("RGB.DbcProof").unwrap();
writeln!(file, "{tt}").unwrap();
let tt = sys.type_tree("RGB.TransitionBundle").unwrap();
writeln!(file, "{tt}").unwrap();
Expand Down
172 changes: 71 additions & 101 deletions src/contract/anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,128 +22,98 @@

use std::cmp::Ordering;

use bp::dbc::opret::OpretProof;
use bp::dbc::opret::{OpretError, OpretProof};
use bp::dbc::tapret::TapretProof;
use bp::dbc::Anchor;
use commit_verify::mpc;
use strict_encoding::StrictDumb;
use bp::dbc::Method;
use bp::{dbc, Tx};
use commit_verify::mpc::Commitment;
use commit_verify::{mpc, ConvolveVerifyError, EmbedVerifyError};
use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize};

use crate::{BundleId, ContractId, WitnessOrd, XWitnessId, LIB_NAME_RGB};
use crate::{WitnessOrd, XWitnessId, LIB_NAME_RGB};

#[derive(Clone, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
)]
#[display(doc_comments)]
pub enum DbcError {
/// transaction doesn't contain OP_RETURN output.
NoOpretOutput,

/// first OP_RETURN output inside the transaction already contains some
/// data.
InvalidOpretScript,

/// commitment doesn't match the message.
CommitmentMismatch,

/// the proof is invalid and the commitment can't be verified since the
/// original container can't be restored from it.
UnrestorableProof,

/// the proof does not match to the proof generated for the same message
/// during the verification.
ProofMismatch,

/// the message is invalid since a valid commitment to it can't be created.
ImpossibleMessage,

/// the proof is invalid and the commitment can't be verified.
InvalidProof,
}

#[derive(Clone, Eq, PartialEq, Debug, From)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB, tags = custom, dumb = Self::Tapret(strict_dumb!()))]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase", untagged)
)]
pub enum AnchorSet<P: mpc::Proof + StrictDumb = mpc::MerkleProof> {
pub enum DbcProof {
#[from]
#[strict_type(tag = 0x01)]
Tapret(Anchor<P, TapretProof>),
Tapret(TapretProof),

#[from]
#[strict_type(tag = 0x02)]
Opret(Anchor<P, OpretProof>),
#[strict_type(tag = 0x03)]
Dual {
tapret: Anchor<P, TapretProof>,
opret: Anchor<P, OpretProof>,
},
Opret(OpretProof),
}

impl<P: mpc::Proof + StrictDumb> AnchorSet<P> {
pub fn from_split(
tapret: Option<Anchor<P, TapretProof>>,
opret: Option<Anchor<P, OpretProof>>,
) -> Option<Self> {
Some(match (tapret, opret) {
(Some(tapret), Some(opret)) => Self::Dual { tapret, opret },
(Some(tapret), None) => Self::Tapret(tapret),
(None, Some(opret)) => Self::Opret(opret),
(None, None) => return None,
})
}
impl StrictSerialize for DbcProof {}
impl StrictDeserialize for DbcProof {}

#[allow(clippy::type_complexity)]
pub fn as_split(&self) -> (Option<&Anchor<P, TapretProof>>, Option<&Anchor<P, OpretProof>>) {
match self {
AnchorSet::Tapret(tapret) => (Some(tapret), None),
AnchorSet::Opret(opret) => (None, Some(opret)),
AnchorSet::Dual { tapret, opret } => (Some(tapret), Some(opret)),
}
}
impl dbc::Proof for DbcProof {
type Error = DbcError;
const METHOD: Method = Method::OpretFirst;

#[allow(clippy::type_complexity)]
pub fn into_split(self) -> (Option<Anchor<P, TapretProof>>, Option<Anchor<P, OpretProof>>) {
fn verify(&self, msg: &Commitment, tx: &Tx) -> Result<(), Self::Error> {
match self {
AnchorSet::Tapret(tapret) => (Some(tapret), None),
AnchorSet::Opret(opret) => (None, Some(opret)),
AnchorSet::Dual { tapret, opret } => (Some(tapret), Some(opret)),
DbcProof::Tapret(tapret) => tapret.verify(msg, tx).map_err(|err| match err {
ConvolveVerifyError::CommitmentMismatch => DbcError::CommitmentMismatch,
ConvolveVerifyError::ImpossibleMessage => DbcError::ImpossibleMessage,
ConvolveVerifyError::InvalidProof => DbcError::InvalidProof,
}),
DbcProof::Opret(opret) => opret.verify(msg, tx).map_err(|err| match err {
EmbedVerifyError::CommitmentMismatch => DbcError::CommitmentMismatch,
EmbedVerifyError::InvalidMessage(OpretError::NoOpretOutput) => {
DbcError::NoOpretOutput
}
EmbedVerifyError::InvalidMessage(OpretError::InvalidOpretScript) => {
DbcError::InvalidOpretScript
}
EmbedVerifyError::InvalidProof => DbcError::UnrestorableProof,
EmbedVerifyError::ProofMismatch => DbcError::ProofMismatch,
}),
}
}

pub fn mpc_proofs(&self) -> impl Iterator<Item = &P> {
let (t, o) = self.as_split();
t.map(|a| &a.mpc_proof)
.into_iter()
.chain(o.map(|a| &a.mpc_proof))
}
}

impl AnchorSet<mpc::MerkleProof> {
pub fn to_merkle_block(
&self,
contract_id: ContractId,
bundle_id: BundleId,
) -> Result<AnchorSet<mpc::MerkleBlock>, mpc::InvalidProof> {
self.clone().into_merkle_block(contract_id, bundle_id)
}

pub fn into_merkle_block(
self,
contract_id: ContractId,
bundle_id: BundleId,
) -> Result<AnchorSet<mpc::MerkleBlock>, mpc::InvalidProof> {
let (tapret, opret) = self.into_split();
let tapret = tapret
.map(|t| t.into_merkle_block(contract_id, bundle_id))
.transpose()?;
let opret = opret
.map(|o| o.into_merkle_block(contract_id, bundle_id))
.transpose()?;
Ok(AnchorSet::from_split(tapret, opret).expect("one must be non-None"))
}
}

impl AnchorSet<mpc::MerkleBlock> {
pub fn known_bundle_ids(&self) -> impl Iterator<Item = (BundleId, ContractId)> + '_ {
self.mpc_proofs().flat_map(|p| {
p.to_known_message_map()
.into_iter()
.map(|(p, m)| (m.into(), p.into()))
})
}

pub fn to_merkle_proof(
&self,
contract_id: ContractId,
) -> Result<AnchorSet<mpc::MerkleProof>, mpc::LeafNotKnown> {
self.clone().into_merkle_proof(contract_id)
}

pub fn into_merkle_proof(
self,
contract_id: ContractId,
) -> Result<AnchorSet<mpc::MerkleProof>, mpc::LeafNotKnown> {
let (tapret, opret) = self.into_split();
let tapret = tapret
.map(|t| t.into_merkle_proof(contract_id))
.transpose()?;
let opret = opret
.map(|o| o.into_merkle_proof(contract_id))
.transpose()?;
Ok(AnchorSet::from_split(tapret, opret).expect("one must be non-None"))
}
}
/// Anchor which DBC proof is either Tapret or Opret.
pub type EAnchor<P = mpc::MerkleProof> = dbc::Anchor<P, DbcProof>;

/// Txid and height information ordered according to the RGB consensus rules.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
Expand Down
8 changes: 7 additions & 1 deletion src/contract/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::collections::{btree_map, BTreeMap};

use amplify::confinement::{Confined, U16 as U16MAX};
use amplify::{Bytes32, Wrapper};
use bp::seals::txout::CloseMethod;
use bp::Vout;
use commit_verify::{mpc, CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, Sha256};
use strict_encoding::{StrictDumb, StrictEncode};
Expand Down Expand Up @@ -108,19 +109,24 @@ impl<'a> IntoIterator for &'a InputMap {
serde(crate = "serde_crate", rename_all = "camelCase")
)]
pub struct TransitionBundle {
pub close_method: CloseMethod,
pub input_map: InputMap,
pub known_transitions: Confined<BTreeMap<OpId, Transition>, 1, U16MAX>,
}

impl CommitEncode for TransitionBundle {
type CommitmentId = BundleId;

fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(&self.input_map); }
fn commit_encode(&self, e: &mut CommitEngine) {
e.commit_to_serialized(&self.close_method);
e.commit_to_serialized(&self.input_map);
}
}

impl StrictDumb for TransitionBundle {
fn strict_dumb() -> Self {
Self {
close_method: strict_dumb!(),
input_map: strict_dumb!(),
known_transitions: confined_bmap! { strict_dumb!() => strict_dumb!() },
}
Expand Down
2 changes: 1 addition & 1 deletion src/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ mod contract;
mod xchain;
mod commit;

pub use anchor::{AnchorSet, Layer1, WitnessAnchor};
pub use anchor::{DbcError, DbcProof, EAnchor, Layer1, WitnessAnchor};
pub use assignments::{
Assign, AssignAttach, AssignData, AssignFungible, AssignRights, Assignments, AssignmentsRef,
TypedAssigns,
Expand Down
6 changes: 3 additions & 3 deletions src/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ use strict_types::typelib::LibBuilder;
use strict_types::{CompileError, TypeLib};

use crate::{
AnchorSet, ContractState, Extension, Genesis, OpCommitment, Schema, TransitionBundle,
ContractState, DbcProof, Extension, Genesis, OpCommitment, Schema, TransitionBundle,
XWitnessId, LIB_NAME_RGB,
};

/// Strict types id for the library providing data types for RGB consensus.
pub const LIB_ID_RGB: &str =
"urn:ubideco:stl:6Yx8ib21pu6se8asaV7z9MQNUuemRZ8iQWhFZFBWcsDp#java-navy-xray";
"urn:ubideco:stl:7oRjK3fd128oNpMWv1ajhBZq6EotU5Zn1sd3LNNADv4w#laptop-humor-film";

fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB), tiny_bset! {
Expand All @@ -48,7 +48,7 @@ fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
})
.transpile::<Schema>()
.transpile::<Genesis>()
.transpile::<AnchorSet>()
.transpile::<DbcProof>()
.transpile::<XWitnessId>()
.transpile::<TransitionBundle>()
.transpile::<Extension>()
Expand Down
8 changes: 4 additions & 4 deletions src/validation/consignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
//! single-use-seal data.
use crate::{
AnchorSet, BundleId, Genesis, OpId, OpRef, Operation, Schema, SecretSeal, TransitionBundle,
BundleId, EAnchor, Genesis, OpId, OpRef, Operation, Schema, SecretSeal, TransitionBundle,
XChain, XWitnessId,
};

Expand Down Expand Up @@ -56,8 +56,8 @@ impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'con
.filter(|b| b.bundle_id() == bundle_id)
}

fn anchors(&self, bundle_id: BundleId) -> Option<(XWitnessId, &AnchorSet)> {
self.0.anchors(bundle_id)
fn anchor(&self, bundle_id: BundleId) -> Option<(XWitnessId, &EAnchor)> {
self.0.anchor(bundle_id)
}

fn op_witness_id(&self, opid: OpId) -> Option<XWitnessId> { self.0.op_witness_id(opid) }
Expand Down Expand Up @@ -99,7 +99,7 @@ pub trait ConsignmentApi {
fn bundle(&self, bundle_id: BundleId) -> Option<&TransitionBundle>;

/// Returns a grip given a bundle id.
fn anchors(&self, bundle_id: BundleId) -> Option<(XWitnessId, &AnchorSet)>;
fn anchor(&self, bundle_id: BundleId) -> Option<(XWitnessId, &EAnchor)>;

/// Returns witness id for a given operation.
fn op_witness_id(&self, opid: OpId) -> Option<XWitnessId>;
Expand Down
12 changes: 7 additions & 5 deletions src/validation/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::contract::Opout;
use crate::schema::{self, SchemaId};
use crate::{
AssignmentType, BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId,
SecretSeal, StateType, Vin, XChain, XGraphSeal, XWitnessId,
SecretSeal, StateType, Vin, XChain, XGraphSeal, XOutputSeal, XWitnessId,
};

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)]
Expand Down Expand Up @@ -306,15 +306,20 @@ pub enum Failure {
SealNoWitnessTx(XWitnessId),
/// witness layer 1 {anchor} doesn't match seal definition {seal}.
SealWitnessLayer1Mismatch { seal: Layer1, anchor: Layer1 },
/// seal {1:?} is defined on {0} which is not in the set of layers allowed
/// seal {1} is defined on {0} which is not in the set of layers allowed
/// by the contract genesis.
SealLayerMismatch(Layer1, XGraphSeal),
/// seal {1} has a different closing method from the bundle {0} requirement.
SealInvalidMethod(BundleId, XOutputSeal),
/// transition bundle {0} doesn't close seal with the witness {1}. Details:
/// {2}
SealsInvalid(BundleId, XWitnessId, String),
/// single-use seals for the operation {0} were not validated, which
/// probably indicates unanchored state transition.
SealsUnvalidated(OpId),
/// anchor provides different type of DBC proof than required by the bundle
/// {0}.
AnchorMethodMismatch(BundleId),
/// transition bundle {0} is not properly anchored to the witness {1}.
/// Details: {2}
MpcInvalid(BundleId, XWitnessId, InvalidProof),
Expand Down Expand Up @@ -385,9 +390,6 @@ pub enum Warning {
TerminalSealAbsent(OpId, XChain<SecretSeal>),
/// terminal witness transaction {0} is not yet mined.
TerminalWitnessNotMined(Txid),
/// transition bundle {0} doesn't close all the seals defined for its
/// inputs.
UnclosedSeals(BundleId),

/// Custom warning by external services on top of RGB Core.
#[display(inner)]
Expand Down
Loading

0 comments on commit 6aa7885

Please sign in to comment.