From 9ca43de7321429bc3de1a9231a0ad4a3e4fa3a6c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 26 Dec 2023 20:18:48 +0100 Subject: [PATCH 1/6] persistence: use ExplicitSeal in transfer method --- src/persistence/inventory.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/persistence/inventory.rs b/src/persistence/inventory.rs index 17a501f8..5718e4a2 100644 --- a/src/persistence/inventory.rs +++ b/src/persistence/inventory.rs @@ -25,8 +25,7 @@ use std::error::Error; use std::ops::Deref; use amplify::confinement::{self, Confined, MediumVec, U24}; -use bp::seals::txout::blind::SingleBlindSeal; -use bp::seals::txout::CloseMethod; +use bp::seals::txout::{CloseMethod, ExplicitSeal}; use bp::{Txid, Vout}; use chrono::Utc; use commit_verify::{mpc, Conceal}; @@ -572,7 +571,7 @@ pub trait Inventory: Deref { fn transfer( &self, contract_id: ContractId, - seals: impl IntoIterator>>, + seals: impl IntoIterator>>>, ) -> Result< Bindle, ConsignerError::Target as Stash>::Error>, From 72393421592dbef2dbf36ebe851c280bc69e2ff0 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 26 Dec 2023 21:41:38 +0100 Subject: [PATCH 2/6] persistence: add Stash::taprets method --- Cargo.lock | 29 +++++++++++++++++++---------- Cargo.toml | 5 +++++ src/persistence/hoard.rs | 24 +++++++++++++++++++++++- src/persistence/stash.rs | 3 +++ 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df941a4c..b4c95c07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -220,6 +220,18 @@ name = "bp-consensus" version = "0.11.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190ac89a2a3c79d5bfb677f48e5393691832c540973341831572edaffdce0881" +dependencies = [ + "amplify", + "chrono", + "commit_verify", + "secp256k1 0.28.0", + "strict_encoding", +] + +[[package]] +name = "bp-consensus" +version = "0.11.0-beta.3" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#50630d40828c522f78066c6ca473f0f3291b977d" dependencies = [ "amplify", "chrono", @@ -233,11 +245,10 @@ dependencies = [ [[package]] name = "bp-core" version = "0.11.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0143f6c7399cb6d0003407e6de197a03b3b42b34380fab02c8fecaf4431b061" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#50630d40828c522f78066c6ca473f0f3291b977d" dependencies = [ "amplify", - "bp-consensus", + "bp-consensus 0.11.0-beta.3 (git+https://github.com/BP-WG/bp-core?branch=v0.11)", "bp-dbc", "bp-seals", "commit_verify", @@ -250,12 +261,11 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.11.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e3e04649c77079cfd1466ba14a62c83585053bb61d294578a39fcfe38f402db" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#50630d40828c522f78066c6ca473f0f3291b977d" dependencies = [ "amplify", "base85", - "bp-consensus", + "bp-consensus 0.11.0-beta.3 (git+https://github.com/BP-WG/bp-core?branch=v0.11)", "commit_verify", "secp256k1 0.28.0", "serde", @@ -271,18 +281,17 @@ dependencies = [ "amplify", "bech32", "bitcoin_hashes", - "bp-consensus", + "bp-consensus 0.11.0-beta.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bp-seals" version = "0.11.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e4955315fad858472320ee5a7fba8a35c61c3928bdacb581931e23d4f25c7b" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#50630d40828c522f78066c6ca473f0f3291b977d" dependencies = [ "amplify", "baid58", - "bp-consensus", + "bp-consensus 0.11.0-beta.3 (git+https://github.com/BP-WG/bp-core?branch=v0.11)", "bp-dbc", "commit_verify", "rand", diff --git a/Cargo.toml b/Cargo.toml index 3eb20bb9..c4f1109e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,3 +90,8 @@ wasm-bindgen-test = "0.3" [package.metadata.docs.rs] features = [ "all" ] + +[patch.crates-io] +bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } +bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } +bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } diff --git a/src/persistence/hoard.rs b/src/persistence/hoard.rs index 827012d0..aee7bf45 100644 --- a/src/persistence/hoard.rs +++ b/src/persistence/hoard.rs @@ -25,7 +25,8 @@ use std::convert::Infallible; use amplify::confinement; use amplify::confinement::{Confined, LargeOrdMap, SmallOrdMap, TinyOrdMap, TinyOrdSet}; use bp::dbc::anchor::MergeError; -use commit_verify::mpc; +use bp::dbc::tapret::TapretCommitment; +use commit_verify::{mpc, CommitmentId}; use rgb::{ AnchoredBundle, AssetTag, AssignmentType, BundleId, ContractId, Extension, Genesis, OpId, Operation, SchemaId, TransitionBundle, WitnessId, XAnchor, @@ -337,4 +338,25 @@ impl Stash for Hoard { .ok_or(StashInconsistency::ContractAbsent(contract_id)) .map_err(StashError::from) } + + fn taprets(&self) -> Result, StashError> { + Ok(self + .anchors + .iter() + .filter_map(|(witness_id, anchor)| { + match anchor { + XAnchor::Bitcoin(set) | XAnchor::Liquid(set) => set, + } + .as_split() + .0 + .map(|a| (*witness_id, a)) + }) + .map(|(witness_id, tapret)| { + (witness_id, TapretCommitment { + mpc: tapret.mpc_proof.commitment_id(), + nonce: tapret.dbc_proof.path_proof.nonce(), + }) + }) + .collect()) + } } diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index 241c8ec7..845a928e 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -25,6 +25,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::error::Error; use amplify::confinement::{TinyOrdMap, TinyOrdSet}; +use bp::dbc::tapret::TapretCommitment; use commit_verify::mpc; use rgb::{ AssetTag, AssignmentType, BundleId, ContractId, Extension, Genesis, OpId, SchemaId, @@ -136,4 +137,6 @@ pub trait Stash { &self, witness_id: WitnessId, ) -> Result<&XAnchor, StashError>; + + fn taprets(&self) -> Result, StashError>; } From 27a999d3c7f0b2b17c2658ff0e01da3e7e532ca1 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 26 Dec 2023 22:50:31 +0100 Subject: [PATCH 3/6] persistence: fix parameter name --- src/persistence/inventory.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/persistence/inventory.rs b/src/persistence/inventory.rs index 5718e4a2..0aeab433 100644 --- a/src/persistence/inventory.rs +++ b/src/persistence/inventory.rs @@ -690,15 +690,20 @@ pub trait Inventory: Deref { invoice: &RgbInvoice, prev_outputs: impl IntoIterator>, method: CloseMethod, - change_vout: Option>, + beneficiary_vout: Option>, allocator: impl Fn(ContractId, AssignmentType, VelocityHint) -> Option, ) -> Result::Target as Stash>::Error>> where Self::Error: From<::Error>, { - self.compose_deterministic(invoice, prev_outputs, method, change_vout, allocator, |_, _| { - BlindingFactor::random() - }) + self.compose_deterministic( + invoice, + prev_outputs, + method, + beneficiary_vout, + allocator, + |_, _| BlindingFactor::random(), + ) } /// Composes a batch of state transitions updating state for the provided From 738d60ea8475ef9342200d4ec6e3bef23eea44e5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 26 Dec 2023 22:50:42 +0100 Subject: [PATCH 4/6] containers: add one more seal converter --- src/containers/util.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/containers/util.rs b/src/containers/util.rs index b6f0bc37..6eee4fca 100644 --- a/src/containers/util.rs +++ b/src/containers/util.rs @@ -20,8 +20,9 @@ // limitations under the License. use amplify::confinement::SmallOrdSet; -use bp::{Outpoint, Tx}; -use rgb::OutputSeal; +use bp::seals::txout::ExplicitSeal; +use bp::{Outpoint, Tx, Txid}; +use rgb::{OutputSeal, XSeal}; use super::TerminalSeal; use crate::LIB_NAME_RGB_STD; @@ -104,3 +105,12 @@ impl From for XchainOutpoint { } } } + +impl From for XSeal> { + fn from(outpoint: XchainOutpoint) -> Self { + match outpoint { + XchainOutpoint::Bitcoin(outpoint) => XSeal::Bitcoin(outpoint.into()), + XchainOutpoint::Liquid(outpoint) => XSeal::Liquid(outpoint.into()), + } + } +} From ab6aacef5ce1a3f3c04525abc9c7807f7a493bee Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 28 Dec 2023 12:47:07 +0100 Subject: [PATCH 5/6] containers: update to new ConsignmentAPI. Add indexer --- Cargo.lock | 3 +- Cargo.toml | 1 + src/containers/consignment.rs | 65 ++----------------- src/containers/indexed.rs | 118 ++++++++++++++++++++++++++++++++++ src/containers/mod.rs | 2 + src/containers/validate.rs | 5 +- 6 files changed, 131 insertions(+), 63 deletions(-) create mode 100644 src/containers/indexed.rs diff --git a/Cargo.lock b/Cargo.lock index b4c95c07..99d557ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -664,8 +664,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd6b8a6d616997c670ea40a5a9badc9744f3e1fa29213affabdd2d2c192ef3b" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#7eb443b87745d2a05030f556d8a33ba8dbed0f0a" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index c4f1109e..15203284 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,3 +95,4 @@ features = [ "all" ] bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.11" } diff --git a/src/containers/consignment.rs b/src/containers/consignment.rs index 3456be98..a0965e1d 100644 --- a/src/containers/consignment.rs +++ b/src/containers/consignment.rs @@ -19,17 +19,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::{BTreeMap, BTreeSet}; -use std::rc::Rc; -use std::{iter, vec}; +use std::collections::BTreeMap; +use std::iter; use amplify::confinement::{LargeVec, MediumBlob, SmallOrdMap, TinyOrdMap, TinyOrdSet}; -use commit_verify::Conceal; -use rgb::validation::{self, ConsignmentApi}; +use rgb::validation::{self}; use rgb::{ AnchoredBundle, AssetTag, AssignmentType, AttachId, BundleId, ContractHistory, ContractId, - Extension, Genesis, GraphSeal, OpId, OpRef, Operation, Schema, SchemaId, SecretSeal, SubSchema, - Transition, XSeal, + Extension, Genesis, GraphSeal, OpId, Operation, Schema, SchemaId, SubSchema, Transition, XSeal, }; use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize}; @@ -157,13 +154,13 @@ impl Consignment { .find(|anchored_bundle| anchored_bundle.bundle.bundle_id() == bundle_id) } - fn transition(&self, opid: OpId) -> Option<&Transition> { + pub(super) fn transition(&self, opid: OpId) -> Option<&Transition> { self.bundles .iter() .find_map(|ab| ab.bundle.known_transitions.get(&opid)) } - fn extension(&self, opid: OpId) -> Option<&Extension> { + pub(super) fn extension(&self, opid: OpId) -> Option<&Extension> { self.extensions .iter() .find(|&extension| extension.id() == opid) @@ -255,53 +252,3 @@ impl Consignment { } } } - -#[derive(Debug)] -pub struct BundleIdIter(vec::IntoIter); - -impl Iterator for BundleIdIter { - type Item = BundleId; - - fn next(&mut self) -> Option { - self.0.next().as_ref().map(AnchoredBundle::bundle_id) - } -} - -impl ConsignmentApi for Consignment { - type Iter<'a> = BundleIdIter; - - fn schema(&self) -> &SubSchema { &self.schema } - - #[inline] - fn asset_tags(&self) -> &BTreeMap { self.asset_tags.as_inner() } - - fn operation(&self, opid: OpId) -> Option { - if opid == self.genesis.id() { - return Some(OpRef::Genesis(&self.genesis)); - } - self.transition(opid) - .map(OpRef::from) - .or_else(|| self.extension(opid).map(OpRef::from)) - } - - fn genesis(&self) -> &Genesis { &self.genesis } - - fn terminals(&self) -> BTreeSet<(BundleId, SecretSeal)> { - self.terminals - .iter() - .flat_map(|(bundle_id, terminal)| { - terminal - .seals - .iter() - .map(|seal| (*bundle_id, seal.conceal())) - }) - .collect() - } - - fn bundle_ids<'a>(&self) -> Self::Iter<'a> { BundleIdIter(self.bundles.clone().into_iter()) } - - fn anchored_bundle(&self, bundle_id: BundleId) -> Option> { - self.anchored_bundle(bundle_id) - .map(|ab| Rc::new(ab.clone())) - } -} diff --git a/src/containers/indexed.rs b/src/containers/indexed.rs new file mode 100644 index 00000000..eeafe38a --- /dev/null +++ b/src/containers/indexed.rs @@ -0,0 +1,118 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::{BTreeMap, BTreeSet}; +use std::ops::Deref; +use std::rc::Rc; +use std::vec; + +use commit_verify::Conceal; +use rgb::validation::ConsignmentApi; +use rgb::{ + AnchoredBundle, AssetTag, AssignmentType, BundleId, Genesis, OpId, OpRef, Operation, SubSchema, + WitnessId, +}; + +use super::Consignment; +use crate::SecretSeal; + +// TODO: Add more indexes +#[derive(Clone, Debug)] +pub struct IndexedConsignment<'c, const TYPE: bool> { + consignment: &'c Consignment, + op_witness_ids: BTreeMap, +} + +impl<'c, const TYPE: bool> Deref for IndexedConsignment<'c, TYPE> { + type Target = Consignment; + + fn deref(&self) -> &Self::Target { self.consignment } +} + +impl<'c, const TYPE: bool> IndexedConsignment<'c, TYPE> { + pub fn new(consignment: &'c Consignment) -> Self { + let mut op_witness_ids = BTreeMap::new(); + for ab in &consignment.bundles { + for opid in ab.bundle.known_transitions.keys() { + op_witness_ids.insert(*opid, ab.anchor.witness_id()); + } + } + Self { + consignment, + op_witness_ids, + } + } +} + +impl<'c, const TYPE: bool> ConsignmentApi for IndexedConsignment<'c, TYPE> { + type Iter<'a> = BundleIdIter; + + fn schema(&self) -> &SubSchema { &self.schema } + + #[inline] + fn asset_tags(&self) -> &BTreeMap { self.asset_tags.as_inner() } + + fn operation(&self, opid: OpId) -> Option { + if opid == self.genesis.id() { + return Some(OpRef::Genesis(&self.genesis)); + } + self.transition(opid) + .map(OpRef::from) + .or_else(|| self.extension(opid).map(OpRef::from)) + } + + fn genesis(&self) -> &Genesis { &self.genesis } + + fn terminals(&self) -> BTreeSet<(BundleId, SecretSeal)> { + self.terminals + .iter() + .flat_map(|(bundle_id, terminal)| { + terminal + .seals + .iter() + .map(|seal| (*bundle_id, seal.conceal())) + }) + .collect() + } + + fn bundle_ids<'a>(&self) -> Self::Iter<'a> { BundleIdIter(self.bundles.clone().into_iter()) } + + fn anchored_bundle(&self, bundle_id: BundleId) -> Option> { + self.consignment + .anchored_bundle(bundle_id) + .map(|ab| Rc::new(ab.clone())) + } + + fn op_witness_id(&self, opid: OpId) -> Option { + self.op_witness_ids.get(&opid).copied() + } +} + +#[derive(Debug)] +pub struct BundleIdIter(vec::IntoIter); + +impl Iterator for BundleIdIter { + type Item = BundleId; + + fn next(&mut self) -> Option { + self.0.next().as_ref().map(AnchoredBundle::bundle_id) + } +} diff --git a/src/containers/mod.rs b/src/containers/mod.rs index 43dc5250..eea20c8e 100644 --- a/src/containers/mod.rs +++ b/src/containers/mod.rs @@ -37,11 +37,13 @@ mod util; mod validate; mod certs; mod partials; +mod indexed; pub use bindle::{Bindle, BindleContent, BindleParseError, LoadError, UniversalBindle}; pub use certs::{Cert, ContentId, ContentSigs, Identity}; pub use consignment::{Consignment, Contract, Transfer}; pub use disclosure::Disclosure; +pub use indexed::IndexedConsignment; pub use partials::{Batch, CloseMethodSet, Fascia, TransitionInfo}; pub use seal::{BuilderSeal, TerminalSeal, VoutSeal}; pub use util::{ContainerVer, Terminal, XchainOutpoint}; diff --git a/src/containers/validate.rs b/src/containers/validate.rs index fe4eb41e..94adff5e 100644 --- a/src/containers/validate.rs +++ b/src/containers/validate.rs @@ -21,7 +21,7 @@ use rgb::validation::{ResolveTx, Validator, Validity, Warning}; -use super::Consignment; +use super::{Consignment, IndexedConsignment}; impl Consignment { pub fn validate( @@ -29,7 +29,8 @@ impl Consignment { resolver: &mut R, testnet: bool, ) -> Result, Consignment> { - let mut status = Validator::validate(&self, resolver, testnet); + let index = IndexedConsignment::new(&self); + let mut status = Validator::validate(&index, resolver, testnet); let validity = status.validity(); From 0d5a826170a6c54040ad274020226b4469790549 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 28 Dec 2023 14:52:48 +0100 Subject: [PATCH 6/6] accessors: fix bugfix from the previous merge --- src/accessors/merge_reveal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/accessors/merge_reveal.rs b/src/accessors/merge_reveal.rs index 6fd33536..e31e4996 100644 --- a/src/accessors/merge_reveal.rs +++ b/src/accessors/merge_reveal.rs @@ -192,7 +192,7 @@ impl MergeReveal for TransitionBundle { .known_transitions .extend(other.known_transitions) .is_err() || - self.input_map.len() < self.known_transitions.len() + self.input_map.len() > self.known_transitions.len() { return Err(MergeRevealError::ExcessiveTransitions); }