Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RCP-240313A: support future SPV proofs by refactoring anchors #228

Merged
merged 2 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,9 @@ wasm-bindgen-test = "0.3"

[package.metadata.docs.rs]
features = ["all"]

[patch.crates-io]
bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "deanchor" }
bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "deanchor" }
bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "deanchor" }
bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "deanchor" }
8 changes: 4 additions & 4 deletions src/bin/rgbcore-stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@
let tt = sys.type_tree("RGB.Transition").unwrap();
writeln!(file, "{tt}").unwrap();

let mut file = fs::File::create(format!("{dir}/AnchoredBundle.vesper")).unwrap();
let mut file = fs::File::create(format!("{dir}/TransitionBundle.vesper")).unwrap();

Check warning on line 122 in src/bin/rgbcore-stl.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/rgbcore-stl.rs#L122

Added line #L122 was not covered by tests
writeln!(
file,
"{{-
Description: RGB Anchored Bundle
Description: RGB Transition Bundle

Check warning on line 126 in src/bin/rgbcore-stl.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/rgbcore-stl.rs#L126

Added line #L126 was not covered by tests
Author: Dr Maxim Orlovsky <[email protected]>
Copyright (C) 2024 LNP/BP Standards Association. All rights reserved.
License: Apache-2.0
Expand All @@ -135,8 +135,8 @@
.unwrap();
let layout = TransitionBundle::commitment_layout();
writeln!(file, "{layout}").unwrap();
let tt = sys.type_tree("RGB.InputMap").unwrap();
let tt = sys.type_tree("RGB.XChainAnchorSet").unwrap();

Check warning on line 138 in src/bin/rgbcore-stl.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/rgbcore-stl.rs#L138

Added line #L138 was not covered by tests
writeln!(file, "{tt}").unwrap();
let tt = sys.type_tree("RGB.AnchoredBundle").unwrap();
let tt = sys.type_tree("RGB.TransitionBundle").unwrap();

Check warning on line 140 in src/bin/rgbcore-stl.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/rgbcore-stl.rs#L140

Added line #L140 was not covered by tests
writeln!(file, "{tt}").unwrap();
}
54 changes: 1 addition & 53 deletions src/contract/anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,48 +25,13 @@ use std::cmp::Ordering;
use bp::dbc::opret::OpretProof;
use bp::dbc::tapret::TapretProof;
use bp::dbc::Anchor;
use bp::Txid;
use commit_verify::mpc;
use strict_encoding::StrictDumb;

use crate::{BundleId, ContractId, TransitionBundle, WitnessId, WitnessOrd, XChain, LIB_NAME_RGB};

#[derive(Clone, Eq, PartialEq, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase")
)]
pub struct AnchoredBundle {
pub anchor: XAnchor,
pub bundle: TransitionBundle,
}

impl AnchoredBundle {
#[inline]
pub fn bundle_id(&self) -> BundleId { self.bundle.bundle_id() }
}

impl Ord for AnchoredBundle {
fn cmp(&self, other: &Self) -> Ordering { self.bundle_id().cmp(&other.bundle_id()) }
}

impl PartialOrd for AnchoredBundle {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
use crate::{BundleId, ContractId, WitnessId, WitnessOrd, XChain, LIB_NAME_RGB};

pub type XAnchor<P = mpc::MerkleProof> = XChain<AnchorSet<P>>;

impl<P: mpc::Proof + StrictDumb> XAnchor<P> {
#[inline]
pub fn witness_id(&self) -> Option<WitnessId> { self.maybe_map_ref(|set| set.txid()) }

#[inline]
pub fn witness_id_unchecked(&self) -> WitnessId { self.map_ref(|set| set.txid_unchecked()) }
}

impl XAnchor<mpc::MerkleBlock> {
pub fn known_bundle_ids(&self) -> impl Iterator<Item = (BundleId, ContractId)> + '_ {
match self {
Expand Down Expand Up @@ -129,23 +94,6 @@ pub enum AnchorSet<P: mpc::Proof + StrictDumb = mpc::MerkleProof> {
}

impl<P: mpc::Proof + StrictDumb> AnchorSet<P> {
pub fn txid(&self) -> Option<Txid> {
match self {
AnchorSet::Tapret(a) => Some(a.txid),
AnchorSet::Opret(a) => Some(a.txid),
AnchorSet::Dual { tapret, opret } if tapret.txid == opret.txid => Some(tapret.txid),
_ => None,
}
}

pub fn txid_unchecked(&self) -> Txid {
match self {
AnchorSet::Tapret(a) => a.txid,
AnchorSet::Opret(a) => a.txid,
AnchorSet::Dual { tapret, opret: _ } => tapret.txid,
}
}

pub fn from_split(
tapret: Option<Anchor<P, TapretProof>>,
opret: Option<Anchor<P, OpretProof>>,
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, AnchoredBundle, Layer1, WitnessAnchor, XAnchor};
pub use anchor::{AnchorSet, Layer1, WitnessAnchor, XAnchor};
pub use assignments::{
Assign, AssignAttach, AssignData, AssignFungible, AssignRights, Assignments, AssignmentsRef,
TypedAssigns,
Expand Down
8 changes: 5 additions & 3 deletions src/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ use strict_types::typelib::LibBuilder;
use strict_types::{CompileError, TypeLib};

use crate::{
AnchoredBundle, ContractState, Extension, Genesis, OpCommitment, SubSchema, LIB_NAME_RGB,
ContractState, Extension, Genesis, OpCommitment, SubSchema, TransitionBundle, XAnchor,
LIB_NAME_RGB,
};

/// Strict types id for the library providing data types for RGB consensus.
pub const LIB_ID_RGB: &str =
"urn:ubideco:stl:py61NAh7V4xHa7if2mF88KL3Z11rUruBNQEAsEqaf2Q#stock-sonata-carlo";
"urn:ubideco:stl:9B8mwkJrtk1nkptoEHaXWunxdRdR4S21DKD5F2quGJDG#doctor-society-gabriel";

fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB), tiny_bset! {
Expand All @@ -47,7 +48,8 @@ fn _rgb_core_stl() -> Result<TypeLib, CompileError> {
})
.transpile::<SubSchema>()
.transpile::<Genesis>()
.transpile::<AnchoredBundle>()
.transpile::<XAnchor>()
.transpile::<TransitionBundle>()
.transpile::<Extension>()
.transpile::<ContractState>()
.transpile::<OpCommitment>()
Expand Down
28 changes: 20 additions & 8 deletions src/validation/consignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
use std::rc::Rc;

use crate::{
AnchoredBundle, AssetTag, AssignmentType, BundleId, Genesis, OpId, OpRef, Operation,
SecretSeal, SubSchema, WitnessId, XChain,
AssetTag, AssignmentType, BundleId, Genesis, OpId, OpRef, Operation, SecretSeal, SubSchema,
TransitionBundle, WitnessId, XAnchor, XChain,
};

pub struct CheckedConsignment<'consignment, C: ConsignmentApi>(&'consignment C);
Expand All @@ -55,10 +55,16 @@

fn bundle_ids<'a>(&self) -> Self::Iter<'a> { self.0.bundle_ids() }

fn anchored_bundle(&self, bundle_id: BundleId) -> Option<Rc<AnchoredBundle>> {
fn bundle(&self, bundle_id: BundleId) -> Option<Rc<TransitionBundle>> {

Check warning on line 58 in src/validation/consignment.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/consignment.rs#L58

Added line #L58 was not covered by tests
self.0
.anchored_bundle(bundle_id)
.filter(|ab| ab.bundle.bundle_id() == bundle_id)
.bundle(bundle_id)
.filter(|b| b.bundle_id() == bundle_id)
}

Check warning on line 62 in src/validation/consignment.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/consignment.rs#L60-L62

Added lines #L60 - L62 were not covered by tests

fn anchor(&self, bundle_id: BundleId) -> Option<Rc<XAnchor>> { self.0.anchor(bundle_id) }

Check warning on line 64 in src/validation/consignment.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/consignment.rs#L64

Added line #L64 was not covered by tests

fn bundle_witness_id(&self, bundle_id: BundleId) -> Option<WitnessId> {
self.0.bundle_witness_id(bundle_id)

Check warning on line 67 in src/validation/consignment.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/consignment.rs#L66-L67

Added lines #L66 - L67 were not covered by tests
}

fn op_witness_id(&self, opid: OpId) -> Option<WitnessId> { self.0.op_witness_id(opid) }
Expand All @@ -81,7 +87,7 @@
/// Asset tags uses in the confidential asset validation.
fn asset_tags(&self) -> &BTreeMap<AssignmentType, AssetTag>;

/// Retrieves reference to a operation (genesis, state transition or state
/// Retrieves reference to an operation (genesis, state transition or state
/// extension) matching the provided id, or `None` otherwise
fn operation(&self, opid: OpId) -> Option<OpRef>;

Expand All @@ -102,8 +108,14 @@
/// Returns iterator over all bundle ids present in the consignment.
fn bundle_ids<'a>(&self) -> Self::Iter<'a>;

/// Returns reference to an anchored bundle given a bundle id.
fn anchored_bundle(&self, bundle_id: BundleId) -> Option<Rc<AnchoredBundle>>;
/// Returns reference to a bundle given a bundle id.
fn bundle(&self, bundle_id: BundleId) -> Option<Rc<TransitionBundle>>;

/// Returns reference to an anchor given a bundle id.
fn anchor(&self, bundle_id: BundleId) -> Option<Rc<XAnchor>>;

/// Returns witness id for a given transition bundle.
fn bundle_witness_id(&self, bundle_id: BundleId) -> Option<WitnessId>;

/// Returns witness id for a given operation.
fn op_witness_id(&self, opid: OpId) -> Option<WitnessId>;
Expand Down
8 changes: 5 additions & 3 deletions src/validation/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,12 @@ pub enum Failure {
/// transition bundle {0} referenced in consignment terminals is absent from
/// the consignment.
TerminalBundleAbsent(BundleId),
/// transition bundle {0} is absent from the consignment.
/// transition bundle {0} is absent in the consignment.
BundleAbsent(BundleId),
/// anchor for transitio bundle {0} is absent in the consignment.
AnchorAbsent(BundleId),
/// witness id for transition bundle {0} is absent in the consignment.
WitnessIdAbsent(BundleId),
/// operation {0} is under a different contract {1}.
ContractMismatch(OpId, ContractId),

Expand All @@ -327,8 +331,6 @@ pub enum Failure {
},
/// transition {0} references non-existing previous output {1}.
NoPrevOut(OpId, Opout),
/// anchors used inside bundle {0} reference different public witness ids.
AnchorSetInvalid(BundleId),
/// seal defined in the history as a part of operation output {0} is
/// confidential and can't be validated.
ConfidentialSeal(Opout),
Expand Down
53 changes: 28 additions & 25 deletions src/validation/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@
#[derive(Clone, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum WitnessResolverError {
/// witness {0} does not exists.
/// witness {0} does not exist.
Unknown(WitnessId),
/// unable to retrieve witness {0}, {1}
Other(WitnessId, String),
}

pub trait ResolveWitness {
// TODO: Return with SPV proof data
fn resolve_pub_witness(
&self,
witness_id: WitnessId,
Expand Down Expand Up @@ -95,11 +96,11 @@
// to detect any potential issues with the consignment structure and notify user
// about them (in form of generated warnings)
for (bundle_id, seal_endpoint) in consignment.terminals() {
let Some(anchored_bundle) = consignment.anchored_bundle(bundle_id) else {
let Some(bundle) = consignment.bundle(bundle_id) else {

Check warning on line 99 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L99

Added line #L99 was not covered by tests
status.add_failure(Failure::TerminalBundleAbsent(bundle_id));
continue;
};
for (opid, transition) in &anchored_bundle.bundle.known_transitions {
for (opid, transition) in &bundle.known_transitions {

Check warning on line 103 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L103

Added line #L103 was not covered by tests
// Checking for endpoint definition duplicates
if !transition
.assignments
Expand Down Expand Up @@ -209,12 +210,12 @@
// treat it as a superposition of subgraphs, one for each endpoint; and validate
// them independently.
for (bundle_id, _) in self.consignment.terminals() {
let Some(anchored_bundle) = self.consignment.anchored_bundle(bundle_id) else {
let Some(bundle) = self.consignment.bundle(bundle_id) else {

Check warning on line 213 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L213

Added line #L213 was not covered by tests
// We already checked and errored here during the terminal validation, so just
// skipping.
continue;
};
for transition in anchored_bundle.bundle.known_transitions.values() {
for transition in bundle.known_transitions.values() {

Check warning on line 218 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L218

Added line #L218 was not covered by tests
self.validate_logic_on_route(schema, transition);
}
}
Expand Down Expand Up @@ -303,27 +304,32 @@
// *** PART III: Validating single-use-seals
fn validate_commitments(&mut self) {
for bundle_id in self.consignment.bundle_ids() {
let Some(anchored_bundle) = self.consignment.anchored_bundle(bundle_id) else {
let Some(bundle) = self.consignment.bundle(bundle_id) else {

Check warning on line 307 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L307

Added line #L307 was not covered by tests
self.status.add_failure(Failure::BundleAbsent(bundle_id));
continue;
};

let layer1 = anchored_bundle.anchor.layer1();

let anchors = &anchored_bundle.anchor;
let bundle = &anchored_bundle.bundle;
let Some(anchor) = self.consignment.anchor(bundle_id) else {
self.status.add_failure(Failure::AnchorAbsent(bundle_id));
continue;

Check warning on line 313 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L311-L313

Added lines #L311 - L313 were not covered by tests
};
let Some(witness_id) = self.consignment.bundle_witness_id(bundle_id) else {
self.status.add_failure(Failure::WitnessIdAbsent(bundle_id));
continue;

Check warning on line 317 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L315-L317

Added lines #L315 - L317 were not covered by tests
};

// [VALIDATION]: We validate that the seals were properly defined on BP-type layers
let (seals, input_map) = self.validate_seal_definitions(layer1, bundle);
let (seals, input_map) =
self.validate_seal_definitions(witness_id.layer1(), bundle.as_ref());

Check warning on line 322 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L321-L322

Added lines #L321 - L322 were not covered by tests

// [VALIDATION]: We validate that the seals were properly closed on BP-type layers
let Some(witness_tx) = self.validate_seal_commitments(&seals, bundle_id, anchors)
let Some(witness_tx) =
self.validate_seal_commitments(&seals, bundle_id, anchor.as_ref(), witness_id)

Check warning on line 326 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L325-L326

Added lines #L325 - L326 were not covered by tests
else {
continue;
};

// [VALIDATION]: We validate bundle commitments to the input map
self.validate_bundle_commitments(bundle_id, bundle, witness_tx, input_map);
self.validate_bundle_commitments(bundle_id, bundle.as_ref(), witness_tx, input_map);

Check warning on line 332 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L332

Added line #L332 was not covered by tests
}
}

Expand Down Expand Up @@ -367,15 +373,12 @@
seals: impl AsRef<[XOutputSeal]>,
bundle_id: BundleId,
anchors: &XAnchor,
witness_id: WitnessId,

Check warning on line 376 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L376

Added line #L376 was not covered by tests
) -> Option<XPubWitness> {
let Some(witness_id) = anchors.witness_id() else {
self.status
.add_failure(Failure::AnchorSetInvalid(bundle_id));
return None;
};

// Check that the anchor is committed into a transaction spending all of the
// Check that the anchor is committed into a transaction spending all the

Check warning on line 378 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L378

Added line #L378 was not covered by tests
// transition inputs.
// Here the method can do SPV proof instead of querying the indexer. The SPV
// proofs can be part of the consignments, but do not require .

Check warning on line 381 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L380-L381

Added lines #L380 - L381 were not covered by tests
match self.resolver.resolve_pub_witness(witness_id) {
Err(_) => {
// We wre unable to retrieve corresponding transaction, so can't check.
Expand Down Expand Up @@ -403,7 +406,7 @@
if let Some(tapret) = tapret {
let witness = pub_witness
.clone()
.map(|tx| Witness::with(tx, tapret.clone()));
.map(|tx| Witness::with(tx, tapret.dbc_proof.clone()));

Check warning on line 409 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L409

Added line #L409 was not covered by tests
self.validate_seal_closing(tapret_seals, witness, bundle_id, tapret)
} else if tapret_seals.count() > 0 {
self.status.add_warning(Warning::UnclosedSeals(bundle_id));
Expand All @@ -416,7 +419,7 @@
if let Some(opret) = opret {
let witness = pub_witness
.clone()
.map(|tx| Witness::with(tx, opret.clone()));
.map(|tx| Witness::with(tx, opret.dbc_proof));

Check warning on line 422 in src/validation/validator.rs

View check run for this annotation

Codecov / codecov/patch

src/validation/validator.rs#L422

Added line #L422 was not covered by tests
self.validate_seal_closing(opret_seals, witness, bundle_id, opret)
} else if opret_seals.count() > 0 {
self.status.add_warning(Warning::UnclosedSeals(bundle_id));
Expand Down Expand Up @@ -530,8 +533,8 @@
/// generic type `Dbc`) and extra-transaction data, which are taken from
/// anchors DBC proof.
///
/// Additionally checks that the provided message contains commitment to the
/// bundle under the current contract.
/// Additionally, checks that the provided message contains commitment to
/// the bundle under the current contract.
fn validate_seal_closing<'seal, 'temp, Seal: 'seal, Dbc: dbc::Proof>(
&mut self,
seals: impl IntoIterator<Item = &'seal Seal>,
Expand Down
Loading
Loading