From 3bc38318bbe689d3083248ef3c4710744ad12ba0 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 15 Oct 2024 18:26:14 +0200 Subject: [PATCH 01/70] epic: refactor state types --- Cargo.lock | 70 +- Cargo.toml | 2 +- invoice/Cargo.toml | 3 +- invoice/src/amount.rs | 500 ----------- invoice/src/builder.rs | 55 +- invoice/src/data.rs | 293 ------- invoice/src/invoice.rs | 54 +- invoice/src/lib.rs | 8 - invoice/src/parse.rs | 103 ++- src/containers/anchors.rs | 2 +- src/containers/seal.rs | 21 +- src/contract/assignments.rs | 122 +-- src/contract/merge_reveal.rs | 101 +-- src/contract/mod.rs | 2 +- src/interface/builder.rs | 861 +----------------- src/interface/contract.rs | 334 +------ src/interface/mod.rs | 5 +- src/lib.rs | 7 +- src/persistence/index.rs | 104 +-- src/persistence/memory.rs | 224 ++--- src/persistence/mod.rs | 4 +- src/persistence/stash.rs | 19 +- src/persistence/state.rs | 32 +- src/persistence/stock.rs | 63 +- src/{stl => }/stl.rs | 106 +-- src/stl/chain.rs | 56 -- src/stl/error.rs | 39 - src/stl/mime.rs | 214 ----- src/stl/mod.rs | 44 - src/stl/specs.rs | 410 --------- stl/RGBContract@0.11.0.sta | 52 -- stl/RGBContract@0.11.0.stl | Bin 2623 -> 0 bytes stl/RGBContract@0.11.0.sty | 111 --- stl/RGBStd@0.11.0.sta | 479 +++++----- stl/RGBStd@0.11.0.stl | Bin 18876 -> 18172 bytes stl/RGBStd@0.11.0.sty | 141 ++- stl/RGBStorage@0.11.0.sta | 331 ++++--- stl/RGBStorage@0.11.0.stl | Bin 13104 -> 11620 bytes stl/RGBStorage@0.11.0.sty | 191 ++-- stl/Transfer.vesper | 1586 ++++++---------------------------- stl/src/main.rs | 26 +- 41 files changed, 1143 insertions(+), 5632 deletions(-) delete mode 100644 invoice/src/amount.rs delete mode 100644 invoice/src/data.rs rename src/{stl => }/stl.rs (54%) delete mode 100644 src/stl/chain.rs delete mode 100644 src/stl/error.rs delete mode 100644 src/stl/mime.rs delete mode 100644 src/stl/mod.rs delete mode 100644 src/stl/specs.rs delete mode 100644 stl/RGBContract@0.11.0.sta delete mode 100644 stl/RGBContract@0.11.0.stl delete mode 100644 stl/RGBContract@0.11.0.sty diff --git a/Cargo.lock b/Cargo.lock index e5bc4d83..28d602ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,6 @@ dependencies = [ "amplify_num", "amplify_syn", "ascii", - "rand", "serde", "stringly_conversions", "wasm-bindgen", @@ -150,6 +149,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + [[package]] name = "base64" version = "0.22.1" @@ -177,12 +182,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" -[[package]] -name = "bitcoin-private" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" - [[package]] name = "bitcoin_hashes" version = "0.14.0" @@ -235,7 +234,7 @@ dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1 0.30.0", + "secp256k1", "serde", "strict_encoding", "strict_types", @@ -268,7 +267,7 @@ dependencies = [ "base85", "bp-consensus", "commit_verify", - "secp256k1 0.30.0", + "secp256k1", "serde", "strict_encoding", ] @@ -433,12 +432,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "fast32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35a73237400bde66c82e38387343f90d7182a2f2f22729e096a2abd57d75db9" - [[package]] name = "fluent-uri" version = "0.1.4" @@ -568,12 +561,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minicov" version = "0.3.5" @@ -686,7 +673,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.9" -source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#50027495bf5e464f0e49edf65417f8caed837a39" +source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#8267ce26b1edf905553a49e5dcc42d5f2f0df338" dependencies = [ "aluvm", "amplify", @@ -695,8 +682,6 @@ dependencies = [ "chrono", "commit_verify", "getrandom", - "mime", - "secp256k1-zkp", "serde", "single_use_seals", "strict_encoding", @@ -710,9 +695,9 @@ version = "0.11.0-beta.9" dependencies = [ "amplify", "baid64", + "base58", "bp-core", "bp-invoice", - "fast32", "fluent-uri", "indexmap", "percent-encoding", @@ -720,7 +705,6 @@ dependencies = [ "rgb-core", "serde", "strict_encoding", - "strict_types", ] [[package]] @@ -788,17 +772,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" -[[package]] -name = "secp256k1" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" -dependencies = [ - "rand", - "secp256k1-sys", - "serde", -] - [[package]] name = "secp256k1" version = "0.30.0" @@ -820,29 +793,6 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-zkp" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" -dependencies = [ - "bitcoin-private", - "rand", - "secp256k1 0.29.1", - "secp256k1-zkp-sys", - "serde", -] - -[[package]] -name = "secp256k1-zkp-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6eea7919e0cab992510edfbf40bd9342c0a3c2bb910f2c51355c2cb2d69839" -dependencies = [ - "cc", - "secp256k1-sys", -] - [[package]] name = "serde" version = "1.0.210" diff --git a/Cargo.toml b/Cargo.toml index f5b96320..55db1cec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,4 +107,4 @@ bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "develop" } +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "feat/fungible-nonconf" } diff --git a/invoice/Cargo.toml b/invoice/Cargo.toml index 05673093..ff70bc69 100644 --- a/invoice/Cargo.toml +++ b/invoice/Cargo.toml @@ -17,10 +17,9 @@ name = "rgbinvoice" [dependencies] amplify = { workspace = true } +base58 = "0.2.0" baid64 = { workspace = true } -fast32 = "1.0.3" strict_encoding = { workspace = true } -strict_types = { workspace = true } bp-core = { workspace = true } bp-invoice = { workspace = true } rgb-core = { workspace = true } diff --git a/invoice/src/amount.rs b/invoice/src/amount.rs deleted file mode 100644 index 9007f085..00000000 --- a/invoice/src/amount.rs +++ /dev/null @@ -1,500 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::cmp::Ordering; -use std::fmt; -use std::fmt::{Display, Formatter, Write}; -use std::iter::Sum; -use std::num::{ParseIntError, TryFromIntError}; -use std::str::FromStr; - -use bp::Sats; -use rgb::{FungibleState, RevealedValue}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -use strict_encoding::{StrictDeserialize, StrictSerialize, VariantError}; -use strict_types::StrictVal; - -use crate::LIB_NAME_RGB_CONTRACT; - -pub const ENC_BASE32_NODIGIT: &[u8; 32] = b"abcdefghkmnABCDEFGHKMNPQRSTVWXYZ"; -fast32::make_base32_alpha!(BASE32_NODIGIT, DEC_BASE32_NODIGIT, ENC_BASE32_NODIGIT); - -#[derive( - Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From -)] -#[wrapper(Add, Sub, Mul, Div, Rem)] -#[wrapper_mut(AddAssign, SubAssign, MulAssign, DivAssign, RemAssign)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Amount( - #[from] - #[from(u32)] - #[from(u16)] - #[from(u8)] - #[from(Sats)] - u64, -); - -impl StrictSerialize for Amount {} -impl StrictDeserialize for Amount {} - -impl From for Amount { - fn from(value: RevealedValue) -> Self { Amount(value.value.as_u64()) } -} - -impl From for Amount { - fn from(state: FungibleState) -> Self { Amount(state.as_u64()) } -} - -impl From for FungibleState { - fn from(amount: Amount) -> Self { FungibleState::Bits64(amount.0) } -} - -impl Amount { - pub const ZERO: Self = Amount(0); - - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - value.unwrap_uint::().into() - } - - pub fn with_precision(amount: u64, precision: impl Into) -> Self { - precision.into().unchecked_convert(amount) - } - - pub fn with_precision_checked(amount: u64, precision: impl Into) -> Option { - precision.into().checked_convert(amount) - } - - pub fn value(self) -> u64 { self.0 } - - pub fn split(self, precision: impl Into) -> (u64, u64) { - let precision = precision.into(); - let int = self.floor(precision); - let fract = self.rem(precision); - (int, fract) - } - - pub fn round(&self, precision: impl Into) -> u64 { - let precision = precision.into(); - let mul = precision.multiplier(); - if self.0 == 0 { - return 0; - } - let inc = 2 * self.rem(precision) / mul; - self.0 / mul + inc - } - - pub fn ceil(&self, precision: impl Into) -> u64 { - let precision = precision.into(); - if self.0 == 0 { - return 0; - } - let inc = if self.rem(precision) > 0 { 1 } else { 0 }; - self.0 / precision.multiplier() + inc - } - - pub fn floor(&self, precision: impl Into) -> u64 { - if self.0 == 0 { - return 0; - } - self.0 / precision.into().multiplier() - } - - pub fn rem(&self, precision: impl Into) -> u64 { - self.0 % precision.into().multiplier() - } - - pub fn saturating_add(&self, other: impl Into) -> Self { - self.0.saturating_add(other.into().0).into() - } - pub fn saturating_sub(&self, other: impl Into) -> Self { - self.0.saturating_sub(other.into().0).into() - } - - pub fn saturating_add_assign(&mut self, other: impl Into) { - *self = self.0.saturating_add(other.into().0).into(); - } - pub fn saturating_sub_assign(&mut self, other: impl Into) { - *self = self.0.saturating_sub(other.into().0).into(); - } - - #[must_use] - pub fn checked_add(&self, other: impl Into) -> Option { - self.0.checked_add(other.into().0).map(Self) - } - #[must_use] - pub fn checked_sub(&self, other: impl Into) -> Option { - self.0.checked_sub(other.into().0).map(Self) - } - - #[must_use] - pub fn checked_add_assign(&mut self, other: impl Into) -> Option<()> { - *self = self.0.checked_add(other.into().0).map(Self)?; - Some(()) - } - #[must_use] - pub fn checked_sub_assign(&mut self, other: impl Into) -> Option<()> { - *self = self.0.checked_sub(other.into().0).map(Self)?; - Some(()) - } -} - -impl Sum for Amount { - fn sum>(iter: I) -> Self { - iter.fold(Amount::ZERO, |sum, value| sum.saturating_add(value)) - } -} - -impl Sum for Amount { - fn sum>(iter: I) -> Self { - iter.fold(Amount::ZERO, |sum, value| sum.saturating_add(value)) - } -} - -impl Display for Amount { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let bytes = self.0.to_le_bytes(); - let pos = bytes.iter().rposition(|b| *b != 0).unwrap_or(0) + 1; - let s = BASE32_NODIGIT.encode(&bytes[..pos]); - f.write_str(&s) - } -} - -impl FromStr for Amount { - type Err = fast32::DecodeError; - - fn from_str(s: &str) -> Result { - let amount = BASE32_NODIGIT.decode_str(s)?; - let len = amount.len(); - if len > 8 { - return Err(fast32::DecodeError::InvalidLength { - length: amount.len(), - }); - } - let mut le = [0u8; 8]; - le[..len].copy_from_slice(&amount); - Ok(Amount(u64::from_le_bytes(le))) - } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] -#[repr(u8)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum Precision { - Indivisible = 0, - Deci = 1, - Centi = 2, - Milli = 3, - DeciMilli = 4, - CentiMilli = 5, - Micro = 6, - DeciMicro = 7, - #[default] - CentiMicro = 8, - Nano = 9, - DeciNano = 10, - CentiNano = 11, - Pico = 12, - DeciPico = 13, - CentiPico = 14, - Femto = 15, - DeciFemto = 16, - CentiFemto = 17, - Atto = 18, -} -impl StrictSerialize for Precision {} -impl StrictDeserialize for Precision {} - -impl Precision { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { value.unwrap_enum() } - pub const fn decimals(self) -> u8 { self as u8 } - - pub const fn multiplier(self) -> u64 { - match self { - Precision::Indivisible => 1, - Precision::Deci => 10, - Precision::Centi => 100, - Precision::Milli => 1000, - Precision::DeciMilli => 10_000, - Precision::CentiMilli => 100_000, - Precision::Micro => 1_000_000, - Precision::DeciMicro => 10_000_000, - Precision::CentiMicro => 100_000_000, - Precision::Nano => 1_000_000_000, - Precision::DeciNano => 10_000_000_000, - Precision::CentiNano => 100_000_000_000, - Precision::Pico => 1_000_000_000_000, - Precision::DeciPico => 10_000_000_000_000, - Precision::CentiPico => 100_000_000_000_000, - Precision::Femto => 1_000_000_000_000_000, - Precision::DeciFemto => 10_000_000_000_000_000, - Precision::CentiFemto => 100_000_000_000_000_000, - Precision::Atto => 1_000_000_000_000_000_000, - } - } - - pub fn unchecked_convert(self, amount: impl Into) -> Amount { - (amount.into() * self.multiplier()).into() - } - - pub fn checked_convert(self, amount: impl Into) -> Option { - amount - .into() - .checked_mul(self.multiplier()) - .map(Amount::from) - } - pub fn saturating_convert(self, amount: impl Into) -> Amount { - amount.into().saturating_mul(self.multiplier()).into() - } -} - -impl From for u16 { - fn from(value: Precision) -> Self { value as u8 as u16 } -} - -impl From for u32 { - fn from(value: Precision) -> Self { value as u8 as u32 } -} - -impl From for u64 { - fn from(value: Precision) -> Self { value as u8 as u64 } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[display("invalid precision")] -pub struct PrecisionError; - -#[derive(Getters, Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct CoinAmount { - #[getter(as_copy)] - int: u64, - #[getter(as_copy)] - fract: u64, - #[getter(as_copy)] - precision: Precision, -} - -impl CoinAmount { - pub fn new(amount: impl Into, precision: impl Into) -> Self { - let precision = precision.into(); - let amount = amount.into(); - let (int, fract) = amount.split(precision); - CoinAmount { - int, - fract, - precision, - } - } - - pub fn with( - int: u64, - fract: u64, - precision: impl Into, - ) -> Result { - let precision = precision.into(); - // 2^64 ~ 10^19 < 10^18 (18 is max value for Precision enum) - let pow = 10u64.pow(precision.decimals() as u32); - // number of decimals can't be larger than the smallest possible integer - if fract >= pow { - return Err(PrecisionError); - } - Ok(CoinAmount { - int, - fract, - precision, - }) - } - - pub(crate) fn to_amount_unchecked(self) -> Amount { - // 2^64 ~ 10^19 < 10^18 (18 is max value for Precision enum) - let pow = 10u64.pow(self.precision.decimals() as u32); - // number of decimals can't be larger than the smallest possible integer - self.int - .checked_mul(pow) - .expect("CoinAmount type garantees are broken") - .checked_add(self.fract) - .expect( - "integer has at least the same number of zeros in the lowest digits as much as \ - decimals has digits at most, so overflow is not possible", - ) - .into() - } -} - -impl Display for CoinAmount { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if ![' ', '_'].contains(&f.fill()) { - panic!("disallowed fill character {} in coin amount formatting string", f.fill()) - } - if f.precision().is_some() { - panic!("formatting precision must not be used for coin amounts") - } - let fill = &f.fill().to_string(); - let to_chunks = |s: &str| -> String { - s.chars() - .rev() - .collect::() - .as_bytes() - .chunks(3) - .map(<[u8]>::to_owned) - .map(|mut chunk| unsafe { - chunk.reverse(); - String::from_utf8_unchecked(chunk) - }) - .rev() - .collect::>() - .join(fill) - }; - let mut int = self.int.to_string(); - if f.alternate() { - int = to_chunks(&int); - } - f.write_str(&int)?; - if self.fract > 0 || f.alternate() { - f.write_char('.')?; - let mut float = self.fract.to_string(); - let len = float.len(); - let decimals = self.precision.decimals() as usize; - match len.cmp(&decimals) { - Ordering::Less => { - float = format!("{:0>width$}{float}", "", width = decimals - len); - } - Ordering::Equal => {} - Ordering::Greater => panic!("float precision overflow for coin amount {self:?}"), - } - if f.alternate() { - float = to_chunks(&float); - } else { - float = float.trim_end_matches('0').to_string(); - } - f.write_str(&float)?; - } - if !f.alternate() { - write!(f, "~{}", self.precision.decimals())?; - } - Ok(()) - } -} - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum AmountParseError { - /// invalid amount integer part - {0} - InvalidInt(ParseIntError), - /// invalid amount fractional part - {0} - InvalidFract(ParseIntError), - /// invalid amount precision - {0} - InvalidPrecision(ParseIntError), - - /// invalid amount precision exceeding 18 - #[from(TryFromIntError)] - PrecisionOverflow, - - /// invalid amount precision exceeding 18 - #[from] - UnknownPrecision(VariantError), -} - -impl FromStr for CoinAmount { - type Err = AmountParseError; - - fn from_str(s: &str) -> Result { - let s = s.replace([' ', '_'], ""); - let (int, remain) = s.split_once('.').unwrap_or_else(|| (&s, "0")); - let (fract, precision) = remain.split_once('~').unwrap_or((remain, "")); - let precision = if precision.is_empty() { - fract.len() as u64 - } else { - precision - .parse() - .map_err(AmountParseError::InvalidPrecision)? - }; - let int: u64 = int.parse().map_err(AmountParseError::InvalidInt)?; - let fract: u64 = fract.parse().map_err(AmountParseError::InvalidFract)?; - let precision = u8::try_from(precision)?; - Ok(CoinAmount { - int, - fract, - precision: Precision::try_from(precision)?, - }) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - #[allow(clippy::inconsistent_digit_grouping)] - fn int_trailing_zeros() { - let amount = CoinAmount::new(10_000__43_608_195u64, Precision::default()); - assert_eq!(amount.int(), 10_000); - assert_eq!(amount.fract(), 436_081_95); - assert_eq!(amount.precision(), Precision::default()); - assert_eq!(format!("{amount}"), "10000.43608195~8"); - assert_eq!(format!("{amount: >#}"), "10 000.43 608 195"); - } - - #[test] - #[allow(clippy::inconsistent_digit_grouping)] - fn sub_fraction() { - let amount = CoinAmount::new(10__00_008_195u64, Precision::default()); - assert_eq!(amount.int(), 10); - assert_eq!(amount.fract(), 8195); - assert_eq!(amount.precision(), Precision::default()); - assert_eq!(format!("{amount}"), "10.00008195~8"); - assert_eq!(format!("{amount:#}"), "10.00 008 195"); - } - - #[test] - #[allow(clippy::inconsistent_digit_grouping)] - fn small_fraction() { - let amount = CoinAmount::new(10__00_000_500u64, Precision::default()); - assert_eq!(amount.int(), 10); - assert_eq!(amount.fract(), 500); - assert_eq!(amount.precision(), Precision::default()); - assert_eq!(format!("{amount}"), "10.000005~8"); - assert_eq!(format!("{amount:_>#}"), "10.00_000_500"); - } - - #[test] - #[allow(clippy::inconsistent_digit_grouping)] - fn zero_fraction() { - let amount = CoinAmount::new(10__00_000_000u64, Precision::default()); - assert_eq!(amount.int(), 10); - assert_eq!(amount.fract(), 0); - assert_eq!(amount.precision(), Precision::default()); - assert_eq!(format!("{amount}"), "10~8"); - assert_eq!(format!("{amount:_>#}"), "10.00_000_000"); - } -} diff --git a/invoice/src/builder.rs b/invoice/src/builder.rs index 17f2da31..00c9d7af 100644 --- a/invoice/src/builder.rs +++ b/invoice/src/builder.rs @@ -21,11 +21,11 @@ use std::str::FromStr; -use rgb::ContractId; -use strict_encoding::{FieldName, TypeName}; +use rgb::{AttachId, ContractId, State}; +use strict_encoding::{FieldName, StrictSerialize, TypeName}; use crate::invoice::{Beneficiary, InvoiceState, RgbInvoice, RgbTransport, XChainNet}; -use crate::{Allocation, Amount, CoinAmount, NonFungible, Precision, TransportParseError}; +use crate::TransportParseError; #[derive(Clone, Eq, PartialEq, Debug)] pub struct RgbInvoiceBuilder(RgbInvoice); @@ -40,7 +40,7 @@ impl RgbInvoiceBuilder { operation: None, assignment: None, beneficiary: beneficiary.into(), - owned_state: InvoiceState::Void, + owned_state: InvoiceState::Any, expiry: None, unknown_query: none!(), }) @@ -78,49 +78,22 @@ impl RgbInvoiceBuilder { self } - pub fn set_amount_raw(mut self, amount: impl Into) -> Self { - self.0.owned_state = InvoiceState::Amount(amount.into()); + pub fn set_state(mut self, state: impl StrictSerialize) -> Self { + self.0.owned_state = InvoiceState::Specific(State::new(state)); self } - pub fn set_amount( - mut self, - integer: u64, - decimals: u64, - precision: Precision, - ) -> Result { - let amount = match CoinAmount::with(integer, decimals, precision) { - Ok(amount) => amount, - Err(_) => return Err(self), - } - .to_amount_unchecked(); - self.0.owned_state = InvoiceState::Amount(amount); + pub fn set_attachment(mut self, attach_id: AttachId) -> Result { + self.0.owned_state = match self.0.owned_state { + InvoiceState::Any | InvoiceState::Attach(_) => InvoiceState::Attach(attach_id), + InvoiceState::Specific(mut state) => { + state.attach = Some(attach_id); + InvoiceState::Specific(state) + } + }; Ok(self) } - pub fn set_allocation_raw(mut self, allocation: impl Into) -> Self { - self.0.owned_state = InvoiceState::Data(NonFungible::RGB21(allocation.into())); - self - } - - pub fn set_allocation(self, token_index: u32, fraction: u64) -> Result { - Ok(self.set_allocation_raw(Allocation::with(token_index, fraction))) - } - - /// # Safety - /// - /// The function may cause the loss of the information about the precise - /// amount of the asset, since f64 type doesn't provide full precision - /// required for that. - pub unsafe fn set_amount_approx(self, amount: f64, precision: Precision) -> Result { - if amount <= 0.0 { - return Err(self); - } - let coins = amount.floor(); - let cents = amount - coins; - self.set_amount(coins as u64, cents as u64, precision) - } - pub fn set_expiry_timestamp(mut self, expiry: i64) -> Self { self.0.expiry = Some(expiry); self diff --git a/invoice/src/data.rs b/invoice/src/data.rs deleted file mode 100644 index 7eaa93f7..00000000 --- a/invoice/src/data.rs +++ /dev/null @@ -1,293 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::str::FromStr; - -use rgb::{DataState, RevealedData}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -use strict_encoding::{StrictDeserialize, StrictSerialize}; -use strict_types::StrictVal; - -use crate::LIB_NAME_RGB_CONTRACT; - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum NonFungible { - #[display(inner)] - RGB21(Allocation), -} - -impl FromStr for NonFungible { - type Err = AllocationParseError; - fn from_str(s: &str) -> Result { - let allocation = Allocation::from_str(s)?; - Ok(NonFungible::RGB21(allocation)) - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(inner)] -pub enum AllocationParseError { - #[display(doc_comments)] - /// invalid token index {0}. - InvalidIndex(String), - - #[display(doc_comments)] - /// invalid fraction {0}. - InvalidFraction(String), - - #[display(doc_comments)] - /// allocation must have format @. - WrongFormat, -} - -#[derive( - Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From -)] -#[wrapper(Display, FromStr, Add, Sub, Mul, Div, Rem)] -#[wrapper_mut(AddAssign, SubAssign, MulAssign, DivAssign, RemAssign)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct TokenIndex(u32); - -#[derive( - Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From -)] -#[wrapper(Display, FromStr, Add, Sub, Mul, Div, Rem)] -#[wrapper_mut(AddAssign, SubAssign, MulAssign, DivAssign, RemAssign)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct OwnedFraction(u64); - -impl OwnedFraction { - pub const ZERO: Self = OwnedFraction(0); - - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - value.unwrap_uint::().into() - } - - pub fn value(self) -> u64 { self.0 } - - pub fn saturating_add(&self, other: impl Into) -> Self { - self.0.saturating_add(other.into().0).into() - } - pub fn saturating_sub(&self, other: impl Into) -> Self { - self.0.saturating_sub(other.into().0).into() - } - - pub fn saturating_add_assign(&mut self, other: impl Into) { - *self = self.0.saturating_add(other.into().0).into(); - } - pub fn saturating_sub_assign(&mut self, other: impl Into) { - *self = self.0.saturating_sub(other.into().0).into(); - } - - #[must_use] - pub fn checked_add(&self, other: impl Into) -> Option { - self.0.checked_add(other.into().0).map(Self) - } - #[must_use] - pub fn checked_sub(&self, other: impl Into) -> Option { - self.0.checked_sub(other.into().0).map(Self) - } - - #[must_use] - pub fn checked_add_assign(&mut self, other: impl Into) -> Option<()> { - *self = self.0.checked_add(other.into().0).map(Self)?; - Some(()) - } - #[must_use] - pub fn checked_sub_assign(&mut self, other: impl Into) -> Option<()> { - *self = self.0.checked_sub(other.into().0).map(Self)?; - Some(()) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default, Display)] -#[display("{1}@{0}")] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct Allocation(TokenIndex, OwnedFraction); - -impl Allocation { - pub fn with(index: impl Into, fraction: impl Into) -> Allocation { - Allocation(index.into(), fraction.into()) - } - - pub fn token_index(self) -> TokenIndex { self.0 } - - pub fn fraction(self) -> OwnedFraction { self.1 } -} - -impl StrictSerialize for Allocation {} -impl StrictDeserialize for Allocation {} - -impl From for Allocation { - fn from(data: RevealedData) -> Self { - Allocation::from_strict_serialized(data.value.into()).expect("invalid allocation data") - } -} - -impl From for Allocation { - fn from(state: DataState) -> Self { - Allocation::from_strict_serialized(state.into()).expect("invalid allocation data") - } -} - -impl From for DataState { - fn from(allocation: Allocation) -> Self { - DataState::from( - allocation - .to_strict_serialized() - .expect("invalid allocation data"), - ) - } -} - -impl FromStr for Allocation { - type Err = AllocationParseError; - - fn from_str(s: &str) -> Result { - if !s.contains('@') { - return Err(AllocationParseError::WrongFormat); - } - - match s.split_once('@') { - Some((fraction, token_index)) => Ok(Allocation( - token_index - .parse() - .map_err(|_| AllocationParseError::InvalidIndex(token_index.to_owned()))?, - fraction - .parse() - .map_err(|_| AllocationParseError::InvalidFraction(fraction.to_lowercase()))?, - )), - None => Err(AllocationParseError::WrongFormat), - } - } -} - -#[cfg(test)] -mod test { - use strict_types::value::StrictNum; - - use super::*; - - #[test] - fn owned_fraction_from_str() { - let owned_fraction = match OwnedFraction::from_str("1") { - Ok(value) => value, - Err(_) => OwnedFraction::ZERO, - }; - - assert_eq!(owned_fraction.value(), 1); - assert_eq!(format!("{owned_fraction}"), "1"); - } - - #[test] - fn owned_fraction_from_strict_val() { - // note that the strict number is u128 but not u64 - let owned_fraction = - OwnedFraction::from_strict_val_unchecked(&StrictVal::Number(StrictNum::Uint(1))); - - assert_eq!(owned_fraction.value(), 1); - assert_eq!(format!("{owned_fraction}"), "1"); - } - - #[test] - fn owned_fraction_add_assign() { - let mut owned_fraction = match OwnedFraction::from_str("1") { - Ok(value) => value, - Err(_) => OwnedFraction::ZERO, - }; - - let _ = owned_fraction.checked_add_assign(OwnedFraction::ZERO); - assert_eq!(owned_fraction.value(), 1); - assert_eq!(format!("{owned_fraction}"), "1"); - } - - #[test] - fn owned_fraction_add() { - let owned_fraction = match OwnedFraction::from_str("1") { - Ok(value) => value, - Err(_) => OwnedFraction::ZERO, - }; - - let owned = match owned_fraction.checked_add(OwnedFraction::ZERO) { - Some(value) => value, - None => OwnedFraction::ZERO, - }; - assert_eq!(owned.value(), 1); - assert_eq!(format!("{owned}"), "1"); - } - - #[test] - fn owned_fraction_sub() { - let owned_fraction = match OwnedFraction::from_str("1") { - Ok(value) => value, - Err(_) => OwnedFraction::ZERO, - }; - - let other_fraction = match OwnedFraction::from_str("1") { - Ok(value) => value, - Err(_) => OwnedFraction::ZERO, - }; - - let owned = match owned_fraction.checked_sub(other_fraction) { - Some(value) => value, - None => OwnedFraction::ZERO, - }; - assert_eq!(owned.value(), 0); - assert_eq!(format!("{owned}"), "0"); - } - - #[test] - fn owned_fraction_sub_assign() { - let mut owned_fraction = match OwnedFraction::from_str("1") { - Ok(value) => value, - Err(_) => OwnedFraction::ZERO, - }; - - let other_fraction = match OwnedFraction::from_str("1") { - Ok(value) => value, - Err(_) => OwnedFraction::ZERO, - }; - - let _ = owned_fraction.checked_sub_assign(other_fraction); - assert_eq!(owned_fraction.value(), 0); - assert_eq!(format!("{owned_fraction}"), "0"); - } -} diff --git a/invoice/src/invoice.rs b/invoice/src/invoice.rs index 853bd702..f48f5b75 100644 --- a/invoice/src/invoice.rs +++ b/invoice/src/invoice.rs @@ -19,18 +19,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::str::FromStr; - use amplify::{ByteArray, Bytes32}; use bp::seals::txout::CloseMethod; use bp::{InvalidPubkey, OutputPk, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; use indexmap::IndexMap; use invoice::{AddressNetwork, AddressPayload, Network}; -use rgb::{AttachId, ContractId, Layer1, SecretSeal}; +use rgb::{AttachId, ContractId, Layer1, SecretSeal, State}; use strict_encoding::{FieldName, TypeName}; -use crate::{Amount, NonFungible}; - #[derive(Clone, Eq, PartialEq, Hash, Debug)] #[non_exhaustive] pub enum RgbTransport { @@ -41,39 +37,29 @@ pub enum RgbTransport { UnspecifiedMeans, } -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(inner)] -pub enum InvoiceStateError { - #[display(doc_comments)] - /// could not parse as amount, data, or attach: {0}. - ParseError(String), -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)] +#[derive(Clone, Eq, PartialEq, Hash, Debug)] pub enum InvoiceState { - #[display("")] - Void, - #[display("{0}")] - Amount(Amount), - #[display(inner)] - Data(NonFungible), - #[display(inner)] + Any, + Specific(State), Attach(AttachId), } -impl FromStr for InvoiceState { - type Err = InvoiceStateError; - fn from_str(s: &str) -> Result { - if s.is_empty() { - Ok(InvoiceState::Void) - } else if let Ok(amount) = Amount::from_str(s) { - Ok(InvoiceState::Amount(amount)) - } else if let Ok(data) = NonFungible::from_str(s) { - Ok(InvoiceState::Data(data)) - } else if let Ok(attach) = AttachId::from_str(s) { - Ok(InvoiceState::Attach(attach)) - } else { - Err(InvoiceStateError::ParseError(s.to_owned())) +impl InvoiceState { + pub fn is_any(&self) -> bool { matches!(self, InvoiceState::Any) } + + pub fn state(&self) -> Option<&State> { + match self { + InvoiceState::Any => None, + InvoiceState::Specific(s) => Some(s), + InvoiceState::Attach(_) => None, + } + } + + pub fn attach_id(&self) -> Option { + match self { + InvoiceState::Any => None, + InvoiceState::Specific(s) => s.attach, + InvoiceState::Attach(id) => Some(*id), } } } diff --git a/invoice/src/lib.rs b/invoice/src/lib.rs index a798caeb..d2820bc8 100644 --- a/invoice/src/lib.rs +++ b/invoice/src/lib.rs @@ -21,8 +21,6 @@ #[macro_use] extern crate amplify; -#[macro_use] -extern crate strict_encoding; extern crate rgbcore as rgb; #[cfg(feature = "serde")] extern crate serde_crate as serde; @@ -34,17 +32,11 @@ pub use ::invoice::*; mod invoice; mod parse; mod builder; -mod amount; -mod data; -pub use amount::{Amount, AmountParseError, CoinAmount, Precision, PrecisionError}; pub use builder::RgbInvoiceBuilder; -pub use data::{Allocation, NonFungible, OwnedFraction, TokenIndex}; pub use parse::{InvoiceParseError, TransportParseError}; pub use crate::invoice::{ Beneficiary, ChainNet, InvoiceState, Pay2Vout, Pay2VoutError, RgbInvoice, RgbTransport, XChainNet, }; - -pub const LIB_NAME_RGB_CONTRACT: &str = "RGBContract"; diff --git a/invoice/src/parse.rs b/invoice/src/parse.rs index 08e4a37e..e2136f79 100644 --- a/invoice/src/parse.rs +++ b/invoice/src/parse.rs @@ -24,13 +24,16 @@ use std::io::{Cursor, Write}; use std::num::ParseIntError; use std::str::FromStr; +use amplify::confinement::{self, SmallBlob}; +use amplify::Wrapper; use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; +use base58::{FromBase58, ToBase58}; use fluent_uri::enc::EStr; use fluent_uri::Uri; use indexmap::IndexMap; use invoice::{AddressPayload, UnknownNetwork}; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; -use rgb::{ContractId, SecretSeal}; +use rgb::{ContractId, SecretSeal, State, StateData}; use strict_encoding::{InvalidRString, TypeName}; use crate::invoice::{ @@ -65,6 +68,22 @@ pub enum TransportParseError { InvalidTransportHost(String), } +#[derive(Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum InvoiceStateError { + #[from] + /// invalid invoice state Base58 encoding. + Base58(base58::FromBase58Error), + + #[from] + /// invoice state size exceeded. + Len(confinement::Error), + + #[from] + /// invalid invoice state encoding - {0} + Deserialize(strict_encoding::DeserializeError), +} + #[derive(Debug, Display, Error, From)] #[display(doc_comments)] pub enum InvoiceParseError { @@ -72,8 +91,11 @@ pub enum InvoiceParseError { #[display(inner)] Uri(fluent_uri::ParseError), - /// invalid invoice. - Invalid, + /// absent invoice URI scheme name. + AbsentScheme, + + /// invalid invoice scheme {0}. + InvalidScheme(String), /// RGB invoice must not contain any URI authority data, including empty /// one. @@ -88,8 +110,9 @@ pub enum InvoiceParseError { /// assignment data is missed from the invoice. AssignmentMissed, - /// invalid invoice scheme {0}. - InvalidScheme(String), + #[from] + #[display(inner)] + InvalidState(InvoiceStateError), /// no invoice transport has been provided. NoTransport, @@ -115,7 +138,7 @@ pub enum InvoiceParseError { #[from] #[display(inner)] - Id(baid64::Baid64ParseError), + Id(Baid64ParseError), /// can't recognize beneficiary "{0}": it should be either a bitcoin address /// or a blinded UTXO seal. @@ -125,10 +148,6 @@ pub enum InvoiceParseError { #[display(inner)] Num(ParseIntError), - /// can't recognize amount "{0}": it should be valid rgb21 allocation - /// data. - Data(String), - #[from] /// invalid interface name. IfaceName(InvalidRString), @@ -158,6 +177,30 @@ impl RgbInvoice { } } +impl Display for InvoiceState { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + InvoiceState::Any => Ok(()), + InvoiceState::Specific(state) => f.write_str(&state.value.to_base58()), + // TODO: Support attachment through invoice params + InvoiceState::Attach(_) => Ok(()), + } + } +} + +impl FromStr for InvoiceState { + type Err = InvoiceStateError; + fn from_str(s: &str) -> Result { + if s.is_empty() { + return Ok(InvoiceState::Any); + } + let data = s.from_base58()?; + let data = SmallBlob::try_from(data)?; + let data = StateData::from_inner(data); + Ok(InvoiceState::Specific(State::from(data))) + } +} + impl Display for RgbTransport { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { @@ -293,6 +336,7 @@ impl FromStr for XChainNet { impl Display for RgbInvoice { fn fmt(&self, f: &mut Formatter) -> fmt::Result { + // TODO: Support attachment through invoice params let amt = self.owned_state.to_string(); if let Some(contract) = self.contract { let id = if f.alternate() { @@ -352,9 +396,10 @@ impl FromStr for RgbInvoice { type Err = InvoiceParseError; fn from_str(s: &str) -> Result { + // TODO: Support attachment through invoice params let uri = Uri::parse(s)?; - let scheme = uri.scheme().ok_or(InvoiceParseError::Invalid)?; + let scheme = uri.scheme().ok_or(InvoiceParseError::AbsentScheme)?; if scheme.as_str() != "rgb" { return Err(InvoiceParseError::InvalidScheme(scheme.to_string())); } @@ -392,18 +437,14 @@ impl FromStr for RgbInvoice { let Some(assignment) = path.next() else { return Err(InvoiceParseError::AssignmentMissed); }; - let (amount, beneficiary) = assignment + let (state, beneficiary) = assignment .as_str() .split_once('+') .map(|(a, b)| (Some(a), Some(b))) .unwrap_or((Some(assignment.as_str()), None)); - // TODO: support other state types - let (beneficiary_str, value) = match (beneficiary, amount) { - (Some(b), Some(a)) => ( - b, - InvoiceState::from_str(a).map_err(|_| InvoiceParseError::Data(a.to_string()))?, - ), - (None, Some(b)) => (b, InvoiceState::Void), + let (beneficiary_str, value) = match (beneficiary, state) { + (Some(b), Some(a)) => (b, InvoiceState::from_str(a)?), + (None, Some(b)) => (b, InvoiceState::Any), _ => unreachable!(), }; @@ -472,22 +513,34 @@ fn map_query_params(uri: &Uri<&str>) -> Result, Invoice #[cfg(test)] mod test { use super::*; - use crate::Amount; #[test] fn parse() { // rgb20/rgb25 parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + T5FhUZEHbQu4B+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.owned_state, InvoiceState::Amount(Amount::from(100u64))); + assert_eq!( + invoice.owned_state, + InvoiceState::Specific(State::from(StateData::from_checked(vec![ + 8, 0, 100, 0, 0, 0, 0, 0, 0, 0 + ]))) + ); assert_eq!(invoice.to_string(), invoice_str); assert_eq!(format!("{invoice:#}"), invoice_str.replace('-', "")); // rgb21 parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB21/1@1+bc:\ - utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB21/\ + 5QsfkEcyanohXadePHZ+bc:utxob:\ + zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + assert_eq!( + invoice.owned_state, + InvoiceState::Specific(State::from(StateData::from_checked(vec![ + 12, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 + ]))) + ); assert_eq!(invoice.to_string(), invoice_str); assert_eq!(format!("{invoice:#}"), invoice_str.replace('-', "")); @@ -590,7 +643,7 @@ mod test { let invoice_str = "2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/~/bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::Invalid))); + assert!(matches!(result, Err(InvoiceParseError::AbsentScheme))); // invalid scheme let invoice_str = "bad:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/~/bc:utxob:\ diff --git a/src/containers/anchors.rs b/src/containers/anchors.rs index 2c7c1671..0a346a0c 100644 --- a/src/containers/anchors.rs +++ b/src/containers/anchors.rs @@ -36,7 +36,7 @@ use rgb::{ use strict_encoding::StrictDumb; use crate::containers::Dichotomy; -use crate::{MergeReveal, MergeRevealError, TypedAssignsExt, LIB_NAME_RGB_STD}; +use crate::{MergeReveal, MergeRevealError, LIB_NAME_RGB_STD}; #[derive(Clone, Eq, PartialEq, Debug, Display, Error)] #[display("state transition {0} is not a part of the bundle.")] diff --git a/src/containers/seal.rs b/src/containers/seal.rs index 49dc3079..6e044604 100644 --- a/src/containers/seal.rs +++ b/src/containers/seal.rs @@ -24,7 +24,7 @@ use bp::seals::txout::{BlindSeal, CloseMethod, SealTxid}; use bp::secp256k1::rand::{thread_rng, RngCore}; use bp::Vout; -use rgb::{GraphSeal, Layer1, SecretSeal, TxoSeal, XChain}; +use rgb::{Assign, ExposedSeal, GraphSeal, Layer1, SecretSeal, State, XChain}; use crate::LIB_NAME_RGB_STD; @@ -109,7 +109,7 @@ impl From for GraphSeal { /// 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 { +pub enum BuilderSeal { Revealed(XChain), #[from] Concealed(XChain), @@ -119,11 +119,26 @@ impl From>> for BuilderSeal> { fn from(seal: XChain>) -> Self { BuilderSeal::Revealed(seal) } } -impl BuilderSeal { +impl BuilderSeal { pub fn layer1(&self) -> Layer1 { match self { BuilderSeal::Revealed(x) => x.layer1(), BuilderSeal::Concealed(x) => x.layer1(), } } + + pub fn assignment(self, state: State) -> Assign { + match self { + BuilderSeal::Revealed(seal) => Assign::Revealed { + seal, + state, + lock: none!(), + }, + BuilderSeal::Concealed(seal) => Assign::Confidential { + seal, + state, + lock: none!(), + }, + } + } } diff --git a/src/contract/assignments.rs b/src/contract/assignments.rs index d4967520..f6be139a 100644 --- a/src/contract/assignments.rs +++ b/src/contract/assignments.rs @@ -24,51 +24,12 @@ use std::collections::HashMap; use std::fmt::Debug; use std::hash::Hash; -use amplify::confinement::SmallVec; -use commit_verify::Conceal; -use invoice::Amount; use rgb::vm::WitnessOrd; -use rgb::{ - Assign, AssignAttach, AssignData, AssignFungible, AssignRights, AssignmentType, AttachState, - DataState, ExposedSeal, ExposedState, OpId, Opout, RevealedAttach, RevealedData, RevealedValue, - TypedAssigns, VoidState, XChain, XOutputSeal, XWitnessId, -}; +use rgb::{AssignmentType, ExposedSeal, OpId, Opout, State, XChain, XOutputSeal, XWitnessId}; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; use crate::LIB_NAME_RGB_STD; -/// Trait used by contract state. Unlike [`ExposedState`] it doesn't allow -/// concealment of the state, i.e. may contain incomplete data without blinding -/// factors, asset tags etc. -pub trait KnownState: Debug + StrictDumb + StrictEncode + StrictDecode + Eq + Clone + Hash { - const IS_FUNGIBLE: bool; -} - -impl KnownState for () { - const IS_FUNGIBLE: bool = false; -} -impl KnownState for VoidState { - const IS_FUNGIBLE: bool = false; -} -impl KnownState for DataState { - const IS_FUNGIBLE: bool = false; -} -impl KnownState for Amount { - const IS_FUNGIBLE: bool = true; -} -impl KnownState for AttachState { - const IS_FUNGIBLE: bool = false; -} -impl KnownState for RevealedValue { - const IS_FUNGIBLE: bool = true; -} -impl KnownState for RevealedData { - const IS_FUNGIBLE: bool = false; -} -impl KnownState for RevealedAttach { - const IS_FUNGIBLE: bool = false; -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_STD)] @@ -83,7 +44,7 @@ pub struct WitnessInfo { } #[allow(clippy::derived_hash_with_manual_eq)] -#[derive(Copy, Clone, Eq, Hash, Debug)] +#[derive(Clone, Eq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_STD)] #[cfg_attr( @@ -91,14 +52,14 @@ pub struct WitnessInfo { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase") )] -pub struct OutputAssignment { +pub struct OutputAssignment { pub opout: Opout, pub seal: XOutputSeal, pub state: State, pub witness: Option, } -impl PartialEq for OutputAssignment { +impl PartialEq for OutputAssignment { fn eq(&self, other: &Self) -> bool { // We ignore difference in witness transactions, state and seal definitions here // in order to support updates from the ephemeral state of the lightning @@ -113,11 +74,11 @@ impl PartialEq for OutputAssignment { } } -impl PartialOrd for OutputAssignment { +impl PartialOrd for OutputAssignment { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for OutputAssignment { +impl Ord for OutputAssignment { fn cmp(&self, other: &Self) -> Ordering { if self == other { return Ordering::Equal; @@ -129,7 +90,7 @@ impl Ord for OutputAssignment { } } -impl OutputAssignment { +impl OutputAssignment { /// # Panics /// /// If the processing is done on invalid stash data, the seal is @@ -175,16 +136,6 @@ impl OutputAssignment { } } - /// Transmutes output assignment from one form of state to another - pub fn transmute>(self) -> OutputAssignment { - OutputAssignment { - opout: self.opout, - seal: self.seal, - state: self.state.into(), - witness: self.witness, - } - } - pub fn check_witness(&self, filter: &HashMap) -> bool { match self.witness { None => true, @@ -194,62 +145,3 @@ impl OutputAssignment { } } } - -pub trait TypedAssignsExt { - fn reveal_seal(&mut self, seal: XChain); - - fn filter_revealed_seals(&self) -> Vec>; -} - -impl TypedAssignsExt for TypedAssigns { - fn reveal_seal(&mut self, seal: XChain) { - fn reveal( - vec: &mut SmallVec>, - revealed: XChain, - ) { - for assign in vec.iter_mut() { - match assign { - Assign::ConfidentialSeal { seal, state, lock } - if *seal == revealed.conceal() => - { - *assign = Assign::Revealed { - seal: revealed, - state: state.clone(), - lock: *lock, - } - } - Assign::Confidential { seal, state, lock } if *seal == revealed.conceal() => { - *assign = Assign::ConfidentialState { - seal: revealed, - state: *state, - lock: *lock, - } - } - _ => {} - } - } - } - - match self { - TypedAssigns::Declarative(v) => reveal(v, seal), - TypedAssigns::Fungible(v) => reveal(v, seal), - TypedAssigns::Structured(v) => reveal(v, seal), - TypedAssigns::Attachment(v) => reveal(v, seal), - } - } - - fn filter_revealed_seals(&self) -> Vec> { - match self { - TypedAssigns::Declarative(s) => { - s.iter().filter_map(AssignRights::revealed_seal).collect() - } - TypedAssigns::Fungible(s) => { - s.iter().filter_map(AssignFungible::revealed_seal).collect() - } - TypedAssigns::Structured(s) => s.iter().filter_map(AssignData::revealed_seal).collect(), - TypedAssigns::Attachment(s) => { - s.iter().filter_map(AssignAttach::revealed_seal).collect() - } - } - } -} diff --git a/src/contract/merge_reveal.rs b/src/contract/merge_reveal.rs index b662f5a5..a8975f24 100644 --- a/src/contract/merge_reveal.rs +++ b/src/contract/merge_reveal.rs @@ -21,13 +21,13 @@ use std::collections::BTreeMap; -use amplify::confinement::Confined; +use amplify::confinement::{Confined, NonEmptyVec}; use amplify::Wrapper; use bp::Txid; use commit_verify::{mpc, Conceal}; use rgb::{ - Assign, Assignments, BundleId, ExposedSeal, ExposedState, Extension, Genesis, OpId, Operation, - Transition, TransitionBundle, TypedAssigns, + Assign, Assignments, BundleId, ExposedSeal, Extension, Genesis, OpId, Operation, Transition, + TransitionBundle, TypedAssigns, }; #[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] @@ -90,7 +90,7 @@ pub trait MergeRevealContract: Sized { } */ -impl MergeReveal for Assign { +impl MergeReveal for Assign { fn merge_reveal(self, other: Self) -> Result { debug_assert_eq!(self.conceal(), other.conceal()); match (self, other) { @@ -98,102 +98,19 @@ impl MergeReveal for Assign (_, state @ Assign::Revealed { .. }) | (state @ Assign::Revealed { .. }, _) => { Ok(state) } - - // ConfidentialAmount + ConfidentialSeal = Revealed - ( - Assign::ConfidentialSeal { - state, lock: lock1, .. - }, - Assign::ConfidentialState { - seal, lock: lock2, .. - }, - ) => { - debug_assert_eq!(lock1, lock2); - Ok(Assign::Revealed { - seal, - state, - lock: lock1, - }) - } - - // ConfidentialSeal + ConfidentialAmount = Revealed - ( - Assign::ConfidentialState { - seal, lock: lock1, .. - }, - Assign::ConfidentialSeal { - state, lock: lock2, .. - }, - ) => { - debug_assert_eq!(lock1, lock2); - Ok(Assign::Revealed { - seal, - state, - lock: lock1, - }) - } - - // if self and other is of same variant return self - (state @ Assign::ConfidentialState { .. }, Assign::ConfidentialState { .. }) => { - Ok(state) - } - (state @ Assign::ConfidentialSeal { .. }, Assign::ConfidentialSeal { .. }) => Ok(state), - // Anything + Confidential = Anything - (state, Assign::Confidential { .. }) | (Assign::Confidential { .. }, state) => { - Ok(state) - } + (state, Assign::Confidential { .. }) => Ok(state), } } } impl MergeReveal for TypedAssigns { fn merge_reveal(self, other: Self) -> Result { - match (self, other) { - (TypedAssigns::Declarative(first_vec), TypedAssigns::Declarative(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); - } - Ok(TypedAssigns::Declarative( - Confined::try_from(result).expect("collection of the same size"), - )) - } - - (TypedAssigns::Fungible(first_vec), TypedAssigns::Fungible(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); - } - Ok(TypedAssigns::Fungible( - Confined::try_from(result).expect("collection of the same size"), - )) - } - - (TypedAssigns::Structured(first_vec), TypedAssigns::Structured(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); - } - Ok(TypedAssigns::Structured( - Confined::try_from(result).expect("collection of the same size"), - )) - } - - (TypedAssigns::Attachment(first_vec), TypedAssigns::Attachment(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); - } - Ok(TypedAssigns::Attachment( - Confined::try_from(result).expect("collection of the same size"), - )) - } - // No other patterns possible, should not reach here - _ => { - unreachable!("Assignments::consensus_commitments is broken") - } + let mut result = Vec::with_capacity(self.len()); + for (first, second) in self.into_iter().zip(other.into_iter()) { + result.push(first.merge_reveal(second)?); } + Ok(TypedAssigns::from(NonEmptyVec::from_checked(result))) } } diff --git a/src/contract/mod.rs b/src/contract/mod.rs index 624830ed..96298642 100644 --- a/src/contract/mod.rs +++ b/src/contract/mod.rs @@ -22,7 +22,7 @@ mod assignments; mod merge_reveal; -pub use assignments::{KnownState, OutputAssignment, TypedAssignsExt, WitnessInfo}; +pub use assignments::{OutputAssignment, WitnessInfo}; pub use merge_reveal::{MergeReveal, MergeRevealError}; use rgb::vm::OrdOpRef; use rgb::{ExtensionType, OpId, TransitionType, XWitnessId}; diff --git a/src/interface/builder.rs b/src/interface/builder.rs index eb8a01c4..7fc6c13e 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -21,19 +21,15 @@ #![allow(clippy::result_large_err)] -use std::collections::{BTreeMap, HashSet}; +use std::collections::btree_map::Entry; -use amplify::confinement::{Confined, SmallOrdSet, TinyOrdMap, U16}; -use amplify::{confinement, Wrapper}; +use amplify::confinement::{self, Confined, SmallOrdSet, TinyOrdMap}; use chrono::Utc; -use invoice::{Allocation, Amount}; use rgb::validation::Scripts; use rgb::{ - validation, AltLayer1, AltLayer1Set, AssetTag, AssetTags, Assign, AssignmentType, Assignments, - AttachState, BlindingFactor, ContractId, DataState, ExposedSeal, FungibleType, Genesis, - GenesisSeal, GlobalState, GraphSeal, Identity, Input, Layer1, MetadataError, Opout, - OwnedStateSchema, RevealedAttach, RevealedData, RevealedValue, Schema, Transition, - TransitionType, TypedAssigns, XChain, XOutpoint, + validation, AltLayer1, AltLayer1Set, AssignmentType, Assignments, ContractId, ExposedSeal, + Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Input, Layer1, MetadataError, Opout, + OwnedStateSchema, Schema, State, Transition, TransitionType, TypedAssigns, XChain, XOutpoint, }; use rgbcore::{GlobalStateSchema, GlobalStateType, MetaType, Metadata, ValencyType}; use strict_encoding::{FieldName, SerializeError, StrictSerialize}; @@ -42,7 +38,6 @@ use strict_types::{decode, SemId, TypeSystem}; use crate::containers::{BuilderSeal, ContainerVer, Contract, ValidConsignment}; use crate::interface::resolver::DumbResolver; use crate::interface::{Iface, IfaceImpl, TransitionIface}; -use crate::persistence::PersistedState; use crate::Outpoint; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] @@ -164,23 +159,6 @@ impl ContractBuilder { } } - pub fn deterministic( - issuer: Identity, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - scripts: Scripts, - ) -> Self { - Self { - builder: OperationBuilder::deterministic(iface, schema, iimpl, types), - testnet: true, - alt_layers1: none!(), - scripts, - issuer, - } - } - pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } pub fn set_mainnet(mut self) -> Self { @@ -208,21 +186,6 @@ impl ContractBuilder { Ok(self) } - #[inline] - pub fn asset_tag(&self, name: impl Into) -> Result { - self.builder.asset_tag(name) - } - - #[inline] - pub fn add_asset_tag( - mut self, - name: impl Into, - asset_tag: AssetTag, - ) -> Result { - self.builder = self.builder.add_asset_tag(name, asset_tag)?; - Ok(self) - } - #[inline] pub fn global_type(&self, name: &FieldName) -> Option { self.builder.global_type(name) @@ -261,60 +224,19 @@ impl ContractBuilder { Ok(self) } - pub fn add_owned_state_det( - mut self, - name: impl Into, - seal: impl Into>, - state: PersistedState, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_owned_state_det(name, seal, state)?; - Ok(self) - } - - pub fn add_rights( - mut self, - name: impl Into, - seal: impl Into>, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_rights(name, seal)?; - Ok(self) - } - - pub fn add_fungible_state( - mut self, - name: impl Into, - seal: impl Into>, - value: impl Into, - ) -> Result { - let name = name.into(); - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder.init_asset_tag(name.clone())?; - self.builder = self.builder.add_fungible_state(name, seal, value)?; - Ok(self) - } - - pub fn add_fungible_state_det( + pub fn add_owned_state_raw( mut self, name: impl Into, seal: impl Into>, - value: impl Into, - blinding: BlindingFactor, + state: State, ) -> Result { - let name = name.into(); let seal = seal.into(); self.check_layer1(seal.layer1())?; - let tag = self.builder.init_asset_tag(name.clone())?; - let state = RevealedValue::with_blinding(value.into(), blinding, tag); - self.builder = self.builder.add_fungible_state_det(name, seal, state)?; + self.builder = self.builder.add_owned_state_raw(name, seal, state)?; Ok(self) } - pub fn add_data( + pub fn add_owned_state( mut self, name: impl Into, seal: impl Into>, @@ -322,51 +244,11 @@ impl ContractBuilder { ) -> Result { let seal = seal.into(); self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_data(name, seal, value)?; - Ok(self) - } - - pub fn add_data_det( - mut self, - name: impl Into, - seal: impl Into>, - data: RevealedData, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_data_det(name, seal, data)?; - Ok(self) - } - - pub fn add_attachment( - mut self, - name: impl Into, - seal: impl Into>, - attachment: AttachState, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_attachment(name, seal, attachment)?; - Ok(self) - } - - pub fn add_attachment_det( - mut self, - name: impl Into, - seal: impl Into>, - attachment: RevealedAttach, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_attachment_det(name, seal, attachment)?; + self.builder = self.builder.add_owned_state(name, seal, value)?; Ok(self) } pub fn issue_contract(self) -> Result, BuilderError> { - debug_assert!( - !self.builder.deterministic, - "for issuing deterministic contracts please use issue_contract_det method" - ); self.issue_contract_raw(Utc::now().timestamp()) } @@ -374,16 +256,11 @@ impl ContractBuilder { self, timestamp: i64, ) -> Result, BuilderError> { - debug_assert!( - self.builder.deterministic, - "for issuing deterministic contracts please use deterministic constructor" - ); self.issue_contract_raw(timestamp) } fn issue_contract_raw(self, timestamp: i64) -> Result, BuilderError> { - let (schema, iface, iimpl, global, assignments, types, asset_tags) = - self.builder.complete(None); + let (schema, iface, iimpl, global, assignments, types) = self.builder.complete(); let genesis = Genesis { ffv: none!(), @@ -392,7 +269,6 @@ impl ContractBuilder { timestamp, testnet: self.testnet, alt_layers1: self.alt_layers1, - asset_tags, metadata: empty!(), globals: global, assignments, @@ -436,7 +312,7 @@ pub struct TransitionBuilder { builder: OperationBuilder, nonce: u64, transition_type: TransitionType, - inputs: TinyOrdMap, + inputs: TinyOrdMap, } impl TransitionBuilder { @@ -450,16 +326,6 @@ impl TransitionBuilder { Self::with(contract_id, iface, schema, iimpl, TransitionType::BLANK, types) } - pub fn blank_transition_det( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - ) -> Self { - Self::deterministic(contract_id, iface, schema, iimpl, TransitionType::BLANK, types) - } - pub fn default_transition( contract_id: ContractId, iface: Iface, @@ -475,21 +341,6 @@ impl TransitionBuilder { Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types)) } - pub fn default_transition_det( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - ) -> Result { - let transition_type = iface - .default_operation - .as_ref() - .and_then(|name| iimpl.transition_type(name)) - .ok_or(BuilderError::NoOperationSubtype)?; - Ok(Self::deterministic(contract_id, iface, schema, iimpl, transition_type, types)) - } - pub fn named_transition( contract_id: ContractId, iface: Iface, @@ -505,21 +356,6 @@ impl TransitionBuilder { Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types)) } - pub fn named_transition_det( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_name: impl Into, - types: TypeSystem, - ) -> Result { - let transition_name = transition_name.into(); - let transition_type = iimpl - .transition_type(&transition_name) - .ok_or(BuilderError::TransitionNotFound(transition_name))?; - Ok(Self::deterministic(contract_id, iface, schema, iimpl, transition_type, types)) - } - fn with( contract_id: ContractId, iface: Iface, @@ -537,23 +373,6 @@ impl TransitionBuilder { } } - fn deterministic( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_type: TransitionType, - types: TypeSystem, - ) -> Self { - Self { - contract_id, - builder: OperationBuilder::deterministic(iface, schema, iimpl, types), - nonce: u64::MAX, - transition_type, - inputs: none!(), - } - } - pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } pub fn transition_type(&self) -> TransitionType { self.transition_type } @@ -563,31 +382,6 @@ impl TransitionBuilder { self } - #[inline] - pub fn asset_tag(&self, name: impl Into) -> Result { - self.builder.asset_tag(name) - } - - #[inline] - pub fn add_asset_tag( - mut self, - name: impl Into, - asset_tag: AssetTag, - ) -> Result { - self.builder = self.builder.add_asset_tag(name, asset_tag)?; - Ok(self) - } - - #[inline] - pub fn add_asset_tag_raw( - mut self, - type_id: AssignmentType, - asset_tag: AssetTag, - ) -> Result { - self.builder = self.builder.add_asset_tag_raw(type_id, asset_tag)?; - Ok(self) - } - #[inline] pub fn add_metadata( mut self, @@ -608,7 +402,7 @@ impl TransitionBuilder { Ok(self) } - pub fn add_input(mut self, opout: Opout, state: PersistedState) -> Result { + pub fn add_input(mut self, opout: Opout, state: State) -> Result { self.inputs.insert(Input::with(opout), state)?; Ok(self) } @@ -642,165 +436,39 @@ impl TransitionBuilder { pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - pub fn add_owned_state_det( - mut self, - name: impl Into, - seal: impl Into>, - state: PersistedState, - ) -> Result { - self.builder = self.builder.add_owned_state_det(name, seal, state)?; - Ok(self) - } - pub fn add_owned_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: PersistedState, - ) -> Result { - if matches!(state, PersistedState::Amount(_, _, tag) if self.builder.asset_tag_raw(type_id)? != tag) - { - return Err(BuilderError::AssetTagInvalid(type_id)); - } - self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; - Ok(self) - } - - pub fn add_rights( mut self, name: impl Into, seal: impl Into>, + state: State, ) -> Result { - self.builder = self.builder.add_rights(name, seal)?; + self.builder = self.builder.add_owned_state_raw(name, seal, state)?; Ok(self) } - pub fn add_fungible_default_state( - self, - seal: impl Into>, - value: u64, - ) -> Result { - let assignment_name = self.default_assignment()?.clone(); - self.add_fungible_state(assignment_name, seal.into(), value) - } - - pub fn add_fungible_default_state_det( - self, - seal: impl Into>, - value: u64, - blinding: BlindingFactor, - ) -> Result { - let assignment_name = self.default_assignment()?.clone(); - self.add_fungible_state_det(assignment_name, seal.into(), value, blinding) - } - - pub fn add_fungible_state( - mut self, - name: impl Into, - seal: impl Into>, - value: impl Into, - ) -> Result { - self.builder = self.builder.add_fungible_state(name.into(), seal, value)?; - Ok(self) - } - - pub fn add_fungible_state_det( - mut self, - name: impl Into, - seal: impl Into>, - value: impl Into, - blinding: BlindingFactor, - ) -> Result { - let name = name.into(); - let type_id = self - .builder - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name.clone()))?; - let tag = self.builder.asset_tag_raw(type_id)?; - let state = RevealedValue::with_blinding(value.into(), blinding, tag); - - self.builder = self.builder.add_fungible_state_det(name, seal, state)?; - Ok(self) - } - - pub fn add_fungible_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - value: impl Into, - blinding: BlindingFactor, - ) -> Result { - let tag = self.builder.asset_tag_raw(type_id)?; - let state = RevealedValue::with_blinding(value.into(), blinding, tag); - self.builder = self.builder.add_fungible_state_raw(type_id, seal, state)?; - Ok(self) - } - - pub fn add_data( + pub fn add_owned_state( mut self, name: impl Into, seal: impl Into>, value: impl StrictSerialize, ) -> Result { - self.builder = self.builder.add_data(name, seal, value)?; - Ok(self) - } - - pub fn add_data_det( - mut self, - name: impl Into, - seal: impl Into>, - data: RevealedData, - ) -> Result { - self.builder = self.builder.add_data_det(name, seal, data)?; + self.builder = self.builder.add_owned_state(name, seal, value)?; Ok(self) } - pub fn add_data_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - allocation: impl Into, - blinding: u64, - ) -> Result { - let revealed_state = RevealedData::with_salt(allocation.into(), blinding.into()); - self.builder = self.builder.add_data_raw(type_id, seal, revealed_state)?; - Ok(self) - } - - pub fn add_data_default( + pub fn add_owned_state_default( self, seal: impl Into>, value: impl StrictSerialize, ) -> Result { let assignment_name = self.default_assignment()?.clone(); - self.add_data(assignment_name, seal.into(), value) - } - - pub fn add_attachment( - mut self, - name: impl Into, - seal: impl Into>, - attachment: AttachState, - ) -> Result { - self.builder = self.builder.add_attachment(name, seal, attachment)?; - Ok(self) - } - - pub fn add_attachment_det( - mut self, - name: impl Into, - seal: impl Into>, - attachment: RevealedAttach, - ) -> Result { - self.builder = self.builder.add_attachment_det(name, seal, attachment)?; - Ok(self) + self.add_owned_state(assignment_name, seal.into(), value) } pub fn has_inputs(&self) -> bool { !self.inputs.is_empty() } pub fn complete_transition(self) -> Result { - let (_, _, _, global, assignments, _, _) = self.builder.complete(Some(&self.inputs)); + let (_, _, _, global, assignments, _) = self.builder.complete(); let transition = Transition { ffv: none!(), @@ -828,17 +496,10 @@ pub struct OperationBuilder { schema: Schema, iface: Iface, iimpl: IfaceImpl, - asset_tags: AssetTags, - deterministic: bool, global: GlobalState, meta: Metadata, - rights: TinyOrdMap>, 1, U16>>, - fungible: - TinyOrdMap, RevealedValue>, 1, U16>>, - data: TinyOrdMap, RevealedData>, 1, U16>>, - attachments: - TinyOrdMap, RevealedAttach>, 1, U16>>, + assignments: Assignments, // TODO: add valencies types: TypeSystem, } @@ -849,34 +510,10 @@ impl OperationBuilder { schema, iface, iimpl, - asset_tags: none!(), - deterministic: false, global: none!(), + assignments: none!(), meta: none!(), - rights: none!(), - fungible: none!(), - attachments: none!(), - data: none!(), - - types, - } - } - - fn deterministic(iface: Iface, schema: Schema, iimpl: IfaceImpl, types: TypeSystem) -> Self { - OperationBuilder { - schema, - iface, - iimpl, - asset_tags: none!(), - deterministic: true, - - global: none!(), - meta: none!(), - rights: none!(), - fungible: none!(), - attachments: none!(), - data: none!(), types, } @@ -938,68 +575,6 @@ impl OperationBuilder { .expect("schema should match interface: must be checked by the constructor") } - pub fn asset_tag(&self, name: impl Into) -> Result { - let name = name.into(); - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name.clone()))?; - self.asset_tag_raw(type_id) - } - - #[inline] - fn asset_tag_raw(&self, type_id: AssignmentType) -> Result { - self.asset_tags - .get(&type_id) - .ok_or(BuilderError::AssetTagMissed(type_id)) - .copied() - } - - #[inline] - pub fn add_asset_tag( - self, - name: impl Into, - asset_tag: AssetTag, - ) -> Result { - let name = name.into(); - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_asset_tag_raw(type_id, asset_tag) - } - - #[inline] - pub fn add_asset_tag_raw( - mut self, - type_id: AssignmentType, - asset_tag: AssetTag, - ) -> Result { - if self.fungible.contains_key(&type_id) { - return Err(BuilderError::AssetTagAutomatic(type_id)); - } - - self.asset_tags.insert(type_id, asset_tag)?; - Ok(self) - } - - pub fn init_asset_tag(&mut self, name: impl Into) -> Result { - let name = name.into(); - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - if let Some(tag) = self.asset_tags.get(&type_id) { - Ok(*tag) - } else { - let asset_tag = AssetTag::new_random( - format!("{}/{}", self.schema.schema_id(), self.iface.iface_id()), - type_id, - ); - self.asset_tags.insert(type_id, asset_tag)?; - Ok(asset_tag) - } - } - pub fn add_metadata( mut self, name: impl Into, @@ -1038,411 +613,41 @@ impl OperationBuilder { Ok(self) } - fn add_owned_state_det( - self, - name: impl Into, - seal: impl Into>, - state: PersistedState, - ) -> Result { - debug_assert!( - self.deterministic, - "to add owned state in deterministic way the builder has to be created using \ - deterministic constructor" - ); - let name = name.into(); - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name.clone()))?; - self.add_owned_state_raw(type_id, seal, state) - } - fn add_owned_state_raw( - self, - type_id: AssignmentType, - seal: impl Into>, - state: PersistedState, - ) -> Result { - match state { - PersistedState::Void => self.add_rights_raw(type_id, seal), - PersistedState::Amount(value, blinding, tag) => { - if self.asset_tag_raw(type_id)? != tag { - return Err(BuilderError::AssetTagInvalid(type_id)); - } - - self.add_fungible_state_raw( - type_id, - seal, - RevealedValue::with_blinding(value, blinding, tag), - ) - } - PersistedState::Data(data, salt) => { - self.add_data_raw(type_id, seal, RevealedData::with_salt(data, salt)) - } - PersistedState::Attachment(attach, salt) => self.add_attachment_raw( - type_id, - seal, - RevealedAttach::with_salt(attach.id, attach.media_type, salt), - ), - } - } - - fn add_rights( - self, - name: impl Into, - seal: impl Into>, - ) -> Result { - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_rights_raw(type_id, seal) - } - - fn add_rights_raw( mut self, - type_id: AssignmentType, - seal: impl Into>, - ) -> Result { - let state_schema = self.state_schema(type_id); - if *state_schema != OwnedStateSchema::Declarative { - return Err(BuilderError::InvalidStateType(type_id)); - } - - let seal = seal.into(); - match self.rights.get_mut(&type_id) { - Some(assignments) => { - assignments.push(seal)?; - } - None => { - self.rights.insert(type_id, Confined::with(seal))?; - } - } - - Ok(self) - } - - fn add_fungible_state( - self, - name: impl Into, - seal: impl Into>, - value: impl Into, - ) -> Result { - debug_assert!( - !self.deterministic, - "for adding state to deterministic contracts you have to use add_*_det methods" - ); - - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - let tag = self.asset_tag_raw(type_id)?; - - let state = RevealedValue::new_random_blinding(value.into(), tag); - self.add_fungible_state_raw(type_id, seal, state) - } - - fn add_fungible_state_det( - self, name: impl Into, seal: impl Into>, - state: RevealedValue, + state: State, ) -> Result { - debug_assert!( - self.deterministic, - "to add owned state in deterministic way the builder has to be created using \ - deterministic constructor" - ); - let name = name.into(); let type_id = self .assignments_type(&name) .ok_or(BuilderError::AssignmentNotFound(name))?; - self.add_fungible_state_raw(type_id, seal, state) - } - fn add_fungible_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: RevealedValue, - ) -> Result { - let state_schema = self.state_schema(type_id); - if *state_schema != OwnedStateSchema::Fungible(FungibleType::Unsigned64Bit) { - return Err(BuilderError::InvalidStateType(type_id)); - } + let assignment = seal.into().assignment(state); - let seal = seal.into(); - match self.fungible.get_mut(&type_id) { - Some(assignments) => { - assignments.insert(seal, state)?; + match self.assignments.entry(type_id)? { + Entry::Vacant(entry) => { + entry.insert(TypedAssigns::with(assignment)); } - None => { - self.fungible - .insert(type_id, Confined::with((seal, state)))?; + Entry::Occupied(mut entry) => { + entry.get_mut().push(assignment)?; } } - Ok(self) } - fn add_data( + fn add_owned_state( self, name: impl Into, seal: impl Into>, value: impl StrictSerialize, ) -> Result { - debug_assert!( - !self.deterministic, - "for adding state to deterministic contracts you have to use add_*_det methods" - ); - - let name = name.into(); - let serialized = value.to_strict_serialized::()?; - let state = DataState::from(serialized); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_data_raw(type_id, seal, RevealedData::new_random_salt(state)) + self.add_owned_state_raw(name, seal, State::new(value)) } - fn add_data_det( - self, - name: impl Into, - seal: impl Into>, - state: RevealedData, - ) -> Result { - debug_assert!( - self.deterministic, - "to add owned state in deterministic way the builder has to be created using \ - deterministic constructor" - ); - - let name = name.into(); - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_data_raw(type_id, seal, state) - } - - fn add_data_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: RevealedData, - ) -> Result { - let state_schema = self.state_schema(type_id); - if let OwnedStateSchema::Structured(_) = *state_schema { - let seal = seal.into(); - match self.data.get_mut(&type_id) { - Some(assignments) => { - assignments.insert(seal, state)?; - } - None => { - self.data.insert(type_id, Confined::with((seal, state)))?; - } - } - } else { - return Err(BuilderError::InvalidStateType(type_id)); - } - Ok(self) - } - - fn add_attachment( - self, - name: impl Into, - seal: impl Into>, - state: AttachState, - ) -> Result { - debug_assert!( - !self.deterministic, - "for adding state to deterministic contracts you have to use add_*_det methods" - ); - - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_attachment_raw( - type_id, - seal, - RevealedAttach::new_random_salt(state.id, state.media_type), - ) - } - - fn add_attachment_det( - self, - name: impl Into, - seal: impl Into>, - state: RevealedAttach, - ) -> Result { - debug_assert!( - self.deterministic, - "to add owned state in deterministic way the builder has to be created using \ - deterministic constructor" - ); - - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_attachment_raw(type_id, seal, state) - } - - fn add_attachment_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: RevealedAttach, - ) -> Result { - let state_schema = self.state_schema(type_id); - if let OwnedStateSchema::Attachment(_) = *state_schema { - let seal = seal.into(); - match self.attachments.get_mut(&type_id) { - Some(assignments) => { - assignments.insert(seal, state)?; - } - None => { - self.attachments - .insert(type_id, Confined::with((seal, state)))?; - } - } - } else { - return Err(BuilderError::InvalidStateType(type_id)); - } - Ok(self) - } - - fn complete( - self, - inputs: Option<&TinyOrdMap>, - ) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments, TypeSystem, AssetTags) { - let owned_state = self.fungible.into_iter().map(|(id, vec)| { - let mut blindings = Vec::with_capacity(vec.len()); - let mut vec = vec - .into_iter() - .map(|(seal, value)| { - blindings.push(value.blinding); - match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: value, - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: value, - lock: none!(), - }, - } - }) - .collect::>(); - if let Some(assignment) = vec.last_mut() { - blindings.pop(); - let state = assignment - .as_revealed_state_mut() - .expect("builder always operates revealed state"); - let mut inputs = inputs - .map(|i| { - i.iter() - .filter(|(out, _)| out.prev_out.ty == id) - .map(|(_, ts)| match ts { - PersistedState::Amount(_, blinding, _) => *blinding, - _ => panic!("previous state has invalid type"), - }) - .collect::>() - }) - .unwrap_or_default(); - if inputs.is_empty() { - inputs = vec![BlindingFactor::EMPTY]; - } - state.blinding = BlindingFactor::zero_balanced(inputs, blindings).expect( - "malformed set of blinding factors; probably random generator is broken", - ); - } - let state = Confined::try_from_iter(vec).expect("at least one element"); - let state = TypedAssigns::Fungible(state); - (id, state) - }); - let owned_data = self.data.into_iter().map(|(id, vec)| { - let vec_data = vec.into_iter().map(|(seal, value)| match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: value, - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: value, - lock: none!(), - }, - }); - let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); - let state_data = TypedAssigns::Structured(state_data); - (id, state_data) - }); - let owned_rights = self.rights.into_iter().map(|(id, vec)| { - let vec_data = vec.into_iter().map(|seal| match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: none!(), - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: none!(), - lock: none!(), - }, - }); - let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); - let state_data = TypedAssigns::Declarative(state_data); - (id, state_data) - }); - let owned_attachments = self.attachments.into_iter().map(|(id, vec)| { - let vec_data = vec.into_iter().map(|(seal, value)| match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: value, - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: value, - lock: none!(), - }, - }); - let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); - let state_data = TypedAssigns::Attachment(state_data); - (id, state_data) - }); - - let owned_state = Confined::try_from_iter(owned_state).expect("same size"); - let owned_data = Confined::try_from_iter(owned_data).expect("same size"); - let owned_rights = Confined::try_from_iter(owned_rights).expect("same size"); - let owned_attachments = Confined::try_from_iter(owned_attachments).expect("same size"); - - let mut assignments = Assignments::from_inner(owned_state); - assignments - .extend(Assignments::from_inner(owned_data).into_inner()) - .expect("too many assignments"); - assignments - .extend(Assignments::from_inner(owned_rights).into_inner()) - .expect("too many assignments"); - assignments - .extend(Assignments::from_inner(owned_attachments).into_inner()) - .expect("too many assignments"); - - (self.schema, self.iface, self.iimpl, self.global, assignments, self.types, self.asset_tags) + fn complete(self) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments, TypeSystem) { + (self.schema, self.iface, self.iimpl, self.global, self.assignments, self.types) } } diff --git a/src/interface/contract.rs b/src/interface/contract.rs index 2709a054..5f03b6d5 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -22,19 +22,14 @@ use std::borrow::Borrow; use std::collections::{BTreeSet, HashMap, HashSet}; -use invoice::{Allocation, Amount}; -use rgb::{ - AssignmentType, AttachState, ContractId, DataState, OpId, RevealedAttach, RevealedData, - RevealedValue, Schema, VoidState, XOutpoint, XOutputSeal, XWitnessId, -}; -use strict_encoding::{FieldName, StrictDecode, StrictDumb, StrictEncode}; +use rgb::{AssignmentType, ContractId, OpId, Schema, State, XOutputSeal, XWitnessId}; +use strict_encoding::FieldName; use strict_types::{StrictVal, TypeSystem}; -use crate::contract::{KnownState, OutputAssignment, WitnessInfo}; +use crate::contract::{OutputAssignment, WitnessInfo}; use crate::info::ContractInfo; use crate::interface::{AssignmentsFilter, IfaceImpl}; use crate::persistence::ContractStateRead; -use crate::LIB_NAME_RGB_STD; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] #[display(doc_comments)] @@ -43,58 +38,6 @@ pub enum ContractError { FieldNameUnknown(FieldName), } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[display(inner)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum AllocatedState { - #[from(())] - #[from(VoidState)] - #[display("~")] - #[strict_type(tag = 0, dumb)] - Void, - - #[from] - #[from(RevealedValue)] - #[strict_type(tag = 1)] - Amount(Amount), - - #[from] - #[from(RevealedData)] - #[from(Allocation)] - #[strict_type(tag = 2)] - Data(DataState), - - #[from] - #[from(RevealedAttach)] - #[strict_type(tag = 3)] - Attachment(AttachState), -} - -impl KnownState for AllocatedState { - const IS_FUNGIBLE: bool = false; -} - -impl AllocatedState { - fn unwrap_fungible(&self) -> Amount { - match self { - AllocatedState::Amount(amount) => *amount, - _ => panic!("unwrapping non-fungible state"), - } - } -} - -pub type OwnedAllocation = OutputAssignment; -pub type RightsAllocation = OutputAssignment; -pub type FungibleAllocation = OutputAssignment; -pub type DataAllocation = OutputAssignment; -pub type AttachAllocation = OutputAssignment; - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] #[cfg_attr( feature = "serde", @@ -118,12 +61,12 @@ pub struct ContractOp { pub direction: OpDirection, pub ty: AssignmentType, pub opids: BTreeSet, - pub state: AllocatedState, + pub state: State, pub to: BTreeSet, pub witness: Option, } -fn reduce_to_ty(allocations: impl IntoIterator) -> AssignmentType { +fn reduce_to_ty(allocations: impl IntoIterator) -> AssignmentType { allocations .into_iter() .map(|a| a.opout.ty) @@ -135,9 +78,7 @@ fn reduce_to_ty(allocations: impl IntoIterator) -> Assig } impl ContractOp { - fn non_fungible_genesis( - our_allocations: HashSet, - ) -> impl ExactSizeIterator { + fn genesis(our_allocations: HashSet) -> impl ExactSizeIterator { our_allocations.into_iter().map(|a| Self { direction: OpDirection::Issued, ty: a.opout.ty, @@ -148,9 +89,9 @@ impl ContractOp { }) } - fn non_fungible_sent( + fn sent( witness: WitnessInfo, - ext_allocations: HashSet, + ext_allocations: HashSet, ) -> impl ExactSizeIterator { ext_allocations.into_iter().map(move |a| Self { direction: OpDirection::Sent, @@ -162,9 +103,9 @@ impl ContractOp { }) } - fn non_fungible_received( + fn received( witness: WitnessInfo, - our_allocations: HashSet, + our_allocations: HashSet, ) -> impl ExactSizeIterator { our_allocations.into_iter().map(move |a| Self { direction: OpDirection::Received, @@ -175,57 +116,6 @@ impl ContractOp { witness: Some(witness), }) } - - fn fungible_genesis(our_allocations: HashSet) -> Self { - let to = our_allocations.iter().map(|a| a.seal).collect(); - let opids = our_allocations.iter().map(|a| a.opout.op).collect(); - let issued = our_allocations - .iter() - .map(|a| a.state.unwrap_fungible()) - .sum(); - Self { - direction: OpDirection::Issued, - ty: reduce_to_ty(our_allocations), - opids, - state: AllocatedState::Amount(issued), - to, - witness: None, - } - } - - fn fungible_sent(witness: WitnessInfo, ext_allocations: HashSet) -> Self { - let opids = ext_allocations.iter().map(|a| a.opout.op).collect(); - let to = ext_allocations.iter().map(|a| a.seal).collect(); - let amount = ext_allocations - .iter() - .map(|a| a.state.unwrap_fungible()) - .sum(); - Self { - direction: OpDirection::Sent, - ty: reduce_to_ty(ext_allocations), - opids, - state: AllocatedState::Amount(amount), - to, - witness: Some(witness), - } - } - - fn fungible_received(witness: WitnessInfo, our_allocations: HashSet) -> Self { - let opids = our_allocations.iter().map(|a| a.opout.op).collect(); - let to = our_allocations.iter().map(|a| a.seal).collect(); - let amount = our_allocations - .iter() - .map(|a| a.state.unwrap_fungible()) - .sum(); - Self { - direction: OpDirection::Received, - ty: reduce_to_ty(our_allocations), - opids, - state: AllocatedState::Amount(amount), - to, - witness: Some(witness), - } - } } /// Contract state is an in-memory structure providing API to read structured @@ -272,148 +162,54 @@ impl ContractIface { })) } - fn extract_state<'c, A, U>( + pub fn assignments_by<'c>( &'c self, - state: impl IntoIterator> + 'c, - name: impl Into, filter: impl AssignmentsFilter + 'c, - ) -> Result> + 'c, ContractError> - where - A: Clone + KnownState + 'c, - U: From + KnownState + 'c, - { - Ok(self - .extract_state_unfiltered(state, name)? - .filter(move |outp| filter.should_include(outp.seal, outp.witness))) + ) -> impl Iterator + 'c { + self.state + .assignments() + .filter(move |outp| filter.should_include(outp.seal, outp.witness)) } - fn extract_state_unfiltered<'c, A, U>( + pub fn assignments_by_type<'c>( &'c self, - state: impl IntoIterator> + 'c, name: impl Into, - ) -> Result> + 'c, ContractError> - where - A: Clone + KnownState + 'c, - U: From + KnownState + 'c, - { + filter: impl AssignmentsFilter + 'c, + ) -> Result + 'c, ContractError> { let name = name.into(); let type_id = self .iface .assignments_type(&name) .ok_or(ContractError::FieldNameUnknown(name))?; - Ok(state - .into_iter() - .filter(move |outp| outp.opout.ty == type_id) - .cloned() - .map(OutputAssignment::::transmute)) - } - - pub fn rights<'c>( - &'c self, - name: impl Into, - filter: impl AssignmentsFilter + 'c, - ) -> Result + 'c, ContractError> { - self.extract_state(self.state.rights_all(), name, filter) - } - - pub fn fungible<'c>( - &'c self, - name: impl Into, - filter: impl AssignmentsFilter + 'c, - ) -> Result + 'c, ContractError> { - self.extract_state(self.state.fungible_all(), name, filter) - } - - pub fn data<'c>( - &'c self, - name: impl Into, - filter: impl AssignmentsFilter + 'c, - ) -> Result + 'c, ContractError> { - self.extract_state(self.state.data_all(), name, filter) - } - - pub fn attachments<'c>( - &'c self, - name: impl Into, - filter: impl AssignmentsFilter + 'c, - ) -> Result + 'c, ContractError> { - self.extract_state(self.state.attach_all(), name, filter) - } - - pub fn allocations<'c>( - &'c self, - filter: impl AssignmentsFilter + Copy + 'c, - ) -> impl Iterator + 'c { - fn f<'a, S, U>( - filter: impl AssignmentsFilter + 'a, - state: impl IntoIterator> + 'a, - ) -> impl Iterator> + 'a - where - S: Clone + KnownState + 'a, - U: From + KnownState + 'a, - { - state - .into_iter() - .filter(move |outp| filter.should_include(outp.seal, outp.witness)) - .cloned() - .map(OutputAssignment::::transmute) - } - - f(filter, self.state.rights_all()) - .map(OwnedAllocation::from) - .chain(f(filter, self.state.fungible_all()).map(OwnedAllocation::from)) - .chain(f(filter, self.state.data_all()).map(OwnedAllocation::from)) - .chain(f(filter, self.state.attach_all()).map(OwnedAllocation::from)) - } - - pub fn outpoint_allocations( - &self, - outpoint: XOutpoint, - ) -> impl Iterator + '_ { - self.allocations(outpoint) + Ok(self + .assignments_by(filter) + .filter(move |outp| outp.opout.ty == type_id)) } pub fn history( &self, - filter_outpoints: impl AssignmentsFilter + Clone, - filter_witnesses: impl AssignmentsFilter + Clone, - ) -> Vec { - self.history_fungible(filter_outpoints.clone(), filter_witnesses.clone()) - .into_iter() - .chain(self.history_rights(filter_outpoints.clone(), filter_witnesses.clone())) - .chain(self.history_data(filter_outpoints.clone(), filter_witnesses.clone())) - .chain(self.history_attach(filter_outpoints, filter_witnesses)) - .collect() - } - - fn operations<'c, T: KnownState + 'c, I: Iterator>>( - &'c self, - state: impl Fn(&'c S) -> I, filter_outpoints: impl AssignmentsFilter, filter_witnesses: impl AssignmentsFilter, - ) -> Vec - where - AllocatedState: From, - { + ) -> Vec { // get all allocations which ever belonged to this wallet and store them by witness id - let mut allocations_our_outpoint = state(&self.state) + let mut allocations_our_outpoint = self + .state + .assignments() .filter(move |outp| filter_outpoints.should_include(outp.seal, outp.witness)) .fold(HashMap::<_, HashSet<_>>::new(), |mut map, a| { - map.entry(a.witness) - .or_default() - .insert(a.clone().transmute::()); + map.entry(a.witness).or_default().insert(a.clone()); map }); // get all allocations which has a witness transaction belonging to this wallet - let mut allocations_our_witness = state(&self.state) + let mut allocations_our_witness = self + .state + .assignments() .filter(move |outp| filter_witnesses.should_include(outp.seal, outp.witness)) .fold(HashMap::<_, HashSet<_>>::new(), |mut map, a| { let witness = a.witness.expect( "all empty witnesses must be already filtered out by wallet.filter_witness()", ); - map.entry(witness) - .or_default() - .insert(a.clone().transmute::()); + map.entry(witness).or_default().insert(a.clone()); map }); @@ -427,12 +223,8 @@ impl ContractIface { // reconstruct contract history from the wallet perspective let mut ops = Vec::with_capacity(witness_ids.len() + 1); // add allocations with no witness to the beginning of the history - if let Some(genesis_allocations) = allocations_our_outpoint.remove(&None) { - if T::IS_FUNGIBLE { - ops.push(ContractOp::fungible_genesis(genesis_allocations)); - } else { - ops.extend(ContractOp::non_fungible_genesis(genesis_allocations)); - } + if let Some(genesis_state) = allocations_our_outpoint.remove(&None) { + ops.extend(ContractOp::genesis(genesis_state)); } for witness_id in witness_ids { let our_outpoint = allocations_our_outpoint.remove(&Some(witness_id)); @@ -444,38 +236,26 @@ impl ContractIface { // we own both allocation and witness transaction: these allocations are changes and // outgoing payments. The difference between the change and the payments are whether // a specific allocation is listed in the first tuple pattern field. - (Some(our_allocations), Some(all_allocations)) => { + (Some(our_assignments), Some(all_assignments)) => { // all_allocations - our_allocations = external payments - let ext_allocations = all_allocations - .difference(&our_allocations) + let ext_assignments = all_assignments + .difference(&our_assignments) .cloned() .collect::>(); // This was a blank state transition with no external payment - if ext_allocations.is_empty() { + if ext_assignments.is_empty() { continue; } - if T::IS_FUNGIBLE { - ops.push(ContractOp::fungible_sent(witness_info, ext_allocations)) - } else { - ops.extend(ContractOp::non_fungible_sent(witness_info, ext_allocations)) - } + ops.extend(ContractOp::sent(witness_info, ext_assignments)) } // the same as above, but the payment has no change - (None, Some(ext_allocations)) => { - if T::IS_FUNGIBLE { - ops.push(ContractOp::fungible_sent(witness_info, ext_allocations)) - } else { - ops.extend(ContractOp::non_fungible_sent(witness_info, ext_allocations)) - } + (None, Some(ext_assignments)) => { + ops.extend(ContractOp::sent(witness_info, ext_assignments)) } // we own allocation but the witness transaction was made by other wallet: // this is an incoming payment to us. - (Some(our_allocations), None) => { - if T::IS_FUNGIBLE { - ops.push(ContractOp::fungible_received(witness_info, our_allocations)) - } else { - ops.extend(ContractOp::non_fungible_received(witness_info, our_allocations)) - } + (Some(our_assignments), None) => { + ops.extend(ContractOp::received(witness_info, our_assignments)) } // these can't get into the `witness_ids` due to the used filters (None, None) => unreachable!("broken allocation filters"), @@ -485,38 +265,6 @@ impl ContractIface { ops } - pub fn history_fungible( - &self, - filter_outpoints: impl AssignmentsFilter, - filter_witnesses: impl AssignmentsFilter, - ) -> Vec { - self.operations(|state| state.fungible_all(), filter_outpoints, filter_witnesses) - } - - pub fn history_rights( - &self, - filter_outpoints: impl AssignmentsFilter, - filter_witnesses: impl AssignmentsFilter, - ) -> Vec { - self.operations(|state| state.rights_all(), filter_outpoints, filter_witnesses) - } - - pub fn history_data( - &self, - filter_outpoints: impl AssignmentsFilter, - filter_witnesses: impl AssignmentsFilter, - ) -> Vec { - self.operations(|state| state.data_all(), filter_outpoints, filter_witnesses) - } - - pub fn history_attach( - &self, - filter_outpoints: impl AssignmentsFilter, - filter_witnesses: impl AssignmentsFilter, - ) -> Vec { - self.operations(|state| state.attach_all(), filter_outpoints, filter_witnesses) - } - pub fn witness_info(&self, witness_id: XWitnessId) -> Option { let ord = self.state.witness_ord(witness_id)?; Some(WitnessInfo { diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 496ce87e..e4bd759f 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -33,10 +33,7 @@ mod contractum; mod inheritance; pub use builder::{BuilderError, ContractBuilder, TransitionBuilder, TxOutpoint}; -pub use contract::{ - AllocatedState, AttachAllocation, ContractError, ContractIface, ContractOp, DataAllocation, - FungibleAllocation, OpDirection, OwnedAllocation, RightsAllocation, -}; +pub use contract::{ContractError, ContractIface, ContractOp, OpDirection}; pub use contractum::IfaceDisplay; pub use filter::{AssignmentsFilter, FilterExclude, FilterIncludeAll}; pub use iface::{ diff --git a/src/lib.rs b/src/lib.rs index d428aa06..a67d7a3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,13 +46,10 @@ mod contract; pub mod info; pub use bp::{Outpoint, Txid}; -pub use contract::{ - KnownState, MergeReveal, MergeRevealError, OutputAssignment, TypedAssignsExt, WitnessInfo, -}; -pub use invoice::{Allocation, Amount, CoinAmount, OwnedFraction, Precision, TokenIndex}; +pub use contract::{MergeReveal, MergeRevealError, OutputAssignment, WitnessInfo}; pub use rgb::prelude::*; pub use rgb::rgbasm; -pub use stl::{LIB_NAME_RGB_CONTRACT, LIB_NAME_RGB_STD, LIB_NAME_RGB_STORAGE}; +pub use stl::{LIB_NAME_RGB_STD, LIB_NAME_RGB_STORAGE}; /// BIP32 derivation index for outputs which may contain assigned RGB state. pub const RGB_NATIVE_DERIVATION_INDEX: u32 = 9; diff --git a/src/persistence/index.rs b/src/persistence/index.rs index b07b831c..2f0ac19e 100644 --- a/src/persistence/index.rs +++ b/src/persistence/index.rs @@ -26,9 +26,8 @@ use std::fmt::Debug; use amplify::confinement; use nonasync::persistence::{CloneNoPersistence, Persisting}; use rgb::{ - Assign, AssignmentType, BundleId, ContractId, ExposedState, Extension, Genesis, GenesisSeal, - GraphSeal, OpId, Operation, Opout, TransitionBundle, TypedAssigns, XChain, XOutputSeal, - XWitnessId, + Assign, AssignmentType, BundleId, ContractId, Extension, Genesis, GenesisSeal, GraphSeal, OpId, + Operation, Opout, TransitionBundle, XChain, XOutputSeal, XWitnessId, }; use crate::containers::{ConsignmentExt, ToWitnessId, WitnessBundle}; @@ -185,25 +184,9 @@ impl Index

{ fn index_genesis(&mut self, id: ContractId, genesis: &Genesis) -> Result<(), IndexError

> { let opid = genesis.id(); - for (type_id, assign) in genesis.assignments.iter() { - match assign { - TypedAssigns::Declarative(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Fungible(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Structured(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Attachment(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - } + for (type_id, assigns) in genesis.assignments.iter() { + self.provider + .index_genesis_assignments(id, assigns, opid, *type_id)?; } Ok(()) } @@ -214,25 +197,9 @@ impl Index

{ extension: &Extension, ) -> Result<(), IndexError

> { let opid = extension.id(); - for (type_id, assign) in extension.assignments.iter() { - match assign { - TypedAssigns::Declarative(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Fungible(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Structured(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Attachment(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - } + for (type_id, assigns) in extension.assignments.iter() { + self.provider + .index_genesis_assignments(id, assigns, opid, *type_id)?; } Ok(()) } @@ -250,45 +217,14 @@ impl Index

{ for (opid, transition) in &bundle.known_transitions { self.provider.register_operation(*opid, bundle_id)?; - for (type_id, assign) in transition.assignments.iter() { - match assign { - TypedAssigns::Declarative(vec) => { - self.provider.index_transition_assignments( - contract_id, - vec, - *opid, - *type_id, - witness_id, - )?; - } - TypedAssigns::Fungible(vec) => { - self.provider.index_transition_assignments( - contract_id, - vec, - *opid, - *type_id, - witness_id, - )?; - } - TypedAssigns::Structured(vec) => { - self.provider.index_transition_assignments( - contract_id, - vec, - *opid, - *type_id, - witness_id, - )?; - } - TypedAssigns::Attachment(vec) => { - self.provider.index_transition_assignments( - contract_id, - vec, - *opid, - *type_id, - witness_id, - )?; - } - } + for (type_id, assigns) in transition.assignments.iter() { + self.provider.index_transition_assignments( + contract_id, + assigns, + *opid, + *type_id, + witness_id, + )?; } } @@ -413,18 +349,18 @@ pub trait IndexWriteProvider: StoreTransaction { bundle_id: BundleId, ) -> Result>; - fn index_genesis_assignments( + fn index_genesis_assignments( &mut self, contract_id: ContractId, - vec: &[Assign], + vec: &[Assign], opid: OpId, type_id: AssignmentType, ) -> Result<(), IndexWriteError>; - fn index_transition_assignments( + fn index_transition_assignments( &mut self, contract_id: ContractId, - vec: &[Assign], + vec: &[Assign], opid: OpId, type_id: AssignmentType, witness_id: XWitnessId, diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index 5b5d229e..1bd3098e 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -29,8 +29,8 @@ use std::{iter, mem}; use aluvm::library::{Lib, LibId}; use amplify::confinement::{ - self, Confined, LargeOrdMap, LargeOrdSet, MediumBlob, MediumOrdMap, MediumOrdSet, SmallOrdMap, - TinyOrdMap, TinyOrdSet, + self, Confined, LargeOrdMap, LargeOrdSet, MediumBlob, MediumOrdMap, MediumOrdSet, SmallBlob, + SmallOrdMap, TinyOrdMap, TinyOrdSet, }; use amplify::num::u24; use bp::dbc::tapret::TapretCommitment; @@ -42,11 +42,10 @@ use rgb::vm::{ OrdOpRef, UnknownGlobalStateType, WitnessOrd, }; use rgb::{ - Assign, AssignmentType, Assignments, AssignmentsRef, AttachId, AttachState, BundleId, - ContractId, DataState, ExposedSeal, ExposedState, Extension, FungibleState, Genesis, - GenesisSeal, GlobalStateType, GraphSeal, Identity, OpId, Operation, Opout, RevealedAttach, - RevealedData, RevealedValue, Schema, SchemaId, SecretSeal, Transition, TransitionBundle, - TypedAssigns, VoidState, XChain, XOutpoint, XOutputSeal, XWitnessId, + Assign, AssignmentType, Assignments, AssignmentsRef, AttachId, BundleId, ContractId, + ExposedSeal, Extension, Genesis, GenesisSeal, GlobalStateType, GraphSeal, Identity, OpId, + Operation, Opout, Schema, SchemaId, SecretSeal, Transition, TransitionBundle, XChain, + XOutpoint, XOutputSeal, XWitnessId, }; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::TypeSystem; @@ -61,7 +60,7 @@ use super::{ use crate::containers::{ AnchorSet, ContentId, ContentRef, ContentSigs, SealWitness, SigBlob, Supplement, TrustLevel, }; -use crate::contract::{GlobalOut, KnownState, OpWitness, OutputAssignment}; +use crate::contract::{GlobalOut, OpWitness, OutputAssignment}; use crate::interface::{Iface, IfaceClass, IfaceId, IfaceImpl, IfaceRef}; use crate::LIB_NAME_RGB_STORAGE; @@ -566,10 +565,7 @@ impl StateReadProvider for MemState { .values() .flat_map(|state| state.known.keys()) .any(|out| out.witness_id() == id) - || unfiltered.rights.iter().any(|a| a.witness == id) - || unfiltered.fungibles.iter().any(|a| a.witness == id) - || unfiltered.data.iter().any(|a| a.witness == id) - || unfiltered.attach.iter().any(|a| a.witness == id) + || unfiltered.state.iter().any(|a| a.witness == id) }) .map(|(id, ord)| (*id, *ord)) .collect(); @@ -684,7 +680,7 @@ impl StateWriteProvider for MemState { #[strict_type(lib = LIB_NAME_RGB_STORAGE)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct MemGlobalState { - known: LargeOrdMap, + known: LargeOrdMap, limit: u24, } @@ -721,10 +717,7 @@ pub struct MemContractState { contract_id: ContractId, #[getter(skip)] global: TinyOrdMap, - rights: LargeOrdSet>, - fungibles: LargeOrdSet>, - data: LargeOrdSet>, - attach: LargeOrdSet>, + state: LargeOrdSet, } impl MemContractState { @@ -739,10 +732,7 @@ impl MemContractState { schema_id: schema.schema_id(), contract_id, global, - rights: empty!(), - fungibles: empty!(), - data: empty!(), - attach: empty!(), + state: empty!(), } } @@ -817,46 +807,30 @@ impl MemContractState { opid: OpId, assignments: &Assignments, ) { - fn process( - contract_state: &mut LargeOrdSet>, - assignments: &[Assign], - opid: OpId, - ty: AssignmentType, - witness_id: Option, - ) { + for (ty, assignments) in assignments.iter() { for (no, seal, state) in assignments .iter() .enumerate() - .filter_map(|(n, a)| a.to_revealed().map(|(seal, state)| (n, seal, state))) + .filter_map(|(n, a)| a.revealed_seal().map(|seal| (n, seal, a.as_state()))) { let assigned_state = match witness_id { - Some(witness_id) => { - OutputAssignment::with_witness(seal, witness_id, state, opid, ty, no as u16) + Some(witness_id) => OutputAssignment::with_witness( + seal, + witness_id, + state.clone(), + opid, + *ty, + no as u16, + ), + None => { + OutputAssignment::with_no_witness(seal, state.clone(), opid, *ty, no as u16) } - None => OutputAssignment::with_no_witness(seal, state, opid, ty, no as u16), }; - contract_state + self.state .push(assigned_state) .expect("contract state exceeded 2^32 items, which is unrealistic"); } } - - for (ty, assignments) in assignments.iter() { - match assignments { - TypedAssigns::Declarative(assignments) => { - process(&mut self.rights, assignments, opid, *ty, witness_id) - } - TypedAssigns::Fungible(assignments) => { - process(&mut self.fungibles, assignments, opid, *ty, witness_id) - } - TypedAssigns::Structured(assignments) => { - process(&mut self.data, assignments, opid, *ty, witness_id) - } - TypedAssigns::Attachment(assignments) => { - process(&mut self.attach, assignments, opid, *ty, witness_id) - } - } - } } } @@ -876,12 +850,12 @@ impl> ContractStateAccess for MemContract { &self, ty: GlobalStateType, ) -> Result, UnknownGlobalStateType> { - type Src<'a> = &'a BTreeMap; - type FilteredIter<'a> = Box + 'a>; + type Src<'a> = &'a BTreeMap; + type FilteredIter<'a> = Box + 'a>; struct Iter<'a> { src: Src<'a>, iter: FilteredIter<'a>, - last: Option<(GlobalOrd, &'a DataState)>, + last: Option<(GlobalOrd, &'a SmallBlob)>, depth: u24, constructor: Box) -> FilteredIter<'a> + 'a>, } @@ -893,7 +867,7 @@ impl> ContractStateAccess for MemContract { } } impl<'a> GlobalStateIter for Iter<'a> { - type Data = &'a DataState; + type Data = &'a SmallBlob; fn size(&mut self) -> u24 { let iter = self.swap(); // TODO: Consuming iterator just to count items is highly inefficient, but I do @@ -964,64 +938,20 @@ impl> ContractStateAccess for MemContract { Ok(GlobalContractState::new(iter)) } - fn rights(&self, outpoint: XOutpoint, ty: AssignmentType) -> u32 { - self.unfiltered - .borrow() - .rights - .iter() - .filter(|assignment| { - assignment.seal.to_outpoint() == outpoint && assignment.opout.ty == ty - }) - .filter(|assignment| assignment.check_witness(&self.filter)) - .count() as u32 - } - - fn fungible( - &self, - outpoint: XOutpoint, - ty: AssignmentType, - ) -> impl DoubleEndedIterator { - self.unfiltered - .borrow() - .fungibles - .iter() - .filter(move |assignment| { - assignment.seal.to_outpoint() == outpoint && assignment.opout.ty == ty - }) - .filter(|assignment| assignment.check_witness(&self.filter)) - .map(|assignment| assignment.state.value) - } - - fn data( - &self, - outpoint: XOutpoint, - ty: AssignmentType, - ) -> impl DoubleEndedIterator> { - self.unfiltered - .borrow() - .data - .iter() - .filter(move |assignment| { - assignment.seal.to_outpoint() == outpoint && assignment.opout.ty == ty - }) - .filter(|assignment| assignment.check_witness(&self.filter)) - .map(|assignment| &assignment.state.value) - } - - fn attach( + fn state( &self, outpoint: XOutpoint, ty: AssignmentType, - ) -> impl DoubleEndedIterator> { + ) -> impl DoubleEndedIterator> { self.unfiltered .borrow() - .attach + .state .iter() .filter(move |assignment| { assignment.seal.to_outpoint() == outpoint && assignment.opout.ty == ty }) .filter(|assignment| assignment.check_witness(&self.filter)) - .map(|assignment| &assignment.state.file) + .map(|assignment| &assignment.state) } } @@ -1088,37 +1018,10 @@ impl> ContractStateRead for MemContract { } #[inline] - fn rights_all(&self) -> impl Iterator> { - self.unfiltered - .borrow() - .rights - .iter() - .filter(|assignment| assignment.check_witness(&self.filter)) - } - - #[inline] - fn fungible_all(&self) -> impl Iterator> { - self.unfiltered - .borrow() - .fungibles - .iter() - .filter(|assignment| assignment.check_witness(&self.filter)) - } - - #[inline] - fn data_all(&self) -> impl Iterator> { + fn assignments(&self) -> impl Iterator { self.unfiltered .borrow() - .data - .iter() - .filter(|assignment| assignment.check_witness(&self.filter)) - } - - #[inline] - fn attach_all(&self) -> impl Iterator> { - self.unfiltered - .borrow() - .attach + .state .iter() .filter(|assignment| assignment.check_witness(&self.filter)) } @@ -1419,10 +1322,10 @@ impl IndexWriteProvider for MemIndex { Ok(!present) } - fn index_genesis_assignments( + fn index_genesis_assignments( &mut self, contract_id: ContractId, - vec: &[Assign], + assignments: &[Assign], opid: OpId, type_id: AssignmentType, ) -> Result<(), IndexWriteError> { @@ -1431,31 +1334,28 @@ impl IndexWriteProvider for MemIndex { .get_mut(&contract_id) .ok_or(IndexInconsistency::ContractAbsent(contract_id))?; - for (no, assign) in vec.iter().enumerate() { + for (no, assign) in assignments.iter().enumerate() { let opout = Opout::new(opid, type_id, no as u16); - if let Assign::ConfidentialState { seal, .. } | Assign::Revealed { seal, .. } = assign { + if let Assign::Revealed { seal, .. } = assign { let output = seal .to_output_seal() .expect("genesis seals always have outpoint"); - match index.outpoint_opouts.get_mut(&output) { - Some(opouts) => { - opouts.push(opout)?; - } - None => { - index.outpoint_opouts.insert(output, medium_bset!(opout))?; - } - } + index + .outpoint_opouts + .entry(output)? + .or_default() + .push(opout)?; } } // We need two cycles due to the borrow checker - self.extend_terminals(vec, opid, type_id) + self.extend_terminals(assignments, opid, type_id) } - fn index_transition_assignments( + fn index_transition_assignments( &mut self, contract_id: ContractId, - vec: &[Assign], + assignments: &[Assign], opid: OpId, type_id: AssignmentType, witness_id: XWitnessId, @@ -1465,44 +1365,38 @@ impl IndexWriteProvider for MemIndex { .get_mut(&contract_id) .ok_or(IndexInconsistency::ContractAbsent(contract_id))?; - for (no, assign) in vec.iter().enumerate() { + for (no, assign) in assignments.iter().enumerate() { let opout = Opout::new(opid, type_id, no as u16); - if let Assign::ConfidentialState { seal, .. } | Assign::Revealed { seal, .. } = assign { + if let Assign::Revealed { seal, .. } = assign { let output = seal.try_to_output_seal(witness_id).unwrap_or_else(|_| { panic!( - "chain mismatch between assignment vout seal ({}) and witness transaction \ - ({})", - seal, witness_id + "chain mismatch between assignment vout seal {seal} and witness \ + transaction {witness_id}", ) }); - match index.outpoint_opouts.get_mut(&output) { - Some(opouts) => { - opouts.push(opout)?; - } - None => { - index.outpoint_opouts.insert(output, medium_bset!(opout))?; - } - } + index + .outpoint_opouts + .entry(output)? + .or_default() + .push(opout)?; } } // We need two cycles due to the borrow checker - self.extend_terminals(vec, opid, type_id) + self.extend_terminals(assignments, opid, type_id) } } impl MemIndex { - fn extend_terminals( + fn extend_terminals( &mut self, - vec: &[Assign], + vec: &[Assign], opid: OpId, type_id: AssignmentType, ) -> Result<(), IndexWriteError> { for (no, assign) in vec.iter().enumerate() { let opout = Opout::new(opid, type_id, no as u16); - if let Assign::Confidential { seal, .. } | Assign::ConfidentialSeal { seal, .. } = - assign - { + if let Assign::Confidential { seal, .. } = assign { self.add_terminal(*seal, opout)?; } } diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index 321f7b14..c92c389a 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -51,8 +51,8 @@ pub use stash::{ StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, }; pub use state::{ - ContractStateRead, ContractStateWrite, PersistedState, State, StateError, StateInconsistency, - StateProvider, StateReadProvider, StateWriteProvider, + ContractStateRead, ContractStateWrite, State, StateError, StateInconsistency, StateProvider, + StateReadProvider, StateWriteProvider, }; pub use stock::{ ComposeError, ConsignError, ContractIfaceError, FasciaError, InputError as StockInputError, diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index c42764e9..c1b3e083 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -299,6 +299,7 @@ impl Stash

{ ) -> Result<(TypeSystem, Scripts), StashError

> { let type_iter = schema .types() + .into_iter() .chain(ifaces.into_iter().flat_map(Iface::types)); let types = self .provider @@ -355,11 +356,10 @@ impl Stash

{ let iimpl = schema_ifaces .get(iface.iface_id()) .ok_or(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()))?; - let genesis = self.provider.genesis(contract_id)?; let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; - let mut builder = if let Some(transition_name) = transition_name { + let builder = if let Some(transition_name) = transition_name { TransitionBuilder::named_transition( contract_id, iface.clone(), @@ -379,12 +379,6 @@ impl Stash

{ } .expect("internal inconsistency"); - for (assignment_type, asset_tag) in genesis.asset_tags.iter() { - builder = builder - .add_asset_tag_raw(*assignment_type, *asset_tag) - .expect("tags are in bset and must not repeat"); - } - Ok(builder) } @@ -399,11 +393,9 @@ impl Stash

{ if schema_ifaces.iimpls.is_empty() { return Err(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()).into()); } - let genesis = self.provider.genesis(contract_id)?; - let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; - let mut builder = if let Some(iimpl) = schema_ifaces.get(iface.iface_id()) { + let builder = if let Some(iimpl) = schema_ifaces.get(iface.iface_id()) { TransitionBuilder::blank_transition( contract_id, iface.clone(), @@ -424,11 +416,6 @@ impl Stash

{ types, ) }; - for (assignment_type, asset_tag) in genesis.asset_tags.iter() { - builder = builder - .add_asset_tag_raw(*assignment_type, *asset_tag) - .expect("tags are in bset and must not repeat"); - } Ok(builder) } diff --git a/src/persistence/state.rs b/src/persistence/state.rs index 4e8c21d8..9545b776 100644 --- a/src/persistence/state.rs +++ b/src/persistence/state.rs @@ -25,14 +25,12 @@ use std::error::Error; use std::fmt::Debug; use std::iter; -use invoice::Amount; use nonasync::persistence::{CloneNoPersistence, Persisting}; use rgb::validation::{ResolveWitness, WitnessResolverError}; use rgb::vm::{ContractStateAccess, WitnessOrd}; use rgb::{ - AssetTag, AttachState, BlindingFactor, ContractId, DataState, Extension, Genesis, Operation, - RevealedAttach, RevealedData, RevealedValue, Schema, SchemaId, Transition, TransitionBundle, - VoidState, XWitnessId, + ContractId, Extension, Genesis, Operation, Schema, SchemaId, Transition, TransitionBundle, + XWitnessId, }; use crate::containers::{ConsignmentExt, ToWitnessId}; @@ -74,27 +72,6 @@ pub enum StateInconsistency { AbsentWitness(XWitnessId), } -#[derive(Clone, Eq, PartialEq, Debug, Hash)] -pub enum PersistedState { - Void, - Amount(Amount, BlindingFactor, AssetTag), - // TODO: Use RevealedData - Data(DataState, u128), - // TODO: Use RevealedAttach - Attachment(AttachState, u64), -} - -impl PersistedState { - pub(crate) fn update_blinding(&mut self, blinding: BlindingFactor) { - match self { - PersistedState::Void => {} - PersistedState::Amount(_, b, _) => *b = blinding, - PersistedState::Data(_, _) => {} - PersistedState::Attachment(_, _) => {} - } - } -} - #[derive(Debug)] pub struct State { provider: P, @@ -309,10 +286,7 @@ pub trait ContractStateRead: ContractStateAccess { fn contract_id(&self) -> ContractId; fn schema_id(&self) -> SchemaId; fn witness_ord(&self, witness_id: XWitnessId) -> Option; - fn rights_all(&self) -> impl Iterator>; - fn fungible_all(&self) -> impl Iterator>; - fn data_all(&self) -> impl Iterator>; - fn attach_all(&self) -> impl Iterator>; + fn assignments(&self) -> impl Iterator; } pub trait ContractStateWrite { diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 4b778ca1..a295c74a 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -31,22 +31,21 @@ use bp::dbc::Method; use bp::seals::txout::CloseMethod; use bp::Vout; use chrono::Utc; -use invoice::{Amount, Beneficiary, InvoiceState, NonFungible, RgbInvoice}; +use invoice::{Beneficiary, InvoiceState, RgbInvoice}; use nonasync::persistence::{CloneNoPersistence, PersistenceError, PersistenceProvider}; use rgb::validation::{DbcProof, ResolveWitness, WitnessResolverError}; use rgb::{ - validation, AssignmentType, BlindingFactor, BundleId, ContractId, DataState, GraphSeal, - Identity, OpId, Operation, Opout, SchemaId, SecretSeal, Transition, TxoSeal, XChain, XOutpoint, - XOutputSeal, XWitnessId, + validation, AssignmentType, BundleId, ContractId, GraphSeal, Identity, OpId, Operation, Opout, + SchemaId, SecretSeal, Transition, TxoSeal, XChain, XOutpoint, XOutputSeal, XWitnessId, }; use strict_encoding::FieldName; use super::{ ContractStateRead, Index, IndexError, IndexInconsistency, IndexProvider, IndexReadProvider, - IndexWriteProvider, MemIndex, MemStash, MemState, PersistedState, SchemaIfaces, Stash, - StashDataError, StashError, StashInconsistency, StashProvider, StashReadProvider, - StashWriteProvider, State, StateError, StateInconsistency, StateProvider, StateReadProvider, - StateWriteProvider, StoreTransaction, + IndexWriteProvider, MemIndex, MemStash, MemState, SchemaIfaces, Stash, StashDataError, + StashError, StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, State, + StateError, StateInconsistency, StateProvider, StateReadProvider, StateWriteProvider, + StoreTransaction, }; use crate::containers::{ AnchorSet, AnchoredBundleMismatch, Batch, BuilderSeal, ClientBundle, Consignment, ContainerVer, @@ -62,7 +61,7 @@ use crate::interface::{ }; use crate::MergeRevealError; -pub type ContractAssignments = HashMap>; +pub type ContractAssignments = HashMap>; #[derive(Debug, Display, Error, From)] #[display(inner)] @@ -617,48 +616,14 @@ impl Stock { let state = self.contract_state(contract_id)?; let mut res = - HashMap::>::with_capacity(outputs.len()); + HashMap::>::with_capacity(outputs.len()); - for item in state.fungible_all() { - let outpoint = item.seal.into(); - if outputs.contains::(&outpoint) { - res.entry(item.seal).or_default().insert( - item.opout, - PersistedState::Amount( - item.state.value.into(), - item.state.blinding, - item.state.tag, - ), - ); - } - } - - for item in state.data_all() { - let outpoint = item.seal.into(); - if outputs.contains::(&outpoint) { - res.entry(item.seal).or_default().insert( - item.opout, - PersistedState::Data(item.state.value.clone(), item.state.salt), - ); - } - } - - for item in state.rights_all() { + for item in state.assignments() { let outpoint = item.seal.into(); if outputs.contains::(&outpoint) { res.entry(item.seal) .or_default() - .insert(item.opout, PersistedState::Void); - } - } - - for item in state.attach_all() { - let outpoint = item.seal.into(); - if outputs.contains::(&outpoint) { - res.entry(item.seal).or_default().insert( - item.opout, - PersistedState::Attachment(item.state.clone().into(), item.state.salt), - ); + .insert(item.opout, item.state.clone()); } } @@ -783,7 +748,7 @@ impl Stock { // 2. Collect secret seals from terminal transitions to add to the consignment terminals 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]; + let seal = typed_assignments.confidential_seals()[index as usize]; if secret_seal == Some(seal) { let res = terminals.insert(bundle_id, seal); assert_eq!(res, None); @@ -920,7 +885,6 @@ impl Stock { beneficiary_vout, u64::MAX, allocator, - |_, _| BlindingFactor::random(), |_, _| rand::random(), ) } @@ -937,7 +901,6 @@ impl Stock { beneficiary_vout: Option>, priority: u64, allocator: impl Fn(ContractId, AssignmentType, VelocityHint) -> Option, - pedersen_blinder: impl Fn(ContractId, AssignmentType) -> BlindingFactor, seal_blinder: impl Fn(ContractId, AssignmentType) -> u64, ) -> Result> { let layer1 = invoice.layer1(); @@ -1153,7 +1116,7 @@ impl Stock { // 3. Prepare other transitions // Enumerate state let mut spent_state = - HashMap::>>::new(); + HashMap::>>::new(); for id in self.contracts_assigning(prev_outputs.iter().copied())? { // Skip current contract if id == contract_id { diff --git a/src/stl/stl.rs b/src/stl.rs similarity index 54% rename from src/stl/stl.rs rename to src/stl.rs index c0243564..1ebfc6a6 100644 --- a/src/stl/stl.rs +++ b/src/stl.rs @@ -19,38 +19,44 @@ // See the License for the specific language governing permissions and // limitations under the License. +use amplify::IoError; +use baid64::Baid64ParseError; pub use bp::bc::stl::bp_tx_stl; pub use bp::stl::bp_core_stl; -#[allow(unused_imports)] pub use commit_verify::stl::{commit_verify_stl, LIB_ID_COMMIT_VERIFY}; -use invoice::{Allocation, Amount}; pub use rgb::stl::{aluvm_stl, rgb_commit_stl, rgb_logic_stl, LIB_ID_RGB_COMMIT, LIB_ID_RGB_LOGIC}; use strict_types::stl::{std_stl, strict_types_stl}; -use strict_types::typesys::SystemBuilder; -use strict_types::{CompileError, LibBuilder, SemId, SymbolicSys, TypeLib, TypeSystem}; +use strict_types::{typesys, CompileError, LibBuilder, TypeLib}; -use super::{ - AssetSpec, BurnMeta, ContractSpec, ContractTerms, Error, IssueMeta, MediaType, - LIB_NAME_RGB_CONTRACT, LIB_NAME_RGB_STORAGE, -}; use crate::containers::{Contract, Kit, Transfer}; use crate::persistence::{MemIndex, MemStash, MemState}; -use crate::stl::ProofOfReserves; -use crate::LIB_NAME_RGB_STD; -/// Strict types id for the library providing standard data types which may be -/// used in RGB smart contracts. -pub const LIB_ID_RGB_STORAGE: &str = - "stl:mG$H7b6I-$T8qp18-07PSNeA-rbEBNS5-$J5X4y0-1vPxRWg#channel-vortex-bandit"; +pub const LIB_NAME_RGB_STD: &str = "RGBStd"; +pub const LIB_NAME_RGB_STORAGE: &str = "RGBStorage"; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. -pub const LIB_ID_RGB_CONTRACT: &str = - "stl:!r5yXt4a-v3XXv0M-E9Z6eoh-BFZweik-fxS6CB4-8AaO!MM#rover-annual-disney"; +pub const LIB_ID_RGB_STORAGE: &str = + "stl:iayFnuhB-sjXxWhi-Pp!FSyO-astclK4-icTXDwX-O0Fb4F4#floor-avatar-lazarus"; /// Strict types id for the library representing of RGB StdLib data types. pub const LIB_ID_RGB_STD: &str = - "stl:JhUC5JgH-Kwps4cO-ZNUklUj-UP6boFp-OY!18Kx-xOSJaVQ#hair-magnum-helena"; + "stl:vdvotNKl-wGrtjuT-Q4qXt4U-UVQlDMB-ONCuwLd-ORBWRTw#zebra-twist-tango"; + +#[allow(dead_code)] +#[derive(Debug, From)] +pub enum Error { + #[from(std::io::Error)] + Io(IoError), + #[from] + Baid64(Baid64ParseError), + #[from] + Compile(CompileError), + #[from] + Link1(typesys::Error), + #[from] + Link2(Vec), +} fn _rgb_std_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB_STD), tiny_bset! { @@ -69,23 +75,6 @@ fn _rgb_std_stl() -> Result { .compile() } -fn _rgb_contract_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_CONTRACT), tiny_bset! { - std_stl().to_dependency(), - bp_tx_stl().to_dependency() - }) - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .compile() -} - fn _rgb_storage_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_RGB_STORAGE), tiny_bset! { std_stl().to_dependency(), @@ -107,65 +96,16 @@ fn _rgb_storage_stl() -> Result { /// Generates strict type library representation of RGB StdLib data types. pub fn rgb_std_stl() -> TypeLib { _rgb_std_stl().expect("invalid strict type RGBStd library") } -/// Generates strict type library providing standard data types which may be -/// used in RGB smart contracts. -pub fn rgb_contract_stl() -> TypeLib { - _rgb_contract_stl().expect("invalid strict type RGBContract library") -} - /// Generates strict type library providing standard storage for state, contract /// state and index. pub fn rgb_storage_stl() -> TypeLib { _rgb_storage_stl().expect("invalid strict type RGBStorage library") } -#[derive(Debug)] -pub struct StandardTypes(SymbolicSys); - -impl Default for StandardTypes { - fn default() -> Self { StandardTypes::new() } -} - -impl StandardTypes { - pub fn new() -> Self { - Self::try_with([std_stl(), bp_tx_stl(), rgb_contract_stl()]) - .expect("error in standard RGBContract type system") - } - - pub fn with(lib: TypeLib) -> Self { - Self::try_with([std_stl(), bp_tx_stl(), rgb_contract_stl(), lib]) - .expect("error in standard RGBContract type system") - } - - #[allow(clippy::result_large_err)] - fn try_with(libs: impl IntoIterator) -> Result { - let mut builder = SystemBuilder::new(); - for lib in libs.into_iter() { - builder = builder.import(lib)?; - } - let sys = builder.finalize()?; - Ok(Self(sys)) - } - - pub fn type_system(&self) -> TypeSystem { self.0.as_types().clone() } - - pub fn get(&self, name: &'static str) -> SemId { - *self.0.resolve(name).unwrap_or_else(|| { - panic!("type '{name}' is absent in standard RGBContract type library") - }) - } -} - #[cfg(test)] mod test { use super::*; - #[test] - fn contract_lib_id() { - let lib = rgb_contract_stl(); - assert_eq!(lib.id().to_string(), LIB_ID_RGB_CONTRACT); - } - #[test] fn std_lib_id() { let lib = rgb_std_stl(); diff --git a/src/stl/chain.rs b/src/stl/chain.rs deleted file mode 100644 index b3d055c3..00000000 --- a/src/stl/chain.rs +++ /dev/null @@ -1,56 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 amplify::confinement::SmallBlob; -use amplify::ByteArray; -use bp::{Outpoint, Txid}; -use strict_encoding::{StrictDeserialize, StrictSerialize}; -use strict_types::StrictVal; - -use super::LIB_NAME_RGB_CONTRACT; - -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = ProofOfReserves::new(strict_dumb!(), strict_dumb!()))] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct ProofOfReserves { - pub utxo: Outpoint, - pub proof: SmallBlob, -} -impl StrictSerialize for ProofOfReserves {} -impl StrictDeserialize for ProofOfReserves {} - -impl ProofOfReserves { - pub fn new(utxo: Outpoint, proof: SmallBlob) -> ProofOfReserves { - ProofOfReserves { utxo, proof } - } - - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let utxo = value.unwrap_struct("utxo"); - let txid = Txid::from_slice_unsafe(utxo.unwrap_struct("txid").unwrap_bytes()); - let vout: u32 = utxo.unwrap_struct("vout").unwrap_uint(); - let utxo = Outpoint::new(txid, vout); - - let proof = SmallBlob::from_checked(value.unwrap_struct("proof").unwrap_bytes().into()); - - Self { utxo, proof } - } -} diff --git a/src/stl/error.rs b/src/stl/error.rs deleted file mode 100644 index 72f9767c..00000000 --- a/src/stl/error.rs +++ /dev/null @@ -1,39 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 amplify::IoError; -use baid64::Baid64ParseError; -use strict_types::{typesys, CompileError}; - -#[allow(dead_code)] -#[derive(Debug, From)] -pub(super) enum Error { - #[from(std::io::Error)] - Io(IoError), - #[from] - Baid64(Baid64ParseError), - #[from] - Compile(CompileError), - #[from] - Link1(typesys::Error), - #[from] - Link2(Vec), -} diff --git a/src/stl/mime.rs b/src/stl/mime.rs deleted file mode 100644 index 4f9c2188..00000000 --- a/src/stl/mime.rs +++ /dev/null @@ -1,214 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -#![allow(unused_braces)] - -use std::fmt::{self, Debug}; -use std::str::FromStr; - -use strict_encoding::stl::AlphaSmall; -use strict_encoding::{ - RString, RestrictedCharSet, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, -}; -use strict_types::StrictVal; - -use super::LIB_NAME_RGB_CONTRACT; - -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Hash)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct MediaType { - #[strict_type(rename = "type")] - #[cfg_attr(feature = "serde", serde(rename = "type"))] - pub ty: MediaRegName, - pub subtype: Option, - pub charset: Option, -} -impl StrictDumb for MediaType { - fn strict_dumb() -> Self { MediaType::with("text/plain") } -} -impl StrictSerialize for MediaType {} -impl StrictDeserialize for MediaType {} - -impl MediaType { - /// # Safety - /// - /// Panics is the provided string is an invalid type specifier. - pub fn with(s: &'static str) -> Self { - let (ty, subty) = s.split_once('/').expect("invalid static media type string"); - MediaType { - ty: MediaRegName::from(ty), - subtype: if subty == "*" { None } else { Some(MediaRegName::from(subty)) }, - charset: None, - } - } - - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let ty = MediaRegName::from_strict_val_unchecked(value.unwrap_struct("type")); - let subtype = value - .unwrap_struct("subtype") - .unwrap_option() - .map(MediaRegName::from_strict_val_unchecked); - let charset = value - .unwrap_struct("charset") - .unwrap_option() - .map(MediaRegName::from_strict_val_unchecked); - Self { - ty, - subtype, - charset, - } - } -} - -impl fmt::Display for MediaType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}/{}", - self.ty, - if let Some(subty) = &self.subtype { subty.to_string() } else { s!("*") } - ) - } -} - -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] -#[wrapper(Deref, Display, FromStr)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { MediaRegName::from("dumb") })] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct MediaRegName(RString); - -impl_ident_type!(MediaRegName); -impl_ident_subtype!(MediaRegName); - -impl MediaRegName { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - MediaRegName::from_str(&value.unwrap_string()).expect("invalid media reg name") - } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT, tags = repr, into_u8, try_from_u8)] -#[display(inner)] -#[repr(u8)] -#[allow(non_camel_case_types)] -pub enum MimeChar { - #[display("!")] - Excl = b'!', - #[display("#")] - Hash = b'#', - #[display("$")] - Dollar = b'$', - #[display("&")] - Amp = b'&', - #[display("+")] - Plus = b'+', - #[display("-")] - Dash = b'-', - #[display(".")] - Dot = b'.', - #[display("0")] - Zero = b'0', - #[display("1")] - One = b'1', - #[display("2")] - Two = b'2', - #[display("3")] - Three = b'3', - #[display("4")] - Four = b'4', - #[display("5")] - Five = b'5', - #[display("6")] - Six = b'6', - #[display("7")] - Seven = b'7', - #[display("8")] - Eight = b'8', - #[display("9")] - Nine = b'9', - #[display("^")] - Caret = b'^', - #[display("_")] - Lodash = b'_', - #[strict_type(dumb)] - #[display("a")] - a = b'a', - #[display("b")] - b = b'b', - #[display("c")] - c = b'c', - #[display("d")] - d = b'd', - #[display("e")] - e = b'e', - #[display("f")] - f = b'f', - #[display("g")] - g = b'g', - #[display("h")] - h = b'h', - #[display("i")] - i = b'i', - #[display("j")] - j = b'j', - #[display("k")] - k = b'k', - #[display("l")] - l = b'l', - #[display("m")] - m = b'm', - #[display("n")] - n = b'n', - #[display("o")] - o = b'o', - #[display("p")] - p = b'p', - #[display("q")] - q = b'q', - #[display("r")] - r = b'r', - #[display("s")] - s = b's', - #[display("t")] - t = b't', - #[display("u")] - u = b'u', - #[display("v")] - v = b'v', - #[display("w")] - w = b'w', - #[display("x")] - x = b'x', - #[display("y")] - y = b'y', - #[display("z")] - z = b'z', -} - -impl RestrictedCharSet for MimeChar {} diff --git a/src/stl/mod.rs b/src/stl/mod.rs deleted file mode 100644 index d2d84c82..00000000 --- a/src/stl/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -mod specs; -#[allow(clippy::module_inception)] -mod stl; -mod error; -mod mime; -mod chain; - -pub use chain::ProofOfReserves; -use error::Error; -pub use invoice::LIB_NAME_RGB_CONTRACT; -pub use mime::{MediaRegName, MediaType}; -pub use specs::{ - Article, AssetSpec, Attachment, BurnMeta, ContractSpec, ContractTerms, Details, IssueMeta, - Name, RicardianContract, Ticker, -}; -pub use stl::{ - aluvm_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, rgb_contract_stl, - rgb_logic_stl, rgb_std_stl, rgb_storage_stl, StandardTypes, LIB_ID_RGB_COMMIT, - LIB_ID_RGB_CONTRACT, LIB_ID_RGB_LOGIC, LIB_ID_RGB_STD, LIB_ID_RGB_STORAGE, -}; - -pub const LIB_NAME_RGB_STD: &str = "RGBStd"; -pub const LIB_NAME_RGB_STORAGE: &str = "RGBStorage"; diff --git a/src/stl/specs.rs b/src/stl/specs.rs deleted file mode 100644 index f51afc5d..00000000 --- a/src/stl/specs.rs +++ /dev/null @@ -1,410 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -#![allow(unused_braces)] // caused by rustc unable to understand strict_dumb - -use std::fmt::{self, Debug, Formatter}; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; - -use amplify::confinement::{Confined, NonEmptyString, SmallOrdSet, SmallString, U8}; -use amplify::Bytes32; -use invoice::Precision; -use strict_encoding::stl::{Alpha, AlphaNum, AsciiPrintable}; -use strict_encoding::{ - InvalidRString, RString, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, - StrictType, -}; -use strict_types::StrictVal; - -use super::{MediaType, ProofOfReserves, LIB_NAME_RGB_CONTRACT}; - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct BurnMeta { - pub burn_proofs: SmallOrdSet, -} -impl StrictSerialize for BurnMeta {} -impl StrictDeserialize for BurnMeta {} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct IssueMeta { - pub reserves: SmallOrdSet, -} -impl StrictSerialize for IssueMeta {} -impl StrictDeserialize for IssueMeta {} - -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] -#[wrapper(Deref, Display, FromStr)] -#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { Article::from("DUMB") })] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Article(RString); - -impl_ident_type!(Article); -impl_ident_subtype!(Article); - -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, From)] -#[wrapper(Deref, Display, FromStr)] -#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { Ticker::from("DUMB") })] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Ticker(RString); - -impl PartialEq for Ticker { - fn eq(&self, other: &Self) -> bool { - self.as_str() - .to_uppercase() - .eq(&other.as_str().to_uppercase()) - } -} - -impl Hash for Ticker { - fn hash(&self, state: &mut H) { self.as_str().to_uppercase().hash(state) } -} - -impl_ident_type!(Ticker); -impl_ident_subtype!(Ticker); - -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] -#[wrapper(Deref, Display, FromStr)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Name(RString); - -impl StrictSerialize for Name {} -impl StrictDeserialize for Name {} - -impl_ident_type!(Name); -impl_ident_subtype!(Name); - -impl Name { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - Name::from_str(&value.unwrap_string()).unwrap() - } -} - -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] -#[wrapper(Deref, Display)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Details(NonEmptyString); -impl StrictSerialize for Details {} -impl StrictDeserialize for Details {} - -impl AsRef for Details { - #[inline] - fn as_ref(&self) -> &str { self.0.as_str() } -} - -impl Details { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - Details::from_str(&value.unwrap_string()).unwrap() - } -} - -impl StrictDumb for Details { - fn strict_dumb() -> Self { - Self(Confined::try_from(s!("Dumb long description which is stupid and so on...")).unwrap()) - } -} - -impl FromStr for Details { - type Err = InvalidRString; - - fn from_str(s: &str) -> Result { - let s = Confined::try_from_iter(s.chars())?; - Ok(Self(s)) - } -} - -impl From<&'static str> for Details { - fn from(s: &'static str) -> Self { Self::from_str(s).expect("invalid details") } -} - -impl TryFrom for Details { - type Error = InvalidRString; - - fn try_from(name: String) -> Result { - let s = Confined::try_from(name)?; - Ok(Self(s)) - } -} - -impl Debug for Details { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_tuple("ContractDetails") - .field(&self.as_str()) - .finish() - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct AssetSpec { - pub ticker: Ticker, - pub name: Name, - pub details: Option

, - pub precision: Precision, -} -impl StrictSerialize for AssetSpec {} -impl StrictDeserialize for AssetSpec {} - -impl AssetSpec { - pub fn new(ticker: &'static str, name: &'static str, precision: Precision) -> AssetSpec { - AssetSpec { - ticker: Ticker::from(ticker), - name: Name::from(name), - details: None, - precision, - } - } - - pub fn with( - ticker: &str, - name: &str, - precision: Precision, - details: Option<&str>, - ) -> Result { - Ok(AssetSpec { - ticker: Ticker::try_from(ticker.to_owned())?, - name: Name::try_from(name.to_owned())?, - details: details.map(Details::from_str).transpose()?, - precision, - }) - } - - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let ticker = value.unwrap_struct("ticker").unwrap_string(); - let name = value.unwrap_struct("name").unwrap_string(); - let details = value - .unwrap_struct("details") - .unwrap_option() - .map(StrictVal::unwrap_string); - let precision = value.unwrap_struct("precision").unwrap_enum(); - Self { - ticker: Ticker::from_str(&ticker).expect("invalid asset ticker"), - name: Name::from_str(&name).expect("invalid asset name"), - details: details - .as_deref() - .map(Details::from_str) - .transpose() - .expect("invalid asset details"), - precision, - } - } - - pub fn ticker(&self) -> &str { self.ticker.as_str() } - - pub fn name(&self) -> &str { self.name.as_str() } - - pub fn details(&self) -> Option<&str> { self.details.as_ref().map(|d| d.as_str()) } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ContractSpec { - pub article: Option
, - pub name: Name, - pub details: Option
, - pub precision: Precision, -} -impl StrictSerialize for ContractSpec {} -impl StrictDeserialize for ContractSpec {} - -impl ContractSpec { - pub fn new(name: &'static str, precision: Precision) -> ContractSpec { - ContractSpec { - article: None, - name: Name::from(name), - details: None, - precision, - } - } - - pub fn with( - article: &str, - name: &str, - precision: Precision, - details: Option<&str>, - ) -> Result { - Ok(ContractSpec { - article: Some(Article::try_from(article.to_owned())?), - name: Name::try_from(name.to_owned())?, - details: details.map(Details::from_str).transpose()?, - precision, - }) - } - - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let article = value.unwrap_struct("article").unwrap_option(); - let name = value.unwrap_struct("name").unwrap_string(); - let details = value - .unwrap_struct("details") - .unwrap_option() - .map(StrictVal::unwrap_string); - let precision = value.unwrap_struct("precision").unwrap_enum(); - Self { - article: article.map(|val| { - Article::from_str(&val.unwrap_string()).expect("invalid contract article") - }), - name: Name::from_str(&name).expect("invalid contract name"), - details: details - .as_deref() - .map(Details::from_str) - .transpose() - .expect("invalid contract details"), - precision, - } - } - - pub fn article(&self) -> Option<&str> { self.article.as_ref().map(|a| a.as_str()) } - - pub fn name(&self) -> &str { self.name.as_str() } - - pub fn details(&self) -> Option<&str> { self.details.as_ref().map(|d| d.as_str()) } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Default)] -#[display(inner)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct RicardianContract(SmallString); -impl StrictSerialize for RicardianContract {} -impl StrictDeserialize for RicardianContract {} - -impl AsRef for RicardianContract { - #[inline] - fn as_ref(&self) -> &str { self.0.as_str() } -} - -impl FromStr for RicardianContract { - type Err = InvalidRString; - - fn from_str(s: &str) -> Result { - let s = Confined::try_from_iter(s.chars())?; - Ok(Self(s)) - } -} - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Attachment { - #[strict_type(rename = "type")] - #[cfg_attr(feature = "serde", serde(rename = "type"))] - pub ty: MediaType, - pub digest: Bytes32, -} -impl StrictSerialize for Attachment {} -impl StrictDeserialize for Attachment {} - -impl Attachment { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let ty = MediaType::from_strict_val_unchecked(value.unwrap_struct("type")); - let digest = value - .unwrap_struct("digest") - .unwrap_bytes() - .try_into() - .expect("invalid digest"); - Self { ty, digest } - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ContractTerms { - pub text: RicardianContract, - pub media: Option, -} -impl StrictSerialize for ContractTerms {} -impl StrictDeserialize for ContractTerms {} - -impl ContractTerms { - pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { - let text = RicardianContract::from_str(&value.unwrap_struct("text").unwrap_string()) - .expect("invalid text"); - let media = value - .unwrap_struct("media") - .unwrap_option() - .map(Attachment::from_strict_val_unchecked); - Self { text, media } - } -} diff --git a/stl/RGBContract@0.11.0.sta b/stl/RGBContract@0.11.0.sta deleted file mode 100644 index 50e247d3..00000000 --- a/stl/RGBContract@0.11.0.sta +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN STRICT TYPE LIB----- -Id: stl:!r5yXt4a-v3XXv0M-E9Z6eoh-BFZweik-fxS6CB4-8AaO!MM#rover-annual-disney -Name: RGBContract -Dependencies: - Std#ralph-blue-lucky, - Bitcoin#signal-color-cipher -Check-SHA256: 6347d5f0a4c36a074fd3b6abb98041f64798a4a233e1742a352edc330dddbf3d - -3sOfyLvL<$a$#e10?I5NZ-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCj(P-Wc6$lVk7oBr%DNv+($;q -`HHK!gIHa)*%m(-e#9sm3I{@IbYpL6ZUP5FX>?<6X>J1mA>%$n#j0HLDJN5-IKgM_J7b(p+0MPGk2Gl) -y2(Rz1Xgc#bfbbo^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1Rs>XdX=LbXK+Rkw`Mu(V|7oQWGN(Z+ -AyvH&RuaL#N1_Q*>km07$+g7b@t4MVjY>G@u4Q3HlB(d+LiLJm-R=h;`?dxDG*c -V`*tna%paKVPb4$UtT8V#RWVYMMP0s#-L?ApehHE`!Nx1aisd$7U5G>2tjOcXkkuuZGt0!^mXvL0b>G|!UaKWaA;xq7YGF1t^|4b)vt7`JJJH?>OpeZskt`?6&l-r#0;SdL2Phn -VN-2kY-|(&3PEgaZ)0I}X>V=?0s&*k#ka7f`< -Z^7s3P_GJP!FFFM4E? -M+l67UG^w8*<_XZ#%uyqCxRn@^mXvL0b>G|!T<;Y$}AplgPGkh3_fq3 -Q7_j=2#kPT_9!;lWR>~GYywm#UtT8V#RWVYMMP0s#-L?ApehHE`!Nx1aisd$7U5G>00000000009{>OV -000002|;snWpq<;Wn%^e26Sm-Yh`i)TX!suv0v9m0LPL+_79KRH|I99{YEOV7tT#ZPWpkW1a4t%WdVR* -#k^Az$U%@qU7>2Bz={du0O&G0&#r1CLJBFZ06hm}WprU_Y;ynv0ssVVZ*FA(00035b8l^B00jX7KPz&# -#IG7-47St%2#c>Z5R>jkTb_MKDq#SE1Nsg8a>I`c#0nSFF19TD^=GS9xE -uuG0V@n0eeL3DIsV`yzV!Z000000RR600000001QKKZgg^CV{}t+Wn%^e2Vrt_X=7|<00aU61a5C`WdHyG0R(ezZDjxj0ReXZ -@I5NQHT;&p7LREnfs~VQpmrfL_JCQxeEQkVIXfYN5c23F83hGCI$$Y9m4l -DXjoK2V`Y*VQFl000aU61a5C`WdHyG0R(ezZDjxj0RcZNa<{~<8ep?nYaleMc%`0D|O6 -*W?Lsa%E#_b7^mG0bK*c7mcZoem^?%L*to!bRZoO^d~aUzM`;8jz95VA`L@tZgg^CV{}wya&2=40t9qr -cys|6%am^tlg}6qop{{FTg974FaQ3n`}K{nn9PGH_DcZ;ZDnL>VE_aI00eGtZe;)f009JZZ*64&1pxs= -s(;1y^<+=wqOM*VsgOd=>xYy=<4kft^@4w~Gv0~^L}hegX>4-^0RRX90RaF2000000RI300000000~KR -b9H4+WprT%0SIzsb7gXNWpe-t0S?j{I~j%e^V!Z000000RR60 -0000001QoKWNBeiWoJ%dZDj=k00ja9$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#`4m;t2@#H=ITLm*{QiV2NfFIf5Z%-00;p*(W0Hqt(%d1CNN)#sHFQL7%(bMbH%I*cn#*O0A6zd00000 -0000#0000000009O=VnH0sEektM3d!V}qV`yP= -b7gb@1OfmAZf|a7000011aog~WdH>M0UWS(jugTGj1K^e=F-$2o*6gc%@3Ir#hQL8;m&)Yy9iBbZDm7f -VR8d41Z8+*Y#{__VRL9B24rt+Y+-UF17U4&CIoP7b#p5OWMOk?Edyk4bS?yXWpZyY18;6+F#~jWZ!!gR -XmVv`GX!RDb#gQWW@&b1H3M^Lcs2!dWp-t5Hw9&BXJ~Xd1a4_=WjO_7VRB`3UIuJ$WMOk?UjboZ0b*hS -V`BkiWC3Mm0cK_aXJ-LuXaQ+y0cvUiYij{)YyoX;0d8&qZ*Ku`Z~<{~0djHyb8`W7bOCjB0d{r)cXt7J -cma8N0eX4_PGN0j1pxpB0s_h`9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3}KjBNr;@ghiU?gEXK9 -KMDE{F?;HZBRuDVqlk6qmbd^20?I5NZ-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCrG{{7b@t4MVjY> -G@u4Q3HlB(d+LiLJm-R=h;`?dxBvhE0000004D$d0000001Z!fZe?Ufa$#e1X>V=?0RR992~cunV`+0~ -Z*Bt<3u$g-X?AIIX<}?;00d-ZV`%{eV`Xl1X#xdpX>4q10|{hhV`)ukY;0)+3S(t%bZJd#Y;0)-1#M|# -a&HC+WMyM%O=)9tZwCrvWo~q7O=)9tZwLf#VQy~;2xMhrX-;8oZwd)xWo~q7PGN3u3j}a!V{Z%yWMyM% -P-$at4GCjqZggo-X=85=1!iS!bZ-v{WMyM%MrCbuZx9M&Wo~q7MrCbuZxIAxbaZbL4^VP%Z)Q(sQe|^x -a&~2N1_A_iba-z9^=uPjBlbC`N(qzPM@Gr{imSMTSY5T*7C#t%#3&jH=xRXCTqXIv;)MTcr4cfxK`S9u -y$)6q!N22#m0-mN1#oh2Z)N}p002M$0000000030{{R300000HQfXsha%5>?ZbNTwbaG*1bOiwb2mk>9 -0000000030{{R3000006RB2;tWpV`p00ja9$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#f+K+R -b@1)9wcJs8k=}EVt)knrbu3HL<`ZBK}4mD(Ht7Eb~PSIG^Pk1R1r{!lqsV^M5AQ(;7`h`rTmdf|Cw**^?URB z9pCFAOJk#=Sw`S+LXcgWG@32hb!Up(e0E>TH3V`pqVY?_P+D9EG%{QItTi6eAk|a>T!Vezf)Q%16P0 zsRw2?nwcWIau+nN9N%~5w+;Q&7hYk9v=jZ8o$*NbZup^n!}e8Hg(^uDjMC2q zo2MuecQ(K$q-(>X-JK=VD;1IIXC716+}{*1x3l=b$71J>(;ix$pr~X{Qoyrmn3Xx< zt`(d6=AwluE6!KKd6gl`EzhTV8S)Q4YZ=j&x=f{|je0y$G!zG{e0Gt4K%q6TA|qe`K~zdDCr|_pr58-* zGRLmYhNxVca1}?yxyCr3YAw%0A=L;81*(u-&4V0RQ81~zE~_~fx$vpB*K_mD@Xnbh zUc`hP_qm#|DDl|`hfxMMK(Id3`hBYRkJ^fb8T)hh*Kbs}BVA#0nvUiML}`L+k$FlI z3OGgc2r5HRhGn4iM}YFI0U{UxkrTO7mScW|+t)w$t2P~*F?8!6F)Q}1jSaz(;*Q15 z9cm*735u6e0y5+lpR(%mqR2UqquY0_6~>P8dJ-7cbhheve0k)bS#N8!f`Aix17rk+ z3>6BE5Y)N1zFa@H_Secws$l=*n!33u38vN*eZ$3ktg0wSw@N`$Igl3+C4wv%i>RVR zj!BTbRRB%41d}l!V z`}-ZpZJ?VS@l@iD%Fzf*JH2w_W2doJ+YJfU)DbFDXZIgr6i~~9$*GYQuwO_ z5Pf)^wYP^%x?6QL)33TBsEPH!2r83P|c56#}GgvM*<-5%pr8 z7oj6-Dh~3HGr`x&S%S^Or7$N^D(bi+V zk+&YvnBDKyAep@LFi4~msO?^)NwuqxJ4*Pi<6`;nb4aNtQhM+DjnVr?hPO3(?iz00 zT@>7Qbxq}WN?y#i)%vSr>r$K0OOy zjvI^5Jg}zfr0{HHiN=KuzEE*_{_T+YJ(tXmnNJQ5$Jrn zClxS|jIrGjZ1c%BRMg1>+$bM5gkng_BoU=FLlKmeI1^xm#DtU#Gf*^5$;gN+Bq_nM3a3 - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -@context -typelib RGBContract - -import Std#ralph-blue-lucky - use AsciiPrintable#ultra-sunset-format - use AlphaNum#window-tractor-alamo - use Alpha#citizen-bicycle-stretch - use AlphaSmall#magnum-martin-soviet - -import Bitcoin#signal-color-cipher - use Vout#brush-gloria-heroic - use Txid#shallow-light-reverse - use Outpoint#logo-alamo-madam - - -@mnemonic(blonde-slang-mobile) -data Allocation : TokenIndex, OwnedFraction - -@mnemonic(monica-tornado-page) -data Amount : U64 - -@mnemonic(infant-father-exhibit) -data Article : Std.Alpha, [Std.AlphaNum ^ ..0x1f] - -@mnemonic(alaska-archive-mailbox) -data AssetSpec : ticker Ticker - , name Name - , details Details? - , precision Precision - -@mnemonic(mono-bagel-falcon) -data Attachment : type MediaType, digest [Byte ^ 32] - -@mnemonic(ivory-speed-finish) -data BurnMeta : burnProofs {ProofOfReserves} - -@mnemonic(hawaii-winter-orca) -data ContractSpec : article Article? - , name Name - , details Details? - , precision Precision - -@mnemonic(voodoo-toga-meaning) -data ContractTerms : text RicardianContract, media Attachment? - -@mnemonic(trivial-halt-nobody) -data Details : [Unicode ^ 1..0xff] - -@mnemonic(alias-analog-icon) -data IssueMeta : reserves {ProofOfReserves} - -@mnemonic(taboo-pogo-exile) -data MediaRegName : Std.AlphaSmall, [MimeChar ^ ..0x3f] - -@mnemonic(brother-burma-book) -data MediaType : type MediaRegName - , subtype MediaRegName? - , charset MediaRegName? - -@mnemonic(amber-alarm-satire) -data MimeChar : excl#33 | hash#35 | dollar | amp#38 - | plus#43 | dash#45 | dot | zero#48 - | one | two | three | four - | five | six | seven | eight - | nine | caret#94 | lodash | a#97 - | b | c | d | e - | f | g | h | i - | j | k | l | m - | n | o | p | q - | r | s | t | u - | v | w | x | y - | z - - -@mnemonic(lexicon-monitor-madonna) -data Name : Std.AsciiPrintable, [Std.AsciiPrintable ^ ..0x27] - -@mnemonic(mission-person-armor) -data OwnedFraction : U64 - -@mnemonic(vendor-anita-british) -data Precision : indivisible | deci | centi | milli - | deciMilli | centiMilli | micro | deciMicro - | centiMicro | nano | deciNano | centiNano - | pico | deciPico | centiPico | femto - | deciFemto | centiFemto | atto - - -@mnemonic(harmony-dolby-golf) -data ProofOfReserves : utxo Bitcoin.Outpoint, proof [Byte] - -@mnemonic(bernard-right-pablo) -data RicardianContract : [Unicode] - -@mnemonic(newton-corona-aloha) -data Ticker : Std.Alpha, [Std.AlphaNum ^ ..0x7] - -@mnemonic(giraffe-correct-modest) -data TokenIndex : U32 - - diff --git a/stl/RGBStd@0.11.0.sta b/stl/RGBStd@0.11.0.sta index 5c9d924c..f1d81936 100644 --- a/stl/RGBStd@0.11.0.sta +++ b/stl/RGBStd@0.11.0.sta @@ -1,20 +1,20 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:JhUC5JgH-Kwps4cO-ZNUklUj-UP6boFp-OY!18Kx-xOSJaVQ#hair-magnum-helena +Id: stl:vdvotNKl-wGrtjuT-Q4qXt4U-UVQlDMB-ONCuwLd-ORBWRTw#zebra-twist-tango Name: RGBStd Dependencies: - RGBCommit#harvest-person-orion, StrictTypes#century-comrade-chess, BPCore#austin-story-retro, AluVM#congo-archive-folio, CommitVerify#miller-pancake-elastic, + RGBCommit#printer-window-alpine, Std#ralph-blue-lucky, Bitcoin#signal-color-cipher -Check-SHA256: 6a9228bc3dd61ed396d19a0d3e71c3a3dfc999d232e57ec13c1488bb0b6eeb91 +Check-SHA256: 9c8622031666c98c3fbaacf4d05380087e07145e9901c83988c8071f09cd9cca -22w{tQ*>kpAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{j2~tNwLvL+uX>>*EqhH(h&*4NaBbD49mT$3z|G4nQgoFBhHh%l@K06L}1!AJ%| -P(yEWWnyqOe<9`Lptgpr6F_xjAC6(~TLj#*ewiHU&X!byiJ!10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUDXLvL+uX>?X)a%pCH$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#15kpMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD*X=8L$d2nTORuk6O)Q5AKbFW;J +EQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pZ~a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjHL2Pwa +O?m?z-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCJaMwZEb0ER%LQ&W_hoT#`k1y;WQvCHXeDDEB)y- +4aXJJr*xW72o5QK9=-`uM?ynyZEb0E$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#15DT%6aZ| SrJerP1pIOD57`7Ol|-ogQ6Pjg~y>s-v>!^VNPLfWv4Jz0xkJm$nc4yMWR2J-cc#Q6SofWC)gp7L6!Sc @@ -43,239 +43,228 @@ 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 -Z0H=mhJ>?uV^xB4~9n`Dx!RtcK)nwJGn -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 -wgM1*ibOB -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 -&Z4!V_T!KN -I`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+pa{vhfMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{ -AMw{vgzX#P!9p!}0yp?_0000000000{{R300000024!+`Z*p@02?9mxqhH(hNn`*70ssVVZ*FA(00035b8l^B00jX8Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C -`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj2y$g{b!l>CWCF@89&dx0-7pM3Z=O*v*GCA9 -fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v=XJ?|;InIPy66cFfOYp#JM2r7_Du+Fb!>ELaBO7)$}AplgPGkh -3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#VTK~nd#>Z4!V_T!KNI`QJ|h6;Zj -^jB$MPK+?7Lu3>C`4HJt76^nC$%1sKzB<;EQA|)S-x88IWKN#S$#@T&w`gPtX>Mp`a%psP00;p)%D{mG -2;nQMTOnwNgyXhzrB~SH04;UKo5i(1Vxw^Y00000000300000000009bZKp6b97;CZ~y>E2yJC_VPs)+ -VE_sOMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!} -0yp?_0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*=q!&6rQG)02XJT?*g=|B=zREie$*y(7k2+ -*P~cYjQ{`u000000RI300000001IbqZ(?C=Q*>c;WdI5SMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C -`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0m=yGke?j1l!xqXd>q7+-P0pRHy9#PwIC -`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0ZXaKh^f@$D{A?t{IfX>#}PNp!L%7{0GY9x -pq!KXGXMYp000000RI3000000010+sY-Mg^X=QT&3IavyqhH(hb7^w{b?qhoJW!8=sKG~^&Ni^C7tcO}co=3CQC(GPVoWSC3v_Z} -ZgXjLX>V?G015&{>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+p< -?Hl01LM?X!H~4Y^Hx3&bJ$HXE2K+s|vHZ6#&ske5?JSDZAfr}PGrQJ;0000000000{{R30000003T1e7 -Wo~n6Z*Fq{3IavyqhH(hD`aAk5~bZKvH00aU61a5C`WdHyG0R(ezZDjxj0RlzpqhH(hC`}q*r35LOoBKkGaY9#cS7Qj{WgyAGcS>>g~&^g7bS0}9Zh)e@p#+${pKVqYC33O>~Wpi|4ZEyepNC<6ZbYWy+bYTDq0lk5UVp0y6#Opn49V(cQc;WdI2QadI6-(bd|-i#!&GYaF>qoh8ar -da{vheR)?jU+FZ2DLr`QR#xHIKjC^A48Li8o -%k$8HEod=_0000000000{{R30000003v_Z}ZgXjLX>V?G00{v&KD$)QXhhr5^*YH=BF-=c -yOsxg-v9sr000000RI300000000w1pa&K~T00{xZXXT7NJOW`Spw3o_*cmz+=1%_1gm*5-D79nn{HtC7 -00000000300000000009WMy_`Y;SO7asnV%C#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i_RFfQB3> -bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7cFHZE$Q!WCZ~L2LJ#-AOHhPX>#x3$o4Af`kVHyQ&~TYC -SRqgV00000000300000000008b7N>_ZDDj_00{yhS0}9Zh)e@ite$I%(jAWg00000000300000000006X=!b6Y;yn!0fbj(2M`|< -m3T|4oDcSEr%ah$$XqR+hQ$77qvA$o%>V!Z000000RI300000001I<Z4!V_T!KNI`QJ|h6;Zj -^jB$MPK+?7Lu3>C`4HLtfv$so3kRF1PV2}fOp_vjQ6FdFHId|lr&gK9B00000 -0096000000000VeX=iR>bairNa{vkf;?xyT5z&Ua+M@}mOiDpYxh>^^GknUxTJ!XL#OUcE0frb5ENEw7 -&f?o%+)B!ZpG}K!%4G?I4vp$|ttu*CMF0Q*000000RI300000000>QQWNBt;WpV=p2w`G#baG*1bN~o% -c4cyMX=G&q1!ie(VQl{xPGN0jWJYOaY-B-mb7^O8ZDnqBRC#b^1_J_VWC9>pC#?5~OapN(_Fs6GvFQy{ -P|gRa2*}s1Y~I%9#i@t>;$>KfZ0H=mhJ>?uVC`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_2y$g}WpZ|9WCD5v -9p7nv%krpqNFdAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jWOW`w -sTH9-LlJ`2|Ay5Z(?oEikl{+~pis;@Q*TJ#1a4t%WdcR&qhH(he1kloHngE|MP08BSqsWn@NaWo%?eY;R&=Y*Tb$ -bY)a|aAgJq0%>FdAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{j)$WoGNre1kloHngE|MP05>8=lWn@NaWo%?kWprUwd2nS00|IGe0w7l>toMja192_( -UwD?W=?zm*&IhOn$k(lG-qz;DsdeN{_}|Wp0vpvv$c&#PW69R$ltr%da5t5w^x+8!q6BVXZDj&Q>Z4!V -_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+pFdAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c -*5<{jG*S<)6P6lYy(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(11a4t%WdcR&qhH(hR6Lh9EroO>_{O=WapR$**)WfhrcWXrXy +KnGOwA#t$mH2bG7pQ)aE=^FQF!@KkQhzLn;aCLM|VQ?5o)zidWvABmX&uCxQ{9vUAsn@)h(<^=)@3p(i +4FwHHWo~72X>(I!Xk~3-9zxS>Jw1!&_U?o#2Tebz`mr;62_Hls_?@=CN?W&A7(sJ$X=iS2Wo~qHLTqVn +WK(5fY*ct@WFNs;Mn8g^E-G}MMdwWnpYo +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 +_Du+KWpQ~GYywm#VTK~nd#>D0(t`--)Viz +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 +qhH(hC`}q*r35LOoBKkGa +Y9#cS7Qj{WgyAGcS>>g~&^g7C`}q*r8?;yf@?frQ$owe+rTo-{ +AMw{vgzX#P!9p!}0yp?_3`b>dWpinBNoHYVWd;TaZEs|0W@%+|0hAo?WyWV%Bqkq0>u^7-u;qAzHYrYi +ZOnAva3v<@st9dmbYWy+bYTDq0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs7 +0;T-agdg$OP=xIp;K4#IcLF!~asU7T000000RI300000000(DmZ(?C=a{vkgMe3tp+xFv-0Xp&G?S=|} +9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0>gzBa)$q57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI3000000 +01IJrb7^O8ZDnqBa{vkgMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{ +AMw{vgzX#P!9p!}0yp?_0>gzBa)$q57bK6Q|uUfIMEX +^1}Vv6tLB!)|10-o)0prc>n+a000000RI3000000010+sY-Mg^X=QT&2?9mxqhH(hC`}q*r35LOoBKkGaY9#cS7Qj{WgyAGcS>>g~ +&^g7ioJpYH;+t0eX2w~A!Q+0eaZ{MVyc +PK^k1WpQ~GYywm#VTK~nd#>yWpZgcQkwbf~^M){{|8P%hsR +k~m~ep32F151Y4WWC&?)Xk~I~baMa*0XxdTfddHPE2~=}XorO3wsWOd*yR8%b;g^;wLfB`aR2}S00000 +0RI3000000010$yZDn(GVQp{#07wXJWprU=VRT^t3IavyqhH(hZ4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C +`4HJ_1fvw5rj-B|XP@r^w5ufb=C_Ju$l1`nW&GEpSWb-q0000000030000000000BXKZg`VQf=$VRU5x +3IavyqhH(h}`A;#FO3ABStqEB2u*`(KJ8e4#|W70000000030000000000BVRLh7XKrm}Zgg`1 +3IavyqhH(ha{vkg +Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_ +0X}Q-^^?(m0E0zBOZWn(@&jfq2YNoZ;ZAl)>;YPDKL7v#000000RI300000000(DfZe??6a{+bjCH_26 +kAtYeN1V@6CZgT(%0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_ +Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~asf9E8yY=#e=i37J-o5}w=U0FTPy7> +iqjyYR#Y>))`9>4000000093000000000VQcywiMb7^mGa{vkgMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uM +rbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0XSPta$W&i*H000000RI300000001#wlW?^+~bWd<)a$$67Z*Bkt0ssVVZ*FA(00035b8l^B00jX8 +Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_ +24!+`Z*p@03IavyqhH(h>gzP9Lqh8!q$B6|*YuiTY;OURW8#d%1{rxIXtTaY^?oCir}VPj=U +WCZ~L2LJ#-AOHzTW?^GxNo{a!1`P*xWpZ_ZDC1d0>gzLZka+XJhss8OG%_CC-Q>(otsF+cqN +0Qy}ddQ=3E5C>^yVPj=UWC1(Mz<~n@;VY|KA!vt$qMEp^75#kD_Tqj3pzX>Db5bYX39002k` +ZDn*}WMOn+00{xTfrw&K4w%I2J!>5*n2+UEn$VY06ag%An>_FbOoG7x0000000030000000000BXKZg` +VQf=$VRU5x2?23(9Y)dB+Qf@I7Kdvbxk#NQ%2Ip^oEeXABZ7(pf`tG8000000093000000000YNb8~5D +Zf#|5baMa+0huBwu~C-QVH212O0vm-vwNnjOqUO({d!Yj6^~`qZ~y=R000000RI3000000010+sY-Mg^ +X=QT&2?17zrJCAYw97+KWFy8eZUu~dV(l5N%b&~h(10yyF^B*F000000093000000000Yga$#@6C +ZgT($0XROpRQe`%bQtg9OuU(MB+3^mE|~AfiD0OzeAWk8kN^Mx000000RI3000000019PzbY*UHX>V?G +00{wU#AUTvyg$3{N++IppJQl5+tKwp$xtHBFa^7o2YcTD00000000300000000006WpZ+Fa&rI)0mEnI +j6FO8VJD!@R*BddIvVCq{>+4TF2^XfWAFT{UH||9000000RI3000000010Gec4cgDaAk4=uZ_m{WNzU! +AS*T=d6X;t=`;<;71O75notN1DSsZmw&;L{94K`ndk%K5+?9Jv$dw7jc}U5p5@2#$kUJ%u2y=8{bY($e +X#uslLXEmL6-F5v>3G|uUigF$Iw^!m+g!OaP0#x3$o4Af` +kVHyQ&~TYCSRqgV00000000300000000008b7N>_ZDDj_00{!GjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQr +PzVkwe;&S;{P@Z4!V_T!KN +I`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HLtfv$so3kRF1PV2}fOp_vjQ6FdFHId|lr +&gK9B000000096000000000VeX=iR>bairNa{vkf;?xyT5z&Ua+M@}mOiDpYxh>^^GknUxTJ!XL#OUcE +0frb5ENEw7&f?o%+)B!ZpG}K!%4G?I4vp$|ttu*CMF0Q*000000RI300000000>QQWNBt;WpV=p2w`G# +baG*1bN~o%c4cyMX=G&q1!ie(VQl{xPGN0jWJYOaY-B-mb7^O8ZDnqBRC#b^1_J_VWCE{^#`k1y;WQvC +HXeDDEB)y-4aXJJr*xW72o5QK9=?bE;$>KfZ0H=mhJ>?uVC`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_2y$g} +WpZ|9WCD5v9p7nv%krpqNFduZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1 +DSsZmWOW`wsTH9-LlJ`2|Ay5Z(?oEikl{+~pis;@Q*TJ#1a4t%WdcR&qhH(he1kloHngE|MP06;5GoWn@NaWo%?t -VQgh?V|i40aAgJq0%>FdAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jM(yUq2ps*m=2xUDT;RqC -gn#@WzFu~@adfH5^@&-|1a4t%WdcR&qhH(he1kloHngE|MP04o+chWn@-ia%o|1bagle0|IGe00035ZeeX@0!8Yh -U)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*$IZhiz50p(P||0m=?fQ^Mv6fMp@;h#Lzj#&aRFSj|g&Q -b7gXNWn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG -64wDPk{-(nPj_x*WJzXWV`T&e00Uuec>n+a0S0nuXJ~YD0000224QV)b#8P30009AVQzUuVRT^t000CD -VQzUrbaY{3XaE2J1q5VabYTDm0RlzpqhH(hioJ -pYH;+t0eX2w~A!Q+0eaZ{MVycPK^psbz)a(bZ%vHa|8ka1ax?5WB>&L0`+VYVk7oBr%DNv+($;q`HHK! -gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1RsjNZcmM?f0`+VYVk7oBr%DNv -+($;q`HHK!gIHa)*%m(-e#9sm3dMUNn!oosZgNI|twmNZeC(lYZa*g7-2eQ3Yy;-pL1po(RWoBV@Y;*ts009Pc +6&DQwR5(-fxrUo0The1kloHngE|MP08BSqsWn@NaWo%?e +Y;R&=Y*Tb$bY)a|aAgJq0%>FduZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm)$WoGNre1kloHngE|MP05>8=lWn@NaWo%?kWprUwd2nS00|IGe0>gzIEhH_}|Wp0vpvv$c&#PW69R$ltr%da5t5w^x+8!q6BVX +ZDj&Q>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+pFduZ_m{WNzU!AS*T=d6X;t=`;<; +71O75notN1DSsZmG*S<)6P6lYy(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(11a4t%WdcR&qhH(he1kloHngE|MP06;5Go +Wn@NaWo%?tVQgh?V|i40aAgJq0%>FduZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmM(yUq2ps*m +=2xUDT;RqCgn#@WzFu~@adfH5^@&-|1a4t%WdcR&qhH(he1kloHngE|MP04o+chWn@-ia%o|1bagle0|IGe00035 +ZeeX@0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*$IZhiz50p(P||0m=?fQ^Mv6fMp@;h#Lzj# +&aRFSj|g&Qb7gXNWn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5w +S6(#;{6ajG64wDPk{-(nPj_x*WJzXWV`T&e00Uuec>n+a0S0nuXJ~YD0000224QV)b#8P30009AVQzUu +VRT^t000CDVQzUrbaY{3XaE2J1q5VabYTDm0RlzpqhH(hioJpYH;+t0eX2w~A!Q+0eaZ{MVycPK^psbz)a(bZ%vHa|8ka1ax?5WB>&L0`+VYVk7oBr%DNv ++($;q`HHK!gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1RsjNZcmM?f0`+VY +Vk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3dMUNn!oosZgNI|twmNZeC(lYZa*g7-2eQ3Yy;-pLpZg6#U0%CAAe<9`Lptgpr6F_xjAC6(~TLj#*ewiHf`^rCgHqw;r~cW`-QaCLM7VsJHo +A?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@3^Lq|9zft}OB~jx>)hO73S(hx +V^4K-aCLM7VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@3^Lq|9zft} +OB~jx>)hO73S(hxV?$_RZf9izVsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*w +g~2q@3^Lq|9zft}OB~jx>)hO72UB%$aBN9r1pxpD002NB00~odaByr%bY*P>1po(RWoBV@Y;*ts009Pc d2nS;ZvX`W0006J2y}UHWlmvjWdH>M0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*;5t>gcQkw bf~^M){{|8P%hsRk~m~ep32F151Y4WWD*HxX=Q9=PGN0j00jX8Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uM rbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_6AN}>a%o|1bWUMyWdH>M0!8YhU)%QM @@ -284,19 +273,19 @@ VQ>Wj015$yz}|oy`cC#6Uw2{wE+Sw~);*uMH+9Bf@aCY-RuiZDn*}0S0GmZ(?C=0tIh(Ze?Tx 2XWo~161PWnub7^O8ZDnqB1qWwkZe??6a|Q}@a$#@6CZU+fvcywiMb7^mG2nl6)V`Xr3X>V=` 3R87(aBO95Wo~o^1PNnrZggdCbV+0Z2AHk4+Bm{3x%H=p>4!*u&n~Wpi|4 -ZEyepNC#tbWnpx0asnV%C#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i_RFfQB3>bs~EXcCXx(drQcb +ZEyepNC#tbWnpx0assc7#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=^8dfQB3>bs~EXcCXx(drQcb 3B`Fx$)^%va$Ar)C7cUkZfdKHyBH|__hx_vscRWAu^w2r{b^x;wDWyGXd29 kG60)seH8)H{-R`;$q)jqasX>@6CZb@cgV`T;j 2yJg~GYywm#VTK~nd#>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_ 0000000000{{R30000002WM<=Vqt7^015&{>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1 -V6JV*{3!yZ{M3XW@z+p_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jHo-KZ +V6JV*{3!yZ{M3XW@z+pGEG0000000000{{R300000025D|^b#!w83IavyqhH(hfc^lq>z|G!4fU)2DQrPzVkwe;&Rz!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4rGOBq10000000030 000000000BVRLh7XKrm}Zgg`13IavyqhH(hfc^lq>z|G!4fU)2DQrPzVkwe;&Rz!8D=zpn(&o -7tVWUa<1Q{n`|;)uYyv!)~4rGOBq100000000300000000009c42H~ZewX>a{vhfMe3tp+xFv-0Xp&G ?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0000000000{{R30 0000024!+`Z*p@02?9mxqhH(huJC38-{*D7fZ(%hZo23R4S;p`Q9JBQllDyoR%LQdZvz4Xb}#?}b}<1BS7~%^Wpi^vb#7#AWd;HY -aCKr=X>@L7b8`Y9S0}9Zh)e@zVQyn+Z*pa1LUnFrY-Mu+hzwODL;*@eYE_8FVm19wjO(ZbIvDI)B0PALl`~a8 +aCKr=X>@L7b8`Z(jmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&T7wrKJIUBJXnP(l%Y$cDDuY1Bm# +?@QxYCjWldxIc>zVQyn+Z*pa1LUnFrY-Mu+fFLn>K7eW<<9zC -----END STRICT TYPE LIB----- diff --git a/stl/RGBStd@0.11.0.stl b/stl/RGBStd@0.11.0.stl index aa9bc8cd62d4d4adf1cd9f0232c7acd89251db46..f341116026f0a76ec56b6e9ce2b2b6d8f2c80c94 100644 GIT binary patch delta 3337 zcmeHJX;4#F7$reM76Jr_ngGd*ppvi@5F*5|2m!JoOfFQ zVxkyu$znNJLx&o)Y(s=Ia7V8O&(K?G6u)+fmsjDFks&3+FvREBSi^#i7%GRV-FK>W zY4qupvq2bcW~^99Js%b5lU?D&knewZj7D~USZneqgl3^pBAv)?>cgkWysT7_aIs7# zPL#_0Bx0$MD-uX}nPKuY+vTcl4jHZ3RXJbYZcwg{H0O7}x^+dh+b?`D&n=Ir4?=Nd zAjUYd919I12q&@5u{SOZAyva+FYC&@X4!NUScee?N_wl#kp5v0u@D4cqZt7^h;A&D zL`7`bmGZ>QDaYZSp8T+Ju$j2>w*Fa%hIC9ord%YIiBqH?)dvFkI3xR|U8S}Y=9%mT z2d@pflExhc>(iHRiyigY9@Xqileyw>L6Vd>frKj;$iYjTo3pYDbMsIs$&ju5GaPyF zH{D9WS?0{#upcwEjw6r@fXX-)w6P$t+9U}eOqb8!J)ymG>_ux} z<_1J(X6%;wZ1bX{F_C)V%SK(p3DH>!)Z5)cP3>u4569JK40Nq*I8bp4dUAic1NM(y z<3~EZmlgJIW{h1sY5=NDV-*c&`YA~hxCIA`8uhJLK-nkfI&UqVQ=;KjXhKZlyz>o% zL{gDVENk*j2=~90;^^qShI!<5p4B(bi((^uzo>N`;56qtJ*JqyQT#o@#loiZMK-_h zF}l2M=yKKes-(v83w7Vm(5q}kuldYZ6IYpx<)xtoIvwPbO1KcXj&1F}H#k3qy<9h9 zR?|#WmuiezjcsE?I~ZMx@P>g}lF=I#A_bCkkqp!kBEfnyTkx}4G~k=l-8BgY*V`W* zuk~hL-aK07P>%0u%c99csR7 zby3F68(x^N!K(^-EBM}Jro6Ow=k!aL3MC?ao$b(ippyitwH8nH5p?iiHdR4N+LST2 zDJE0nG}wo%-)(MJhW(&Ho|Jroip7fh}~z_A<5n_`EhR@acOAbsJo0d53o<(#))en6CrUPz7qGj-CV@CX5U(?dmTC)e zF#cwJgNoOx%%_J&NgYMa?5APGCEeJa<;lDt_n`4=HiUq!usVjugh%}^*2jLl|G8Ko zhE@Y&=Gnuls{5-z;L_SK6?4`#H9zD{kdHh56Wq8sp_6YMMSpbk6)n!M`afdNExny~7NrHaa cbbZ$x8~@E7E&30}%cJ5F`kt?Q+%^{T7xQzLJ^%m! delta 4240 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 diff --git a/stl/RGBStd@0.11.0.sty b/stl/RGBStd@0.11.0.sty index 25c3be31..fe69e9d0 100644 --- a/stl/RGBStd@0.11.0.sty +++ b/stl/RGBStd@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:JhUC5JgH-Kwps4cO-ZNUklUj-UP6boFp-OY!18Kx-xOSJaVQ#hair-magnum-helena + Id: stl:vdvotNKl-wGrtjuT-Q4qXt4U-UVQlDMB-ONCuwLd-ORBWRTw#zebra-twist-tango Name: RGBStd Version: 0.11.0 Description: RGB standard library @@ -11,76 +11,6 @@ @context typelib RGBStd -import RGBCommit#harvest-person-orion - use ExtensionSchema#active-eddie-empty - use BundleId#carmen-farmer-diesel - use AttachState#lady-japan-fiesta - use GlobalValues#pilot-boris-alice - use MetaValue#split-package-recycle - use InputMap#octavia-north-gram - use GenesisSchema#iron-forbid-hamlet - use AltLayer1Set#flute-flex-bottle - use OwnedStateSchema#python-snake-capsule - use AssetTags#anita-nice-deliver - use VoidState#email-snow-safari - use DataState#short-noise-postal - use TransitionType#picture-reflex-brigade - use Occurrences#source-olga-mirage - use AssignVoidStateBlindSealTxPtr#profit-granite-fuji - use Schema#vocal-hammer-logic - use MediaType#isabel-heaven-north - use AssignmentsBlindSealTxPtr#village-result-bahama - use ValencyType#aloha-dublin-brush - use PedersenCommitment#pupil-scale-jerome - use ConcealedFungible#story-shrink-aloha - use GlobalStateSchema#silk-college-august - use Extension#ambient-greek-jackson - use AssignRevealedAttachBlindSealTxid#local-memo-modern - use TypedAssignsBlindSealTxid#garlic-project-zigzag - use AssignRevealedDataBlindSealTxid#fantasy-monica-jump - use AssignmentsBlindSealTxid#electra-bishop-helena - use ExtensionType#apropos-scoop-viva - use RevealedFungible#origin-iris-insect - use ConcealedData#ivan-tripod-young - use MetaType#quebec-mission-quota - use TransitionSchema#jumbo-matrix-normal - use TypedAssignsBlindSealTxPtr#airline-video-travel - use AssignRevealedDataBlindSealTxPtr#ritual-license-arcade - use XChainBlindSealTxid#dynamic-life-brown - use AttachId#factor-hair-everest - use BlindingFactor#animal-plume-minus - use AssignmentType#secret-penguin-limit - use XChainBlindSealTxPtr#senator-limbo-raymond - use Opout#yoga-samba-karma - use AssignVoidStateBlindSealTxid#senior-beyond-cement - use SchemaId#ramirez-patron-simon - use OpId#picnic-single-gloria - use ContractId#uniform-welcome-papa - use FungibleState#guide-poker-coconut - use Inputs#herman-liberal-galaxy - use XChainPubWitness#carrot-import-nova - use TransitionBundle#mambo-anita-plate - use Identity#smart-pioneer-nominal - use AltLayer1#edison-survive-nitro - use AssetTag#slang-amber-club - use Input#actor-minus-multi - use GlobalStateType#yoga-quick-jasmine - use Transition#tactic-arcade-manager - use AssignRevealedAttachBlindSealTxPtr#wave-comet-arnold - use Ffv#pigment-career-hippie - use AssignRevealedValueBlindSealTxPtr#cuba-needle-salami - use XChainSecretSeal#alex-griffin-left - use Valencies#light-letter-comet - use GlobalState#stadium-barcode-bazaar - use Redeemed#mile-lady-perfect - use RevealedAttach#slalom-phantom-voyage - use Genesis#round-sound-nectar - use Metadata#member-nobody-imitate - use FungibleType#matrix-optimal-sinatra - use ConcealedAttach#meter-arizona-albino - use RevealedData#olivia-copper-stamp - use AssignRevealedValueBlindSealTxid#photo-jump-silicon - import StrictTypes#century-comrade-chess use VariantName#theory-austin-before use FieldName#present-flute-herman @@ -126,6 +56,56 @@ import CommitVerify#miller-pancake-elastic use ReservedBytes4#young-goblin-academy use ReservedBytes8#rudolf-tape-adrian +import RGBCommit#printer-window-alpine + use ExtensionSchema#active-eddie-empty + use BundleId#carmen-farmer-diesel + use MetaValue#split-package-recycle + use InputMap#octavia-north-gram + use GenesisSchema#iron-forbid-hamlet + use AssignmentsBlindSealTxid#private-lesson-compare + use TypedAssignsBlindSealTxPtr#arsenal-immune-martin + use AssignmentsBlindSealTxPtr#ship-panic-magic + use AltLayer1Set#flute-flex-bottle + use TypedAssignsBlindSealTxid#siren-float-child + use TransitionType#picture-reflex-brigade + use Occurrences#source-olga-mirage + use Extension#capital-police-factor + use ValencyType#aloha-dublin-brush + use GlobalState#mouse-bambino-brigade + use GlobalStateSchema#silk-college-august + use OwnedStateSchema#cover-shampoo-weather + use ExtensionType#apropos-scoop-viva + use MetaType#quebec-mission-quota + use TransitionSchema#jumbo-matrix-normal + use StateData#nissan-pattern-inside + use XChainBlindSealTxid#dynamic-life-brown + use AttachId#factor-hair-everest + use AssignmentType#secret-penguin-limit + use XChainBlindSealTxPtr#senator-limbo-raymond + use Opout#yoga-samba-karma + use SchemaId#ramirez-patron-simon + use OpId#picnic-single-gloria + use Schema#eternal-block-totem + use ContractId#uniform-welcome-papa + use State#octavia-kermit-fast + use Inputs#herman-liberal-galaxy + use XChainPubWitness#carrot-import-nova + use Genesis#sincere-block-graph + use AssignBlindSealTxid#light-basket-trick + use Transition#race-korea-capital + use Identity#smart-pioneer-nominal + use AltLayer1#edison-survive-nitro + use GlobalValues#verona-iris-senator + use Input#actor-minus-multi + use GlobalStateType#yoga-quick-jasmine + use Ffv#pigment-career-hippie + use XChainSecretSeal#alex-griffin-left + use Valencies#light-letter-comet + use Redeemed#mile-lady-perfect + use AssignBlindSealTxPtr#alamo-dallas-caesar + use Metadata#member-nobody-imitate + use TransitionBundle#final-numeric-berlin + import Std#ralph-blue-lucky use AlphaCaps#picnic-soprano-aurora use AsciiPrintable#ultra-sunset-format @@ -176,17 +156,17 @@ data AssignIface : ownedState OwnedIface , required Std.Bool , multiple Std.Bool -@mnemonic(scoop-deluxe-action) +@mnemonic(monaco-pilot-nitro) data ClientBundleOpretProof : mpcProof CommitVerify.MerkleProof , dbcProof BPCore.OpretProof , bundle RGBCommit.TransitionBundle -@mnemonic(fame-iris-habitat) +@mnemonic(lithium-shrink-actor) data ClientBundleTapretProof : mpcProof CommitVerify.MerkleProof , dbcProof BPCore.TapretProof , bundle RGBCommit.TransitionBundle -@mnemonic(tango-hotel-jamaica) +@mnemonic(center-saddle-annual) data Consignmentfalse : version ContainerVer , transfer Std.Bool , terminals {RGBCommit.BundleId -> RGBCommit.XChainSecretSeal} @@ -201,7 +181,7 @@ data Consignmentfalse : version ContainerVer , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} , signatures {ContentId -> ^ ..0xff ContentSigs} -@mnemonic(postage-canary-oxygen) +@mnemonic(permit-simon-summer) data Consignmenttrue : version ContainerVer , transfer Std.Bool , terminals {RGBCommit.BundleId -> RGBCommit.XChainSecretSeal} @@ -279,7 +259,7 @@ data Iface : version VerNo @mnemonic(nova-cola-carbon) data IfaceId : [Byte ^ 32] -@mnemonic(chris-earth-pony) +@mnemonic(sphere-emotion-east) data IfaceImpl : version VerNo , schemaId RGBCommit.SchemaId , ifaceId IfaceId @@ -292,11 +272,12 @@ data IfaceImpl : version VerNo , extensions {NamedFieldExtensionType ^ ..0xff} , errors {NamedVariantu8 ^ ..0xff} , developer RGBCommit.Identity + , stateAbi StateAbi @mnemonic(seminar-data-table) data ImplId : [Byte ^ 32] -@mnemonic(sultan-dexter-lotus) +@mnemonic(polka-neptune-star) data Kit : version ContainerVer , ifaces {Iface ^ ..0xff} , schemata {RGBCommit.Schema ^ ..0xff} @@ -360,6 +341,12 @@ data PubWitness : txid Bitcoin.Txid @mnemonic(insect-cello-avalon) data SigBlob : [Byte ^ 1..0x1000] +@mnemonic(thermos-demo-fragile) +data StateAbi : regInput AluVM.LibSite + , regOutput AluVM.LibSite + , calcOutput AluVM.LibSite + , calcChange AluVM.LibSite + @mnemonic(pilot-claudia-minute) data SupplId : [Byte ^ 32] diff --git a/stl/RGBStorage@0.11.0.sta b/stl/RGBStorage@0.11.0.sta index 3a12b1b6..8ef355eb 100644 --- a/stl/RGBStorage@0.11.0.sta +++ b/stl/RGBStorage@0.11.0.sta @@ -1,24 +1,24 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:mG$H7b6I-$T8qp18-07PSNeA-rbEBNS5-$J5X4y0-1vPxRWg#channel-vortex-bandit +Id: stl:iayFnuhB-sjXxWhi-Pp!FSyO-astclK4-icTXDwX-O0Fb4F4#floor-avatar-lazarus Name: RGBStorage Dependencies: - RGBCommit#harvest-person-orion, - RGBStd#hair-magnum-helena, StrictTypes#century-comrade-chess, BPCore#austin-story-retro, AluVM#congo-archive-folio, CommitVerify#miller-pancake-elastic, - RGBLogic#import-boxer-seminar, + RGBCommit#printer-window-alpine, + RGBStd#zebra-twist-tango, Std#ralph-blue-lucky, + RGBLogic#ohio-electra-dilemma, Bitcoin#signal-color-cipher -Check-SHA256: 1b751fa1bbeea231625cc17129d356fefecb85e0974f343cadf022d6c227ad17 +Check-SHA256: b78e8c45504383900212ce4d621bac70640f73758b4785d2451f48687eebdc7c -3Q|WxQ*>`~VP|CtAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{j2~tNwLvL+uX>=wP0_2znD++Ak -!AD4^=04ZLvBczwX;cPMM?zC{WJT(uU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*$Y#2 -a%p39RC#b^b5;}9*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3ONCrYsLvM0rVsJHoA?4$swuZp1Wc+9A -Of`(TIbyKWjTy4WkGaM+1wm|eR!w>X9p7nv%krpqN@X!nKLI&Lh~GYywm#15`~VP|CtMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD*X=8L$d2nTORuk6O)Q5AK +bFW;JEQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pZ~a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjH +L2PwaO?m?z-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCJaMwZEb0ER%LQ&W_hoT#`k1y;WQvCHXeDD +EB)y-4aXJJr*xW72o5QK9=-`uM?ynyZEb0Ez1!%t(xt#^?T+No;-&53MHNC&%mm{?y8_)g5LQJz22w{t +Q*>m?EFN!zncXl9K5w2;FV{y1jDTJCC^p$-mHEbO0#qjhQ*>nKQ=pGEdKZ=MPb)<*m$;LvDR$csb;@mC +=QtLlJD!;cQb$5eZ)a&^^=uPjBlbC`N(qzPM@Gr{imSMTSY5T*7C#t%#3&jH2SRCdV{d702?arHbyiIV 01^bJwgM1*ibOBDT%6aZ|SrJerP1pIOD57`7Ol|-ogQ6Pjg~y>s-v>!^VNPLfWv4Jz0xkJm$nc4y MWR2J-cc#Q6SofWC)gp7L6!Sc3I$AQVo7AP4Jk3r!|EoW{Zi$060oMN(jLzPuNboiNpoRS @@ -51,173 +51,150 @@ H8-hI70Bv^+*0?ef%0)>Q3WPbltNdpi4*91)SI!>2Tf&jb75y?IG#g>Clv)aMjKgwAH@`bu1x<7g|G$} _h5K%L=laq&yA1JoJ^{7>oKLkF4~iax8KK|47hp@Qe|^xa&~28LV0v$b1}=fEj#9D^K)f#Cf|Xn@L3mU 0Z2&n-dr?jcD1Ll0RawDWpib6c4cHjd30rSGT61bmh)A>-9G+(AKhLw+s!eDmlO2>&}_PPHjCBJR|r&c Wo1rpWM%K_6AuO0fiYoI|8ZKC9(55{UNs2(LOhfb*8wh)9?K3=Wpib6c4cHjd30rSH2#7XN#A(BKKz&v -`r;e6DUv<<*U}c>;b184%wsNMHUptBVZ#B!U% +`r;e6DUv<<*U}c>CH184%wsNMHUptBVZ#B!U% rHo-i1kG~VoNp!e_~i}U4@G!%Wo~n6Z*Eg#Xk~3-1ACLTJsO2B2U!6ncg?mz@CdC==Kxq?gSEg)z2E{| -2tsvkWNc+gWC^x^65s1c;WeUUgB8EM+V1n+T -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 -*TS*H2rNlD$O59e#ogQsB77jPl+h5j -^*S;FAXg`>_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{j?6T%|znQ^KeoD%bg94CLCf*q;P?fLY7qq^# -2NiM*0000000000{{R30000001#@+9aBKhy0wxs#KG(vr#N>%-R0f!> -x7s+uExGllhUte$e$Op^sMk_Bzn7+|3$axzr2q*6CKUqYmH4o{!1*GOa*TS*H_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{juZ@?{0aPfN4Did>Ze%hHN@6KP -lLd+s#TneAz-EYx0000000000|NsC0000003T1e7Wo~n6Z*Fq{3IZTkC#?5~OapN(_Fs6GvFQy{P|gRa -2*}s1Y~I%9#i^CZ=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(GrS0}9Zh)e@_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jiECIT&Bl;lSX#$ms8AQN7m&qYKG(vr#N>%-RL5UwIaVYs3AVDiqia*@S>E2s&92Kh -8W}@zf2sFIAOHXW000000RR90{{R3001IJsbYWv?ZDnqBa{vkgAXg`>_lQgbaV_>=c$Ts04O39g2dD_h -*R5>c*5<{jgmDd%EKc;pw+KsVi?D}qDSkO*B!5Mb*xG|_(S5o&00;m8KmY&$000000RR900000000000 -000000RR600000001I_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jkGsO? -N19ILP2yc~f4%w>xYW^+v~7{W03rq(;firJ0000000000|Ns90000003UqmJWm9=`bY*PC`}q*r{eiB7ehUYis7~w1CQOqefKeZ3;Wd%uopqe!>_vj93Tb3zZggpM -X=QT&3IZTkC#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#i_RFfQB3>bs~EXcCXx(drQcb3B`Fx$)^%v -a$Ar)C7c2#6$0d#2P+C};lr6VNhMM>59zuEq~<=?!m-5UiD^`#;91nsu+1H%suE1D6u@lRoC;S?XbB(j -&QSOSPz0a=0000000030{{R3000004Y-wV1015(Pa5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCl9 -FjWFA`CQ2GiK9iLKbGE6DZmrA4)G`0A&^0p`%?-6VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ -5(KBV0uX$PL@)I=)&*`^S@`8Scoz5#{lyP)a751L0000000000|Nj60000001aoO;a{vkgCKUqYmH4o{!1*GOa*TS*H^^GknUxTJ!XL#OUcE0wxs#KG(vr#N>%-RE8K3ENEw7&f?o%+)B!ZpG}K!%4G?I4vp$|ttu*CMF0Q*00000 -0RR600000000>QGZBuk%bY%tt33q99Ze??GWpe-u0w7l>toMja192_(UwD?W=?zm*&IhOn$k(lG-qz;D -sflY?CC$c=UszhlV5m?Ru@{iVU*wrVdeH+Q@FPbX@dBEuZK_k`JKyPG=Rp7@Nbf+-FrJ*HF>i&!wTZgU -Bh_-dLdY0XT`|v$|M|2EBF6^D+OST}`A!+zFZPFTn&AKd0000000960|Nj60000SNZ*FvQVPkZ2015&i -S0}9Zh)e@2rNlD$O59e#ogQsB77jPl+h5j^*S;E -cA8SzdwhWF9dgX`>ZnjA*51^hO#z=?KV_fm3KoU?0000000000{{R3000000 +2tsvkWNc+gWE3Slj!?y>j|MdwWnpYo +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 +{{R30000001#@+9aBKhy0=?Vlw9=)(YVD5X(Bh@-;YAffP|O75Lc0RpIS^JwJO-Gpx7s+uExGllhUte$ +e$Op^sMk_Bzn7+|3$axzr2q*6z1!%t(xt#^?T+No;-&53MHNC&%mm{?y8_)g5LQJzV?EP}uuDl+D$lsi +ICW4a8e$Z2e6I7`3evG=Yh^sO0000000000{{R30000000000000000{{R30000002V!+@WNc+~015)H +jmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&RAdy}<28ig(gSpg+?&9*`C2(3=%09avzwZKZf-~wC% +uZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm{b~4y9C9`4X%pen_fPY +0000000000|NsC0000003T1e7Wo~n6Z*Fq{3IeZ<#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=?^x +=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(IQjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&R? +krgyL25hbsyp?a}5-x=-+yHc@4oMPeoYe!lEU|R}0000000030|Ns9000009cWHEPWpi_7a{vkguZ_m{ +WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmiECIT&Bl;lSX#$ms8AQN7m&qYE2s&92Kh8W}@zf2sFIAOHXW +000000RR90{{R3001IJsbYWv?ZDnqBa{vkguZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmgmDd% +EKc;pw+KsVi?D}qDSkO*B!5Mb*xG|_(S5o&00;m8KmY&$000000RR900000000000000000RR6000000 +01I +xYW^+v~7{W03rq(;firJ0000000000|Ns90000003UqmJWm9=`bY*PC`}q*r{eiB7ehUYis7~w1CQOqefKeZ3;Wd%uopqe!>_vj93Tb3zZggpMX=QT&3IeZ<#`k1y +;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=^8dfQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7c4i+vv2? +rNCR2XhQO_4{AcS-HH^7AVzASV8M4NYxyCl9FjWFA`CQ2GiK9iL +KbGE6DZmrA4)G`0A&^0p`%?-6VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+5(KBV0uX$PL@)I= +)&*`^S@`8Scoz5#{lyP)a751L0000000000|Nj60000001aoO;a{vkgz1!%t(xt#^?T+No;-&53MHNC& +%mm{?y8_)g5LQJz;?xyT5z&Ua+M@}mOiDpYxh>^^GknUxTJ!XL#OUcE0=?Vlw9=)(YVD5X(Bh@-;YAff +P|O75Lc0RpIS^JwJcbw$ENEw7&f?o%+)B!ZpG}K!%4G?I4vp$|ttu*CMF0Q*000000RR600000000>QG +ZBuk%bY%tt33q99Ze??GWpe-u0>gzKLsCCC$c=Uszhl +V5m?Ru@{iVU*wrVdeH+Q@FPbX@dD>lppP|r7nSZ$D@8DuxRa_WcH0nj%57ffI2NNjo|$sHLdY0XT`|v$ +|M|2EBF6^D+OST}`A!+zFZPFTn&AKd0000000960|Nj60000SNZ*FvQVPkZ2015)HjmGz6Zs9Z_D>fc^ +lq>z|G!4fU)2DQrPzVkwe;&S{2rNlD$O59e#ogQsB77jPl+h5j^*S;E4$E#+hX^`zsZ&Tl +gCG9;!;p0|>d6h~fj!Md?2W%$0000000000{{R3000000 -----END STRICT TYPE LIB----- diff --git a/stl/RGBStorage@0.11.0.stl b/stl/RGBStorage@0.11.0.stl index 29e2bdda2817d518b0a000782bd5db9ec3e3610b..948dd4ca60be646faafeccd9df39ff83afb2c88d 100644 GIT binary patch delta 3146 zcma)8do+}39CnFj#(fwyVtlisn2Tv#D-~l9Dj8-fC2E*aqnRNyQ>wL73^s}CRkT{E z+*`MhN~_DBN<~|#4rXnMvN=oIwTvW4+mZV@h1qVqW*r#{ zrus2*&w~o`c9p68wm7nXq2=kt1;;!!st4-b|gyM1yrNggDA{igurSSEnT|* z#hW1|WoD39`B<&XZnUkh?dbRCnwN(+t_43B;}y17!&g5GkXm0NFxNna4r zVnnG!w{op3X|&?*j2G~|rBdN$iIgQ0O86WBPsB}R%M$EXRi)5&G-KAKe)FhSxqgj# zWcT|Ax2le^LI%@a({Z}^sZ(NsME3c~wV@q?J;TRu$AUo&$-{BKUZ~kw3?t&+^&y?A zSM0ZyIZJ1eIx=k7W&>G0C(h&lrw1V)Ts8=&_#MKzdgzO)aF>q6y};5_X}@U6N{j=s z!sCy0FVJe`Xum|6Kq3{!NkFe5jk;WwZTHSRaf!>xJA=;naYx=Z`SO$q^}>T;O-!QH z*}%YG6c@!4ab!FhkQ%u%lq&T7;%xlPCCU#WIwxP7WO*7=>aZP=udL@j9;ga44c;LU z@F&m$PV^RmmnxgjnOG4~B z1DBJT^}05zk>s;;8GEz8${OM3j|7=SdG4F(FOUeNLTLjtCdB7KoTDRSlY8mMbn6<% z;)qb@_6p|#-=;MBbAtKQO#fp9A-~~jCh3nn!%x>v%J2(|qPg z)NwI}n}FhJ^p{OcpcTt;yxY#a=lhWTcIz8#Q4_8%d&JnI{_fb&A&N>7QaezAH=LTl z8lFflkb+7Q0=Afofsch9D7Od)3>?{QBu1~Tz3)tgr+Z71I)|2P^rSxhiMll}KR2~2 zdE6n=;)^yleg!o+GSIhla(XWuO(RsP-4|J&NhogWvc4hZq`z9QZ^Wo7qbEPoGsl#h z@K3)ixr8qgfJc^Fv>oa^XANpoe9=DGXM>85Rf+w@YJ5j#(~^ERE}$E8I9JT|ck>@d z2gdNC1%cvt5uoBb0Mm*K+N}y4cN9M_(B0(T>$mzTZ~S0&>4R^reUcUwoL-RPhKWx* zeAIAitdobOVA~uD=yXEB^Er7=1;gUA7_a88lryidr0sgLxC1=fL!Zn$N5tCxwYqR3IDi3eF3pxSW3Iq1G|Soaue(tX}h zLQrPi2h=uYb)AIJ83=5JfngE@>?UF1z)BJc4jLwfQfHu~ler1x>p-iE?PzdPO)@C@ zncgpXlj zpPh47d+Y U;FeMU-lc7RzaO|9{<-=821vhYH2?qr delta 4647 zcma)Admxng8a8qpGs9rrFEg&W3?{OayGTir8QBmG^BGffkr^UtToR>1KPB1d9MT2J zZHpY2u_UEBvMO6HU08Hk<=9F%GbZg;XV2&RW4`(0{hs%IpWpMm-#hax@N&d9SwBxV z5|Zs#&(5i~5Z#F2xIi7O*{bk$ds9gTXsOFBn5@|?x3YW4_1SmoU@m4K=JLt7D zz?O|{3^mcu>$5jh3Eg++ zvGW*^B<4;`%sBPdXOqmBf99AvUyMQ`WpT4QZJ8XS-}S@>1bu4Mksw3Pp1u zmPleuh{g4a+#{WB*GPUy4-S4)TX!s(+@<*oNedO=+7c^QpE{$khRq5Wv<6Yv#;|Dg zFa}6KujHM3JB~0J=07X-h?7QTcxO76w2pwb|HsIZ-3#FP7P$!YYdwPJ%Zm| ze=@;(T0U2`e+?UCPBKYEY%DC!uH@8AvThl;Uj|A-B#OgKd(q2wDA%n`pf2i-> zp$2d$6>&Nh45BSUneH7^mOCU@uThpS9pMvx{%y~5Lhd`MUi8^V>C-Vs&R`dt{6r)a zg@LfuDamZy702g_0&fP$ob{trh!6EP1-9QgH;%-7re0VXz+h5%)iz9**fy5dGTV!p z$tNdXVBO=aUt-ygM^^LiygKcq@i$ZmRGF+ZnkSdtyv^%Xcs3}w=7BzhOOko~U2-mlc=VR^i74Q|w~Id6s9t z+yaMm7HushTrl;3vRs`bXvqy$JQ0u{bw4tO`PxnE^k8l6;oI>Z1;xKN&>cH1v_#qe zm!kyiR^jkqT+RYG%bS^$9wz2^Zs=Og4?BGQxcd>p-0g{K5+SMNww?t%QV#(1Iflj#srMktis0;`= zVM!)8vQAxSliHv$J4@5dYc%~h=N*}a<8+!&>|&473-l^w1l2CgATX(e2Lo6puTKrS zDYfzZR6wD9)@ft4Wl3B8tt5^R^ibu6zrGA`vXT8WPhX>TRckCsX7Eixd{x_Q{D^c~3JS#^FQM3<}nAo*x?D<;s;%N(o4>l{V;C)=_ z@i_Dj1~p%M?Ieo6HA=~q*p{#dL; zSnX8MYMB}JQUd2c2@ylli`5G~IN#$rl1`o}(UQiBS?T`}<4AQcDKn^+)hywENbvaw zAMc7=crz?M^EJl;E!QYUB1~(vlwKl$wekbU?auK${(EBK-Qhmu9+WQ4Ql=i)Xxk9? zdaVWHZcj&m)}|P4R18<73E{k6gkBg4C>633y(_28J49k+)a`&fDOfAK3TwB0pIOd7 z4()s}d~5Qt&ffuu+6N&jMZi?m)O3G9gfteXbUbdu#UJITcb@ak-_{vyUU=Z=Ia=|P zwNN*5eFP;OTF;DP01N>SxT+_Cqna7WQG3Sg*=-p!dPTE^dU@5I4*zasl+LXaBmc>p zFH8C5MrNTE87+F@EdX%t1!~k4_#P6+8`tdpHPvT7v*1W&dyj+<_ouBFXZ)LYY5!fl z3taZjXZ;jqcOkJ($@Xbo?~|~>ZN+-vpnC4=sq^=T($^_wm+jZcuPEJ9yS}#n1ESqh zr~RbZlgUntVD+zIKaZLkZ4EyOJltLevUJ?wgC=$K;e)bth=7XIGn1C#ENndMsp7EN zt8fH(U}t$e(8kNc2Wl$dd5D$Q*QKv|P0u)^X|>kt3LR%1b1uBCmv^sjj_>evsKZ|D z(>4F;E)`9uMRGY}NO8E$6z(j9fIQ*HyxoPdOY!fO#+f+{fXH&ye# zU8v!#D1!YHSc*~S> z5%qP!8a*TUz#$}F7hd8*^^PwEj;Ox`lRYxV1E9YGzBpl834Y(x}=I73AfvMOmaUmM`R`wSwW diff --git a/stl/RGBStorage@0.11.0.sty b/stl/RGBStorage@0.11.0.sty index e6631235..805aadf7 100644 --- a/stl/RGBStorage@0.11.0.sty +++ b/stl/RGBStorage@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:mG$H7b6I-$T8qp18-07PSNeA-rbEBNS5-$J5X4y0-1vPxRWg#channel-vortex-bandit + Id: stl:iayFnuhB-sjXxWhi-Pp!FSyO-astclK4-icTXDwX-O0Fb4F4#floor-avatar-lazarus Name: RGBStorage Version: 0.11.0 Description: RGB storage library @@ -11,80 +11,111 @@ @context typelib RGBStorage -import RGBCommit#harvest-person-orion +import StrictTypes#century-comrade-chess + use VariantName#theory-austin-before + use FieldName#present-flute-herman + use Primitive#deliver-arrow-boxer + use TySemId#popcorn-super-young + use FieldSemId#spiral-road-marco + use TypeName#edgar-carol-mystery + use UnnamedFieldsSemId#freedom-degree-gregory + use SemId#logic-absorb-hilton + use Variant#humor-regard-promise + use Sizing#courage-alien-salon + use NamedFieldsSemId#solar-salad-smoke + use EnumVariants#dispute-natasha-vega + use VariantInfoSemId#museum-edward-mirror + use UnionVariantsSemId#santana-address-pepper + use TypeSystem#adrian-boris-sponsor + +import BPCore#austin-story-retro + use TapretNodePartner#roger-member-educate + use ExplicitSealTxid#nova-roger-campus + use TapretProof#marco-border-sample + use TapretPathProof#kiwi-mirror-paris + use Method#bali-boris-plasma + use TapretRightBranch#miracle-patriot-touch + use BlindSealTxPtr#fortune-iron-salmon + use OpretProof#good-village-flex + use AnchorMerkleBlockTapretProof#ventura-palma-trumpet + use AnchorMerkleBlockOpretProof#sheriff-alex-degree + use SecretSeal#dollar-iris-wizard + use BlindSealTxid#media-judge-anita + use TxPtr#italian-july-eddie + +import AluVM#congo-archive-folio + use Lib#gate-biology-optimal + use LibSite#ultra-grace-message + use IsaName#taboo-olympic-cloud + use LibId#germany-culture-olivia + use IsaSeg#size-shake-olga + use LibSeg#lemon-philips-horse + +import CommitVerify#miller-pancake-elastic + use ProtocolId#shadow-eclipse-program + use Message#druid-blitz-rover + use MerkleHash#horse-popcorn-bundle + use MerkleBlock#pegasus-delta-eddie + use ReservedBytes1#origin-roger-relax + use ReservedBytes2#florida-libra-circus + use TreeNode#kansas-scarlet-ricardo + use ReservedBytes4#young-goblin-academy + use ReservedBytes8#rudolf-tape-adrian + +import RGBCommit#printer-window-alpine use ExtensionSchema#active-eddie-empty use BundleId#carmen-farmer-diesel - use AttachState#lady-japan-fiesta - use GlobalValues#pilot-boris-alice use MetaValue#split-package-recycle use InputMap#octavia-north-gram use GenesisSchema#iron-forbid-hamlet + use AssignmentsBlindSealTxid#private-lesson-compare + use TypedAssignsBlindSealTxPtr#arsenal-immune-martin + use AssignmentsBlindSealTxPtr#ship-panic-magic use AltLayer1Set#flute-flex-bottle - use OwnedStateSchema#python-snake-capsule - use AssetTags#anita-nice-deliver - use VoidState#email-snow-safari - use DataState#short-noise-postal + use TypedAssignsBlindSealTxid#siren-float-child use TransitionType#picture-reflex-brigade use Occurrences#source-olga-mirage - use AssignVoidStateBlindSealTxPtr#profit-granite-fuji - use Schema#vocal-hammer-logic - use MediaType#isabel-heaven-north - use AssignmentsBlindSealTxPtr#village-result-bahama + use Extension#capital-police-factor use ValencyType#aloha-dublin-brush - use PedersenCommitment#pupil-scale-jerome - use ConcealedFungible#story-shrink-aloha + use GlobalState#mouse-bambino-brigade use GlobalStateSchema#silk-college-august - use Extension#ambient-greek-jackson - use AssignRevealedAttachBlindSealTxid#local-memo-modern - use TypedAssignsBlindSealTxid#garlic-project-zigzag - use AssignRevealedDataBlindSealTxid#fantasy-monica-jump - use AssignmentsBlindSealTxid#electra-bishop-helena + use OwnedStateSchema#cover-shampoo-weather use ExtensionType#apropos-scoop-viva - use RevealedFungible#origin-iris-insect - use ConcealedData#ivan-tripod-young use MetaType#quebec-mission-quota use TransitionSchema#jumbo-matrix-normal use Layer1#camilla-basket-justin - use TypedAssignsBlindSealTxPtr#airline-video-travel - use AssignRevealedDataBlindSealTxPtr#ritual-license-arcade + use StateData#nissan-pattern-inside use XChainBlindSealTxid#dynamic-life-brown use AttachId#factor-hair-everest - use BlindingFactor#animal-plume-minus use AssignmentType#secret-penguin-limit use XChainTxid#liquid-river-absorb use XChainBlindSealTxPtr#senator-limbo-raymond use Opout#yoga-samba-karma - use AssignVoidStateBlindSealTxid#senior-beyond-cement use SchemaId#ramirez-patron-simon use OpId#picnic-single-gloria + use Schema#eternal-block-totem use ContractId#uniform-welcome-papa - use FungibleState#guide-poker-coconut + use State#octavia-kermit-fast use Inputs#herman-liberal-galaxy - use TransitionBundle#mambo-anita-plate + use Genesis#sincere-block-graph + use AssignBlindSealTxid#light-basket-trick + use Transition#race-korea-capital use Identity#smart-pioneer-nominal use AltLayer1#edison-survive-nitro - use AssetTag#slang-amber-club + use GlobalValues#verona-iris-senator use XChainExplicitSealTxid#acid-nepal-melon use Input#actor-minus-multi use GlobalStateType#yoga-quick-jasmine - use Transition#tactic-arcade-manager - use AssignRevealedAttachBlindSealTxPtr#wave-comet-arnold use Ffv#pigment-career-hippie - use AssignRevealedValueBlindSealTxPtr#cuba-needle-salami use XChainSecretSeal#alex-griffin-left use Valencies#light-letter-comet - use GlobalState#stadium-barcode-bazaar use Redeemed#mile-lady-perfect - use RevealedAttach#slalom-phantom-voyage - use Genesis#round-sound-nectar + use AssignBlindSealTxPtr#alamo-dallas-caesar use Metadata#member-nobody-imitate - use FungibleType#matrix-optimal-sinatra use XChainPubWitness#figure-gram-wave - use ConcealedAttach#meter-arizona-albino - use RevealedData#olivia-copper-stamp - use AssignRevealedValueBlindSealTxid#photo-jump-silicon + use TransitionBundle#final-numeric-berlin -import RGBStd#hair-magnum-helena +import RGBStd#zebra-twist-tango use PubWitness#paper-visa-storm use ContentRef#polo-ramirez-parker use SigBlob#insect-cello-avalon @@ -96,92 +127,35 @@ import RGBStd#hair-magnum-helena use IfaceId#nova-cola-carbon use ValencyIface#buzzer-holiday-fiber use Annotations#spend-linda-romeo + use IfaceImpl#coconut-snake-formula use AssignIface#fractal-baker-outside use VerNo#textile-next-stretch use NamedFieldValencyType#invest-apollo-inca use ImplId#seminar-data-table use SupplSub#canoe-denmark-short - use OutputAssignmentRevealedData#dinner-honey-saturn use Supplement#caviar-zebra-precise use SupplId#pilot-claudia-minute - use OutputAssignmentRevealedAttach#miami-diagram-mineral use NamedFieldExtensionType#tuna-archer-melon use NamedFieldGlobalStateType#museum-ohio-arizona use GenesisIface#rocket-paradox-press + use SchemaIfaces#popcorn-rider-panel use AnchorSet#pluto-plasma-diagram - use IfaceImpl#permit-learn-samba use ContentSigs#oval-sister-triton use SupplItem#jargon-orchid-forget use Modifier#saturn-escort-jordan use NamedFieldAssignmentType#origin-caramel-flipper + use OutputAssignment#chicago-neuron-concept use TrustLevel#cobra-script-albino + use StateAbi#thermos-demo-fragile use NamedFieldMetaType#prefix-carmen-artist use NamedVariantu8#star-pilgrim-pilgrim use OpWitness#valid-toronto-gibson use SealWitness#cotton-lopez-isabel use GlobalIface#concert-combat-charm - use SchemaIfaces#fossil-nepal-airline - use OutputAssignmentRevealedValue#aspect-caramel-diana use SupplMap#sailor-observe-bundle use OwnedIface#delphi-athlete-fresh use ContentId#scarlet-portal-office use GlobalOut#capital-agatha-bruno - use OutputAssignmentVoidState#mars-alabama-public - -import StrictTypes#century-comrade-chess - use VariantName#theory-austin-before - use FieldName#present-flute-herman - use Primitive#deliver-arrow-boxer - use TySemId#popcorn-super-young - use FieldSemId#spiral-road-marco - use TypeName#edgar-carol-mystery - use UnnamedFieldsSemId#freedom-degree-gregory - use SemId#logic-absorb-hilton - use Variant#humor-regard-promise - use Sizing#courage-alien-salon - use NamedFieldsSemId#solar-salad-smoke - use EnumVariants#dispute-natasha-vega - use VariantInfoSemId#museum-edward-mirror - use UnionVariantsSemId#santana-address-pepper - use TypeSystem#adrian-boris-sponsor - -import BPCore#austin-story-retro - use TapretNodePartner#roger-member-educate - use ExplicitSealTxid#nova-roger-campus - use TapretProof#marco-border-sample - use TapretPathProof#kiwi-mirror-paris - use Method#bali-boris-plasma - use TapretRightBranch#miracle-patriot-touch - use BlindSealTxPtr#fortune-iron-salmon - use OpretProof#good-village-flex - use AnchorMerkleBlockTapretProof#ventura-palma-trumpet - use AnchorMerkleBlockOpretProof#sheriff-alex-degree - use SecretSeal#dollar-iris-wizard - use BlindSealTxid#media-judge-anita - use TxPtr#italian-july-eddie - -import AluVM#congo-archive-folio - use Lib#gate-biology-optimal - use LibSite#ultra-grace-message - use IsaName#taboo-olympic-cloud - use LibId#germany-culture-olivia - use IsaSeg#size-shake-olga - use LibSeg#lemon-philips-horse - -import CommitVerify#miller-pancake-elastic - use ProtocolId#shadow-eclipse-program - use Message#druid-blitz-rover - use MerkleHash#horse-popcorn-bundle - use MerkleBlock#pegasus-delta-eddie - use ReservedBytes1#origin-roger-relax - use ReservedBytes2#florida-libra-circus - use TreeNode#kansas-scarlet-ricardo - use ReservedBytes4#young-goblin-academy - use ReservedBytes8#rudolf-tape-adrian - -import RGBLogic#import-boxer-seminar - use WitnessPos#cliff-enrico-nominal - use WitnessOrd#frank-ohio-forum import Std#ralph-blue-lucky use AlphaCaps#picnic-soprano-aurora @@ -194,6 +168,10 @@ import Std#ralph-blue-lucky use AlphaCapsLodash#duet-hammer-labor use AlphaSmallLodash#pioneer-eagle-spell +import RGBLogic#ohio-electra-dilemma + use WitnessPos#cliff-enrico-nominal + use WitnessOrd#frank-ohio-forum + import Bitcoin#signal-color-cipher use SeqNo#copper-verbal-ingrid use TxIn#slang-cherry-gizmo @@ -220,17 +198,14 @@ import Bitcoin#signal-color-cipher @mnemonic(carol-salute-aroma) data ContractIndex : publicOpouts {RGBCommit.Opout ^ ..0xffffff}, outpointOpouts {RGBCommit.XChainExplicitSealTxid -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xffffff}} -@mnemonic(shake-square-wizard) +@mnemonic(carbon-arena-ivan) data MemContractState : schemaId RGBCommit.SchemaId , contractId RGBCommit.ContractId , global {RGBCommit.GlobalStateType -> ^ ..0xff MemGlobalState} - , rights {RGBStd.OutputAssignmentVoidState ^ ..0xffffffff} - , fungibles {RGBStd.OutputAssignmentRevealedValue ^ ..0xffffffff} - , data {RGBStd.OutputAssignmentRevealedData ^ ..0xffffffff} - , attach {RGBStd.OutputAssignmentRevealedAttach ^ ..0xffffffff} + , state {RGBStd.OutputAssignment ^ ..0xffffffff} -@mnemonic(gilbert-torpedo-digital) -data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.DataState}, limit U24 +@mnemonic(mary-mineral-frame) +data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.StateData}, limit U24 @mnemonic(savage-joshua-clone) data MemIndex : opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit.BundleId} @@ -239,7 +214,7 @@ data MemIndex : opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit , contractIndex {RGBCommit.ContractId -> ^ ..0xff ContractIndex} , terminalIndex {RGBCommit.XChainSecretSeal -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xff}} -@mnemonic(level-open-morph) +@mnemonic(kinetic-deal-blast) data MemStash : schemata {RGBCommit.SchemaId -> ^ ..0xff RGBStd.SchemaIfaces} , ifaces {RGBStd.IfaceId -> ^ ..0xff RGBStd.Iface} , geneses {RGBCommit.ContractId -> ^ ..0xff RGBCommit.Genesis} diff --git a/stl/Transfer.vesper b/stl/Transfer.vesper index ca6ac774..36c8e481 100644 --- a/stl/Transfer.vesper +++ b/stl/Transfer.vesper @@ -48,211 +48,43 @@ Consignmenttrue rec testnet enum Bool false=0 true=1 altLayers1 set len=0..MAX8 aka=AltLayer1Set AltLayer1 enum liquid=1 - assetTags map len=0..MAX8 aka=AssetTags - key is U16 aka=AssignmentType - value bytes len=32 aka=AssetTag metadata map len=0..MAX8 aka=Metadata key is U16 aka=MetaType value bytes len=0..MAX16 aka=MetaValue globals map len=0..MAX8 aka=GlobalState key is U16 aka=GlobalStateType value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState + element bytes len=0..MAX16 aka=StateData assignments map len=0..MAX8 aka=AssignmentsBlindSealTxid key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxid - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 + value list len=1..MAX16 aka=TypedAssignsBlindSealTxid + AssignBlindSealTxid union + confidential rec tag=0 + seal union XChainSecretSeal + bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 + liquid bytes len=32 wrapped aka=SecretSeal tag=1 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 + revealed rec tag=1 + seal union XChainBlindSealTxid + bitcoin rec BlindSealTxid wrapped tag=0 + method enum Method opretFirst=0 tapretFirst=1 + txid bytes len=32 aka=Txid + vout is U32 aka=Vout + blinding is U64 + liquid rec BlindSealTxid wrapped tag=1 + method enum Method opretFirst=0 tapretFirst=1 + txid bytes len=32 aka=Txid + vout is U32 aka=Vout + blinding is U64 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies element is U16 aka=ValencyType validator bytes len=1 aka=ReservedBytes1 @@ -268,202 +100,37 @@ Consignmenttrue rec globals map len=0..MAX8 aka=GlobalState key is U16 aka=GlobalStateType value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState + element bytes len=0..MAX16 aka=StateData assignments map len=0..MAX8 aka=AssignmentsBlindSealTxid key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxid - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 + value list len=1..MAX16 aka=TypedAssignsBlindSealTxid + AssignBlindSealTxid union + confidential rec tag=0 + seal union XChainSecretSeal + bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 + liquid bytes len=32 wrapped aka=SecretSeal tag=1 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 + revealed rec tag=1 + seal union XChainBlindSealTxid + bitcoin rec BlindSealTxid wrapped tag=0 + method enum Method opretFirst=0 tapretFirst=1 + txid bytes len=32 aka=Txid + vout is U32 aka=Vout + blinding is U64 + liquid rec BlindSealTxid wrapped tag=1 + method enum Method opretFirst=0 tapretFirst=1 + txid bytes len=32 aka=Txid + vout is U32 aka=Vout + blinding is U64 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 redeemed map len=0..MAX8 aka=Redeemed key is U16 aka=ValencyType value bytes len=32 aka=OpId @@ -472,272 +139,79 @@ Consignmenttrue rec validator bytes len=1 aka=ReservedBytes1 witness bytes len=2 aka=ReservedBytes2 bundles set len=0..MAX32 - WitnessBundle rec - anchoredBundles union AnchoredBundles - tapret rec ClientBundleTapretProof wrapped tag=0 - mpcProof rec MerkleProof - pos is U32 - cofactor is U16 - path list len=0..32 - element bytes len=32 aka=MerkleHash - dbcProof rec TapretProof - pathProof rec TapretPathProof - some union TapretNodePartner option wrapped tag=1 - rightBranch rec TapretRightBranch wrapped tag=2 - nonce is U8 - bundle rec TransitionBundle - closeMethod enum Method opretFirst=0 tapretFirst=1 - inputMap map len=1..MAX16 aka=InputMap - key is U32 aka=Vout - value bytes len=32 aka=OpId - knownTransitions map len=1..MAX16 - key bytes len=32 aka=OpId - value rec Transition - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - transitionType is U16 aka=TransitionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState - inputs set len=0..MAX16 aka=Inputs - Input rec - prevOut rec Opout - op bytes len=32 aka=OpId - ty is U16 aka=AssignmentType - no is U16 - reserved bytes len=2 aka=ReservedBytes2 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr - key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxPtr - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 + WitnessBundle rec + anchoredBundles union AnchoredBundles + tapret rec ClientBundleTapretProof wrapped tag=0 + mpcProof rec MerkleProof + pos is U32 + cofactor is U16 + path list len=0..32 + element bytes len=32 aka=MerkleHash + dbcProof rec TapretProof + pathProof rec TapretPathProof + some union TapretNodePartner option wrapped tag=1 + rightBranch rec TapretRightBranch wrapped tag=2 + nonce is U8 + bundle rec TransitionBundle + closeMethod enum Method opretFirst=0 tapretFirst=1 + inputMap map len=1..MAX16 aka=InputMap + key is U32 aka=Vout + value bytes len=32 aka=OpId + knownTransitions map len=1..MAX16 + key bytes len=32 aka=OpId + value rec Transition + ffv is U16 aka=Ffv + contractId bytes len=32 aka=ContractId + nonce is U64 + transitionType is U16 aka=TransitionType + metadata map len=0..MAX8 aka=Metadata + key is U16 aka=MetaType + value bytes len=0..MAX16 aka=MetaValue + globals map len=0..MAX8 aka=GlobalState + key is U16 aka=GlobalStateType + value list len=1..MAX16 aka=GlobalValues + element bytes len=0..MAX16 aka=StateData + inputs set len=0..MAX16 aka=Inputs + Input rec + prevOut rec Opout + op bytes len=32 aka=OpId + ty is U16 aka=AssignmentType + no is U16 + reserved bytes len=2 aka=ReservedBytes2 + assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr + key is U16 aka=AssignmentType + value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr + AssignBlindSealTxPtr union + confidential rec tag=0 + seal union XChainSecretSeal + bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 + liquid bytes len=32 wrapped aka=SecretSeal tag=1 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 + revealed rec tag=1 + seal union XChainBlindSealTxPtr + bitcoin rec BlindSealTxPtr wrapped tag=0 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + liquid rec BlindSealTxPtr wrapped tag=1 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies element is U16 aka=ValencyType validator bytes len=1 aka=ReservedBytes1 @@ -767,7 +241,7 @@ Consignmenttrue rec globals map len=0..MAX8 aka=GlobalState key is U16 aka=GlobalStateType value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState + element bytes len=0..MAX16 aka=StateData inputs set len=0..MAX16 aka=Inputs Input rec prevOut rec Opout @@ -777,231 +251,38 @@ Consignmenttrue rec reserved bytes len=2 aka=ReservedBytes2 assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxPtr - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 + value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr + AssignBlindSealTxPtr union + confidential rec tag=0 + seal union XChainSecretSeal + bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 + liquid bytes len=32 wrapped aka=SecretSeal tag=1 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 + revealed rec tag=1 + seal union XChainBlindSealTxPtr + bitcoin rec BlindSealTxPtr wrapped tag=0 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + liquid rec BlindSealTxPtr wrapped tag=1 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies element is U16 aka=ValencyType validator bytes len=1 aka=ReservedBytes1 @@ -1036,7 +317,7 @@ Consignmenttrue rec globals map len=0..MAX8 aka=GlobalState key is U16 aka=GlobalStateType value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState + element bytes len=0..MAX16 aka=StateData inputs set len=0..MAX16 aka=Inputs Input rec prevOut rec Opout @@ -1046,231 +327,38 @@ Consignmenttrue rec reserved bytes len=2 aka=ReservedBytes2 assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxPtr - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 + value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr + AssignBlindSealTxPtr union + confidential rec tag=0 + seal union XChainSecretSeal + bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 + liquid bytes len=32 wrapped aka=SecretSeal tag=1 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 + revealed rec tag=1 + seal union XChainBlindSealTxPtr + bitcoin rec BlindSealTxPtr wrapped tag=0 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + liquid rec BlindSealTxPtr wrapped tag=1 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies element is U16 aka=ValencyType validator bytes len=1 aka=ReservedBytes1 @@ -1300,7 +388,7 @@ Consignmenttrue rec globals map len=0..MAX8 aka=GlobalState key is U16 aka=GlobalStateType value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState + element bytes len=0..MAX16 aka=StateData inputs set len=0..MAX16 aka=Inputs Input rec prevOut rec Opout @@ -1310,231 +398,38 @@ Consignmenttrue rec reserved bytes len=2 aka=ReservedBytes2 assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxPtr - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 + value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr + AssignBlindSealTxPtr union + confidential rec tag=0 + seal union XChainSecretSeal + bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 + liquid bytes len=32 wrapped aka=SecretSeal tag=1 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 + revealed rec tag=1 + seal union XChainBlindSealTxPtr + bitcoin rec BlindSealTxPtr wrapped tag=0 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + liquid rec BlindSealTxPtr wrapped tag=1 + method enum Method opretFirst=0 tapretFirst=1 + txid union TxPtr + witnessTx is Unit tag=0 + txid bytes len=32 wrapped aka=Txid tag=1 + vout is U32 aka=Vout + blinding is U64 + state rec State + reserved bytes len=1 aka=ReservedBytes1 + value bytes len=0..MAX16 aka=StateData + some bytes len=32 option wrapped aka=AttachId tag=1 + lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies element is U16 aka=ValencyType validator bytes len=1 aka=ReservedBytes1 @@ -1556,11 +451,9 @@ Consignmenttrue rec maxItems is U24 ownedTypes map len=0..MAX8 key is U16 aka=AssignmentType - value union OwnedStateSchema - declarative is Unit tag=0 - fungible enum FungibleType wrapped unsigned64Bit=8 tag=1 - structured bytes len=32 wrapped aka=SemId tag=2 - attachment enum MediaType wrapped any=255 tag=3 + value rec OwnedStateSchema + reserved bytes len=1 aka=ReservedBytes1 + semId bytes len=32 aka=SemId valencyTypes set len=0..MAX8 element is U16 aka=ValencyType genesis rec GenesisSchema @@ -1776,6 +669,19 @@ Consignmenttrue rec name ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 reserved bytes len=4 aka=ReservedBytes4 developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 + stateAbi rec StateAbi + regInput rec LibSite + lib bytes len=32 aka=LibId + pos is U16 + regOutput rec LibSite + lib bytes len=32 aka=LibId + pos is U16 + calcOutput rec LibSite + lib bytes len=32 aka=LibId + pos is U16 + calcChange rec LibSite + lib bytes len=32 aka=LibId + pos is U16 supplements set len=0..MAX8 Supplement rec contentId union ContentRef diff --git a/stl/src/main.rs b/stl/src/main.rs index 3cf24119..f41e32da 100644 --- a/stl/src/main.rs +++ b/stl/src/main.rs @@ -26,8 +26,8 @@ use std::io::Write; use commit_verify::CommitmentLayout; use rgbstd::containers::Transfer; use rgbstd::stl::{ - aluvm_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, rgb_contract_stl, - rgb_logic_stl, rgb_std_stl, rgb_storage_stl, + aluvm_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, rgb_logic_stl, + rgb_std_stl, rgb_storage_stl, }; use strict_types::stl::{std_stl, strict_types_stl}; use strict_types::{parse_args, StlFormat, SystemBuilder}; @@ -36,28 +36,6 @@ fn main() { let (_, dir) = parse_args(); let dir = dir.unwrap_or_else(|| "./stl".to_owned()); - let contract_stl = rgb_contract_stl(); - contract_stl - .serialize(StlFormat::Binary, Some(&dir), "0.11.0", None) - .expect("unable to write to the file"); - contract_stl - .serialize(StlFormat::Armored, Some(&dir), "0.11.0", None) - .expect("unable to write to the file"); - contract_stl - .serialize( - StlFormat::Source, - Some(&dir), - "0.11.0", - Some( - " - Description: Types for writing RGB contracts and interfaces - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0", - ), - ) - .expect("unable to write to the file"); - let rgb_std = rgb_std_stl(); rgb_std .serialize(StlFormat::Binary, Some(&dir), "0.11.0", None) From c3ef1e3f79eccabc9f8e938c130f931e0013262c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 15 Oct 2024 23:22:35 +0200 Subject: [PATCH 02/70] iface: make invoice state calculable with AluVM --- src/containers/file.rs | 2 - src/interface/builder.rs | 115 ++++++++++++----------- src/interface/calc.rs | 192 ++++++++++++++++++++++++++++++++++++++ src/interface/contract.rs | 11 --- src/interface/iimpl.rs | 3 +- src/interface/mod.rs | 2 + src/persistence/memory.rs | 18 ++-- src/persistence/stash.rs | 9 ++ src/persistence/stock.rs | 131 ++++++-------------------- 9 files changed, 303 insertions(+), 180 deletions(-) create mode 100644 src/interface/calc.rs diff --git a/src/containers/file.rs b/src/containers/file.rs index 4cd722c0..02a567b8 100644 --- a/src/containers/file.rs +++ b/src/containers/file.rs @@ -273,7 +273,6 @@ mod test { issuer: Default::default(), testnet: Default::default(), alt_layers1: Default::default(), - asset_tags: Default::default(), metadata: Default::default(), globals: Default::default(), assignments: Default::default(), @@ -371,7 +370,6 @@ mod test { issuer: Default::default(), testnet: Default::default(), alt_layers1: Default::default(), - asset_tags: Default::default(), metadata: Default::default(), globals: Default::default(), assignments: Default::default(), diff --git a/src/interface/builder.rs b/src/interface/builder.rs index 7fc6c13e..2ba1d8c3 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -29,7 +29,7 @@ use rgb::validation::Scripts; use rgb::{ validation, AltLayer1, AltLayer1Set, AssignmentType, Assignments, ContractId, ExposedSeal, Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Input, Layer1, MetadataError, Opout, - OwnedStateSchema, Schema, State, Transition, TransitionType, TypedAssigns, XChain, XOutpoint, + Schema, State, Transition, TransitionType, TypedAssigns, XChain, XOutpoint, }; use rgbcore::{GlobalStateSchema, GlobalStateType, MetaType, Metadata, ValencyType}; use strict_encoding::{FieldName, SerializeError, StrictSerialize}; @@ -37,7 +37,7 @@ use strict_types::{decode, SemId, TypeSystem}; use crate::containers::{BuilderSeal, ContainerVer, Contract, ValidConsignment}; use crate::interface::resolver::DumbResolver; -use crate::interface::{Iface, IfaceImpl, TransitionIface}; +use crate::interface::{Iface, IfaceImpl, StateCalc, StateCalcError, TransitionIface}; use crate::Outpoint; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] @@ -68,19 +68,7 @@ pub enum BuilderError { /// state `{0}` provided to the builder has invalid type. InvalidStateType(AssignmentType), - /// asset tag for state `{0}` must be added before any fungible state of - /// the same type. - AssetTagMissed(AssignmentType), - - /// asset tag for state `{0}` was already automatically created. Please call - /// `add_asset_tag` before adding any fungible state to the builder. - AssetTagAutomatic(AssignmentType), - - /// state data for state type `{0}` are invalid: asset tag doesn't match the - /// tag defined by the contract. - AssetTagInvalid(AssignmentType), - - /// interface doesn't specifies default operation name, thus an explicit + /// interface doesn't specify default operation name, thus an explicit /// operation type must be provided with `set_operation_type` method. NoOperationSubtype, @@ -90,6 +78,10 @@ pub enum BuilderError { /// {0} is not supported by the contract genesis. InvalidLayer1(Layer1), + #[from] + #[display(inner)] + Calc(StateCalcError), + #[from] #[display(inner)] StrictEncode(SerializeError), @@ -226,13 +218,13 @@ impl ContractBuilder { pub fn add_owned_state_raw( mut self, - name: impl Into, + type_id: AssignmentType, seal: impl Into>, state: State, ) -> Result { let seal = seal.into(); self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_owned_state_raw(name, seal, state)?; + self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; Ok(self) } @@ -306,13 +298,15 @@ impl ContractBuilder { } } -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct TransitionBuilder { contract_id: ContractId, builder: OperationBuilder, nonce: u64, transition_type: TransitionType, inputs: TinyOrdMap, + // TODO: Remove option once we have blank builder + calc: Option, } impl TransitionBuilder { @@ -323,7 +317,7 @@ impl TransitionBuilder { iimpl: IfaceImpl, types: TypeSystem, ) -> Self { - Self::with(contract_id, iface, schema, iimpl, TransitionType::BLANK, types) + Self::with(contract_id, iface, schema, iimpl, TransitionType::BLANK, types, None) } pub fn default_transition( @@ -332,13 +326,15 @@ impl TransitionBuilder { schema: Schema, iimpl: IfaceImpl, types: TypeSystem, + scripts: Scripts, ) -> Result { let transition_type = iface .default_operation .as_ref() .and_then(|name| iimpl.transition_type(name)) .ok_or(BuilderError::NoOperationSubtype)?; - Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types)) + let calc = StateCalc::new(scripts, iimpl.state_abi); + Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types, Some(calc))) } pub fn named_transition( @@ -348,12 +344,14 @@ impl TransitionBuilder { iimpl: IfaceImpl, transition_name: impl Into, types: TypeSystem, + scripts: Scripts, ) -> Result { let transition_name = transition_name.into(); let transition_type = iimpl .transition_type(&transition_name) .ok_or(BuilderError::TransitionNotFound(transition_name))?; - Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types)) + let calc = StateCalc::new(scripts, iimpl.state_abi); + Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types, Some(calc))) } fn with( @@ -363,6 +361,7 @@ impl TransitionBuilder { iimpl: IfaceImpl, transition_type: TransitionType, types: TypeSystem, + calc: Option, ) -> Self { Self { contract_id, @@ -370,6 +369,7 @@ impl TransitionBuilder { nonce: u64::MAX, transition_type, inputs: none!(), + calc, } } @@ -403,6 +403,9 @@ impl TransitionBuilder { } pub fn add_input(mut self, opout: Opout, state: State) -> Result { + if let Some(calc) = &mut self.calc { + calc.reg_input(opout.ty, &state)?; + } self.inputs.insert(Input::with(opout), state)?; Ok(self) } @@ -430,39 +433,54 @@ impl TransitionBuilder { self.builder.valency_type(name) } + #[inline] pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { self.builder.valency_name(type_id) } pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } + /// NB: Doesn't process the state with VM pub fn add_owned_state_raw( mut self, - name: impl Into, + type_id: AssignmentType, seal: impl Into>, state: State, ) -> Result { - self.builder = self.builder.add_owned_state_raw(name, seal, state)?; + self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; Ok(self) } - pub fn add_owned_state( + pub fn fulfill_owned_state( mut self, - name: impl Into, + type_id: AssignmentType, seal: impl Into>, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_owned_state(name, seal, value)?; - Ok(self) - } - - pub fn add_owned_state_default( - self, + state: State, + ) -> Result<(Self, Option), BuilderError> { + let calc = self + .calc + .as_mut() + .expect("you must not call fulfill_owned_state for the blank transition builder"); + let state = calc.calc_output(type_id, &state)?; + self.builder = self + .builder + .add_owned_state_raw(type_id, seal, state.sufficient)?; + Ok((self, state.insufficient)) + } + + pub fn add_owned_state_change( + mut self, + type_id: AssignmentType, seal: impl Into>, - value: impl StrictSerialize, ) -> Result { - let assignment_name = self.default_assignment()?.clone(); - self.add_owned_state(assignment_name, seal.into(), value) + let calc = self + .calc + .as_mut() + .expect("you must not call add_owned_state_change for the blank transition builder"); + if let Some(state) = calc.calc_change(type_id)? { + self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; + } + Ok(self) } pub fn has_inputs(&self) -> bool { !self.inputs.is_empty() } @@ -514,7 +532,6 @@ impl OperationBuilder { global: none!(), assignments: none!(), meta: none!(), - types, } } @@ -551,14 +568,6 @@ impl OperationBuilder { self.iimpl.valency_name(ty).expect("internal inconsistency") } - #[inline] - fn state_schema(&self, type_id: AssignmentType) -> &OwnedStateSchema { - self.schema - .owned_types - .get(&type_id) - .expect("schema should match interface: must be checked by the constructor") - } - #[inline] fn meta_schema(&self, type_id: MetaType) -> &SemId { self.schema @@ -615,16 +624,10 @@ impl OperationBuilder { fn add_owned_state_raw( mut self, - name: impl Into, + type_id: AssignmentType, seal: impl Into>, state: State, ) -> Result { - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - let assignment = seal.into().assignment(state); match self.assignments.entry(type_id)? { @@ -644,7 +647,13 @@ impl OperationBuilder { seal: impl Into>, value: impl StrictSerialize, ) -> Result { - self.add_owned_state_raw(name, seal, State::new(value)) + let name = name.into(); + + let type_id = self + .assignments_type(&name) + .ok_or(BuilderError::AssignmentNotFound(name))?; + + self.add_owned_state_raw(type_id, seal, State::new(value)) } fn complete(self) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments, TypeSystem) { diff --git a/src/interface/calc.rs b/src/interface/calc.rs new file mode 100644 index 00000000..50a6fd50 --- /dev/null +++ b/src/interface/calc.rs @@ -0,0 +1,192 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 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 aluvm::data::ByteStr; +use aluvm::library::{LibId, LibSite}; +use aluvm::reg::{Reg16, Reg32, RegA, RegR, RegS}; +use amplify::num::{u256, u4}; +use amplify::{ByteArray, Wrapper}; +use rgb::validation::Scripts; +use rgb::{AssignmentType, AttachId, StateData}; + +use crate::LIB_NAME_RGB_STD; + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error)] +#[display(doc_comments)] +pub enum StateCalcError { + /// reserved byte value {0} is not 0x00 for assignment type {1}. + InvalidReserved(AssignmentType, u8), + /// error registering input state of type {0} - {1}. + InputReg(AssignmentType, String), + /// error registering output state of type {0} - {1}. + OutputReg(AssignmentType, String), + /// error computing output state of type {0} - {1}. + OutputCalc(AssignmentType, String), + /// error computing change state of type {0} - {1}. + ChangeCalc(AssignmentType, String), + /// failed script for calculating output state of type {0}; please update interface + /// implementation for the schema + InsufficientState(AssignmentType), +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, 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 StateAbi { + pub reg_input: LibSite, + pub reg_output: LibSite, + pub calc_output: LibSite, + pub calc_change: LibSite, +} + +impl StateAbi { + pub fn lib_ids(&self) -> impl Iterator { + [self.reg_input, self.reg_output, self.calc_output, self.calc_change] + .into_iter() + .map(|site| site.lib) + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct AllocatedState { + pub sufficient: rgb::State, + pub insufficient: Option, +} + +#[derive(Debug)] +pub struct StateCalc { + vm: aluvm::Vm, + abi: StateAbi, + scripts: Scripts, +} + +impl StateCalc { + pub fn new(scripts: Scripts, abi: StateAbi) -> Self { + let vm = aluvm::Vm::new(); + Self { vm, abi, scripts } + } + + fn run(&mut self, site: LibSite) -> Result<(), String> { + if !self.vm.exec(site, |id| self.scripts.get(&id), &()) { + if let Some(err) = self.vm.registers.get_s(RegS::from(15)).cloned() { + return Err(err.to_string()); + } + } + Ok(()) + } + + fn put_state(&mut self, ty: AssignmentType, state: &rgb::State) { + self.vm + .registers + .set_n(RegA::A16, Reg32::Reg0, Some(ty.to_inner())); + assert_eq!(state.reserved, none!()); + self.vm.registers.set_n(RegA::A8, Reg32::Reg0, Some(0u8)); + self.vm + .registers + .set_s(RegS::from(0), Some(ByteStr::with(&state.value))); + self.vm.registers.set_n( + RegR::R256, + Reg32::Reg0, + state.attach.map(|a| u256::from_le_bytes(a.to_byte_array())), + ); + } + + fn fetch_state( + &self, + ty: AssignmentType, + idx: Reg16, + ) -> Result, StateCalcError> { + let Some(value) = self.vm.registers.get_s(RegS::from(u4::from(idx))) else { + return Ok(None); + }; + let reserved = self + .vm + .registers + .get_n(RegA::A8, idx) + .map(|n| u8::from(n)) + .unwrap_or_default(); + let attach = self + .vm + .registers + .get_n(RegR::R256, idx) + .map(|n| AttachId::from_byte_array(u256::from(n).to_le_bytes())); + if reserved != 0x00 { + return Err(StateCalcError::InvalidReserved(ty, reserved)); + } + Ok(Some(rgb::State { + reserved: none!(), + value: StateData::from_checked(value.to_vec()), + attach, + })) + } + + pub fn reg_input( + &mut self, + ty: AssignmentType, + state: &rgb::State, + ) -> Result<(), StateCalcError> { + self.put_state(ty, state); + self.run(self.abi.reg_input) + .map_err(|err| StateCalcError::InputReg(ty, err)) + } + + pub fn reg_output( + &mut self, + ty: AssignmentType, + state: &rgb::State, + ) -> Result<(), StateCalcError> { + self.put_state(ty, state); + self.run(self.abi.reg_output) + .map_err(|err| StateCalcError::OutputReg(ty, err)) + } + + pub fn calc_output( + &mut self, + ty: AssignmentType, + state: &rgb::State, + ) -> Result { + self.put_state(ty, state); + self.run(self.abi.calc_output) + .map_err(|err| StateCalcError::OutputCalc(ty, err))?; + let Some(sufficient) = self.fetch_state(ty, Reg16::Reg0)? else { + return Err(StateCalcError::InsufficientState(ty)); + }; + let insufficient = self.fetch_state(ty, Reg16::Reg1)?; + Ok(AllocatedState { + sufficient, + insufficient, + }) + } + + pub fn calc_change( + &mut self, + ty: AssignmentType, + ) -> Result, StateCalcError> { + self.run(self.abi.calc_change) + .map_err(|err| StateCalcError::ChangeCalc(ty, err))?; + self.fetch_state(ty, Reg16::Reg0) + } +} diff --git a/src/interface/contract.rs b/src/interface/contract.rs index 5f03b6d5..a5113fdf 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -66,17 +66,6 @@ pub struct ContractOp { pub witness: Option, } -fn reduce_to_ty(allocations: impl IntoIterator) -> AssignmentType { - allocations - .into_iter() - .map(|a| a.opout.ty) - .reduce(|ty1, ty2| { - assert_eq!(ty1, ty2); - ty1 - }) - .expect("empty list of allocations") -} - impl ContractOp { fn genesis(our_allocations: HashSet) -> impl ExactSizeIterator { our_allocations.into_iter().map(|a| Self { diff --git a/src/interface/iimpl.rs b/src/interface/iimpl.rs index 1e528ed1..69f9eb76 100644 --- a/src/interface/iimpl.rs +++ b/src/interface/iimpl.rs @@ -36,7 +36,7 @@ use strict_encoding::{FieldName, StrictDumb, VariantName}; use strict_types::encoding::{StrictDecode, StrictEncode, StrictType}; use crate::interface::iface::IfaceId; -use crate::interface::{Iface, VerNo}; +use crate::interface::{Iface, StateAbi, VerNo}; use crate::{ReservedBytes, LIB_NAME_RGB_STD}; pub trait SchemaTypeIndex: @@ -228,6 +228,7 @@ pub struct IfaceImpl { pub extensions: TinyOrdSet>, pub errors: TinyOrdSet>, pub developer: Identity, + pub state_abi: StateAbi, } impl IfaceImpl { diff --git a/src/interface/mod.rs b/src/interface/mod.rs index e4bd759f..4e0edd21 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -31,8 +31,10 @@ mod filter; pub(crate) mod resolver; mod contractum; mod inheritance; +mod calc; pub use builder::{BuilderError, ContractBuilder, TransitionBuilder, TxOutpoint}; +pub use calc::{AllocatedState, StateAbi, StateCalc, StateCalcError}; pub use contract::{ContractError, ContractIface, ContractOp, OpDirection}; pub use contractum::IfaceDisplay; pub use filter::{AssignmentsFilter, FilterExclude, FilterIncludeAll}; diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index 1bd3098e..cb14ee79 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -29,8 +29,8 @@ use std::{iter, mem}; use aluvm::library::{Lib, LibId}; use amplify::confinement::{ - self, Confined, LargeOrdMap, LargeOrdSet, MediumBlob, MediumOrdMap, MediumOrdSet, SmallBlob, - SmallOrdMap, TinyOrdMap, TinyOrdSet, + self, Confined, LargeOrdMap, LargeOrdSet, MediumBlob, MediumOrdMap, MediumOrdSet, SmallOrdMap, + TinyOrdMap, TinyOrdSet, }; use amplify::num::u24; use bp::dbc::tapret::TapretCommitment; @@ -44,8 +44,8 @@ use rgb::vm::{ use rgb::{ Assign, AssignmentType, Assignments, AssignmentsRef, AttachId, BundleId, ContractId, ExposedSeal, Extension, Genesis, GenesisSeal, GlobalStateType, GraphSeal, Identity, OpId, - Operation, Opout, Schema, SchemaId, SecretSeal, Transition, TransitionBundle, XChain, - XOutpoint, XOutputSeal, XWitnessId, + Operation, Opout, Schema, SchemaId, SecretSeal, StateData, Transition, TransitionBundle, + XChain, XOutpoint, XOutputSeal, XWitnessId, }; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::TypeSystem; @@ -680,7 +680,7 @@ impl StateWriteProvider for MemState { #[strict_type(lib = LIB_NAME_RGB_STORAGE)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct MemGlobalState { - known: LargeOrdMap, + known: LargeOrdMap, limit: u24, } @@ -850,12 +850,12 @@ impl> ContractStateAccess for MemContract { &self, ty: GlobalStateType, ) -> Result, UnknownGlobalStateType> { - type Src<'a> = &'a BTreeMap; - type FilteredIter<'a> = Box + 'a>; + type Src<'a> = &'a BTreeMap; + type FilteredIter<'a> = Box + 'a>; struct Iter<'a> { src: Src<'a>, iter: FilteredIter<'a>, - last: Option<(GlobalOrd, &'a SmallBlob)>, + last: Option<(GlobalOrd, &'a StateData)>, depth: u24, constructor: Box) -> FilteredIter<'a> + 'a>, } @@ -867,7 +867,7 @@ impl> ContractStateAccess for MemContract { } } impl<'a> GlobalStateIter for Iter<'a> { - type Data = &'a SmallBlob; + type Data = &'a StateData; fn size(&mut self) -> u24 { let iter = self.swap(); // TODO: Consuming iterator just to count items is highly inefficient, but I do diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index c1b3e083..bd0dba10 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -312,6 +312,7 @@ impl Stash

{ let lib = self.provider.lib(id)?; scripts.insert(id, lib.clone()); } + // TODO: Make sure we have all the libs including their dependencies let scripts = Scripts::try_from(scripts) .map_err(|_| StashDataError::TooManyLibs(schema.schema_id()))?; @@ -358,6 +359,12 @@ impl Stash

{ .ok_or(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()))?; let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; + let mut scripts = BTreeMap::new(); + for id in iimpl.state_abi.lib_ids() { + let lib = self.provider.lib(id)?; + scripts.insert(id, lib.clone()); + } + let scripts = Scripts::from_checked(scripts); let builder = if let Some(transition_name) = transition_name { TransitionBuilder::named_transition( @@ -367,6 +374,7 @@ impl Stash

{ iimpl.clone(), transition_name.into(), types, + scripts, ) } else { TransitionBuilder::default_transition( @@ -375,6 +383,7 @@ impl Stash

{ schema.clone(), iimpl.clone(), types, + scripts, ) } .expect("internal inconsistency"); diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index a295c74a..1d8191a7 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -31,7 +31,7 @@ use bp::dbc::Method; use bp::seals::txout::CloseMethod; use bp::Vout; use chrono::Utc; -use invoice::{Beneficiary, InvoiceState, RgbInvoice}; +use invoice::{Beneficiary, RgbInvoice}; use nonasync::persistence::{CloneNoPersistence, PersistenceError, PersistenceProvider}; use rgb::validation::{DbcProof, ResolveWitness, WitnessResolverError}; use rgb::{ @@ -230,6 +230,9 @@ pub enum ComposeError { /// the invoice contains no interface information. NoIface, + /// the invoice lacks specific state information. + NoInvoiceState, + /// the invoice requirements can't be fulfilled using available assets or /// smart contract state. InsufficientState, @@ -904,6 +907,11 @@ impl Stock { seal_blinder: impl Fn(ContractId, AssignmentType) -> u64, ) -> Result> { let layer1 = invoice.layer1(); + let invoice_state = invoice + .owned_state + .state() + .ok_or(ComposeError::NoInvoiceState)? + .clone(); let prev_outputs = prev_outputs .into_iter() .map(|o| o.into()) @@ -961,7 +969,6 @@ impl Stock { // allocate a different state transition spending them as a change. let mut alt_builder = self.transition_builder(contract_id, iface.clone(), invoice.operation.clone())?; - let mut alt_inputs = Vec::::new(); let layer1 = invoice.beneficiary.chain_network().layer1(); let beneficiary = match (invoice.beneficiary.into_inner(), beneficiary_vout) { @@ -983,16 +990,7 @@ impl Stock { // 2. Prepare transition let mut main_inputs = Vec::::new(); - let mut sum_inputs = Amount::ZERO; - let mut sum_alt = Amount::ZERO; - let mut data_inputs = vec![]; - let mut data_main = true; - let lookup_state = - if let InvoiceState::Data(NonFungible::RGB21(allocation)) = &invoice.owned_state { - Some(DataState::from(*allocation)) - } else { - None - }; + let mut alt_inputs = Vec::::new(); for (output, list) in self.contract_assignments_for(contract_id, prev_outputs.iter().copied())? @@ -1002,7 +1000,7 @@ impl Stock { } else { alt_inputs.push(output) }; - for (opout, mut state) in list { + for (opout, state) in list { if output.method() == method { main_builder = main_builder.add_input(opout, state.clone())?; } else { @@ -1010,109 +1008,34 @@ impl Stock { } if opout.ty != assignment_id { let seal = output_for_assignment(contract_id, opout.ty)?; - state.update_blinding(pedersen_blinder(contract_id, assignment_id)); if output.method() == method { main_builder = main_builder.add_owned_state_raw(opout.ty, seal, state)?; } else { alt_builder = alt_builder.add_owned_state_raw(opout.ty, seal, state)?; } - } else if let PersistedState::Amount(value, _, _) = state { - sum_inputs += value; - if output.method() != method { - sum_alt += value; - } - } else if let PersistedState::Data(value, _) = state { - if lookup_state.as_ref() == Some(&value) && output.method() != method { - data_main = false; - } - data_inputs.push(value); } } } - // Add payments to beneficiary and change - match invoice.owned_state.clone() { - InvoiceState::Amount(amt) => { - // Pay beneficiary - if sum_inputs < amt { - return Err(ComposeError::InsufficientState.into()); - } - - let sum_main = sum_inputs - sum_alt; - let (paid_main, paid_alt) = - if sum_main < amt { (sum_main, amt - sum_main) } else { (amt, Amount::ZERO) }; - let blinding_beneficiary = pedersen_blinder(contract_id, assignment_id); - - if paid_main > Amount::ZERO { - main_builder = main_builder.add_fungible_state_raw( - assignment_id, - beneficiary, - paid_main, - blinding_beneficiary, - )?; - } - if paid_alt > Amount::ZERO { - alt_builder = alt_builder.add_fungible_state_raw( - assignment_id, - beneficiary, - paid_alt, - blinding_beneficiary, - )?; - } - let blinding_change = pedersen_blinder(contract_id, assignment_id); - let change_seal = output_for_assignment(contract_id, assignment_id)?; - - // Pay change - if sum_main > paid_main { - main_builder = main_builder.add_fungible_state_raw( - assignment_id, - change_seal, - sum_main - paid_main, - blinding_change, - )?; - } - if sum_alt > paid_alt { - alt_builder = alt_builder.add_fungible_state_raw( - assignment_id, - change_seal, - sum_alt - paid_alt, - blinding_change, - )?; - } - } - InvoiceState::Data(data) => match data { - NonFungible::RGB21(allocation) => { - let lookup_state = DataState::from(allocation); - if !data_inputs.into_iter().any(|x| x == lookup_state) { - return Err(ComposeError::InsufficientState.into()); - } - - let seal = seal_blinder(contract_id, assignment_id); - if data_main { - main_builder = main_builder.add_data_raw( - assignment_id, - beneficiary, - allocation, - seal, - )?; - } else { - alt_builder = alt_builder.add_data_raw( - assignment_id, - beneficiary, - allocation, - seal, - )?; - } - } - }, - _ => { - todo!( - "only PersistedState::Amount and PersistedState::Allocation are currently \ - supported" - ) + // Add payments to beneficiary + let (builder, partial_state) = + main_builder.fulfill_owned_state(assignment_id, beneficiary, invoice_state)?; + main_builder = builder; + if let Some(partial_state) = partial_state { + let (builder, remaining_state) = + alt_builder.fulfill_owned_state(assignment_id, beneficiary, partial_state)?; + alt_builder = builder; + if let Some(_) = remaining_state { + // TODO: Add information about remaining state to the error + return Err(ComposeError::InsufficientState.into()); } } + // Pay change + let change_seal = output_for_assignment(contract_id, assignment_id)?; + main_builder = main_builder.add_owned_state_change(assignment_id, change_seal)?; + alt_builder = alt_builder.add_owned_state_change(assignment_id, change_seal)?; + // 3. Prepare other transitions // Enumerate state let mut spent_state = From 8f7020c5a04d019e2fb376d95031be1fecfdedf6 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 15 Oct 2024 23:59:09 +0200 Subject: [PATCH 03/70] iface: add abiloity to select inputs for a given state to ContractIface --- Cargo.lock | 2 +- src/interface/calc.rs | 6 +++++- src/interface/contract.rs | 22 +++++++++++++++++++++- src/persistence/stash.rs | 19 +++++++++++++------ src/persistence/stock.rs | 2 ++ 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28d602ca..2cdf0702 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "aluvm" version = "0.11.0-beta.9" -source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#24bff9f61570ea26d14e86aa5e127937aa122440" +source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#7adf61dbe4a3b39834bc3d665800024d66658e9c" dependencies = [ "amplify", "ascii-armor", diff --git a/src/interface/calc.rs b/src/interface/calc.rs index 50a6fd50..32043aa1 100644 --- a/src/interface/calc.rs +++ b/src/interface/calc.rs @@ -76,7 +76,7 @@ pub struct AllocatedState { pub insufficient: Option, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct StateCalc { vm: aluvm::Vm, abi: StateAbi, @@ -189,4 +189,8 @@ impl StateCalc { .map_err(|err| StateCalcError::ChangeCalc(ty, err))?; self.fetch_state(ty, Reg16::Reg0) } + + pub fn is_sufficient_for(&self, ty: AssignmentType, state: &rgb::State) -> bool { + self.clone().calc_output(ty, state).is_ok() + } } diff --git a/src/interface/contract.rs b/src/interface/contract.rs index a5113fdf..f3fca6d8 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -22,13 +22,14 @@ use std::borrow::Borrow; use std::collections::{BTreeSet, HashMap, HashSet}; +use rgb::validation::Scripts; use rgb::{AssignmentType, ContractId, OpId, Schema, State, XOutputSeal, XWitnessId}; use strict_encoding::FieldName; use strict_types::{StrictVal, TypeSystem}; use crate::contract::{OutputAssignment, WitnessInfo}; use crate::info::ContractInfo; -use crate::interface::{AssignmentsFilter, IfaceImpl}; +use crate::interface::{AssignmentsFilter, IfaceImpl, StateCalc}; use crate::persistence::ContractStateRead; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] @@ -115,6 +116,7 @@ pub struct ContractIface { pub schema: Schema, pub iface: IfaceImpl, pub types: TypeSystem, + pub scripts: Scripts, pub info: ContractInfo, } @@ -175,6 +177,24 @@ impl ContractIface { .filter(move |outp| outp.opout.ty == type_id)) } + pub fn assignments_fulfilling<'c, K: Ord + 'c>( + &'c self, + name: impl Into, + filter: impl AssignmentsFilter + 'c, + state: &'c State, + sorting: impl FnMut(&&OutputAssignment) -> K, + ) -> Result + 'c, ContractError> { + let mut selected = self.assignments_by_type(name, filter)?.collect::>(); + selected.sort_by_key(sorting); + let mut calc = StateCalc::new(self.scripts.clone(), self.iface.state_abi); + Ok(selected.into_iter().take_while(move |a| { + if calc.reg_input(a.opout.ty, &a.state).is_err() { + return false; + } + calc.is_sufficient_for(a.opout.ty, state) + })) + } + pub fn history( &self, filter_outpoints: impl AssignmentsFilter, diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index bd0dba10..a5822a7b 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -292,6 +292,18 @@ impl Stash

{ .map_err(StashError::ReadProvider) } + pub(super) fn scripts<'a>( + &self, + lib_ids: impl IntoIterator, + ) -> Result> { + let mut scripts = BTreeMap::new(); + for id in lib_ids { + let lib = self.provider.lib(id)?; + scripts.insert(id, lib.clone()); + } + Ok(Scripts::from_checked(scripts)) + } + pub(super) fn extract<'a>( &self, schema: &Schema, @@ -359,12 +371,7 @@ impl Stash

{ .ok_or(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()))?; let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; - let mut scripts = BTreeMap::new(); - for id in iimpl.state_abi.lib_ids() { - let lib = self.provider.lib(id)?; - scripts.insert(id, lib.clone()); - } - let scripts = Scripts::from_checked(scripts); + let scripts = self.scripts(iimpl.state_abi.lib_ids())?; let builder = if let Some(transition_name) = transition_name { TransitionBuilder::named_transition( diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 1d8191a7..a142358e 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -579,6 +579,7 @@ impl Stock { state, schema: schema_ifaces.schema.clone(), iface: iimpl.clone(), + scripts: self.stash.scripts(iimpl.state_abi.lib_ids())?, types, info, })) @@ -604,6 +605,7 @@ impl Stock { state, schema: schema_ifaces.schema.clone(), iface: iimpl.clone(), + scripts: self.stash.scripts(iimpl.state_abi.lib_ids())?, types, info, }) From 3c4dcd4254c907d0b439b31f75eccb80c2d0fa01 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 00:27:16 +0200 Subject: [PATCH 04/70] iface: use StrictVal instead of State in ContractOp --- Cargo.lock | 5 +- Cargo.toml | 2 +- src/interface/contract.rs | 102 +++++++++++++++++++++++--------------- 3 files changed, 65 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cdf0702..3f6459a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -526,6 +526,7 @@ checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", + "serde", ] [[package]] @@ -910,9 +911,9 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f16e8855a575633815f01482ac927ebaca3d2485aec8e17226c6826de29154e" +checksum = "3188d65ee78a90da3545df762a1363b5b4f9c3b845f182a18fc40ae991c235ce" dependencies = [ "amplify", "ascii-armor", diff --git a/Cargo.toml b/Cargo.toml index 55db1cec..e4200e51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ nonasync = "0.1.0" ascii-armor = "0.7.2" baid64 = "0.2.2" strict_encoding = "2.7.0" -strict_types = "2.7.0" +strict_types = "2.7.1" commit_verify = { version = "0.11.0-beta.9", features = ["stl"] } bp-core = { version = "0.11.0-beta.9", features = ["stl"] } bp-invoice = { version = "0.11.0-beta.9" } diff --git a/src/interface/contract.rs b/src/interface/contract.rs index f3fca6d8..fe9db18b 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -22,8 +22,9 @@ use std::borrow::Borrow; use std::collections::{BTreeSet, HashMap, HashSet}; +use amplify::confinement::SmallBlob; use rgb::validation::Scripts; -use rgb::{AssignmentType, ContractId, OpId, Schema, State, XOutputSeal, XWitnessId}; +use rgb::{AssignmentType, AttachId, ContractId, OpId, Schema, State, XOutputSeal, XWitnessId}; use strict_encoding::FieldName; use strict_types::{StrictVal, TypeSystem}; @@ -52,59 +53,50 @@ pub enum OpDirection { Sent, } -#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(Clone, Eq, PartialEq, Debug)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "type") + serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct ContractOp { pub direction: OpDirection, pub ty: AssignmentType, pub opids: BTreeSet, - pub state: State, + pub state: StrictVal, + pub attach_id: Option, pub to: BTreeSet, pub witness: Option, } impl ContractOp { - fn genesis(our_allocations: HashSet) -> impl ExactSizeIterator { - our_allocations.into_iter().map(|a| Self { - direction: OpDirection::Issued, - ty: a.opout.ty, - opids: bset![a.opout.op], - state: a.state, - to: bset![a.seal], - witness: None, - }) + fn new( + direction: OpDirection, + assignment: OutputAssignment, + value: StrictVal, + witness: Option, + ) -> Self { + Self { + direction, + ty: assignment.opout.ty, + opids: bset![assignment.opout.op], + state: value, + attach_id: assignment.state.attach, + to: bset![assignment.seal], + witness, + } } - fn sent( - witness: WitnessInfo, - ext_allocations: HashSet, - ) -> impl ExactSizeIterator { - ext_allocations.into_iter().map(move |a| Self { - direction: OpDirection::Sent, - ty: a.opout.ty, - opids: bset![a.opout.op], - state: a.state, - to: bset![a.seal], - witness: Some(witness), - }) + fn issued(assignment: OutputAssignment, value: StrictVal) -> Self { + Self::new(OpDirection::Issued, assignment, value, None) } - fn received( - witness: WitnessInfo, - our_allocations: HashSet, - ) -> impl ExactSizeIterator { - our_allocations.into_iter().map(move |a| Self { - direction: OpDirection::Received, - ty: a.opout.ty, - opids: bset![a.opout.op], - state: a.state, - to: bset![a.seal], - witness: Some(witness), - }) + fn received(assignment: OutputAssignment, value: StrictVal, witness: WitnessInfo) -> Self { + Self::new(OpDirection::Received, assignment, value, Some(witness)) + } + + fn sent(assignment: OutputAssignment, value: StrictVal, witness: WitnessInfo) -> Self { + Self::new(OpDirection::Sent, assignment, value, Some(witness)) } } @@ -121,6 +113,19 @@ pub struct ContractIface { } impl ContractIface { + fn assignment_value(&self, ty: AssignmentType, value: &SmallBlob) -> StrictVal { + let sem_id = self + .schema + .owned_types + .get(&ty) + .expect("invalid contract state") + .sem_id; + self.types + .strict_deserialize_type(sem_id, value.as_slice()) + .expect("invalid contract state") + .unbox() + } + pub fn contract_id(&self) -> ContractId { self.state.contract_id() } /// # Panics @@ -233,7 +238,10 @@ impl ContractIface { let mut ops = Vec::with_capacity(witness_ids.len() + 1); // add allocations with no witness to the beginning of the history if let Some(genesis_state) = allocations_our_outpoint.remove(&None) { - ops.extend(ContractOp::genesis(genesis_state)); + for assignment in genesis_state { + let value = self.assignment_value(assignment.opout.ty, &assignment.state.value); + ops.push(ContractOp::issued(assignment, value)) + } } for witness_id in witness_ids { let our_outpoint = allocations_our_outpoint.remove(&Some(witness_id)); @@ -255,16 +263,28 @@ impl ContractIface { if ext_assignments.is_empty() { continue; } - ops.extend(ContractOp::sent(witness_info, ext_assignments)) + for assignment in ext_assignments { + let value = + self.assignment_value(assignment.opout.ty, &assignment.state.value); + ops.push(ContractOp::sent(assignment, value, witness_info)) + } } // the same as above, but the payment has no change (None, Some(ext_assignments)) => { - ops.extend(ContractOp::sent(witness_info, ext_assignments)) + for assignment in ext_assignments { + let value = + self.assignment_value(assignment.opout.ty, &assignment.state.value); + ops.push(ContractOp::sent(assignment, value, witness_info)) + } } // we own allocation but the witness transaction was made by other wallet: // this is an incoming payment to us. (Some(our_assignments), None) => { - ops.extend(ContractOp::received(witness_info, our_assignments)) + for assignment in our_assignments { + let value = + self.assignment_value(assignment.opout.ty, &assignment.state.value); + ops.push(ContractOp::received(assignment, value, witness_info)) + } } // these can't get into the `witness_ids` due to the used filters (None, None) => unreachable!("broken allocation filters"), From 10ee5cc0047c368472ca18f21b9d7c5eaf9617e8 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 01:41:37 +0200 Subject: [PATCH 05/70] iface: provide clients with owned state in form of StrictVal --- .../{assignments.rs => allocation.rs} | 16 +- src/contract/mod.rs | 4 +- src/interface/contract.rs | 145 +++++++++++---- src/interface/mod.rs | 2 +- src/lib.rs | 2 +- src/persistence/memory.rs | 22 +-- src/persistence/state.rs | 4 +- src/stl.rs | 2 +- stl/RGBStorage@0.11.0.sta | 176 +++++++++--------- stl/RGBStorage@0.11.0.stl | Bin 11620 -> 11614 bytes stl/RGBStorage@0.11.0.sty | 8 +- 11 files changed, 228 insertions(+), 153 deletions(-) rename src/contract/{assignments.rs => allocation.rs} (92%) diff --git a/src/contract/assignments.rs b/src/contract/allocation.rs similarity index 92% rename from src/contract/assignments.rs rename to src/contract/allocation.rs index f6be139a..cb3cdc64 100644 --- a/src/contract/assignments.rs +++ b/src/contract/allocation.rs @@ -43,6 +43,8 @@ pub struct WitnessInfo { pub ord: WitnessOrd, } +/// Allocation is an owned state assignment, equipped with information about the operation defining +/// the assignment and the witness id, containing the commitment to the operation. #[allow(clippy::derived_hash_with_manual_eq)] #[derive(Clone, Eq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -52,14 +54,14 @@ pub struct WitnessInfo { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase") )] -pub struct OutputAssignment { +pub struct Allocation { pub opout: Opout, pub seal: XOutputSeal, pub state: State, pub witness: Option, } -impl PartialEq for OutputAssignment { +impl PartialEq for Allocation { fn eq(&self, other: &Self) -> bool { // We ignore difference in witness transactions, state and seal definitions here // in order to support updates from the ephemeral state of the lightning @@ -74,11 +76,11 @@ impl PartialEq for OutputAssignment { } } -impl PartialOrd for OutputAssignment { +impl PartialOrd for Allocation { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for OutputAssignment { +impl Ord for Allocation { fn cmp(&self, other: &Self) -> Ordering { if self == other { return Ordering::Equal; @@ -90,7 +92,7 @@ impl Ord for OutputAssignment { } } -impl OutputAssignment { +impl Allocation { /// # Panics /// /// If the processing is done on invalid stash data, the seal is @@ -103,7 +105,7 @@ impl OutputAssignment { ty: AssignmentType, no: u16, ) -> Self { - OutputAssignment { + Allocation { opout: Opout::new(opid, ty, no), seal: seal.try_to_output_seal(witness_id).expect( "processing contract from unverified/invalid stash: witness seal chain doesn't \ @@ -125,7 +127,7 @@ impl OutputAssignment { ty: AssignmentType, no: u16, ) -> Self { - OutputAssignment { + Allocation { opout: Opout::new(opid, ty, no), seal: seal.to_output_seal().expect( "processing contract from unverified/invalid stash: seal must have txid \ diff --git a/src/contract/mod.rs b/src/contract/mod.rs index 96298642..cc0c48f2 100644 --- a/src/contract/mod.rs +++ b/src/contract/mod.rs @@ -19,10 +19,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod assignments; +mod allocation; mod merge_reveal; -pub use assignments::{OutputAssignment, WitnessInfo}; +pub use allocation::{Allocation, WitnessInfo}; pub use merge_reveal::{MergeReveal, MergeRevealError}; use rgb::vm::OrdOpRef; use rgb::{ExtensionType, OpId, TransitionType, XWitnessId}; diff --git a/src/interface/contract.rs b/src/interface/contract.rs index fe9db18b..1452779f 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -22,13 +22,16 @@ use std::borrow::Borrow; use std::collections::{BTreeSet, HashMap, HashSet}; +use amplify::confinement; use amplify::confinement::SmallBlob; use rgb::validation::Scripts; -use rgb::{AssignmentType, AttachId, ContractId, OpId, Schema, State, XOutputSeal, XWitnessId}; -use strict_encoding::FieldName; -use strict_types::{StrictVal, TypeSystem}; +use rgb::{ + AssignmentType, AttachId, ContractId, OpId, Opout, Schema, State, XOutputSeal, XWitnessId, +}; +use strict_encoding::{FieldName, SerializeError, StrictSerialize}; +use strict_types::{typify, SemId, StrictVal, TypeSystem}; -use crate::contract::{OutputAssignment, WitnessInfo}; +use crate::contract::{Allocation, WitnessInfo}; use crate::info::ContractInfo; use crate::interface::{AssignmentsFilter, IfaceImpl, StateCalc}; use crate::persistence::ContractStateRead; @@ -38,6 +41,30 @@ use crate::persistence::ContractStateRead; pub enum ContractError { /// field name {0} is unknown to the contract interface FieldNameUnknown(FieldName), + + /// the provided state object is invalid; {0} + #[from] + Typify(typify::Error), + + /// the provided state exceeds maximum allowed length when serialized. + #[from] + Strict(SerializeError), +} + +/// Allocation is an owned state assignment, equipped with information about the operation defining +/// the assignment and the witness id, containing the commitment to the operation. +#[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct Output { + pub opout: Opout, + pub seal: XOutputSeal, + pub state: StrictVal, + pub attach_id: Option, + pub witness: Option, } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] @@ -72,7 +99,7 @@ pub struct ContractOp { impl ContractOp { fn new( direction: OpDirection, - assignment: OutputAssignment, + assignment: Allocation, value: StrictVal, witness: Option, ) -> Self { @@ -87,15 +114,15 @@ impl ContractOp { } } - fn issued(assignment: OutputAssignment, value: StrictVal) -> Self { + fn issued(assignment: Allocation, value: StrictVal) -> Self { Self::new(OpDirection::Issued, assignment, value, None) } - fn received(assignment: OutputAssignment, value: StrictVal, witness: WitnessInfo) -> Self { + fn received(assignment: Allocation, value: StrictVal, witness: WitnessInfo) -> Self { Self::new(OpDirection::Received, assignment, value, Some(witness)) } - fn sent(assignment: OutputAssignment, value: StrictVal, witness: WitnessInfo) -> Self { + fn sent(assignment: Allocation, value: StrictVal, witness: WitnessInfo) -> Self { Self::new(OpDirection::Sent, assignment, value, Some(witness)) } } @@ -113,19 +140,50 @@ pub struct ContractIface { } impl ContractIface { - fn assignment_value(&self, ty: AssignmentType, value: &SmallBlob) -> StrictVal { - let sem_id = self - .schema + fn assignment_type(&self, name: impl Into) -> Result { + let name = name.into(); + self.iface + .assignments_type(&name) + .ok_or(ContractError::FieldNameUnknown(name)) + } + + fn assignment_sem_id(&self, ty: AssignmentType) -> SemId { + self.schema .owned_types .get(&ty) .expect("invalid contract state") - .sem_id; + .sem_id + } + + fn assignment_value(&self, ty: AssignmentType, value: &SmallBlob) -> StrictVal { self.types - .strict_deserialize_type(sem_id, value.as_slice()) + .strict_deserialize_type(self.assignment_sem_id(ty), value.as_slice()) .expect("invalid contract state") .unbox() } + fn allocation_to_output(&self, a: &Allocation) -> Output { + Output { + opout: a.opout, + seal: a.seal, + state: self.assignment_value(a.opout.ty, &a.state.value), + attach_id: a.state.attach, + witness: a.witness, + } + } + + fn state_convert( + &self, + ty: AssignmentType, + value: StrictVal, + ) -> Result { + let t = self.types.typify(value, self.assignment_sem_id(ty))?; + Ok(self + .types + .strict_serialize_type::<{ confinement::U16 }>(&t)? + .to_strict_serialized()?) + } + pub fn contract_id(&self) -> ContractId { self.state.contract_id() } /// # Panics @@ -158,46 +216,63 @@ impl ContractIface { })) } - pub fn assignments_by<'c>( + pub fn allocations<'c>( &'c self, filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { + ) -> impl Iterator + 'c { self.state .assignments() - .filter(move |outp| filter.should_include(outp.seal, outp.witness)) + .filter(move |a| filter.should_include(a.seal, a.witness)) + } + + pub fn outputs<'c>( + &'c self, + filter: impl AssignmentsFilter + 'c, + ) -> impl Iterator + 'c { + self.allocations(filter) + .map(|a| self.allocation_to_output(a)) } - pub fn assignments_by_type<'c>( + pub fn outputs_by_type<'c>( &'c self, name: impl Into, filter: impl AssignmentsFilter + 'c, - ) -> Result + 'c, ContractError> { - let name = name.into(); - let type_id = self - .iface - .assignments_type(&name) - .ok_or(ContractError::FieldNameUnknown(name))?; + ) -> Result + 'c, ContractError> { + let type_id = self.assignment_type(name)?; Ok(self - .assignments_by(filter) + .outputs(filter) .filter(move |outp| outp.opout.ty == type_id)) } - pub fn assignments_fulfilling<'c, K: Ord + 'c>( + pub fn output_selection<'c, K: Ord + 'c>( &'c self, name: impl Into, filter: impl AssignmentsFilter + 'c, - state: &'c State, - sorting: impl FnMut(&&OutputAssignment) -> K, - ) -> Result + 'c, ContractError> { - let mut selected = self.assignments_by_type(name, filter)?.collect::>(); + value: StrictVal, + attach: Option, + sorting: impl FnMut(&&Allocation) -> K, + ) -> Result + 'c, ContractError> { + let type_id = self.assignment_type(name)?; + let mut selected = self + .allocations(filter) + .filter(move |a| a.opout.ty == type_id) + .collect::>(); selected.sort_by_key(sorting); let mut calc = StateCalc::new(self.scripts.clone(), self.iface.state_abi); - Ok(selected.into_iter().take_while(move |a| { - if calc.reg_input(a.opout.ty, &a.state).is_err() { - return false; - } - calc.is_sufficient_for(a.opout.ty, state) - })) + let state = State { + reserved: none!(), + value: self.state_convert(type_id, value)?.into(), + attach, + }; + Ok(selected + .into_iter() + .take_while(move |a| { + if calc.reg_input(a.opout.ty, &a.state).is_err() { + return false; + } + calc.is_sufficient_for(a.opout.ty, &state) + }) + .map(|a| self.allocation_to_output(a))) } pub fn history( diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 4e0edd21..78403f1b 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -35,7 +35,7 @@ mod calc; pub use builder::{BuilderError, ContractBuilder, TransitionBuilder, TxOutpoint}; pub use calc::{AllocatedState, StateAbi, StateCalc, StateCalcError}; -pub use contract::{ContractError, ContractIface, ContractOp, OpDirection}; +pub use contract::{ContractError, ContractIface, ContractOp, OpDirection, Output}; pub use contractum::IfaceDisplay; pub use filter::{AssignmentsFilter, FilterExclude, FilterIncludeAll}; pub use iface::{ diff --git a/src/lib.rs b/src/lib.rs index a67d7a3d..58f9e507 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ mod contract; pub mod info; pub use bp::{Outpoint, Txid}; -pub use contract::{MergeReveal, MergeRevealError, OutputAssignment, WitnessInfo}; +pub use contract::{Allocation, MergeReveal, MergeRevealError, WitnessInfo}; pub use rgb::prelude::*; pub use rgb::rgbasm; pub use stl::{LIB_NAME_RGB_STD, LIB_NAME_RGB_STORAGE}; diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index cb14ee79..81acbf70 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -60,7 +60,7 @@ use super::{ use crate::containers::{ AnchorSet, ContentId, ContentRef, ContentSigs, SealWitness, SigBlob, Supplement, TrustLevel, }; -use crate::contract::{GlobalOut, OpWitness, OutputAssignment}; +use crate::contract::{Allocation, GlobalOut, OpWitness}; use crate::interface::{Iface, IfaceClass, IfaceId, IfaceImpl, IfaceRef}; use crate::LIB_NAME_RGB_STORAGE; @@ -565,7 +565,7 @@ impl StateReadProvider for MemState { .values() .flat_map(|state| state.known.keys()) .any(|out| out.witness_id() == id) - || unfiltered.state.iter().any(|a| a.witness == id) + || unfiltered.owned.iter().any(|a| a.witness == id) }) .map(|(id, ord)| (*id, *ord)) .collect(); @@ -717,7 +717,7 @@ pub struct MemContractState { contract_id: ContractId, #[getter(skip)] global: TinyOrdMap, - state: LargeOrdSet, + owned: LargeOrdSet, } impl MemContractState { @@ -732,7 +732,7 @@ impl MemContractState { schema_id: schema.schema_id(), contract_id, global, - state: empty!(), + owned: empty!(), } } @@ -814,7 +814,7 @@ impl MemContractState { .filter_map(|(n, a)| a.revealed_seal().map(|seal| (n, seal, a.as_state()))) { let assigned_state = match witness_id { - Some(witness_id) => OutputAssignment::with_witness( + Some(witness_id) => Allocation::with_witness( seal, witness_id, state.clone(), @@ -822,11 +822,9 @@ impl MemContractState { *ty, no as u16, ), - None => { - OutputAssignment::with_no_witness(seal, state.clone(), opid, *ty, no as u16) - } + None => Allocation::with_no_witness(seal, state.clone(), opid, *ty, no as u16), }; - self.state + self.owned .push(assigned_state) .expect("contract state exceeded 2^32 items, which is unrealistic"); } @@ -945,7 +943,7 @@ impl> ContractStateAccess for MemContract { ) -> impl DoubleEndedIterator> { self.unfiltered .borrow() - .state + .owned .iter() .filter(move |assignment| { assignment.seal.to_outpoint() == outpoint && assignment.opout.ty == ty @@ -1018,10 +1016,10 @@ impl> ContractStateRead for MemContract { } #[inline] - fn assignments(&self) -> impl Iterator { + fn assignments(&self) -> impl Iterator { self.unfiltered .borrow() - .state + .owned .iter() .filter(|assignment| assignment.check_witness(&self.filter)) } diff --git a/src/persistence/state.rs b/src/persistence/state.rs index 9545b776..216e63df 100644 --- a/src/persistence/state.rs +++ b/src/persistence/state.rs @@ -34,7 +34,7 @@ use rgb::{ }; use crate::containers::{ConsignmentExt, ToWitnessId}; -use crate::contract::OutputAssignment; +use crate::contract::Allocation; use crate::persistence::{StoreTransaction, UpdateRes}; #[derive(Debug, Display, Error, From)] @@ -286,7 +286,7 @@ pub trait ContractStateRead: ContractStateAccess { fn contract_id(&self) -> ContractId; fn schema_id(&self) -> SchemaId; fn witness_ord(&self, witness_id: XWitnessId) -> Option; - fn assignments(&self) -> impl Iterator; + fn assignments(&self) -> impl Iterator; } pub trait ContractStateWrite { diff --git a/src/stl.rs b/src/stl.rs index 1ebfc6a6..d6e1a7a8 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -37,7 +37,7 @@ pub const LIB_NAME_RGB_STORAGE: &str = "RGBStorage"; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. pub const LIB_ID_RGB_STORAGE: &str = - "stl:iayFnuhB-sjXxWhi-Pp!FSyO-astclK4-icTXDwX-O0Fb4F4#floor-avatar-lazarus"; + "stl:RMDj!yyo-ca0Rmdl-pBBc50W-ciu1!P3-U8gHIqL-0Y83X50#memo-ballet-fresh"; /// Strict types id for the library representing of RGB StdLib data types. pub const LIB_ID_RGB_STD: &str = diff --git a/stl/RGBStorage@0.11.0.sta b/stl/RGBStorage@0.11.0.sta index 8ef355eb..0a7db3fc 100644 --- a/stl/RGBStorage@0.11.0.sta +++ b/stl/RGBStorage@0.11.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:iayFnuhB-sjXxWhi-Pp!FSyO-astclK4-icTXDwX-O0Fb4F4#floor-avatar-lazarus +Id: stl:RMDj!yyo-ca0Rmdl-pBBc50W-ciu1!P3-U8gHIqL-0Y83X50#memo-ballet-fresh Name: RGBStorage Dependencies: StrictTypes#century-comrade-chess, @@ -11,7 +11,7 @@ Dependencies: Std#ralph-blue-lucky, RGBLogic#ohio-electra-dilemma, Bitcoin#signal-color-cipher -Check-SHA256: b78e8c45504383900212ce4d621bac70640f73758b4785d2451f48687eebdc7c +Check-SHA256: 1e7e30d1c26d606642c6284e6be3f07d74d165c362f24ee5def19faaca9d5330 3Q|WxQ*>`~VP|CtMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD*X=8L$d2nTORuk6O)Q5AK bFW;JEQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pZ~a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjH @@ -109,92 +109,92 @@ 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 -WRj~^37YhpmjD0&000000RI300000000000000000RR900000000>QGZBuk%b7%$)2yfc^lq>z|G!4fU)2DQrPzVkwe;&S{2rNlD$O59e#ogQsB77jPl+h5j^*S;FuZ_m{WNzU! -AS*T=d6X;t=`;<;71O75notN1DSsZmvAF3TYWxc`p^UTx9aSKLvL!Hqk0OrrRGaio4`M!v0000000000 -{{R30000001#@+9aBKhy0=?Vlw9=)(YVD5X(Bh@-;YAffP|O75Lc0RpIS^JwJO-Gpx7s+uExGllhUte$ -e$Op^sMk_Bzn7+|3$axzr2q*6z1!%t(xt#^?T+No;-&53MHNC&%mm{?y8_)g5LQJzV?EP}uuDl+D$lsi -ICW4a8e$Z2e6I7`3evG=Yh^sO0000000000{{R30000000000000000{{R30000002V!+@WNc+~015)H -jmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&RAdy}<28ig(gSpg+?&9*`C2(3=%09avzwZKZf-~wC% -uZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm{b~4y9C9`4X%pen_fPY -0000000000|NsC0000003T1e7Wo~n6Z*Fq{3IeZ<#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=?^x -=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(IQjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&R? -krgyL25hbsyp?a}5-x=-+yHc@4oMPeoYe!lEU|R}0000000030|Ns9000009cWHEPWpi_7a{vkguZ_m{ -WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmiECIT&Bl;lSX#$ms8AQN7m&qYE2s&92Kh8W}@zf2sFIAOHXW -000000RR90{{R3001IJsbYWv?ZDnqBa{vkguZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmgmDd% -EKc;pw+KsVi?D}qDSkO*B!5Mb*xG|_(S5o&00;m8KmY&$000000RR900000000000000000RR6000000 -01I -xYW^+v~7{W03rq(;firJ0000000000|Ns90000003UqmJWm9=`bY*PC`}q*r{eiB7ehUYis7~w1CQOqefKeZ3;Wd%uopqe!>_vj93Tb3zZggpMX=QT&3IeZ<#`k1y -;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=^8dfQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7c4i+vv2? -rNCR2XhQO_4{AcS-HH^7AVzASV8M4NYxyCl9FjWFA`CQ2GiK9iL -KbGE6DZmrA4)G`0A&^0p`%?-6VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+5(KBV0uX$PL@)I= -)&*`^S@`8Scoz5#{lyP)a751L0000000000|Nj60000001aoO;a{vkgz1!%t(xt#^?T+No;-&53MHNC& -%mm{?y8_)g5LQJz;?xyT5z&Ua+M@}mOiDpYxh>^^GknUxTJ!XL#OUcE0=?Vlw9=)(YVD5X(Bh@-;YAff -P|O75Lc0RpIS^JwJcbw$ENEw7&f?o%+)B!ZpG}K!%4G?I4vp$|ttu*CMF0Q*000000RR600000000>QG -ZBuk%bY%tt33q99Ze??GWpe-u0>gzKLsCCC$c=Uszhl -V5m?Ru@{iVU*wrVdeH+Q@FPbX@dD>lppP|r7nSZ$D@8DuxRa_WcH0nj%57ffI2NNjo|$sHLdY0XT`|v$ -|M|2EBF6^D+OST}`A!+zFZPFTn&AKd0000000960|Nj60000SNZ*FvQVPkZ2015)HjmGz6Zs9Z_D>fc^ -lq>z|G!4fU)2DQrPzVkwe;&S{2rNlD$O59e#ogQsB77jPl+h5j^*S;E4$E#+hX^`zsZ&Tl -gCG9;!;p0|>d6h~fj!Md?2W%$0000000000{{R3000000 +b7^O8ZDnqBRC#b^owA~_)i}*_Qj`w<0nYCCRFDc{!UsZqyzOYb66V_43PEgaZ)0I}X>V?#;91nsu+1H% +suE1D6u@lRoC;S?XbB(j&QSOSPz0a~RC0B5bWCM-Wo)&%LXEmL6-F5v>3G|uUigF$Iw^!m+g!OaP05*n2+UEn$VY06ag%An>_FbOoG7@PGN0jWJYOaY-CMkbYWC^aAm`1 +<%~T%0%0eh&Q^)o89Ex~PX5e}`A;#FO3ABStqEB2u*`(KJ8e4#|WIM{I9mVQfieVPj>~|BtqCIH`QK6F1|v)Z${_ +U85pQj^zm^DU~vi8uS+kQ+04~Y)xTs-Vzs+-~y(u)KQ?3g=q&>T!Ej;9TxQjc0+10Fg2)p3Qu=#Wn@Wa +VPj?D)D=(>(T2L(qY0=?Nkr04IdejB5_YJg;9E|1`d*r&;qSS3+uh`0YNLave-Im7x;m>=zTw_)ojDN{iR+YxT1qeJQTRI%yh?{hxxA$L2PhnVMAeXb4+h!VRLBFJq*Jt8?Abr +ta^#~Iw-!oZ%zqO(A&rh^vGm~tg_w^L2PhnVN-2kY-~(#WMOk?3sZD*X=8L$d2nTO4*&^LN2 +X=Q9=Q)O*QWK$LhgcQkwbf~^M){{|8P%hsRk~m~ep32F151Y4WWC&DwaAi(mZDnMP)DN(0hN+Kdp}ZAoN($wDX8VgT7DmW3qm%zcviBmGB|7z0dgBIJ4&sCG^VR$+2!VQzGR(<~&{!{{>E!(#o& +^pB98KZhv1GEPn8Orhb4n;8ZMQ)zl>ZfBCy0{K32d-H~a`3x8b375ImR&CF_#3#*gz1^xtuG$bzVQpn( +MrmbiWOGwxZAoO8A%m*X98W>f2s0TH8C&EH;|vtDTYgh)4~t7}WW`YoMQ(L%R$+2!VQzGDn938Qb#DiI +%LhXtBc@pg0t!L7$2{bU&sPXOO(dS=5LRJwX<=@3Np5CuQ)O*QWc?UbbJ9Xwr}~3wv^yxa@v}v^+kiGS +R2X#8M$tG2GZIy9X>V>;VRC6_vj93RHP; +Wm9=`bY*P@01ZQLZgg^CV{}PwWMy~;0t|3>gzLOBVfUz`Mi!Z}iQtl5;XwV(E`Zdd&WRj~^37YhpmjD0&000000RR900000001j_;bZ~EJ +Zgfv@Z*_EY015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&TkXBWLg67cp3gzo-sO&$va11I@T +$h!rSEX2t%Czh%J2?DQ;#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=?+hynwMZT8l5kSW@l}O=!>^ +xB4~9n`Dx!RtcK)nwJ0o0000000960{{R30000000000000960{{R30000n8Wo<)mZgg^CV{}t=VRU5% +1PF6uXk~3-Nn`@AjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S+Qq$W5tE;F{pQrXd&=l*`O?@#x +{Qdy?T_k!`1dtF4V{dMBa$#e1Nn`@AjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S{2rNlD$O59e +#ogQsB77jPl+h5j^*S;JXKZg`VQc^j0>g +zSZuM4oQf!Y4K`P(FaQVwIle)QgI&pHa%8Z1>xis%K>dbv;0wBb*7)Id;7I5;T&_H+G%6DVUHTf +p;u=X0|Kv&#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=>}YR2^S7pk#{MS?zgMX@X{kfl~;6wBm#t +C>wDnA0009BO=WFKZe(S61_cdoa6)x%WNc+gZe(S6015)HjmGz6 +Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S-$mV(;bz)!CmQ_M(k?Vd!kfCo{nDM?)_qK{868FUduZ_m{ +WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm1ACLTJsO2B2U!6ncg?mz@CdC==Kxq?gSEg)z2E{|00000 +00000|Ns90000006Jm94WNc+aZ*FvQVPkYjZe(S6015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkw +e;&RAdy}<28ig(gSpg+?&9*`C2(3=%09avzwZKZf-~wC%uZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1 +DSsZmp9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0000000000|Ns90000005@L03WNc+uX>@L7 +b8|^g)RqK0VQ|Mwn6X+txo3v +SYd;;z)HQ~0$czI0>gzKLsCCC$c=UszhlV5m?Ru@{iV +U*wrVdeH+Q@FPbX@c;k-000000RI300000000000000000RR900000001abrZgg^CV{}PwWMy~&3IeZ< +#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=@LlEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22Ix+z) +)N;MU`Np56icmN6l +uZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm+lpEmf)o&SDDwD>KtpQ8M_qJyiO1VIUJ=H=)@ii_ +00{!GjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S*5WIk~G+K)5%bR49t5yk` +^qQ9d000000003000000000000000000030|Nj6000008O=WFUbYXL71`P;vV`ybE<3hUv-8m3eMLapj8a{pyIM27f +oOFHbufC9*xQ=a*L`qQ5aG5b!Ay5DS000000093000000000MPWo~72Wpe-u0>gzMlvzNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6JuS#`k1y;WQvCHXeDD +EB)y-4aXJJr*xW72o5QK9=@@-=^kqQ3p1gNv;!SgAcC?bFoBOEj`UQU^i2<9K8XMT000000093000000 +000GZb#QQO015)V+vv2?rNCE<3hUv-8m3eMLc6Y(}}Q4NmeS)xXw6rP$n8; +6mfj6^V>gz5{!cwLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O1>gzD1E0G&%-s +t`)qMZ{`v%g)H0vbfykT5^0>(1Gy}*bpQYW000000RR90{{R30010<#bZ%vHb7gY?3IeZ<#`k1y;WQvC +HXeDDEB)y-4aXJJr*xW72o5QK9=?fdSS8KIkY89@$6%;X7qJ(R#b4x^L3+^xAn+qc8}S0Y+vv2?rNCjuaWwz{0000000960{{R30000Vfd2nS@d2@7SZ30E=qhH(h&PZdlOljoA7|k;k>s6qoa5|8f~g8=WMyu2X>@62a{vkguZ_m{WNzU!AS*T= +d6X;t=`;<;71O75notN1DSsZmw&;L{94K`ndk%K5+?9Jv$dw7jc}U5p5@2#$kUJ%u0=?Vlw9=)(YVD5X +(Bh@-;YAffP|O75Lc0RpIS^JwJfh%P)X}ib9i^%gOs*8bY}uR&S59aNAMwsm_ykY{pa1{>000000RR60 +0000000eAlVsiir0%CAAe<9`Lptgpr6F_xjAC6(~TLj#*ewiHm5LE0xkJm$nc4yMWR2J-cc#Q +6SofWC)gp7L6!Sc3IbwqHGd)Hlr&gK9B000000096000000000DYX=if)3Ie^`=(N(Mz-sM|E<3hUv +-8m3eMLgov6;Kh;hPv9L38+j;K}xwT<$*JN%D`Il^nAqV=^+BW+vv2?rNCUOOvDqlqa0000000030{{R3000008O=WFUbYXO5 +1_B9pX>@L7b8}^L015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&SxYgi@C#*klFTE}3hP#3Wm +ki}o*nL&Ed10e7tM;q}1=To4MHF_77?oTU4FqgQKswsBc5OvCJUgtO#qdT6Na=Svv7*ky_&y4^1v>gzMlvzNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6Ac7Ex1s`aa6PN-Fgk0S2h>I +cS>a?4Yu+n!-bhcpbh{4000000093000000000 -----END STRICT TYPE LIB----- diff --git a/stl/RGBStorage@0.11.0.stl b/stl/RGBStorage@0.11.0.stl index 948dd4ca60be646faafeccd9df39ff83afb2c88d..3d8ee703ca4a1251c390d95c56a78d30ba1f1635 100644 GIT binary patch delta 153 zcmaD7buVfIkA(KzO^Y^OwK!WGG==XU$54X;AUckoy1^=Nm0NW-)761SM delta 159 zcmcZ?^(1NokA&g854oGT?DySjUj6YvTh$}ui|?E@mRKy&3;8y)CVc<@JOTgGl7i9_ z$KvA5^t{~Eypql45-}XC#U+U)sgt?Yl@$mXu=%z^FpmM>>Ac`}4y)po!5;R_^8bDx ao=|H1>Ll;;M%%NlZ+iDfGeE(AC=CGMUPgBS diff --git a/stl/RGBStorage@0.11.0.sty b/stl/RGBStorage@0.11.0.sty index 805aadf7..67c9f1b5 100644 --- a/stl/RGBStorage@0.11.0.sty +++ b/stl/RGBStorage@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:iayFnuhB-sjXxWhi-Pp!FSyO-astclK4-icTXDwX-O0Fb4F4#floor-avatar-lazarus + Id: stl:RMDj!yyo-ca0Rmdl-pBBc50W-ciu1!P3-U8gHIqL-0Y83X50#memo-ballet-fresh Name: RGBStorage Version: 0.11.0 Description: RGB storage library @@ -144,7 +144,7 @@ import RGBStd#zebra-twist-tango use SupplItem#jargon-orchid-forget use Modifier#saturn-escort-jordan use NamedFieldAssignmentType#origin-caramel-flipper - use OutputAssignment#chicago-neuron-concept + use Allocation#mimosa-savage-future use TrustLevel#cobra-script-albino use StateAbi#thermos-demo-fragile use NamedFieldMetaType#prefix-carmen-artist @@ -198,11 +198,11 @@ import Bitcoin#signal-color-cipher @mnemonic(carol-salute-aroma) data ContractIndex : publicOpouts {RGBCommit.Opout ^ ..0xffffff}, outpointOpouts {RGBCommit.XChainExplicitSealTxid -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xffffff}} -@mnemonic(carbon-arena-ivan) +@mnemonic(dolby-mammal-pogo) data MemContractState : schemaId RGBCommit.SchemaId , contractId RGBCommit.ContractId , global {RGBCommit.GlobalStateType -> ^ ..0xff MemGlobalState} - , state {RGBStd.OutputAssignment ^ ..0xffffffff} + , owned {RGBStd.Allocation ^ ..0xffffffff} @mnemonic(mary-mineral-frame) data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.StateData}, limit U24 From 46694a58ec46495cca6689a2bb3a7a31ffefaf00 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 02:20:17 +0200 Subject: [PATCH 06/70] iface: remove OwnedIface, change owned state inheritance mechanics --- src/interface/contractum.rs | 14 +- src/interface/iface.rs | 47 +----- src/interface/inheritance.rs | 16 +- src/interface/mod.rs | 2 +- src/stl.rs | 4 +- stl/RGBStd@0.11.0.sta | 318 +++++++++++++++++------------------ stl/RGBStd@0.11.0.stl | Bin 18172 -> 18172 bytes stl/RGBStd@0.11.0.sty | 15 +- stl/RGBStorage@0.11.0.sta | 211 ++++++++++++----------- stl/RGBStorage@0.11.0.stl | Bin 11614 -> 11571 bytes stl/RGBStorage@0.11.0.sty | 11 +- stl/Transfer.vesper | 9 +- 12 files changed, 293 insertions(+), 354 deletions(-) diff --git a/src/interface/contractum.rs b/src/interface/contractum.rs index 01cbdbe6..0fa8b927 100644 --- a/src/interface/contractum.rs +++ b/src/interface/contractum.rs @@ -28,9 +28,7 @@ use rgb::Occurrences; use strict_encoding::{FieldName, TypeName, VariantName}; use strict_types::{SemId, SymbolicSys}; -use super::{ - ArgMap, ExtensionIface, GenesisIface, Iface, IfaceId, Modifier, OwnedIface, TransitionIface, -}; +use super::{ArgMap, ExtensionIface, GenesisIface, Iface, IfaceId, Modifier, TransitionIface}; struct ArgMapDisplay<'a>(&'a ArgMap); @@ -266,13 +264,9 @@ impl<'a> Display for IfaceDisplay<'a> { write!(f, "{fname}")?; sugar(f, a.required, a.multiple)?; f.write_str(": ")?; - match a.owned_state { - OwnedIface::Any => write!(f, "AnyType")?, - OwnedIface::Amount => write!(f, "Zk64")?, - OwnedIface::AnyData => write!(f, "Any")?, - OwnedIface::AnyAttach => write!(f, "AnyAttachment")?, - OwnedIface::Rights => write!(f, "Rights")?, - OwnedIface::Data(id) => resolve(f, self.types, id)?, + match a.state_ty { + None => write!(f, "T any => T")?, + Some(id) => resolve(f, self.types, id)?, } writeln!(f)?; } diff --git a/src/interface/iface.rs b/src/interface/iface.rs index d4a904fc..684cfc1c 100644 --- a/src/interface/iface.rs +++ b/src/interface/iface.rs @@ -200,25 +200,28 @@ impl GlobalIface { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct AssignIface { - pub owned_state: OwnedIface, + pub state_ty: Option, + pub attach: Option, pub public: bool, pub required: bool, pub multiple: bool, } impl AssignIface { - pub fn public(owned_state: OwnedIface, req: Req) -> Self { + pub fn public(state_ty: Option, attach: Option, req: Req) -> Self { AssignIface { - owned_state, + state_ty, + attach, public: true, required: req.is_required(), multiple: req.is_multiple(), } } - pub fn private(owned_state: OwnedIface, req: Req) -> Self { + pub fn private(state_ty: Option, attach: Option, req: Req) -> Self { AssignIface { - owned_state, + state_ty, + attach, public: false, required: req.is_required(), multiple: req.is_multiple(), @@ -226,34 +229,6 @@ impl AssignIface { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum OwnedIface { - #[strict_type(dumb)] - Any, - Rights, - Amount, - AnyData, - AnyAttach, - Data(SemId), -} - -impl OwnedIface { - pub fn sem_id(&self) -> Option { - if let Self::Data(id) = self { - Some(*id) - } else { - None - } - } -} - pub type ArgMap = TinyOrdMap; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Default)] @@ -434,11 +409,7 @@ impl Iface { .values() .copied() .chain(self.global_state.values().filter_map(|i| i.sem_id)) - .chain( - self.assignments - .values() - .filter_map(|i| i.owned_state.sem_id()), - ) + .chain(self.assignments.values().filter_map(|i| i.state_ty)) } pub fn find_abstractable_impl<'a>( diff --git a/src/interface/inheritance.rs b/src/interface/inheritance.rs index 518c0595..2c746494 100644 --- a/src/interface/inheritance.rs +++ b/src/interface/inheritance.rs @@ -27,7 +27,7 @@ use rgb::{ use strict_encoding::{FieldName, TypeName}; use crate::interface::{ - ExtensionIface, GenesisIface, Iface, IfaceImpl, Modifier, OpName, OwnedIface, TransitionIface, + ExtensionIface, GenesisIface, Iface, IfaceImpl, Modifier, OpName, TransitionIface, }; #[derive(Clone, PartialEq, Eq, Debug, Display, From)] @@ -273,18 +273,6 @@ pub enum ExtensionError { InheritanceOverflow, } -impl OwnedIface { - pub fn is_superset(self, other: OwnedIface) -> bool { - if self == Self::Any { - return true; - } - if self == Self::AnyData && matches!(other, Self::Data(_)) { - return true; - } - self == other - } -} - impl Modifier { pub fn is_final(self) -> bool { self == Self::Final } pub fn can_be_overridden_by(self, other: Modifier) -> bool { @@ -401,7 +389,7 @@ impl Iface { } } Some(orig) => { - if !orig.owned_state.is_superset(e.owned_state) { + if orig.state_ty.is_some() && orig.state_ty != e.state_ty { errors.push(ExtensionError::AssignmentType(name)); } else if orig.required & !e.required { errors.push(ExtensionError::AssignmentOcc(name)); diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 78403f1b..7b70ae47 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -40,7 +40,7 @@ pub use contractum::IfaceDisplay; pub use filter::{AssignmentsFilter, FilterExclude, FilterIncludeAll}; pub use iface::{ ArgMap, AssignIface, ExtensionIface, GenesisIface, GlobalIface, Iface, IfaceClass, IfaceId, - IfaceInconsistency, IfaceRef, IfaceWrapper, Modifier, OpName, OwnedIface, Req, TransitionIface, + IfaceInconsistency, IfaceRef, IfaceWrapper, Modifier, OpName, Req, TransitionIface, ValencyIface, }; pub use iimpl::{IfaceImpl, ImplId, NamedField, NamedType, NamedVariant, SchemaTypeIndex}; diff --git a/src/stl.rs b/src/stl.rs index d6e1a7a8..7507e045 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -37,11 +37,11 @@ pub const LIB_NAME_RGB_STORAGE: &str = "RGBStorage"; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. pub const LIB_ID_RGB_STORAGE: &str = - "stl:RMDj!yyo-ca0Rmdl-pBBc50W-ciu1!P3-U8gHIqL-0Y83X50#memo-ballet-fresh"; + "stl:lnl6QOG0-EYfOLKP-MHdEyA3-$cyUNuc-F3XmU!W-0glc1M0#alaska-phone-bagel"; /// Strict types id for the library representing of RGB StdLib data types. pub const LIB_ID_RGB_STD: &str = - "stl:vdvotNKl-wGrtjuT-Q4qXt4U-UVQlDMB-ONCuwLd-ORBWRTw#zebra-twist-tango"; + "stl:yMGmidPl-LcWFyh!-W6sQ3K5-JQ8evpO-BGuI!lA-0htx!kg#chemist-enjoy-sound"; #[allow(dead_code)] #[derive(Debug, From)] diff --git a/stl/RGBStd@0.11.0.sta b/stl/RGBStd@0.11.0.sta index f1d81936..1491d12d 100644 --- a/stl/RGBStd@0.11.0.sta +++ b/stl/RGBStd@0.11.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:vdvotNKl-wGrtjuT-Q4qXt4U-UVQlDMB-ONCuwLd-ORBWRTw#zebra-twist-tango +Id: stl:yMGmidPl-LcWFyh!-W6sQ3K5-JQ8evpO-BGuI!lA-0htx!kg#chemist-enjoy-sound Name: RGBStd Dependencies: StrictTypes#century-comrade-chess, @@ -9,7 +9,7 @@ Dependencies: RGBCommit#printer-window-alpine, Std#ralph-blue-lucky, Bitcoin#signal-color-cipher -Check-SHA256: 9c8622031666c98c3fbaacf4d05380087e07145e9901c83988c8071f09cd9cca +Check-SHA256: 4b921710f4ab25f21c5be62b8015e9456f1d473c6aca46706d8a71155de55640 22w{tQ*>kpMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD*X=8L$d2nTORuk6O)Q5AKbFW;J EQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pZ~a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjHL2Pwa @@ -93,7 +93,7 @@ WPQm(C)8p9*(R2SB=5|9lKCV3N0b-?Ol>0MdKRd5P6t+Da%o|1bb-?>B-g{}GTFmo{mAr>kexq=D7-RG P2^0W;fb3W1_o1UdTDNFlG6hDK5~2WhJ*PG7zYWLxz$!}&%4AY&2YWlsz$Eb5KdujWn@NaWo%?~Q)O*Q WS1d>s?i)zLD2{^84?*=6Qgx+2Ybs0Lm?xkSqB0N LAl2~i-ZdPG(X<=@3b5mt)No4(ju7iFH2b-u)>&PZdlOljoA7|k;k>s6qoa5|8f~g8rd2nS@d2@7SZ7Bc` +Rc>i-ZdPG(X<=@3b5mt)No4(ju7iFH2b-u)>&PZdlOljoA7|k;k>s6qoa5|8f~g8rd2nS@d2@7SZ72W_ L2hGcZ*pa1LUnFrY-Mu<0|5qfVQ_L~bN~eb0U2t1clvx>c=Rsq;sPX6HoL|NSa7!~_8VA>68!B7oB{=J aB^jI00jX7%7on+S(hIgz7_S^D)_zOM5Br0>DDqZ(Q0|sPobz*E~00sgEbYXCEWpn`I^CwqAYJB+ZKALhJOg5MR2m;D19&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~_8cxJL| x?WKK>7x;m>=zTw_)c;WdYt27n9%urmoacppk`X2UT2wpUNE;^#pc9YB4Z1sCou)bz*F3 -V*<)79&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v=XJ?|;InIPy66cFfOYp#JM2r7 -_Du+KWpQ~GYywm#VTK~nd#>D0(t`--)Viz -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 -qhH(hC`}q*r35LOoBKkGa -Y9#cS7Qj{WgyAGcS>>g~&^g7C`}q*r8?;yf@?frQ$owe+rTo-{ -AMw{vgzX#P!9p!}0yp?_3`b>dWpinBNoHYVWd;TaZEs|0W@%+|0hAo?WyWV%Bqkq0>u^7-u;qAzHYrYi -ZOnAva3v<@st9dmbYWy+bYTDq0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs7 -0;T-agdg$OP=xIp;K4#IcLF!~asU7T000000RI300000000(DmZ(?C=a{vkgMe3tp+xFv-0Xp&G?S=|} -9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0>gzBa)$q57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI3000000 -01IJrb7^O8ZDnqBa{vkgMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{ -AMw{vgzX#P!9p!}0yp?_0>gzBa)$q57bK6Q|uUfIMEX -^1}Vv6tLB!)|10-o)0prc>n+a000000RI3000000010+sY-Mg^X=QT&2?9mxqhH(hC`}q*r35LOoBKkGaY9#cS7Qj{WgyAGcS>>g~ -&^g7ioJpYH;+t0eX2w~A!Q+0eaZ{MVyc -PK^k1WpQ~GYywm#VTK~nd#>yWpZgcQkwbf~^M){{|8P%hsR -k~m~ep32F151Y4WWC&?)Xk~I~baMa*0XxdTfddHPE2~=}XorO3wsWOd*yR8%b;g^;wLfB`aR2}S00000 -0RI3000000010$yZDn(GVQp{#07wXJWprU=VRT^t3IavyqhH(hZ4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C -`4HJ_1fvw5rj-B|XP@r^w5ufb=C_Ju$l1`nW&GEpSWb-q0000000030000000000BXKZg`VQf=$VRU5x -3IavyqhH(h}`A;#FO3ABStqEB2u*`(KJ8e4#|W70000000030000000000BVRLh7XKrm}Zgg`1 -3IavyqhH(ha{vkg -Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_ -0X}Q-^^?(m0E0zBOZWn(@&jfq2YNoZ;ZAl)>;YPDKL7v#000000RI300000000(DfZe??6a{+bjCH_26 -kAtYeN1V@6CZgT(%0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_ -Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~asf9E8yY=#e=i37J-o5}w=U0FTPy7> -iqjyYR#Y>))`9>4000000093000000000VQcywiMb7^mGa{vkgMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uM -rbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0XSPta$W&i*H000000RI300000001#wlW?^+~bWd<)a$$67Z*Bkt0ssVVZ*FA(00035b8l^B00jX8 -Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_ -24!+`Z*p@03IavyqhH(h>gzP9Lqh8!q$B6|*YuiTY;OURW8#d%1{rxIXtTaY^?oCir}VPj=U -WCZ~L2LJ#-AOHzTW?^GxNo{a!1`P*xWpZ_ZDC1d0>gzLZka+XJhss8OG%_CC-Q>(otsF+cqN -0Qy}ddQ=3E5C>^yVPj=UWC1(Mz<~n@;VY|KA!vt$qMEp^75#kD_Tqj3pzX>Db5bYX39002k` -ZDn*}WMOn+00{xTfrw&K4w%I2J!>5*n2+UEn$VY06ag%An>_FbOoG7x0000000030000000000BXKZg` -VQf=$VRU5x2?23(9Y)dB+Qf@I7Kdvbxk#NQ%2Ip^oEeXABZ7(pf`tG8000000093000000000YNb8~5D -Zf#|5baMa+0huBwu~C-QVH212O0vm-vwNnjOqUO({d!Yj6^~`qZ~y=R000000RI3000000010+sY-Mg^ -X=QT&2?17zrJCAYw97+KWFy8eZUu~dV(l5N%b&~h(10yyF^B*F000000093000000000Yga$#@6C -ZgT($0XROpRQe`%bQtg9OuU(MB+3^mE|~AfiD0OzeAWk8kN^Mx000000RI3000000019PzbY*UHX>V?G -00{wU#AUTvyg$3{N++IppJQl5+tKwp$xtHBFa^7o2YcTD00000000300000000006WpZ+Fa&rI)0mEnI -j6FO8VJD!@R*BddIvVCq{>+4TF2^XfWAFT{UH||9000000RI3000000010Gec4cgDaAk4=uZ_m{WNzU! -AS*T=d6X;t=`;<;71O75notN1DSsZmw&;L{94K`ndk%K5+?9Jv$dw7jc}U5p5@2#$kUJ%u2y=8{bY($e -X#uslLXEmL6-F5v>3G|uUigF$Iw^!m+g!OaP0#x3$o4Af` -kVHyQ&~TYCSRqgV00000000300000000008b7N>_ZDDj_00{!GjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQr -PzVkwe;&S;{P@Z4!V_T!KN -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 +ZP9(YH~bairNa{vkf;?xyT5z&Ua ++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 +B=zREie$*y(7k2+*P~cYjR +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 +aaxrgbrDxyH3fc^ +lq>z|G!4fU)2DQrPzVkwe;&SMbsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez*ZeeX@0!8YhU)%QM +kO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~atLx|b7gXN +Wn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDP +k{-($PGN0jWJYOaY-C4lZ(?C=Q*>c;WmI`^Wd;KRX=DPgjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkw +e;&To?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(vPGN0jWJYOaY-CMk +bYWC^aAgJq0%>FduZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmb>vO>-_DBy8`Vb0jGrW9$=2qS +MXvL3He1kloHngE|MP07*1hrWn@NaWo%?ra$#@6CZd7@2Wd;KRX=DPgjmGz6 +Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&RxQV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y)ZeeX@ +0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~ +atLx|b7gXNWn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#; +{6ajG64wDPk{-(yPGN0jWJYOaY-CnpY-Mg^c~p6DWd;KRX=DPgjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQr +PzVkwe;&R@?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNABZeeX@0!8YhU)%QMkO4aJ;_ZeCe;xE! +X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~atLx|b7gXNWn=<+10COKearHw +cS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(rPGN0jWL9Bv +X<=@3bvOnC0%>Fb009JUVQpmsMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r35LOoBKkGaY9#cS +7Qj{WgyAGcS>>g~&^g7&L0`+VYVk7oBr%DNv +($;q`HHK!gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1RsjNZcmM?f0`+VY Vk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3dMUNn!oosZgNI|twmNZeC(lYZa*g7-2eQ3Yy;-pLpZg6#U0%CAAe<9`Lptgp8_Mvcw;M9wpEva%PKB$lLxR8HRDYBt%9Ac~*scS^hWjPt6N{BwQjsm*;-$%ozd;zkHMYQ8YvDt&dXWl1-*ujFaOPZ*RUQ z8_qdo8_M$OIpM9wpsuyEy<=cT3umn4>?GTsvspZtJn*}5x%3nsQ^vWLbr z&Oaq9_LZf~Im^(%bVU_gL1|J>X7c2Xa*mrPieG0@uskkhS0`X`e*3;TCAF{D@0&1t zM_=v)7q5T|1v3pJ6azN*n{qKuey4bQbFN%C6LHEnzf*j|qu{;rM90c2kF~RYF8{OH zlIOUf`PqY8By$*MZk)AX&g5UllRv0SZ|2p1%SzZ#DN|PtUw@D ^ ..0xff [Byte]} -@mnemonic(baby-infant-cake) -data AssignIface : ownedState OwnedIface +@mnemonic(optic-hippie-isabel) +data AssignIface : stateTy StrictTypes.SemId? + , attach Std.Bool? , public Std.Bool , required Std.Bool , multiple Std.Bool @@ -326,14 +327,6 @@ data NamedVariantu8 : id U8 , name StrictTypes.VariantName , reserved CommitVerify.ReservedBytes4 -@mnemonic(delphi-athlete-fresh) -data OwnedIface : any () - | rights () - | amount () - | anyData () - | anyAttach () - | data StrictTypes.SemId - @mnemonic(paper-visa-storm) data PubWitness : txid Bitcoin.Txid | tx Bitcoin.Tx diff --git a/stl/RGBStorage@0.11.0.sta b/stl/RGBStorage@0.11.0.sta index 0a7db3fc..6b324b0b 100644 --- a/stl/RGBStorage@0.11.0.sta +++ b/stl/RGBStorage@0.11.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:RMDj!yyo-ca0Rmdl-pBBc50W-ciu1!P3-U8gHIqL-0Y83X50#memo-ballet-fresh +Id: stl:lnl6QOG0-EYfOLKP-MHdEyA3-$cyUNuc-F3XmU!W-0glc1M0#alaska-phone-bagel Name: RGBStorage Dependencies: StrictTypes#century-comrade-chess, @@ -7,16 +7,16 @@ Dependencies: AluVM#congo-archive-folio, CommitVerify#miller-pancake-elastic, RGBCommit#printer-window-alpine, - RGBStd#zebra-twist-tango, + RGBStd#chemist-enjoy-sound, Std#ralph-blue-lucky, RGBLogic#ohio-electra-dilemma, Bitcoin#signal-color-cipher -Check-SHA256: 1e7e30d1c26d606642c6284e6be3f07d74d165c362f24ee5def19faaca9d5330 +Check-SHA256: 3b654f8a5eb432f7f3c40cabf94f95336a3e9973df24330917273e0b228f8e88 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 -R2X#8M$tG2GZIy9X>V>;VRC6_vj93RHP; -Wm9=`bY*P@01ZQLZgg^CV{}PwWMy~;0t|3>gzLOBVfUz`Mi!Z}iQtl5;XwV(E`Zdd&WRj~^37YhpmjD0&000000RR900000001j_;bZ~EJ -Zgfv@Z*_EY015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&TkXBWLg67cp3gzo-sO&$va11I@T -$h!rSEX2t%Czh%J2?DQ;#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=?+hynwMZT8l5kSW@l}O=!>^ -xB4~9n`Dx!RtcK)nwJ0o0000000960{{R30000000000000960{{R30000n8Wo<)mZgg^CV{}t=VRU5% -1PF6uXk~3-Nn`@AjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S+Qq$W5tE;F{pQrXd&=l*`O?@#x -{Qdy?T_k!`1dtF4V{dMBa$#e1Nn`@AjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S{2rNlD$O59e -#ogQsB77jPl+h5j^*S;JXKZg`VQc^j0>g -zSZuM4oQf!Y4K`P(FaQVwIle)QgI&pHa%8Z1>xis%K>dbv;0wBb*7)Id;7I5;T&_H+G%6DVUHTf -p;u=X0|Kv&#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=>}YR2^S7pk#{MS?zgMX@X{kfl~;6wBm#t -C>wDnA0009BO=WFKZe(S61_cdoa6)x%WNc+gZe(S6015)HjmGz6 -Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S-$mV(;bz)!CmQ_M(k?Vd!kfCo{nDM?)_qK{868FUduZ_m{ -WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm1ACLTJsO2B2U!6ncg?mz@CdC==Kxq?gSEg)z2E{|00000 -00000|Ns90000006Jm94WNc+aZ*FvQVPkYjZe(S6015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkw -e;&RAdy}<28ig(gSpg+?&9*`C2(3=%09avzwZKZf-~wC%uZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1 -DSsZmp9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0000000000|Ns90000005@L03WNc+uX>@L7 -b8|^g)RqK0VQ|Mwn6X+txo3v -SYd;;z)HQ~0$czI0>gzKLsCCC$c=UszhlV5m?Ru@{iV -U*wrVdeH+Q@FPbX@c;k-000000RI300000000000000000RR900000001abrZgg^CV{}PwWMy~&3IeZ< -#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=@LlEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22Ix+z) -)N;MU`Np56icmN6l -uZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm+lpEmf)o&SDDwD>KtpQ8M_qJyiO1VIUJ=H=)@ii_ -00{!GjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S*5WIk~G+K)5%bR49t5yk` -^qQ9d000000003000000000000000000030|Nj6000008O=WFUbYXL71`P;vV`ybE<3hUv-8m3eMLapj8a{pyIM27f -oOFHbufC9*xQ=a*L`qQ5aG5b!Ay5DS000000093000000000MPWo~72Wpe-u0>gzMlvzNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6JuS#`k1y;WQvCHXeDD -EB)y-4aXJJr*xW72o5QK9=@@-=^kqQ3p1gNv;!SgAcC?bFoBOEj`UQU^i2<9K8XMT000000093000000 -000GZb#QQO015)V+vv2?rNCE<3hUv-8m3eMLc6Y(}}Q4NmeS)xXw6rP$n8; -6mfj6^V>gz5{!cwLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O1>gzD1E0G&%-s -t`)qMZ{`v%g)H0vbfykT5^0>(1Gy}*bpQYW000000RR90{{R30010<#bZ%vHb7gY?3IeZ<#`k1y;WQvC -HXeDDEB)y-4aXJJr*xW72o5QK9=?fdSS8KIkY89@$6%;X7qJ(R#b4x^L3+^xAn+qc8}S0Y+vv2?rNCjuaWwz{0000000960{{R30000Vfd2nS@d2@7SZ30E=qhH(h&PZdlOljoA7|k;k>s6qoa5|8f~g8=WMyu2X>@62a{vkguZ_m{WNzU!AS*T= -d6X;t=`;<;71O75notN1DSsZmw&;L{94K`ndk%K5+?9Jv$dw7jc}U5p5@2#$kUJ%u0=?Vlw9=)(YVD5X -(Bh@-;YAffP|O75Lc0RpIS^JwJfh%P)X}ib9i^%gOs*8bY}uR&S59aNAMwsm_ykY{pa1{>000000RR60 -0000000eAlVsiir0%CAAe<9`Lptgpr6F_xjAC6(~TLj#*ewiHm5LE0xkJm$nc4yMWR2J-cc#Q -6SofWC)gp7L6!Sc3IbwqHGd)Hlr&gK9B000000096000000000DYX=if)3Ie^`=(N(Mz-sM|E<3hUv --8m3eMLgov6;Kh;hPv9L38+j;K}xwT<$*JN%D`Il^nAqV=^+BW+vv2?rNCUOOvDqlqa0000000030{{R3000008O=WFUbYXO5 -1_B9pX>@L7b8}^L015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&SxYgi@C#*klFTE}3hP#3Wm -ki}o*nL&Ed10e7tM;q}1=To4MHF_77?oTU4FqgQKswsBc5OvCJUgtO#qdT6Na=Svv7*ky_&y4^1v>gzMlvzNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6Ac7Ex1s`aa6PN-Fgk0S2h>I -cS>a?4Yu+n!-bhcpbh{4000000093000000000 +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 +5w0WYK++p=`bayqMEp^75#kD_Tqj3Vr!KR7RO +I1#QR=|IvOar#K!YERg2%AQl=6Lc4y4BuUum=K}#_8Itcm>%s+B6*|$00000000300000000007XJu|> +b7gY?3IeZ<#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=@LlEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G +;Jw22Ix+&UjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&TExal5h{0lRojI;wCRUm@0B`|@HB98P_ +oAgZ&Vm^rg00000000300000000005b9HcVYyb)Z$ib$G)8#G2g~}h6>clrIl2GyM={OOtBk4fW8*%zb +2AHk4+Bm{3x%H=p>4!*u&nOI1#QR=|IvO +ar#JOJ=2M>OG#EL&$!Mwbxg)RqK0VQ|Mwn6X+ +txo3vSYd;;z)HQ~0$c*GjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&U5Y50a7uJ<-M7OQflyV@Ma +b5n=!H;MEOu8QHCUOton0000000030|Ns900000AWq5RDZgXjGZgT(%0>gzLm)4dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#R9L5#`k1y;WQvCHXeDDEB)y- +4aXJJr*xW72o5QK9==796*M{qY_1i&m2c(}E`==I0Cc7fNfK$C)dRUKv2_3d0000000960|Nj60000Sh +X>@L7b8}^L015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&SxYgi@C#*klFTE}3hP#3Wmki}o* +nL&Ed10e7tM;q}1$ib$G)8#G2g~}h6>clrIl2GyM={OOtBk4fW8*%zb$6skVRwOM6wz9dSYg6i3-rmX0 +uFE(Y8AEY@srN=80000000000|NsC0000003t@D0VPj}*Wo~qH015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU +)2DQrPzVkwe;&SsaSf9!PV~dK2uo>;u!nFdemP_$e?^hl+JkM;eY!XR2mk;;0000000000|Ns9000000 +0000000000|Nj60000003v*>-a%FT=WnpY{00{!GjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S% +yTa&4noi_R;$3lnz4{Zl)X|Z&ZIQtMA_g1big7gn0000000030|Nj600000Aba`-PQ+acAWo-gQ>Z4!V +_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HLtfv$so3kRF1PV2}fOp_vjQ6FdFHId|>gzP9Lqh8!q$B6|*YuiTY;OURW8#d%1{ +rxIXtTaY^?oC3(fris(#Eyab(AC~IGH!G4*@$2b05w0WYK++p=`beVSS=7<6%^jtx5=^cXz--x^3Rg~O +2_Ny!Q1}E;1fT!_000000096000000000DRX<~B#3IbwqHGd)HR2XhQO_4{AcS-HH^7AVzASV8M4NY +xyCjU1gEwF5PXV6FZDLo1#Vec_~kix7WfVQ#Sd|CM9$^_0000000030{{R3000004b7^OD015)g!KR7R +OI1#QR=|IvOar#K&)D=(>(T2L(qY0=?N$ib$G +)8#G2g~}h6>clrIl2GyM={OOtBk4fW8*%zbh8PemXlG!~;@e)_O3H?xO^a~KWeI~0jp}x-Dk@(^00000 +00000|Nj60000002u)>eQ*>c;Wd;HXcWHEPWpi_7a{vkguZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1 +DSsZmiECIT&Bl;lSX#$ms8AQN7m&qYX% +7Na|!nR2^A$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;Q#;t000000RR90{{R30010DnZgg^CV{~%> +3IeZ<#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=@LlEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22 +Ix+#PeJ!|9#Bo%!^4)q3npZX#!goq#B@MRnCBuc8L!b@-0000000030000000000 -----END STRICT TYPE LIB----- diff --git a/stl/RGBStorage@0.11.0.stl b/stl/RGBStorage@0.11.0.stl index 3d8ee703ca4a1251c390d95c56a78d30ba1f1635..88c58d859b8d57018d666676535185568e82aae5 100644 GIT binary patch delta 607 zcmcZ?wK;0S9fcDImvvr#s(ZBcl>D?;N6fV+1$=z{(n4^Z@=J$H(uKb~HvW+pVpQKO zBkaaFxkF_2=6F$NW}QuS3O-YIKDww=y!swv_+9g>o*^&Jm&G``{VG}ffu-RLw_|Z} zW_q4yT4HkQ<|GMoMujZ@8~LZ^1wRrl5ueL*KX&E}frVebN&YCBA@|ltsd5SH=6#ZP z*$6sjGLMA9Gyc%D-X?ldDyw2rKLmQE+4;6kPWRcyzLu+E&6= ty;f5usA#jE`bkE@s>C(t5mq(X92l-&wKftoZt^j0MS_Ypv+IO20su~!G}8b8 delta 646 zcmdlSbuVhd9fiHOUu?Ow^g!0zz9$zREq(jYRn#fq49jDu-As2a1;SiyHvW+pV$|3y zBkabgXn9=9u1>(>{PulwN@`!P-#20Qj=tOpE?xl_3T7HcCW~9>3N=MiOH#(c}1C-H`_>1ru8{*+XL*=bw@l`^r-0oMmWWx}u89zdSEB1*~cEY;A?jJ0y3o5p?|I z2?|~W6>a{dAjU#a)no%zE5eGpR23Zvg(#s=ocvmKD`A@ss3{Xxv{O`Jv$Fb1M#3sT dN+@jR(X1mvPO<~!Qqi~uMkLstL* diff --git a/stl/RGBStorage@0.11.0.sty b/stl/RGBStorage@0.11.0.sty index 67c9f1b5..dda1de3d 100644 --- a/stl/RGBStorage@0.11.0.sty +++ b/stl/RGBStorage@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:RMDj!yyo-ca0Rmdl-pBBc50W-ciu1!P3-U8gHIqL-0Y83X50#memo-ballet-fresh + Id: stl:lnl6QOG0-EYfOLKP-MHdEyA3-$cyUNuc-F3XmU!W-0glc1M0#alaska-phone-bagel Name: RGBStorage Version: 0.11.0 Description: RGB storage library @@ -115,7 +115,7 @@ import RGBCommit#printer-window-alpine use XChainPubWitness#figure-gram-wave use TransitionBundle#final-numeric-berlin -import RGBStd#zebra-twist-tango +import RGBStd#chemist-enjoy-sound use PubWitness#paper-visa-storm use ContentRef#polo-ramirez-parker use SigBlob#insect-cello-avalon @@ -123,12 +123,10 @@ import RGBStd#zebra-twist-tango use TransitionIface#axiom-parker-pyramid use NamedFieldTransitionType#express-brush-desire use ExtensionIface#model-ramirez-mentor - use Iface#violin-student-system use IfaceId#nova-cola-carbon use ValencyIface#buzzer-holiday-fiber use Annotations#spend-linda-romeo use IfaceImpl#coconut-snake-formula - use AssignIface#fractal-baker-outside use VerNo#textile-next-stretch use NamedFieldValencyType#invest-apollo-inca use ImplId#seminar-data-table @@ -146,6 +144,7 @@ import RGBStd#zebra-twist-tango use NamedFieldAssignmentType#origin-caramel-flipper use Allocation#mimosa-savage-future use TrustLevel#cobra-script-albino + use AssignIface#optic-hippie-isabel use StateAbi#thermos-demo-fragile use NamedFieldMetaType#prefix-carmen-artist use NamedVariantu8#star-pilgrim-pilgrim @@ -153,7 +152,7 @@ import RGBStd#zebra-twist-tango use SealWitness#cotton-lopez-isabel use GlobalIface#concert-combat-charm use SupplMap#sailor-observe-bundle - use OwnedIface#delphi-athlete-fresh + use Iface#citizen-oxford-norway use ContentId#scarlet-portal-office use GlobalOut#capital-agatha-bruno @@ -214,7 +213,7 @@ data MemIndex : opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit , contractIndex {RGBCommit.ContractId -> ^ ..0xff ContractIndex} , terminalIndex {RGBCommit.XChainSecretSeal -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xff}} -@mnemonic(kinetic-deal-blast) +@mnemonic(alfonso-office-suzuki) data MemStash : schemata {RGBCommit.SchemaId -> ^ ..0xff RGBStd.SchemaIfaces} , ifaces {RGBStd.IfaceId -> ^ ..0xff RGBStd.Iface} , geneses {RGBCommit.ContractId -> ^ ..0xff RGBCommit.Genesis} diff --git a/stl/Transfer.vesper b/stl/Transfer.vesper index 36c8e481..cc718eeb 100644 --- a/stl/Transfer.vesper +++ b/stl/Transfer.vesper @@ -540,13 +540,8 @@ Consignmenttrue rec assignments map len=0..MAX8 key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 value rec AssignIface - ownedState union OwnedIface - any is Unit tag=0 - rights is Unit tag=1 - amount is Unit tag=2 - anyData is Unit tag=3 - anyAttach is Unit tag=4 - data bytes len=32 wrapped aka=SemId tag=5 + some bytes len=32 option wrapped aka=SemId tag=1 + some enum Bool option wrapped false=0 true=1 tag=1 public enum Bool false=0 true=1 required enum Bool false=0 true=1 multiple enum Bool false=0 true=1 From 624e84c2b4d27d9ba77f7d9b5c2c25a4b6f18294 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 02:33:46 +0200 Subject: [PATCH 07/70] persistence: add access to type system --- src/persistence/stash.rs | 16 ++++++++++++---- src/persistence/stock.rs | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index a5822a7b..a1c522d4 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -304,7 +304,15 @@ impl Stash

{ Ok(Scripts::from_checked(scripts)) } - pub(super) fn extract<'a>( + pub(super) fn type_system(&self, iface: &Iface) -> Result> { + Ok(self + .provider + .type_system() + .map_err(StashError::ReadProvider)? + .extract(iface.types())?) + } + + pub(super) fn types_scripts<'a>( &self, schema: &Schema, ifaces: impl IntoIterator, @@ -344,7 +352,7 @@ impl Stash

{ .get(iface_id) .ok_or(StashDataError::NoIfaceImpl(schema_id, iface_id))?; - let (types, scripts) = self.extract(&schema_ifaces.schema, [iface])?; + let (types, scripts) = self.types_scripts(&schema_ifaces.schema, [iface])?; let builder = ContractBuilder::with( issuer, @@ -370,7 +378,7 @@ impl Stash

{ .get(iface.iface_id()) .ok_or(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()))?; - let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; + let types = self.type_system(iface)?; let scripts = self.scripts(iimpl.state_abi.lib_ids())?; let builder = if let Some(transition_name) = transition_name { @@ -409,7 +417,7 @@ impl Stash

{ if schema_ifaces.iimpls.is_empty() { return Err(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()).into()); } - let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; + let types = self.type_system(iface)?; let builder = if let Some(iimpl) = schema_ifaces.get(iface.iface_id()) { TransitionBuilder::blank_transition( diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index a142358e..273af067 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -39,6 +39,7 @@ use rgb::{ SchemaId, SecretSeal, Transition, TxoSeal, XChain, XOutpoint, XOutputSeal, XWitnessId, }; use strict_encoding::FieldName; +use strict_types::TypeSystem; use super::{ ContractStateRead, Index, IndexError, IndexInconsistency, IndexProvider, IndexReadProvider, @@ -494,6 +495,9 @@ impl Stock { pub fn iface(&self, iface: impl Into) -> Result<&Iface, StockError> { Ok(self.stash.iface(iface)?) } + pub fn type_system(&self, iface: &Iface) -> Result> { + Ok(self.stash.type_system(iface)?) + } pub fn schemata(&self) -> Result + '_, StockError> { Ok(self.stash.schemata()?.map(SchemaInfo::with)) } @@ -573,7 +577,7 @@ impl Stock { let iimpl = self.stash.impl_for::(schema_ifaces)?; let iface = self.stash.iface(iimpl.iface_id)?; - let (types, _) = self.stash.extract(&schema_ifaces.schema, [iface])?; + let types = self.stash.type_system(iface)?; Ok(C::Wrapper::with(ContractIface { state, @@ -599,7 +603,7 @@ impl Stock { ContractIfaceError::NoAbstractImpl(iface_id, schema_ifaces.schema.schema_id()) })?; - let (types, _) = self.stash.extract(&schema_ifaces.schema, [iface])?; + let types = self.stash.type_system(iface)?; Ok(ContractIface { state, @@ -678,7 +682,9 @@ impl Stock { kit.iimpls .extend(schema_ifaces.iimpls.values().cloned()) .expect("type guarantees"); - let (types, scripts) = self.stash.extract(&schema_ifaces.schema, &kit.ifaces)?; + let (types, scripts) = self + .stash + .types_scripts(&schema_ifaces.schema, &kit.ifaces)?; kit.scripts .extend(scripts.into_values()) .expect("type guarantees"); @@ -843,7 +849,9 @@ impl Stock { let terminals = Confined::try_from(terminals).map_err(|_| ConsignError::TooManyTerminals)?; - let (types, scripts) = self.stash.extract(&schema_ifaces.schema, ifaces.keys())?; + let (types, scripts) = self + .stash + .types_scripts(&schema_ifaces.schema, ifaces.keys())?; let scripts = Confined::from_iter_checked(scripts.into_values()); let supplements = Confined::try_from(supplements).map_err(|_| ConsignError::TooManySupplements)?; From 0bfe36d65dd3f5dda1eec377c85b39ade80a2f71 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 12:50:55 +0200 Subject: [PATCH 08/70] epic: improve invoice and interface state APIs --- Cargo.lock | 2 +- invoice/src/builder.rs | 107 ++++++++++++++++--- invoice/src/parse.rs | 2 +- src/interface/builder.rs | 2 +- src/interface/calc.rs | 6 +- src/interface/contract.rs | 65 +++++++----- src/stl.rs | 4 +- stl/RGBStd@0.11.0.sta | 192 ++++++++++++++++----------------- stl/RGBStd@0.11.0.stl | Bin 18172 -> 18172 bytes stl/RGBStd@0.11.0.sty | 34 +++--- stl/RGBStorage@0.11.0.sta | 216 +++++++++++++++++++------------------- stl/RGBStorage@0.11.0.stl | Bin 11571 -> 11571 bytes stl/RGBStorage@0.11.0.sty | 64 +++++------ stl/Transfer.vesper | 24 ++--- 14 files changed, 406 insertions(+), 312 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3f6459a7..80e12cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,7 +674,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.9" -source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#8267ce26b1edf905553a49e5dcc42d5f2f0df338" +source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#75424505e4f24df90d9ee1d284c4ee25103c185b" dependencies = [ "aluvm", "amplify", diff --git a/invoice/src/builder.rs b/invoice/src/builder.rs index 00c9d7af..1805ee9e 100644 --- a/invoice/src/builder.rs +++ b/invoice/src/builder.rs @@ -21,7 +21,7 @@ use std::str::FromStr; -use rgb::{AttachId, ContractId, State}; +use rgb::{AttachId, ContractId, State, StateData}; use strict_encoding::{FieldName, StrictSerialize, TypeName}; use crate::invoice::{Beneficiary, InvoiceState, RgbInvoice, RgbTransport, XChainNet}; @@ -50,19 +50,13 @@ impl RgbInvoiceBuilder { Self::new(beneficiary).set_contract(contract_id) } - pub fn rgb20(contract_id: ContractId, beneficiary: impl Into>) -> Self { - Self::with(contract_id, beneficiary).set_interface("RGB20") - } - - pub fn rgb20_anything(beneficiary: impl Into>) -> Self { - Self::new(beneficiary).set_interface("RGB20") - } - pub fn set_contract(mut self, contract_id: ContractId) -> Self { self.0.contract = Some(contract_id); self } + /// Sets interface for the invoice. Interface can be a concrete interface (name or id), or a + /// name of an interface standard, like `RGB20`, `RGB21` etc. pub fn set_interface(mut self, name: impl Into) -> Self { self.0.iface = Some(name.into()); self @@ -78,14 +72,101 @@ impl RgbInvoiceBuilder { self } - pub fn set_state(mut self, state: impl StrictSerialize) -> Self { - self.0.owned_state = InvoiceState::Specific(State::new(state)); + /// Set the invoiced state, which includes both state data and an optional attachment + /// information. + /// + /// # Panics + /// + /// If any state information or attachment requirements are already present in the invoice. + /// + /// # See also + /// + /// - [`Self::add_state_data`], adding just state data information, not affecting attachment + /// requirements; + /// - [`Self::serialize_state_data`], for adding state data by serializing them from a state + /// object; + /// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state + /// information. + pub fn set_state(mut self, state: State) -> Self { + if !self.0.owned_state.is_any() { + panic!("invoice already has state information"); + } + self.0.owned_state = InvoiceState::Specific(state); + self + } + + /// Add state data to the invoice. + /// + /// NB: This keeps existing attachment requirements. + /// + /// # Panics + /// + /// If the invoice already have any state information (excluding attachment requirements). + /// + /// # See also + /// + /// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment + /// requirements; + /// - [`Self::serialize_state_data`], for adding state data by serializing them from a state + /// object; + /// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state + /// information. + pub fn add_state_data(mut self, data: StateData) -> Self { + self.0.owned_state = match self.0.owned_state { + InvoiceState::Any => InvoiceState::Specific(State::from(data)), + InvoiceState::Specific(_) => panic!("invoice already has state information"), + InvoiceState::Attach(attach_id) => InvoiceState::Specific(State::with(data, attach_id)), + }; + self + } + + /// Add state data to the invoice by strict-serializing the provided object. + /// + /// NB: This keeps existing attachment requirements. + /// + /// Use the function carefully, since the common pitfall here is to perform double serialization + /// of an already serialized data type, like `SmallBlob`. This produces an invalid state object + /// which can't be properly parsed later. + /// + /// # Panics + /// + /// If the invoice already has any state information (excluding attachment requirements). + /// + /// # See also + /// + /// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment + /// requirements; + /// - [`Self::add_state_data`], adding just state data information, not affecting attachment + /// requirements; + /// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state + /// information. + pub fn serialize_state_data(mut self, data: impl StrictSerialize) -> Self { + self.0.owned_state = InvoiceState::Specific(State::from_serialized(data)); self } - pub fn set_attachment(mut self, attach_id: AttachId) -> Result { + /// Add attachment requirements to an invoice, keeping the rest of the invoice state information + /// unchanged. + /// + /// # Panics + /// + /// If the invoice already has attachment requirements defined. + /// + /// # See also + /// + /// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment + /// requirements; + /// - [`Self::add_state_data`], adding just state data information, not affecting attachment + /// requirements; + /// - [`Self::serialize_state_data`], for adding state data by serializing them from a state + /// object; + pub fn add_attachment(mut self, attach_id: AttachId) -> Result { self.0.owned_state = match self.0.owned_state { - InvoiceState::Any | InvoiceState::Attach(_) => InvoiceState::Attach(attach_id), + InvoiceState::Any => InvoiceState::Attach(attach_id), + InvoiceState::Attach(_) + | InvoiceState::Specific(State { + attach: Some(_), .. + }) => panic!("invoice already has attachment requirements"), InvoiceState::Specific(mut state) => { state.attach = Some(attach_id); InvoiceState::Specific(state) diff --git a/invoice/src/parse.rs b/invoice/src/parse.rs index e2136f79..49a49dca 100644 --- a/invoice/src/parse.rs +++ b/invoice/src/parse.rs @@ -181,7 +181,7 @@ impl Display for InvoiceState { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { InvoiceState::Any => Ok(()), - InvoiceState::Specific(state) => f.write_str(&state.value.to_base58()), + InvoiceState::Specific(state) => f.write_str(&state.data.to_base58()), // TODO: Support attachment through invoice params InvoiceState::Attach(_) => Ok(()), } diff --git a/src/interface/builder.rs b/src/interface/builder.rs index 2ba1d8c3..e794dad5 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -653,7 +653,7 @@ impl OperationBuilder { .assignments_type(&name) .ok_or(BuilderError::AssignmentNotFound(name))?; - self.add_owned_state_raw(type_id, seal, State::new(value)) + self.add_owned_state_raw(type_id, seal, State::from_serialized(value)) } fn complete(self) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments, TypeSystem) { diff --git a/src/interface/calc.rs b/src/interface/calc.rs index 32043aa1..2932f775 100644 --- a/src/interface/calc.rs +++ b/src/interface/calc.rs @@ -106,7 +106,7 @@ impl StateCalc { self.vm.registers.set_n(RegA::A8, Reg32::Reg0, Some(0u8)); self.vm .registers - .set_s(RegS::from(0), Some(ByteStr::with(&state.value))); + .set_s(RegS::from(0), Some(ByteStr::with(&state.data))); self.vm.registers.set_n( RegR::R256, Reg32::Reg0, @@ -119,7 +119,7 @@ impl StateCalc { ty: AssignmentType, idx: Reg16, ) -> Result, StateCalcError> { - let Some(value) = self.vm.registers.get_s(RegS::from(u4::from(idx))) else { + let Some(data) = self.vm.registers.get_s(RegS::from(u4::from(idx))) else { return Ok(None); }; let reserved = self @@ -138,7 +138,7 @@ impl StateCalc { } Ok(Some(rgb::State { reserved: none!(), - value: StateData::from_checked(value.to_vec()), + data: StateData::from_checked(data.to_vec()), attach, })) } diff --git a/src/interface/contract.rs b/src/interface/contract.rs index 1452779f..075fafb1 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -23,10 +23,10 @@ use std::borrow::Borrow; use std::collections::{BTreeSet, HashMap, HashSet}; use amplify::confinement; -use amplify::confinement::SmallBlob; use rgb::validation::Scripts; use rgb::{ - AssignmentType, AttachId, ContractId, OpId, Opout, Schema, State, XOutputSeal, XWitnessId, + AssignmentType, AttachId, ContractId, OpId, Opout, Schema, State, StateData, XOutputSeal, + XWitnessId, }; use strict_encoding::{FieldName, SerializeError, StrictSerialize}; use strict_types::{typify, SemId, StrictVal, TypeSystem}; @@ -155,33 +155,52 @@ impl ContractIface { .sem_id } - fn assignment_value(&self, ty: AssignmentType, value: &SmallBlob) -> StrictVal { - self.types - .strict_deserialize_type(self.assignment_sem_id(ty), value.as_slice()) - .expect("invalid contract state") - .unbox() - } - fn allocation_to_output(&self, a: &Allocation) -> Output { Output { opout: a.opout, seal: a.seal, - state: self.assignment_value(a.opout.ty, &a.state.value), + state: self.value_from_state_raw(a.opout.ty, &a.state), attach_id: a.state.attach, witness: a.witness, } } - fn state_convert( + pub fn value_from_state_raw(&self, ty: AssignmentType, state: &State) -> StrictVal { + self.types + .strict_deserialize_type(self.assignment_sem_id(ty), state.data.as_slice()) + .expect("invalid contract state") + .unbox() + } + + pub fn value_from_state( + &self, + name: impl Into, + state: &State, + ) -> Result { + let type_id = self.assignment_type(name)?; + Ok(self.value_from_state_raw(type_id, state)) + } + + pub fn value_to_state_raw( &self, ty: AssignmentType, value: StrictVal, - ) -> Result { + ) -> Result { let t = self.types.typify(value, self.assignment_sem_id(ty))?; - Ok(self + let value = self .types .strict_serialize_type::<{ confinement::U16 }>(&t)? - .to_strict_serialized()?) + .to_strict_serialized()?; + Ok(value.into()) + } + + pub fn value_to_state( + &self, + name: impl Into, + value: StrictVal, + ) -> Result { + let type_id = self.assignment_type(name)?; + self.value_to_state_raw(type_id, value) } pub fn contract_id(&self) -> ContractId { self.state.contract_id() } @@ -248,9 +267,8 @@ impl ContractIface { &'c self, name: impl Into, filter: impl AssignmentsFilter + 'c, - value: StrictVal, - attach: Option, sorting: impl FnMut(&&Allocation) -> K, + state: &'c State, ) -> Result + 'c, ContractError> { let type_id = self.assignment_type(name)?; let mut selected = self @@ -259,18 +277,13 @@ impl ContractIface { .collect::>(); selected.sort_by_key(sorting); let mut calc = StateCalc::new(self.scripts.clone(), self.iface.state_abi); - let state = State { - reserved: none!(), - value: self.state_convert(type_id, value)?.into(), - attach, - }; Ok(selected .into_iter() .take_while(move |a| { if calc.reg_input(a.opout.ty, &a.state).is_err() { return false; } - calc.is_sufficient_for(a.opout.ty, &state) + calc.is_sufficient_for(a.opout.ty, state) }) .map(|a| self.allocation_to_output(a))) } @@ -314,7 +327,7 @@ impl ContractIface { // add allocations with no witness to the beginning of the history if let Some(genesis_state) = allocations_our_outpoint.remove(&None) { for assignment in genesis_state { - let value = self.assignment_value(assignment.opout.ty, &assignment.state.value); + let value = self.value_from_state_raw(assignment.opout.ty, &assignment.state); ops.push(ContractOp::issued(assignment, value)) } } @@ -340,7 +353,7 @@ impl ContractIface { } for assignment in ext_assignments { let value = - self.assignment_value(assignment.opout.ty, &assignment.state.value); + self.value_from_state_raw(assignment.opout.ty, &assignment.state); ops.push(ContractOp::sent(assignment, value, witness_info)) } } @@ -348,7 +361,7 @@ impl ContractIface { (None, Some(ext_assignments)) => { for assignment in ext_assignments { let value = - self.assignment_value(assignment.opout.ty, &assignment.state.value); + self.value_from_state_raw(assignment.opout.ty, &assignment.state); ops.push(ContractOp::sent(assignment, value, witness_info)) } } @@ -357,7 +370,7 @@ impl ContractIface { (Some(our_assignments), None) => { for assignment in our_assignments { let value = - self.assignment_value(assignment.opout.ty, &assignment.state.value); + self.value_from_state_raw(assignment.opout.ty, &assignment.state); ops.push(ContractOp::received(assignment, value, witness_info)) } } diff --git a/src/stl.rs b/src/stl.rs index 7507e045..d20e7c85 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -37,11 +37,11 @@ pub const LIB_NAME_RGB_STORAGE: &str = "RGBStorage"; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. pub const LIB_ID_RGB_STORAGE: &str = - "stl:lnl6QOG0-EYfOLKP-MHdEyA3-$cyUNuc-F3XmU!W-0glc1M0#alaska-phone-bagel"; + "stl:dYzM3Ct9-SJ8PljY-C!6hB6y-VlWvDE7-DAtNg3y-zanf6hE#media-fresh-cadet"; /// Strict types id for the library representing of RGB StdLib data types. pub const LIB_ID_RGB_STD: &str = - "stl:yMGmidPl-LcWFyh!-W6sQ3K5-JQ8evpO-BGuI!lA-0htx!kg#chemist-enjoy-sound"; + "stl:3QsSNDHr-YPIKTR9-5O!fLuv-xhcxKT2-0LWrO9b-pG15Nvw#mango-inside-shelf"; #[allow(dead_code)] #[derive(Debug, From)] diff --git a/stl/RGBStd@0.11.0.sta b/stl/RGBStd@0.11.0.sta index 1491d12d..589d596b 100644 --- a/stl/RGBStd@0.11.0.sta +++ b/stl/RGBStd@0.11.0.sta @@ -1,20 +1,20 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:yMGmidPl-LcWFyh!-W6sQ3K5-JQ8evpO-BGuI!lA-0htx!kg#chemist-enjoy-sound +Id: stl:3QsSNDHr-YPIKTR9-5O!fLuv-xhcxKT2-0LWrO9b-pG15Nvw#mango-inside-shelf Name: RGBStd Dependencies: StrictTypes#century-comrade-chess, BPCore#austin-story-retro, AluVM#congo-archive-folio, CommitVerify#miller-pancake-elastic, - RGBCommit#printer-window-alpine, + RGBCommit#trident-rover-tape, Std#ralph-blue-lucky, Bitcoin#signal-color-cipher -Check-SHA256: 4b921710f4ab25f21c5be62b8015e9456f1d473c6aca46706d8a71155de55640 +Check-SHA256: d003c3fbc2fb3bbf7c1af3b580825dfbf43f509f0b75adb51c4f3096e33e53f5 22w{tQ*>kpMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD*X=8L$d2nTORuk6O)Q5AKbFW;J EQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pZ~a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjHL2Pwa -O?m?z-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCJaMwZEb0ER%LQ&W_hoT#`k1y;WQvCHXeDDEB)y- -4aXJJr*xW72o5QK9=-`uM?ynyZEb0E$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#15~GYywm#15DT%6aZ| SrJerP1pIOD57`7Ol|-ogQ6Pjg~y>s-v>!^VNPLfWv4Jz0xkJm$nc4yMWR2J-cc#Q6SofWC)gp7L6!Sc @@ -47,37 +47,37 @@ c)mXTm=OBn8@DNvJ^I(u7Ttc@lJ^C)`OzK@Qe|^xa&~28LV0v$b2tf7M?ynyZEb0EFaQH+0?er0_e!9% 6%WL6o5Q7yVM7GXa@w44CHDB`4cre!cywiMb7^mGQ)6glZD9j@leIk>g)RqK0VQ|Mwn6X+txo3vSYd;; z)HQ~0$d0}b#7#AWl3ZdB|MH$#iox7(epK^GJZz3uq*Cb2l>R6Lh9EroO>_{O=WapR$**)WfhrcWXrXy KnGOwA#t$mH2bG7pQ)aE=^FQF!@KkQhzLn;aCLM|VQ?5o)zidWvABmX&uCxQ{9vUAsn@)h(<^=)@3p(i -4FwHHWo~72X>(I!Xk~3-9zxS>Jw1!&_U?o#2Tebz`mr;62_Hls_?@=CN?W&A7(sJ$X=iS2Wo~qHLTqVn -WK(5fY*ct@WFNs;Mn8g^E-G}MMdwWnpYo -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 @@ -94,10 +94,10 @@ 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 ZP9(YH~bairNa{vkf;?xyT5z&Ua +M@}mOiDpYxh>^^GknUxTJ!XL#OUcE0frb5ENEw7&f?o%+)B!ZpG}K!%4G?I4vp$|ttu*CMF0Q*00000 -0RI300000001QKKZggR3Ze?;-WpV=n0(LS22}5sgbY*UINn`{C00whoXk~3-00jX8uZ_m{WNzU!AS*T= -d6X;t=`;<;71O75notN1DSsZmlv2~%1FNg3QJ<&wKF}2F)J=UcKm7gx`duV?R0NO^0S9MgZe??6a{vVa -0>gzMlvzNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6 +0RI300000001QKKZggR3Ze?;-WpV=n0(LS22}5sgbY*UINn`{C00whoXk~3-00jX8dp?5NXDLVVImIB- +z9!%DK7l%`-}aulY!amxHJkmclv2~%1FNg3QJ<&wKF}2F)J=UcKm7gx`duV?R0NO^0S9MgZe??6a{vVa +0((A!+Gi<8@j1mH(!M6&@;-q&tKasXxoi@p7d4yxte*%hNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6 G6Dr@W?^Gx00jX7JIcU;0|?p#+${pKVqYC0|{wnVPj=UZE$P=1pxt8$PakD #zGc4+eY|aXXwx;YM0QXyiqR;Jsw2Z*{J&j1#@+9aBKht0Rd++hrkGM>lKfc^lq>z|G!4fU)2DQrPzVkwe;&S+ -Qq$W5tE;F{pQrXd&=l*`O?@#x{Qdy?T_k!`1dtE`2WMq&WpinB00jX8uZ_m{WNzU!AS*T=d6X;t=`;<; -71O75notN1DSsZmp9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0tIPiVPj-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0tIPiVPjm(ZiUQ7;QU -9z@vLsQU{;Z*FvDZgf*=XLAJs015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&TJ=zxYCD0L!x +9z@vLsQU{;Z*FvDZgf*=XLAJs015(oK7!h3DM#@+#URqYCg1WtfjX<-_MW+H5~UY4oBgb|=zxYCD0L!x 4tB5Hm3vFbl?lapNXe%XU~*fKJ0+X}A;%YO&?-P3O4E?M+l67UG^w8*<_XZ#%uyqCt-#n(R;4&W&+>mb;*F>vukd; =m`ygb@x#_>`RmOO$cpebYWy+bYTDq0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3 ZOHs70;T-agdg$OP=xIp;K4#IcLF!~asU7T000000RI300000000(DmZ(?C=a{vkgMe3tp+xFv-0Xp&G -?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0>gzBa)$q57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI30 +?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0((A!+Gi<8@j1mH +(!M6&@;-q&tKasXxoi@p7d4yxtTw?kq57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI30 0000001IJrb7^O8ZDnqBa{vkgMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+ -rTo-{AMw{vgzX#P!9p!}0yp?_0>gzBa)$q57bK6Q|uU +rTo-{AMw{vgzX#P!9p!}0yp?_0((A!+Gi<8@j1mH(!M6&@;-q&tKasXxoi@p7d4yxtTw?kq57bK6Q|uU fIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI300000000(kqWMyS-a{vhfMe3tp+xFv-0Xp&G?S=|} 9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0000000000{{R3000000 33g#@Wo~0>Wpe-t0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$O @@ -179,9 +179,9 @@ v{(W1V6JV*{3!yZ{M3XW@z+pZODNcTE%yi#yB_`&o2yJC_VPs)+VE_pNMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C `}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0000000000{{R30000002WM<=Vqt7^015&{ >Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+pGEG +dp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amxHJkmcHo-KZ`k;Xmr`<4sJYKN!!u{G5u+^j1lf!PF4>GEG 0000000000{{R30000003t@9}X=iS2Wo~qH015&{>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~ -v{(W1V6JV*{3!yZ{M3XW@z+pGEG0000000000{{R300000033g#@Wo~0>Wpe-t0!8Yh U)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~asU7T 000000RI300000000w1pa&K~T00{y`>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI&hQW&>`ZdvN @@ -209,9 +209,9 @@ I`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+pZ4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW @z+pn8fQnYaJ?>kL6XG(3esa0W5QyJn#ohg24a)00000 0093000000000YTY;R&=Y*Tb$bY%bu0daC2M$y&U#EU!@hie?UNS!6hQhW-W8INxxf{Fuzg#Z8m00000 @@ -220,11 +220,11 @@ aS3#3ZDn(GVQp{#07wXJWprU=VRT^t2?4!n8fQnYaJ?>kL6XG(3esa0W5QyJn#ohg24a)00000 0000001I?-VQzD2bZKvHa{vheI6k{n`X+XC81LasyqR+($`>jwnD57lV5q8m)(2RS0000000000{{R30 000003T1e7Wo~n6Z*Fq{2?1%uWwlwnKfCTqC!TnpV`xO%(e*mXP$JGS1-q69d*1*6000000093000000 000JMa&m8Sa{vhe!)N7;Jv;(oC!o$&iP#xB8s<*^%!GF?$0)U9@BFJ?0000000000{{R300000031nq< -Wo&P7WpVfc^lq>z|G!4fU)2DQrPzVkwe;&TJ=zxYCD0L!x4tB5Hm3vFbl?lapNXe%X +Wo&P7WpV<0K7!h3DM#@+#URqYCg1WtfjX<-_MW+H5~UY4oBgb|=zxYCD0L!x4tB5Hm3vFbl?lapNXe%X U~*fKJ0+Y5b97;JWkF(T0kye8jk+}zMj0CEc-y32_=FESDTGMdT)8q$(GFPM`UXjDaBN9r1pxpD002NB 00T>DbOs0qc4cyNX>V=;l-_zLn%tmAe68Jly{Qj?Kss0ny)C8xzFm#1PkyMk25DwtV`Xyy2?5?}PuOqD -o>SrzbQhfr-(8uQ5TW$;8TfLT9_>sbd87aU000000093000000000PcV`ybSrzbQhfr-(8uQ5TW$;8TfLT9_>sbd87aU000000093000000000PcV`ybD+9a{vheLR+L0000000000{{R3000000 3v+dFaBO95Wo~qH00{wOJ=2M>OG#EL&$!Mwbx&PZdlOljoA7|k;k>s6q @@ -232,26 +232,26 @@ oa5|8f~f~{V{&P5baMa+0%CAAe<9`Lptgpr6F_xjAC6(~TLj#*ewiHWCD(T2L(qY0=?N>gzK8zeWmt%8=p4R=gtK{LClh6Z#kObxUW*hK +0|IGe0((A!+Gi<8@j1mH(!M6&@;-q&tKasXxoi@p7d4yxtcU*MWmt%8=p4R=gtK{LClh6Z#kObxUW*hK HnBv9xdd)uZDj&Q>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+p< ?Hl01LM?X!H~4Z0a%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OChzJK4+YqPF=12x -aaxrgbrDxyH3fc^ -lq>z|G!4fU)2DQrPzVkwe;&SMbsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez*ZeeX@0!8YhU)%QM +aaxrgbrDxyH3K7!h3DM#@+#URqY +Cg1WtfjX<-_MW+H5~UY4oBgb0bsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez*ZeeX@0!8YhU)%QM kO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~atLx|b7gXN Wn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDP -k{-($PGN0jWJYOaY-C4lZ(?C=Q*>c;WmI`^Wd;KRX=DPgjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkw -e;&To?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%c;WmI`^Wd;KRX=DO>K7!h3DM#@+#URqYCg1WtfjX<-_MW+H5~UY4 +oBgcS?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(vPGN0jWJYOaY-CMk -bYWC^aAgJq0%>FduZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmb>vO>-_DBy8`Vb0jGrW9$=2qS +bYWC^aAgJq0%>Fddp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amxHJkmcb>vO>-_DBy8`Vb0jGrW9$=2qS MXvL3He1kloHngE|MP07*1hrWn@NaWo%?ra$#@6CZd7@2Wd;KRX=DPgjmGz6 -Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&RxQV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y)ZeeX@ +1=xWxVN?HcT9qDk5m#O{2>e1kloHngE|MP07*1hrWn@NaWo%?ra$#@6CZd7@2Wd;KRX=DO>K7!h3 +DM#@+#URqYCg1WtfjX<-_MW+H5~UY4oBgabQV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y)ZeeX@ 0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~ atLx|b7gXNWn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#; -{6ajG64wDPk{-(yPGN0jWJYOaY-CnpY-Mg^c~p6DWd;KRX=DPgjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQr -PzVkwe;&R@?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNABZeeX@0!8YhU)%QMkO4aJ;_ZeCe;xE! +{6ajG64wDPk{-(yPGN0jWJYOaY-CnpY-Mg^c~p6DWd;KRX=DO>K7!h3DM#@+#URqYCg1WtfjX<-_MW+H +5~UY4oBgat?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNABZeeX@0!8YhU)%QMkO4aJ;_ZeCe;xE! X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~atLx|b7gXNWn=<+10COKearHw cS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(rPGN0jWL9Bv X<=@3bvOnC0%>Fb009JUVQpmsMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r35LOoBKkGaY9#cS @@ -273,19 +273,19 @@ VQ>Wj015$yz}|oy`cC#6Uw2{wE+Sw~);*uMH+9Bf@aCY-RuiZDn*}0S0GmZ(?C=0tIh(Ze?Tx 2XWo~161PWnub7^O8ZDnqB1qWwkZe??6a|Q}@a$#@6CZU+fvcywiMb7^mG2nl6)V`Xr3X>V=` 3R87(aBO95Wo~o^1PNnrZggdCbV+0Z2AHk4+Bm{3x%H=p>4!*u&n~Wpi|4 -ZEyepNC#tbWnpx0assc7#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=^8dfQB3>bs~EXcCXx(drQcb +ZEyepNC#tbWnpx0asqokg4$;(NAWquAkw}j-|{|zI;-FIp1Euir581u{j9d=fQB3>bs~EXcCXx(drQcb 3B`Fx$)^%va$Ar)C7cUkZfdKHyBH|__hx_vscRWAu^w2r{b^x;wDWyGXd29 kG60)seH8)H{-R`;$q)jqasX>@6CZb@cgV`T;j 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 Ydx2$cvNmU*$z2Q1NvskzK}O!*07-npmH+?% delta 2609 zcmey<%lN04al$%<^}WZwr{p~}QP4J%tDK_!_oWH%anZ}mOJ)Ud@M+e|?b~?Hi6c_Z z>2i*(ZTGWp?^?9jeeGBN+Gt$ODeofxWA3(nUeVjbB^-;3Gt={OQ}arSopLhsQi4+x zb3!UIQ{)duxY;+&*3&AP_jskEl0so$`HL zk*#%CH?~BD3CG?2d+Fr5X-)r?a zTsy^9T=_LK&Q<1}IvYzlT`Njb^NKU`^Cq*~C`=aRIyu>vyJhol?si7CMemc=m%q9l zzH!0qZ3@rs`RQ_Z$4rzhTm-2OW4HC?j|8JMsU|<~^v$Z#Dhah!erE zCZMEfa=U=0;or<3ZF1|rn^}sjE?T<#mdvr@;P&_ConLs@bv>LNXE#M4qzG&mFu2^zh*Ni>4lflzuU6adz11A$9(=aj>KU%Jud|FyMV&AU!T6aviW^{wg8sbKdn{Y!f1P6-iz zDSe*-3jPBDh{;x*oRONFNYM7l2E2-!<7K=U2?vcnkHY4cvSLK291UqKB|m8)J^7_< z%jAEkY9MT!f|kMNrRvd4 z#Hb`}+~xyXC)fxZ1@yz@6NUkV722yPY>qH`PlRVdMz))*Cv2nvufpas)AK|a8Ns74 zxz(I-+hg(uE``a(78?lL-NLUhIoWb0VTHEb3X^@Ti13ZH^%;VuZDzM=XC=^HxxOWA8Xup+_1 T{NVTWh@`Yfud| diff --git a/stl/RGBStd@0.11.0.sty b/stl/RGBStd@0.11.0.sty index e30b7842..1b257773 100644 --- a/stl/RGBStd@0.11.0.sty +++ b/stl/RGBStd@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:yMGmidPl-LcWFyh!-W6sQ3K5-JQ8evpO-BGuI!lA-0htx!kg#chemist-enjoy-sound + Id: stl:3QsSNDHr-YPIKTR9-5O!fLuv-xhcxKT2-0LWrO9b-pG15Nvw#mango-inside-shelf Name: RGBStd Version: 0.11.0 Description: RGB standard library @@ -56,28 +56,28 @@ import CommitVerify#miller-pancake-elastic use ReservedBytes4#young-goblin-academy use ReservedBytes8#rudolf-tape-adrian -import RGBCommit#printer-window-alpine +import RGBCommit#trident-rover-tape use ExtensionSchema#active-eddie-empty use BundleId#carmen-farmer-diesel use MetaValue#split-package-recycle use InputMap#octavia-north-gram use GenesisSchema#iron-forbid-hamlet - use AssignmentsBlindSealTxid#private-lesson-compare - use TypedAssignsBlindSealTxPtr#arsenal-immune-martin - use AssignmentsBlindSealTxPtr#ship-panic-magic use AltLayer1Set#flute-flex-bottle - use TypedAssignsBlindSealTxid#siren-float-child + use Genesis#ford-acrobat-border + use AssignBlindSealTxPtr#harbor-charm-nelson use TransitionType#picture-reflex-brigade use Occurrences#source-olga-mirage - use Extension#capital-police-factor use ValencyType#aloha-dublin-brush use GlobalState#mouse-bambino-brigade use GlobalStateSchema#silk-college-august use OwnedStateSchema#cover-shampoo-weather use ExtensionType#apropos-scoop-viva + use State#aroma-sailor-manila + use AssignmentsBlindSealTxid#shelter-declare-chrome use MetaType#quebec-mission-quota use TransitionSchema#jumbo-matrix-normal use StateData#nissan-pattern-inside + use AssignmentsBlindSealTxPtr#clone-mayor-patient use XChainBlindSealTxid#dynamic-life-brown use AttachId#factor-hair-everest use AssignmentType#secret-penguin-limit @@ -87,14 +87,15 @@ import RGBCommit#printer-window-alpine use OpId#picnic-single-gloria use Schema#eternal-block-totem use ContractId#uniform-welcome-papa - use State#octavia-kermit-fast + use TransitionBundle#rubber-permit-martin + use AssignBlindSealTxid#piano-baker-lola use Inputs#herman-liberal-galaxy use XChainPubWitness#carrot-import-nova - use Genesis#sincere-block-graph - use AssignBlindSealTxid#light-basket-trick - use Transition#race-korea-capital + use TypedAssignsBlindSealTxPtr#python-baboon-money + use Extension#swing-virgo-wisdom use Identity#smart-pioneer-nominal use AltLayer1#edison-survive-nitro + use TypedAssignsBlindSealTxid#algebra-fresh-wedding use GlobalValues#verona-iris-senator use Input#actor-minus-multi use GlobalStateType#yoga-quick-jasmine @@ -102,9 +103,8 @@ import RGBCommit#printer-window-alpine use XChainSecretSeal#alex-griffin-left use Valencies#light-letter-comet use Redeemed#mile-lady-perfect - use AssignBlindSealTxPtr#alamo-dallas-caesar + use Transition#economy-ethnic-audio use Metadata#member-nobody-imitate - use TransitionBundle#final-numeric-berlin import Std#ralph-blue-lucky use AlphaCaps#picnic-soprano-aurora @@ -157,17 +157,17 @@ data AssignIface : stateTy StrictTypes.SemId? , required Std.Bool , multiple Std.Bool -@mnemonic(monaco-pilot-nitro) +@mnemonic(prague-peru-under) data ClientBundleOpretProof : mpcProof CommitVerify.MerkleProof , dbcProof BPCore.OpretProof , bundle RGBCommit.TransitionBundle -@mnemonic(lithium-shrink-actor) +@mnemonic(baron-liberal-burger) data ClientBundleTapretProof : mpcProof CommitVerify.MerkleProof , dbcProof BPCore.TapretProof , bundle RGBCommit.TransitionBundle -@mnemonic(center-saddle-annual) +@mnemonic(jordan-episode-duet) data Consignmentfalse : version ContainerVer , transfer Std.Bool , terminals {RGBCommit.BundleId -> RGBCommit.XChainSecretSeal} @@ -182,7 +182,7 @@ data Consignmentfalse : version ContainerVer , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} , signatures {ContentId -> ^ ..0xff ContentSigs} -@mnemonic(permit-simon-summer) +@mnemonic(gustav-people-message) data Consignmenttrue : version ContainerVer , transfer Std.Bool , terminals {RGBCommit.BundleId -> RGBCommit.XChainSecretSeal} diff --git a/stl/RGBStorage@0.11.0.sta b/stl/RGBStorage@0.11.0.sta index 6b324b0b..f87233bf 100644 --- a/stl/RGBStorage@0.11.0.sta +++ b/stl/RGBStorage@0.11.0.sta @@ -1,24 +1,24 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:lnl6QOG0-EYfOLKP-MHdEyA3-$cyUNuc-F3XmU!W-0glc1M0#alaska-phone-bagel +Id: stl:dYzM3Ct9-SJ8PljY-C!6hB6y-VlWvDE7-DAtNg3y-zanf6hE#media-fresh-cadet Name: RGBStorage Dependencies: + RGBLogic#leonid-melody-quick, StrictTypes#century-comrade-chess, BPCore#austin-story-retro, AluVM#congo-archive-folio, CommitVerify#miller-pancake-elastic, - RGBCommit#printer-window-alpine, - RGBStd#chemist-enjoy-sound, + RGBCommit#trident-rover-tape, Std#ralph-blue-lucky, - RGBLogic#ohio-electra-dilemma, + RGBStd#mango-inside-shelf, Bitcoin#signal-color-cipher -Check-SHA256: 3b654f8a5eb432f7f3c40cabf94f95336a3e9973df24330917273e0b228f8e88 +Check-SHA256: 9253c34c5b44ddbc699161987833ea989bcdcd22aa105c8cf57fbdc138fdbcb6 -3Q|WxQ*>`~VP|CtMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD*X=8L$d2nTORuk6O)Q5AK -bFW;JEQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pZ~a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjH -L2PwaO?m?z-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCJaMwZEb0ER%LQ&W_hoT#`k1y;WQvCHXeDD -EB)y-4aXJJr*xW72o5QK9=-`uM?ynyZEb0E$ib$G)8#G2g~}h6>clrIl2GyM={OOtBk4fW8*%zb22w{t -Q*>m?EFN!zncXl9K5w2;FV{y1jDTJCC^p$-mHEbO0#qjhQ*>nKQ=pGEdKZ=MPb)<*m$;LvDR$csb;@mC -=QtLlJD!;cQb$5eZ)a&^^=uPjBlbC`N(qzPM@Gr{imSMTSY5T*7C#t%#3&jH2SRCdV{d702?arHbyiIV +3Q|WxQ*>`~VP|CtE%Dq(^gpz7jp7pJ!qRo6KcERC_=qjv!(mxp;l`5z2vSEvOmAmtV@2wtU)%QMkO4aJ +;_ZeCe;xE!X<$x_Fs4If6Z`oP*$Y#2a%p39RC#b^b5;}9*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3O +NCrYsLvM0rVsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+1wm|eR!w>X9p7nv%krpqN4E?M+l67UG^w8*<_XZ#%uyqCj(P-WZerAG%@R7@(N8Kc{}IJy8K~t5|i6P +)~xSaq-}XN{034-LQ`~P^=uPjBlbC`N(qzPM@Gr{imSMTSY5T*7C#t%#3&jH2SRCdV{d702?arHbyiIV 01^bJwgM1*ibOBDT%6aZ|SrJerP1pIOD57`7Ol|-ogQ6Pjg~y>s-v>!^VNPLfWv4Jz0xkJm$nc4y MWR2J-cc#Q6SofWC)gp7L6!Sc3I$AQVo7AP4Jk3r!|EoW{Zi$060oMN(jLzPuNboiNpoRS @@ -55,39 +55,39 @@ Wo1rpWM%K_6AuO0fiYoI|8ZKC9(55{UNs2(LOhfb*8wh)9?K3=Wpib6c4cHjd30rSH2#7XN#A(BKKz&v rHo-i1kG~VoNp!e_~i}U4@G!%Wo~n6Z*Eg#Xk~3-1ACLTJsO2B2U!6ncg?mz@CdC==Kxq?gSEg)z2E{| 2tsvkWNc+gWE3Slj!?y>j|MdwWnpYo -cxhxG!B|E=f}1WXbe`j>AsRK~st@E%Ar$n40xlXfv!=HiRC#b^WI=OtX=iS8LTqVnWK(5fY*ctqbaEt4 -u7fOhz6x1|e$}yrT2>QY-Tl(Zu9iYk?T0jn6$2STb8~5DZf#|5baO&%X>MdwWnpYocu;h5Bv(?{Wq|OU -%4#DwR1!oWV0@!2f9}lj6c7M!3JEHV3_)ykOksItaxqh7bS;YoQW3HWFkR5a?gFmwQ2DKtJr^U`iXBi9 ->W<-`xEWM=aAjmcb8~5DZgWCxX>MdwWnpYocxhxbQV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y^ -RB~Z%b7^#GZ*Ek1aAh{ZG@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^s(A}fV`Fu4a%FB~WphQ56*M{q -Y_1i&m2c(}E`==I0Cc7fNfK$C)dRUKv2_VWcywiMb7^mGM(yUq2ps*m=2xUDT;RqCgn#@WzFu~@adfH5 -^@&-|3szxlWo~16RC#b^O52Yl{1bRQGoj1vG8y|VVR3azgI)JHkXXAwA#*Yd3rB2kVqt7kbYXO5QxVNW -sw`2k$dAVYYJsYG;e2<6^ZE|08O7j~NF%g#J+iq45un -J`5_e64+kv93|H3u2>LHcWz~5Q*>c;Wm98lWo=<(bsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez^ -MR;^&ZgXjGZd7@2Wp(6D_}|Wp0vpvv$c&#PW69R$ltr%da5t5w^x+8!q6kf8bYWC^aAkJ28)%E7`<-;o -vk@YSJ+V~kNcmIwC6DJ=V=(On#Mls2a$#@6CZc}4uWo==3#Mns)Y&M6LqDeqU-jv95KHlThh+c{3 -8p;h*Y8ns*OksItaxr@!R2^S7pk#{MS?zgMX@X{kfl~;6wBm#tC>wYyC6< -cPOa7QgE1g-_nt(I(wNyhqRZ!p{J?a6IerNVQFqcY-w&}Q)OXnRCsA*gmDd%EKc;pw+KsVi?D}qDSkO* -B!5Mb*xG|_(S5o&2tjmoVPj}XWQYFZWmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xeh^db7^O8ZDnqB -RC#b^iECIT&Bl;lSX#$ms8AQN7m&qYLMnX>MdwWnpYocu;h5lMuXsu{2tXFT+?;?hj39&>gq>HOrf1lB-q; -n)I5N1y68qb##h5j^*S;NLvL<$a$#e1No1n$Vy}1V+gGumo3O{MSF6AB* -L349yXKq4lX>MdwWnpYocxhy{!HgsFm<-5+?#Q2zpK7%G#jU~w0Gz%EU@t)QVw`OXRB~Z%b7^#GZ*I2e -fQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7cLJWMyu2X>@tWYl3?VT7AZm1SE3hA}5c~&&3*7XrN0! -sxd$tJbohyL2PtPVR>b8G0xLK&_vWw`D^wPq`MWfkMs^Yw9fkOkt*ANQL*Z(84O2kZ(?C=R$**)WpmMI -7rjFg@b(FW?*48~9t#5lC;3juy9JUg#K|!ymZ}z5Lug@XZbf)-Y-wX@bW>$vY*ct@WYvvd2n?Horiuqf -0^m>2O`jNRziT$b7#=ya6uYYC;sr@=aCLOm?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%LWpm%psgd=EMdwWnpYocu;h5^?FS>S$_F2)vN@Mb6UJ-F(lri_dqer -x4lR4>iBsz2u)>lVPs)+Vfq$knAcm{gpRnazG2}LOJH|wPc!@bMkfvN&8?kIwGdcCXklq?P<3KgX>@L7 -b94P^_=X;?_cl2et8%5g+8oAnQ-|+2iS!Mwis74HK9mqta$#@6CZbEf#WNc*!Qb$5eZ)a&^0svgx +WpinBQ)6glZDAx=QrKmH@SMtOBR5nML?B>%qbz^!%<&Wu0B;HjDvS(4Y;;Uvd1Z1jQ)P4~huszhuS%Gw +>J36#@&i>}*{wKf47Hg5JxV=iU{?qSM`dnhb7^xaG~Qz4rf|COpMQA6DFZhcbS+pFfT9t%(h@vS@2O@K +L349yXKq4lX>MdwWnpYocu;h5G*S<)6P6lYy(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(14peesZgXjLX>V>+ +d2nSm!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4rGOBqCPh(?sa&l#EV`Xzj?dHP>9R0ZFSEMRj;Km4q +fBYZ5UUs>0bg9bqiCNAIR$**qZew{=d2nS)+m9st6L>r`q08+u8T&0^adk?AUH3SUSi3+Wb21AHM{I9m +VQf=$VRU6v5zRxYEK#t?kH-RPfvS1oe0PQO`VOrdl$-fvv-}wmM{I9mVQf=$VRU6vV`ybpR6heI$}l1ygikbY*KE +2S>RllQnv!#Bdhn{LP$;qli}WS_~%;XE5$2GG`b;b8~5DZf#|5baO&%X>MdwWnpYocxhyHV>*V`yb=iRT*14O40w5C%+Pd1Z1jdmmICUpAm* +irZQ3c~xnGW`==N2!6EUgc~Rug%*0A2~%`obY(_oQ7|GShenHHQk6Kc**bJ*e3IRag>U{QO}* +5#AX=b8~5DZf#|5baO&%X>MdwWnpYocu;h5f(#9>YyC6LMnX>Mdw +WnpYocu;h5lMuXsu{2tXFT+?;?hj39&>gq>HOrf1lB-q;n)I5N1y68qb##h5j +^*S;NLvL<$a$#e1No1gfw_qjpC#e%OW}_qta$#@6CZbEf#WNc-q +Ht(`hF}jj5^Xl;{(HZPSTKb&GEytIZbS*TmyWyh~L349yXKq4lX>MdwWnpYocxhy*qIy@8$eYR~OKp92 +)%PJ48iGR>vvBgJ_74J{Jehz7Np5g;baS$EAbXV}DW}urw59q*`|HcZksRt+CA}j9C82<;s1zDhd2nT9 +L349yXKr&sY-w&}Q)OXnRCrKyaV?} +=zxYCD0L!x4tB5Hm3vFbl?lapNXe%XU~*fKJ0+Y5Nn~YibZK;X$ZLXo3tD}~kpv`i_>4e9YQ#rfba;u! ++d5tm#=h2RwFD4YLug@XZc}Ara%FT=WnpaHg=PS6VPp{$?vC--s`v@B8YHl)C#jpVFzBk!DMw8SR$**q +ZewX>bKlRYk@bh=O+>c=6@6CZuNRiI9Y!AFx9LCk8@hQXE7w+qW3^C%eTEp@#^?_H3&^*bYWy+ +bYc1yW|-Go+Jug{t-fL56H8!sY)>=$`$i`X@y)HBPPGtNLug@XZcue%S7~%^Wpi@~Qb$5eZ)a&^0svgx 4kHyWc_Q0~!}**;il?3%&@4zfV)l6Vw93c;fD#H@L7b8}E{b8@>v$QV;yG0%+u`Lqfm#|FpRuujhT P8r)T_J?np;R;u2bZ%vHb5C+)22w{tQ*>k}00uitlB|?L;LPn)fIF!^9U_+Ia*^@2K#bcvtFTdm;R;Z7 VpnN&Ze??G2AHk4+Bm{3x%H=p>4!*u&n{7wQSPJQFX$PK`>V6xnyyv_mEW!L2hnubYXO9Z*Fr$2}2U%?SKESc;}_}8Q6@wJm*jqNZksOmu*x> HAnjiNoHYVWl3#tY)o`QW|2#K;wB)k0g*C`Fwq1F!!?eFe@CD1{Hz9}!v$7la!zknhozd@T(rwWP-G*< FKz{ld}8ext;?Uw^U#1TXfcQtPGN0jWJYOaY-CnpY-Mg^c~p6DWmd=!c)Z3!7CPHT_+Dq|&?jn_(4)Lj -FAF^$MA+G=`vysEaBN9rSoRTJ>~32(7)!VKwhueASIYDuGM{9p;;;bXCQUmt2vc=%aBNd`Vq-niiLgsa -Rw~c9&Ny{YCK_TCaeS`x+X~XLW@}|UwF*;paBys8ZDnqBXEKMt2yp8annvOGPI~_sbHU;fx2Gv#gJM&> -FkgU`2UB%$aBN9rX~bo}HX&M*bLmIr&^7fxYqWn@NaWo%?ccywiMb7^mG -RC#b^adI6-(bd|-i#!&GYaF>qoh8ard&ZODNcTE%yi#yB_`&o2u*KfX=Z6< -a+xA1u~C-QVH212O0vm-vwNnjOqUO({d!Yj6^~`qa2QTuZDnLeX=Q9=L349yXKrm}Zgf<6aAlpcqOsLD -&2v(e4*mho?)OxX3Sz)X}ib9i^%gOs*8bY}uR&S59aNAMwsm +FAF^$MA+G=`vysEaBN9rSoRTJ>~32(7)!VKwhueASIYDuGM{9p;;;bXCQUmt2vc=%aBNd`Vqp@I4KBh^ +1`?WeT6!q1%r17uTo3T2=}n^?e(vEz0t!KFY;R*>bZKvHV?EP}uuDl+D$lsiICW4a8e$Z2e6I7`3evG= +Yh^sO3R87(aBO95Wo~q5GKatjaO)MCM&b8PdjA-6!Qv6Orzv5BVpF^@Ux1YdQ+04~Y)NEk#AUTvyg$3{ +N++IppJQl5+tKwp$xtHBFa^7o2YcTaPGN0jWJYOaY-B}vbY*UHX>V>+d2nTMaves|)!M|1JQjy*9JxrH +CCXBK3Y-~_ZzF<=1A>JaPGN0jWJYOaY-C4lZ(?C=Q*>c;WmI`^Wp(W({yb2RgQ&qroX$3|s~68cgLoKb +6;WMPYGO<*F$_m#Ze??6b4g}lV`X=x<(>mzHseKA;9>iaucy+897BCKo})K|H41Qsl9mipV`yb?(bB4g)fE@Zx_8VV!VgW89U{2OOpSL%4#$e>_yXHjFISEsBaByr% +bY*Rn9PeeuXILaAA3^JIKdZ3ic!M@6PJV67bl-3#Cg!RLO>bmrW@%+|nIb5$QI^$V6PNW$vdMt6d#0>R +mk*`=dQ)K)k7d+w7*1hrWn@NaWo%?Yb8~5DZf#|5bX0k8Wuo9&)X}ib9i^%gOs*8bY}uR&S59aNAMwsm _ykY{pbAuSb#rt~Wp-t3vVI^;l)2*3EOV>g0ax8O)k#$7&vslvM*4K4@C1O&3qf;pX=iRpW?^GxwYfr# x-}I>85-$$+oWFjgbz9?gh<<5xiU@B4p`m#2vc-nbY($eX}y7nVp0y6#Opn49V(cQioJpYH;+t0eX2w~A!Q+0eaZ{MVycPK^aqWo=1heaS*6)M5bHCYFUH@63IY`6K;Dlo$g{Z6f4)7N~Yk )mClKyTm8WaJ}8CMy}crPGN0jWJYOaY-Dp&Wo=1hmm!0y(Hu`f(Fijc5*b_M4dVsY!8b|ZDhq! 3`K5rZB}7&X<=@3bC}8#qjhfwd&>tyAtR<)2LcK~xyL-@iqBUFK20Q^G*lRL(MHiY2Qv~?ZfS3BR$+2!VQzGDQ)O*QWc`7zgMJGKo2X9f$R^xB4~9n`Dx!RtcK)nwJ0o -0000000960{{R30000heb#!oVX>N2+aBp>Va{vkguZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZm -(PtOELlW@z354$cZcQEw0|O`dPRP3jk}Sl@F(;O)00{!GjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkw -e;&S*5WIk~G+K)5%bR49t5yk`^qQ9d0000000030|Nj60000000000000030|Nj60 -0000GO=WFEZ*FvQVPkYtbYXO51_TImV`ybbaG*1bV+0auZ_m{WNzU!AS*T=d6X;t=`;<; -71O75notN1DSsZmp9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b24`$^Q$ib$G)8#G2g~}h6>clrI -l2GyM={OOtBk4fW8*%zbowA~_)i}*_Qj`w<0nYCCRFDc{!UsZqyzOYb66V_40000000000|NsC000000 -4ozikM{I9mVQf=$VRU5%0tIVsZ+C703IfQ%ris(#Eyab(AC~IGH!G4*@$2b05w0WYK++p=`bgtr9kcvV -UUjCQt9$#kE#Vwfc^lq>z|G!4fU)2DQrPzVkwe;&SjA5^xB4~9n`Dx!RtcK)nwJ0o +0000000960{{R30000heb#!oVX>N2+aBp>Va{vkgdp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amxHJkmc +(PtOELlW@z354$cZcQEw0|O`dPRP3jk}Sl@F(;O)00{znK7!h3DM#@+#URqYCg1WtfjX<-_MW+H5~UY4 +oBgbl5WIk~G+K)5%bR49t5yk`^qQ9d0000000030|Nj60000000000000030|Nj60 +0000GO=WFEZ*FvQVPkYtbYXO51_TImV`ybbaG*1bV+0adp?5NXDLVVImIB-z9!%DK7l%` +-}aulY!amxHJkmcp9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b24`$^Q-3t;lG3#LR3QZq*JLk)~ +{9$tvliNbptnXW-ZFx5QVG@xIF2Ya-5}I{ddMK{UE_TLT5AdbwO`{xs?%_iM0000000000|NsC000000 +4ozikM{I9mVQf=$VRU5%0tIVsZ+C703Ig2=5;QUEVDbu0A9*|H%ewqwa}tx=Le{MBTcmAyHvHpb9kcvV +UUjCQt9$#kE#Vwuv7J8ll0000000030|Ns9000005Y-w$2bN~PY2u)>eNp56icm@Rx -Z*W3&Ze(m_Np56icmN6luZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmmB{9L9(7`0)Rt93YLV-H -LXe?vTA1;^Q1`ZqBog<<0>gz5{!cwLKbzE(ciwC3nrX -LGTEzPUiqvVS}~6O1>gzMlvzNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G5`Po00000 -0RR900000001{$#Ze(m_S7~%^Wpi^$Ze(S6015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&RA -dy}<28ig(gSpg+?&9*`C2(3=%09avzwZKZf-~wC#2?DQ;#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK -9=?fdSS8KIkY89@$6%;X7qJ(R#b4x^L3+^xAn+qc8}R@D000000093000000000000000000960{{R30 -000eRZ*FvQVPkYjZe(S6015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S{2rNlD$O59e#ogQs +Z*W3&Ze(m_Np56icmN6ldp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amxHJkmcmB{9L9(7`0)Rt93YLV-H +LXe?vTA1;^Q1`ZqBog<<0((A!+Gi<8@j1mH(!M6&@;-q&tKasXxoi@p7d4yxtOI+KwLKbzE(ciwC3nrX +LGTEzPUiqvVS}~6O1h5j^*S;EEYxz&xd)D|X2*0_E|OYH;h*YvvIyS{G&S`ex{XQ}0000000000{{R30 -000004RmF4ZE0>{Y)NipWq1Gz0>gzT1jg8iEuMbtv-q -j6g$b#7A9pc!|f`I$jaRzSe2A1ON#FuZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1DSsZmlMuXsu{2tX +000004RmF4ZE0>{Y)NipWq1Gz0((A!+Gi<8@j1mH(!M6&@;-q&tKasXxoi@p7d4yxtlNrO8iEuMbtv-q +j6g$b#7A9pc!|f`I$jaRzSe2A1ON#Fdp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amxHJkmclMuXsu{2tX FT+?;?hj39&>gq>HOrf1lB-q;n)I5N0000000000{{R30000000000000000|Ns90000002u)>eQ*>c- -Xa)@kb7N>_ZDDj_015)HjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&S+Qq$W5tE;F{pQrXd&=l*` -O?@#x{Qdy?T_k!`1dtE{$ib$G)8#G2g~}h6>clrIl2GyM={OOtBk4fW8*%zbcctZ?17J4eMOENo`;f1v -(uf>GeK($?H-j|_aE6kW0000000000{{R300000025DwtV`Xyy3IfQ%ris(#Eyab(AC~IGH!G4*@$2b0 -5w0WYK++p=`bayqMEp^75#kD_Tqj3Vr!KR7RO -I1#QR=|IvOar#K!YERg2%AQl=6Lc4y4BuUum=K}#_8Itcm>%s+B6*|$00000000300000000007XJu|> -b7gY?3IeZ<#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=@LlEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G -;Jw22Ix+&UjmGz6Zs9Z_D>fc^lq>z|G!4fU)2DQrPzVkwe;&TExal5h{0lRojI;wCRUm@0B`|@HB98P_ -oAgZ&Vm^rg00000000300000000005b9HcVYyb)Z$ib$G)8#G2g~}h6>clrIl2GyM={OOtBk4fW8*%zb -2AHk4+Bm{3x%H=p>4!*u&nOI1#QR=|IvO -ar#JOJ=2M>OG#EL&$!Mwbxg)RqK0VQ|Mwn6X+ -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 -OI1#QR=|IvOar#K&)D=(>(T2L(qY0=?N$ib$G -)8#G2g~}h6>clrIl2GyM={OOtBk4fW8*%zbh8PemXlG!~;@e)_O3H?xO^a~KWeI~0jp}x-Dk@(^00000 -00000|Nj60000002u)>eQ*>c;Wd;HXcWHEPWpi_7a{vkguZ_m{WNzU!AS*T=d6X;t=`;<;71O75notN1 -DSsZmiECIT&Bl;lSX#$ms8AQN7m&qYX% -7Na|!nR2^A$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;Q#;t000000RR90{{R30010DnZgg^CV{~%> -3IeZ<#`k1y;WQvCHXeDDEB)y-4aXJJr*xW72o5QK9=@LlEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22 -Ix+#PeJ!|9#Bo%!^4)q3npZX#!goq#B@MRnCBuc8L!b@-0000000030000000000 +xyCjU1gEwF5PXV6FZDLo1#Vec_~kix7WfVQ#Sd|CM9$^_0000000030{{R3000004b7^OD015)#3lcOj +>tON(T2L(qY0=?N-3t;l +G3#LR3QZq*JLk)~{9$tvliNbptnXW-ZFx5Qh8PemXlG!~;@e)_O3H?xO^a~KWeI~0jp}x-Dk@(^00000 +00000|Nj60000002u)>eQ*>c;Wd;HXcWHEPWpi_7a{vkgdp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amx +HJkmciECIT&Bl;lSX#$ms8AQN7m&qY<-*c+r9YqvBlw6d-@{>9 +U*X1+0dl)S$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;Q#;t000000RR90{{R30010DnZgg^CV{~%> +3IcmRg4$;(NAWquAkw}j-|{|zI;-FIp1Euir581u{j8q|EJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22 +Ix+!#bL(f8`U$>X>B)Y_u0zsDWJXxNV$=kC)4@UGUHf+c0000000030000000000 -----END STRICT TYPE LIB----- diff --git a/stl/RGBStorage@0.11.0.stl b/stl/RGBStorage@0.11.0.stl index 88c58d859b8d57018d666676535185568e82aae5..314dabd9b729ebe90683305cd9be550b05c02b5e 100644 GIT binary patch delta 2550 zcmdlSwK>X^E6Cj`xFo+QF+G)2_v0P+FZNrCdmjlsJ#?vbsr>>@nZ znUMpi)+awbGkGG&B|L-xXtB?=@rjD_*ClPt2jQH`iKZ@@$>)-`2}EJt3Tf-90rgwK%g_)8t;# z<7EZAKFqJLIIPKRE>WTzA=DN!t>HSZN`Tid-|@1-I}p>`;LQK!>7bnfB2qw`|4}!qjt3_lLA`v*p;` zcdAb|ty+4dKY~zbVLY*CfNwuRdyDlzih7 z^=r-v-Q&}zmFSwR-~Dj0Fos`&ZkoWap0uf0p?a#4=JLx=w=DhT`up|iBNJs_MX2so zW>#I;uzH1vR7hn(Y6?VmF=|k47B#WI=b8NdQcNq0*6Ycudk#!#T4w#fX#VY2g2pM+ z6gXWgN>cNRCtC}IS)Hl4!!G-y{m3=t@BJd7c8#oe6s2|=YVOg${X6pa|5|@Z9M)u} zY@R5P#Hjs9qu4v^m0CcDCr{_>`@F5|*iOILm+qOOCt>CzCw@?u3lSibHH4xzZx&)> z)=m_f$g6iKfK6ytX;hWQx-)uZ$71+DEPd&_Sf=jXLuV!~$DEw}aXoSYM3MF-@R2`h?|Gnm|<$u-$lo(RPa@;Zb~wC7it{6?OOutI4; zg~?_LRt|)6Afa%ayg@-rfsi4Se<>&uc2Xa&!sKX0Q^E>2C=y}XM@4tSCVf;?P-G$) z;h;d>sia1Xaf(Wugw0#6p)ff~*^sb#Ad4?66Or2T1r?MTh_E?MPIK}?6+OZ>H^>76 zhG4WBs9F(@`z}>Q!ir9-S`&5@FgWT7hAyERf&mKtLuuCH(t?5<1}=iWWdl|Qw(`pSOBK)I- z!ekyzdBUc>0hS8cnkIx5?$_)htjJD)m~_2L>muPuo~=!UH}7bB5Ox$OzzDUnCchL? zn7mYnh~Nk25<|wC;@9cZesS)LdwH_%_&VoH9w}}S`;xA(R9`;m_&D}=IeIPt0O(bv ARR910 delta 2510 zcmdlSwKwAxVPsw{|qM&UiS2;!d?@JTjWI1aq=1jFUs?#RQ-0}iNxJZt z2OHS*l*z1&Dw@xO7xbG}iBEm!ukC6ueaGZgnq{{IN>Am+J+}~BY&~x#2T-j~etKr| z<^V=3P6auq%Q?2T-Os+gYtdr&wO{#bqj5E-yo>ygx!d-6MQ;zEJda0GLH=Nbn|;%4 zJ*|>?k5?*6nLb{{|HM~Oao|MVvW!oqJ;+Ixb@mtrdQ@)QYvbFB&#+Ils;kdhh zFP&UB%_;D0yGgq!v*hIYJYviNB}J3FxOA;_yIF$-H*p!nUO4)WY2EvPpKGVsiYwpf zk_`}i)%S4z4#|+pg47hp;^NHoyke)E%)FG~)Wn>Sip-SBBHYnht`kK~tk`naiSC)2 z|4c})Rp$;v$ud4qq0Bi~nRn`JEah~qC`rvL&dkr7oX`Do@^+rpo9FOuVpLo7K52dV ztJ~ol7tG$K@a&$S4%g?Yzn9;%^XYzAtM%*j3fAC~#FEs>oB7r2H|}^Tm-UC+cwx^L zX4z1MrcJ5_jr~e}UqWVo@#Rml>tuIN%}XuLEZ*vn7U+B_Usu;4!EE{ec9{(Z*0Dhj zWvh%{x$JJ!dnzXk@dSz=wjS(J{xpNyJHHU&cIcygSa6JbRMMk9*u2#m3X_wR4GEhEviPzx5h-kypn@_35jMxkX-;0KqDR=~26 z5R6g-RV%{r-leKYSkY-!Yr>8K21h-?&?Qv1F+jn8D9u`2T2PR~z(vrvY%|twzcu-& znjB%@JP}oxtgNn0*hj$h=Sa{;gi5{1=hfv1TLsKC4un!Vp{i$co`x)8n^tQO5#b*t z6eja%$`dy20 ^ ..0xffffff {RGBCommit.Opout ^ ..0xffffff}} -@mnemonic(dolby-mammal-pogo) +@mnemonic(fire-domingo-monaco) data MemContractState : schemaId RGBCommit.SchemaId , contractId RGBCommit.ContractId , global {RGBCommit.GlobalStateType -> ^ ..0xff MemGlobalState} @@ -213,7 +213,7 @@ data MemIndex : opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit , contractIndex {RGBCommit.ContractId -> ^ ..0xff ContractIndex} , terminalIndex {RGBCommit.XChainSecretSeal -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xff}} -@mnemonic(alfonso-office-suzuki) +@mnemonic(summer-sardine-disney) data MemStash : schemata {RGBCommit.SchemaId -> ^ ..0xff RGBStd.SchemaIfaces} , ifaces {RGBStd.IfaceId -> ^ ..0xff RGBStd.Iface} , geneses {RGBCommit.ContractId -> ^ ..0xff RGBCommit.Genesis} diff --git a/stl/Transfer.vesper b/stl/Transfer.vesper index cc718eeb..08cfaa9f 100644 --- a/stl/Transfer.vesper +++ b/stl/Transfer.vesper @@ -65,7 +65,7 @@ Consignmenttrue rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=1 @@ -82,7 +82,7 @@ Consignmenttrue rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies @@ -111,7 +111,7 @@ Consignmenttrue rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=1 @@ -128,7 +128,7 @@ Consignmenttrue rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 redeemed map len=0..MAX8 aka=Redeemed @@ -188,7 +188,7 @@ Consignmenttrue rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=1 @@ -209,7 +209,7 @@ Consignmenttrue rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies @@ -259,7 +259,7 @@ Consignmenttrue rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=1 @@ -280,7 +280,7 @@ Consignmenttrue rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies @@ -335,7 +335,7 @@ Consignmenttrue rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=1 @@ -356,7 +356,7 @@ Consignmenttrue rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies @@ -406,7 +406,7 @@ Consignmenttrue rec liquid bytes len=32 wrapped aka=SecretSeal tag=1 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 revealed rec tag=1 @@ -427,7 +427,7 @@ Consignmenttrue rec blinding is U64 state rec State reserved bytes len=1 aka=ReservedBytes1 - value bytes len=0..MAX16 aka=StateData + data bytes len=0..MAX16 aka=StateData some bytes len=32 option wrapped aka=AttachId tag=1 lock bytes len=2 aka=ReservedBytes2 valencies set len=0..MAX8 aka=Valencies From 1a1ad23a0ee94e6b9ea02a3568bc5742f95a105c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 15:09:08 +0200 Subject: [PATCH 09/70] further invoice and interface state improvements --- Cargo.lock | 10 +-- invoice/Cargo.toml | 1 - invoice/src/builder.rs | 111 ++++------------------------ invoice/src/invoice.rs | 32 +------- invoice/src/lib.rs | 3 +- invoice/src/parse.rs | 155 ++++++++++++++------------------------- src/interface/builder.rs | 149 +++++++++++++++++++++++++------------ src/persistence/stock.rs | 25 +++---- 8 files changed, 190 insertions(+), 296 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80e12cd3..2420f764 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,12 +149,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "base58" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" - [[package]] name = "base64" version = "0.22.1" @@ -674,11 +668,12 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.9" -source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#75424505e4f24df90d9ee1d284c4ee25103c185b" +source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#b59f1ca4c13c62ce53152f7f4c34094e435a1be4" dependencies = [ "aluvm", "amplify", "baid64", + "base64", "bp-core", "chrono", "commit_verify", @@ -696,7 +691,6 @@ version = "0.11.0-beta.9" dependencies = [ "amplify", "baid64", - "base58", "bp-core", "bp-invoice", "fluent-uri", diff --git a/invoice/Cargo.toml b/invoice/Cargo.toml index ff70bc69..60607596 100644 --- a/invoice/Cargo.toml +++ b/invoice/Cargo.toml @@ -17,7 +17,6 @@ name = "rgbinvoice" [dependencies] amplify = { workspace = true } -base58 = "0.2.0" baid64 = { workspace = true } strict_encoding = { workspace = true } bp-core = { workspace = true } diff --git a/invoice/src/builder.rs b/invoice/src/builder.rs index 1805ee9e..9d84fb61 100644 --- a/invoice/src/builder.rs +++ b/invoice/src/builder.rs @@ -21,11 +21,10 @@ use std::str::FromStr; -use rgb::{AttachId, ContractId, State, StateData}; -use strict_encoding::{FieldName, StrictSerialize, TypeName}; +use rgb::{ContractId, StateData}; +use strict_encoding::{FieldName, SerializeError, StrictSerialize, TypeName}; -use crate::invoice::{Beneficiary, InvoiceState, RgbInvoice, RgbTransport, XChainNet}; -use crate::TransportParseError; +use crate::{Beneficiary, RgbInvoice, RgbTransport, TransportParseError, XChainNet}; #[derive(Clone, Eq, PartialEq, Debug)] pub struct RgbInvoiceBuilder(RgbInvoice); @@ -40,7 +39,7 @@ impl RgbInvoiceBuilder { operation: None, assignment: None, beneficiary: beneficiary.into(), - owned_state: InvoiceState::Any, + state: None, expiry: None, unknown_query: none!(), }) @@ -72,106 +71,26 @@ impl RgbInvoiceBuilder { self } - /// Set the invoiced state, which includes both state data and an optional attachment - /// information. - /// - /// # Panics - /// - /// If any state information or attachment requirements are already present in the invoice. - /// - /// # See also - /// - /// - [`Self::add_state_data`], adding just state data information, not affecting attachment - /// requirements; - /// - [`Self::serialize_state_data`], for adding state data by serializing them from a state - /// object; - /// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state - /// information. - pub fn set_state(mut self, state: State) -> Self { - if !self.0.owned_state.is_any() { - panic!("invoice already has state information"); - } - self.0.owned_state = InvoiceState::Specific(state); - self - } - /// Add state data to the invoice. /// - /// NB: This keeps existing attachment requirements. - /// - /// # Panics - /// - /// If the invoice already have any state information (excluding attachment requirements). - /// - /// # See also - /// - /// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment - /// requirements; - /// - [`Self::serialize_state_data`], for adding state data by serializing them from a state - /// object; - /// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state - /// information. - pub fn add_state_data(mut self, data: StateData) -> Self { - self.0.owned_state = match self.0.owned_state { - InvoiceState::Any => InvoiceState::Specific(State::from(data)), - InvoiceState::Specific(_) => panic!("invoice already has state information"), - InvoiceState::Attach(attach_id) => InvoiceState::Specific(State::with(data, attach_id)), - }; + /// See also [`Self::serialize_state_data`], which adds state data by serializing them from a + /// state object. + pub fn set_state(mut self, data: StateData) -> Self { + self.0.state = Some(data); self } /// Add state data to the invoice by strict-serializing the provided object. /// - /// NB: This keeps existing attachment requirements. - /// /// Use the function carefully, since the common pitfall here is to perform double serialization /// of an already serialized data type, like `SmallBlob`. This produces an invalid state object - /// which can't be properly parsed later. - /// - /// # Panics - /// - /// If the invoice already has any state information (excluding attachment requirements). - /// - /// # See also - /// - /// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment - /// requirements; - /// - [`Self::add_state_data`], adding just state data information, not affecting attachment - /// requirements; - /// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state - /// information. - pub fn serialize_state_data(mut self, data: impl StrictSerialize) -> Self { - self.0.owned_state = InvoiceState::Specific(State::from_serialized(data)); - self - } - - /// Add attachment requirements to an invoice, keeping the rest of the invoice state information - /// unchanged. - /// - /// # Panics - /// - /// If the invoice already has attachment requirements defined. - /// - /// # See also - /// - /// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment - /// requirements; - /// - [`Self::add_state_data`], adding just state data information, not affecting attachment - /// requirements; - /// - [`Self::serialize_state_data`], for adding state data by serializing them from a state - /// object; - pub fn add_attachment(mut self, attach_id: AttachId) -> Result { - self.0.owned_state = match self.0.owned_state { - InvoiceState::Any => InvoiceState::Attach(attach_id), - InvoiceState::Attach(_) - | InvoiceState::Specific(State { - attach: Some(_), .. - }) => panic!("invoice already has attachment requirements"), - InvoiceState::Specific(mut state) => { - state.attach = Some(attach_id); - InvoiceState::Specific(state) - } - }; + /// which can't be properly parsed later. See also [`Self::set_state`], which sets state data + /// directly with no serialization. + pub fn serialize_state_data( + mut self, + data: &impl StrictSerialize, + ) -> Result { + self.0.state = Some(StateData::from_serialized(data)?); Ok(self) } diff --git a/invoice/src/invoice.rs b/invoice/src/invoice.rs index f48f5b75..41f1720d 100644 --- a/invoice/src/invoice.rs +++ b/invoice/src/invoice.rs @@ -24,7 +24,7 @@ use bp::seals::txout::CloseMethod; use bp::{InvalidPubkey, OutputPk, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; use indexmap::IndexMap; use invoice::{AddressNetwork, AddressPayload, Network}; -use rgb::{AttachId, ContractId, Layer1, SecretSeal, State}; +use rgb::{ContractId, Layer1, SecretSeal, StateData}; use strict_encoding::{FieldName, TypeName}; #[derive(Clone, Eq, PartialEq, Hash, Debug)] @@ -37,33 +37,6 @@ pub enum RgbTransport { UnspecifiedMeans, } -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -pub enum InvoiceState { - Any, - Specific(State), - Attach(AttachId), -} - -impl InvoiceState { - pub fn is_any(&self) -> bool { matches!(self, InvoiceState::Any) } - - pub fn state(&self) -> Option<&State> { - match self { - InvoiceState::Any => None, - InvoiceState::Specific(s) => Some(s), - InvoiceState::Attach(_) => None, - } - } - - pub fn attach_id(&self) -> Option { - match self { - InvoiceState::Any => None, - InvoiceState::Specific(s) => s.attach, - InvoiceState::Attach(id) => Some(*id), - } - } -} - #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] #[non_exhaustive] pub enum ChainNet { @@ -237,9 +210,10 @@ pub struct RgbInvoice { pub operation: Option, pub assignment: Option, pub beneficiary: XChainNet, - pub owned_state: InvoiceState, + pub state: Option, /// UTC unix timestamp pub expiry: Option, + // Attachment requirements should go here pub unknown_query: IndexMap, } diff --git a/invoice/src/lib.rs b/invoice/src/lib.rs index d2820bc8..9ffe2999 100644 --- a/invoice/src/lib.rs +++ b/invoice/src/lib.rs @@ -37,6 +37,5 @@ pub use builder::RgbInvoiceBuilder; pub use parse::{InvoiceParseError, TransportParseError}; pub use crate::invoice::{ - Beneficiary, ChainNet, InvoiceState, Pay2Vout, Pay2VoutError, RgbInvoice, RgbTransport, - XChainNet, + Beneficiary, ChainNet, Pay2Vout, Pay2VoutError, RgbInvoice, RgbTransport, XChainNet, }; diff --git a/invoice/src/parse.rs b/invoice/src/parse.rs index 49a49dca..3ae6b546 100644 --- a/invoice/src/parse.rs +++ b/invoice/src/parse.rs @@ -24,21 +24,16 @@ use std::io::{Cursor, Write}; use std::num::ParseIntError; use std::str::FromStr; -use amplify::confinement::{self, SmallBlob}; -use amplify::Wrapper; use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use base58::{FromBase58, ToBase58}; use fluent_uri::enc::EStr; use fluent_uri::Uri; use indexmap::IndexMap; use invoice::{AddressPayload, UnknownNetwork}; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; -use rgb::{ContractId, SecretSeal, State, StateData}; +use rgb::{ContractId, SecretSeal, StateData, StateParseError}; use strict_encoding::{InvalidRString, TypeName}; -use crate::invoice::{ - Beneficiary, ChainNet, InvoiceState, Pay2Vout, RgbInvoice, RgbTransport, XChainNet, -}; +use crate::invoice::{Beneficiary, ChainNet, Pay2Vout, RgbInvoice, RgbTransport, XChainNet}; const OMITTED: &str = "~"; const EXPIRY: &str = "expiry"; @@ -68,22 +63,6 @@ pub enum TransportParseError { InvalidTransportHost(String), } -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum InvoiceStateError { - #[from] - /// invalid invoice state Base58 encoding. - Base58(base58::FromBase58Error), - - #[from] - /// invoice state size exceeded. - Len(confinement::Error), - - #[from] - /// invalid invoice state encoding - {0} - Deserialize(strict_encoding::DeserializeError), -} - #[derive(Debug, Display, Error, From)] #[display(doc_comments)] pub enum InvoiceParseError { @@ -112,7 +91,7 @@ pub enum InvoiceParseError { #[from] #[display(inner)] - InvalidState(InvoiceStateError), + InvalidState(StateParseError), /// no invoice transport has been provided. NoTransport, @@ -177,30 +156,6 @@ impl RgbInvoice { } } -impl Display for InvoiceState { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - InvoiceState::Any => Ok(()), - InvoiceState::Specific(state) => f.write_str(&state.data.to_base58()), - // TODO: Support attachment through invoice params - InvoiceState::Attach(_) => Ok(()), - } - } -} - -impl FromStr for InvoiceState { - type Err = InvoiceStateError; - fn from_str(s: &str) -> Result { - if s.is_empty() { - return Ok(InvoiceState::Any); - } - let data = s.from_base58()?; - let data = SmallBlob::try_from(data)?; - let data = StateData::from_inner(data); - Ok(InvoiceState::Specific(State::from(data))) - } -} - impl Display for RgbTransport { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { @@ -337,7 +292,6 @@ impl FromStr for XChainNet { impl Display for RgbInvoice { fn fmt(&self, f: &mut Formatter) -> fmt::Result { // TODO: Support attachment through invoice params - let amt = self.owned_state.to_string(); if let Some(contract) = self.contract { let id = if f.alternate() { contract.to_string().replace('-', "") @@ -359,8 +313,8 @@ impl Display for RgbInvoice { if let Some(ref assignment_name) = self.assignment { write!(f, "{assignment_name}/")?; } - if !amt.is_empty() { - write!(f, "{amt}+")?; + if let Some(state) = self.state.as_ref() { + write!(f, "{state}+")?; } let beneficiary = if f.alternate() { self.beneficiary.to_string().replace('-', "") @@ -442,9 +396,9 @@ impl FromStr for RgbInvoice { .split_once('+') .map(|(a, b)| (Some(a), Some(b))) .unwrap_or((Some(assignment.as_str()), None)); - let (beneficiary_str, value) = match (beneficiary, state) { - (Some(b), Some(a)) => (b, InvoiceState::from_str(a)?), - (None, Some(b)) => (b, InvoiceState::Any), + let (beneficiary_str, state) = match (beneficiary, state) { + (Some(b), Some(a)) => (b, Some(StateData::from_str(a)?)), + (None, Some(b)) => (b, None), _ => unreachable!(), }; @@ -480,7 +434,7 @@ impl FromStr for RgbInvoice { operation: None, assignment: None, beneficiary, - owned_state: value, + state, expiry, unknown_query: query_params, }) @@ -518,31 +472,22 @@ mod test { fn parse() { // rgb20/rgb25 parameters let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - T5FhUZEHbQu4B+bc:utxob:\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!( - invoice.owned_state, - InvoiceState::Specific(State::from(StateData::from_checked(vec![ - 8, 0, 100, 0, 0, 0, 0, 0, 0, 0 - ]))) - ); + assert_eq!(invoice.state, Some(StateData::from_checked(vec![100, 0, 0, 0, 0, 0, 0, 0]))); assert_eq!(invoice.to_string(), invoice_str); - assert_eq!(format!("{invoice:#}"), invoice_str.replace('-', "")); // rgb21 parameters let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB21/\ - 5QsfkEcyanohXadePHZ+bc:utxob:\ + -p----p---------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!( - invoice.owned_state, - InvoiceState::Specific(State::from(StateData::from_checked(vec![ - 12, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 - ]))) + invoice.state, + Some(StateData::from_checked(vec![1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0])) ); assert_eq!(invoice.to_string(), invoice_str); - assert_eq!(format!("{invoice:#}"), invoice_str.replace('-', "")); // no amount let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/bc:utxob:\ @@ -584,47 +529,51 @@ mod test { Err(InvoiceParseError::InvalidContractId(c)) if c == invalid_contract_id)); // with expiration - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?\ - expiry=1682086371"; + let invoice_str = + "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ + zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry=1682086371"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // bad expiration - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry=six"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidExpiration(_)))); // with bad query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // with an unknown query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?unknown=new"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // with two unknown query parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?unknown=new&\ - another=new"; + let invoice_str = + "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ + zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?unknown=new&another=new"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // with expiration and an unknown query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?\ - expiry=1682086371&unknown=new"; + let invoice_str = + "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ + zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry=1682086371&unknown=new"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // with an unknown query parameter containing percent-encoded text - let invoice_base = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:\ - utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?"; + let invoice_base = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ + zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?"; let query_key_encoded = ":@-%20%23"; let query_key_decoded = ":@- #"; let query_val_encoded = "?/.%26%3D"; @@ -652,26 +601,30 @@ mod test { assert!(matches!(result, Err(InvoiceParseError::InvalidScheme(_)))); // empty transport endpoint specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints="; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // invalid transport endpoint specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=bad"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // invalid transport variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpca:/\ /host.example.com"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // rgb-rpc variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://\ host.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); @@ -682,7 +635,8 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb-rpc variant, host containing authentication, "-" characters and port - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs:/\ /user:pass@host-1.ex-ample.com:1234"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); @@ -693,7 +647,8 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb-rpc variant, IPv6 host - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs:/\ /%5B2001:db8::1%5D:1234"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); @@ -704,29 +659,30 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb-rpc variant with missing host - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // rgb-rpc variant with invalid separator - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc/\ - host.example.com"; + let invoice_str = + "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ + zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc/host.example.com"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // rgb-rpc variant with invalid transport host specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://\ - ho]t"; + let invoice_str = + "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ + zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://ho]t"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::Uri(_)))); // rgb+http variant let invoice_str = "rgb:\ 11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - BF+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=https://\ + y----------+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=https://\ host.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); let transports = vec![RgbTransport::RestHttp { @@ -737,7 +693,8 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb+ws variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ + let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ + y----------+bc:utxob:\ zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=wss://\ host.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); @@ -753,7 +710,7 @@ mod test { // multiple transports let invoice_str = "rgb:\ 11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - BF+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs://\ + y----------+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs://\ host1.example.com,http://host2.example.com,ws://host3.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); let transports = vec![ diff --git a/src/interface/builder.rs b/src/interface/builder.rs index e794dad5..5f444a82 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -27,13 +27,14 @@ use amplify::confinement::{self, Confined, SmallOrdSet, TinyOrdMap}; use chrono::Utc; use rgb::validation::Scripts; use rgb::{ - validation, AltLayer1, AltLayer1Set, AssignmentType, Assignments, ContractId, ExposedSeal, - Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Input, Layer1, MetadataError, Opout, - Schema, State, Transition, TransitionType, TypedAssigns, XChain, XOutpoint, + validation, AltLayer1, AltLayer1Set, AssignmentType, Assignments, AttachId, ContractId, + ExposedSeal, Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Input, Layer1, + MetadataError, Opout, Schema, State, StateData, Transition, TransitionType, TypedAssigns, + XChain, XOutpoint, }; use rgbcore::{GlobalStateSchema, GlobalStateType, MetaType, Metadata, ValencyType}; use strict_encoding::{FieldName, SerializeError, StrictSerialize}; -use strict_types::{decode, SemId, TypeSystem}; +use strict_types::{decode, typify, SemId, StrictVal, TypeSystem}; use crate::containers::{BuilderSeal, ContainerVer, Contract, ValidConsignment}; use crate::interface::resolver::DumbResolver; @@ -59,15 +60,12 @@ pub enum BuilderError { /// assignment `{0}` is not known to the schema. AssignmentNotFound(FieldName), + /// valency `{0}` is not known to the schema. + ValencyNotFound(FieldName), + /// transition `{0}` is not known to the schema. TransitionNotFound(FieldName), - /// unknown owned state name `{0}`. - InvalidStateField(FieldName), - - /// state `{0}` provided to the builder has invalid type. - InvalidStateType(AssignmentType), - /// interface doesn't specify default operation name, thus an explicit /// operation type must be provided with `set_operation_type` method. NoOperationSubtype, @@ -90,6 +88,10 @@ pub enum BuilderError { #[display(inner)] Reify(decode::Error), + #[from] + #[display(inner)] + Typify(typify::Error), + #[from] #[display(inner)] Confinement(confinement::Error), @@ -179,23 +181,28 @@ impl ContractBuilder { } #[inline] - pub fn global_type(&self, name: &FieldName) -> Option { + pub fn meta_type(&self, name: impl Into) -> Result { + self.builder.meta_type(name) + } + + #[inline] + pub fn global_type(&self, name: impl Into) -> Result { self.builder.global_type(name) } #[inline] - pub fn valency_type(&self, name: &FieldName) -> Option { + pub fn valency_type(&self, name: impl Into) -> Result { self.builder.valency_type(name) } + #[inline] + pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } + #[inline] pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { self.builder.valency_name(type_id) } - #[inline] - pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - #[inline] pub fn add_metadata( mut self, @@ -232,11 +239,27 @@ impl ContractBuilder { mut self, name: impl Into, seal: impl Into>, - value: impl StrictSerialize, + state: StrictVal, + attach: Option, ) -> Result { let seal = seal.into(); self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_owned_state(name, seal, value)?; + self.builder = self.builder.add_owned_state(name, seal, state, attach)?; + Ok(self) + } + + pub fn serialize_owned_state( + mut self, + name: impl Into, + seal: impl Into>, + value: &impl StrictSerialize, + attach: Option, + ) -> Result { + let seal = seal.into(); + self.check_layer1(seal.layer1())?; + self.builder = self + .builder + .serialize_owned_state(name, seal, value, attach)?; Ok(self) } @@ -419,17 +442,20 @@ impl TransitionBuilder { } #[inline] - pub fn assignments_type(&self, name: &FieldName) -> Option { + pub fn assignments_type( + &self, + name: impl Into, + ) -> Result { self.builder.assignments_type(name) } #[inline] - pub fn global_type(&self, name: &FieldName) -> Option { + pub fn global_type(&self, name: impl Into) -> Result { self.builder.global_type(name) } #[inline] - pub fn valency_type(&self, name: &FieldName) -> Option { + pub fn valency_type(&self, name: impl Into) -> Result { self.builder.valency_type(name) } @@ -440,8 +466,9 @@ impl TransitionBuilder { pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - /// NB: Doesn't process the state with VM - pub fn add_owned_state_raw( + // TODO: We won't need this once we will have Blank Transition builder + /// NB: This does not process the state with VM + pub fn add_owned_state_blank( mut self, type_id: AssignmentType, seal: impl Into>, @@ -546,22 +573,36 @@ impl OperationBuilder { .expect("internal inconsistency") } - fn assignments_type(&self, name: &FieldName) -> Option { - self.iimpl.assignments_type(name) + fn assignments_type(&self, name: impl Into) -> Result { + let name = name.into(); + self.iimpl + .assignments_type(&name) + .ok_or(BuilderError::AssignmentNotFound(name)) } - fn meta_type(&self, name: &FieldName) -> Option { self.iimpl.meta_type(name) } + fn meta_type(&self, name: impl Into) -> Result { + let name = name.into(); + self.iimpl + .meta_type(&name) + .ok_or(BuilderError::MetadataNotFound(name)) + } fn meta_name(&self, ty: MetaType) -> &FieldName { self.iimpl.meta_name(ty).expect("internal inconsistency") } - fn global_type(&self, name: &FieldName) -> Option { - self.iimpl.global_type(name) + fn global_type(&self, name: impl Into) -> Result { + let name = name.into(); + self.iimpl + .global_type(&name) + .ok_or(BuilderError::GlobalNotFound(name)) } - fn valency_type(&self, name: &FieldName) -> Option { - self.iimpl.valency_type(name) + fn valency_type(&self, name: impl Into) -> Result { + let name = name.into(); + self.iimpl + .valency_type(&name) + .ok_or(BuilderError::ValencyNotFound(name)) } fn valency_name(&self, ty: ValencyType) -> &FieldName { @@ -589,13 +630,8 @@ impl OperationBuilder { name: impl Into, value: impl StrictSerialize, ) -> Result { - let name = name.into(); + let type_id = self.meta_type(name)?; let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; - - let Some(type_id) = self.meta_type(&name) else { - return Err(BuilderError::MetadataNotFound(name)); - }; - let sem_id = self.meta_schema(type_id); self.types.strict_deserialize_type(*sem_id, &serialized)?; self.meta.add_value(type_id, serialized.into())?; @@ -607,13 +643,9 @@ impl OperationBuilder { name: impl Into, value: impl StrictSerialize, ) -> Result { - let name = name.into(); + let type_id = self.global_type(name)?; let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; - // Check value matches type requirements - let Some(type_id) = self.global_type(&name) else { - return Err(BuilderError::GlobalNotFound(name)); - }; let sem_id = self.global_schema(type_id).sem_id; self.types.strict_deserialize_type(sem_id, &serialized)?; @@ -645,15 +677,40 @@ impl OperationBuilder { self, name: impl Into, seal: impl Into>, - value: impl StrictSerialize, + value: StrictVal, + attach: Option, ) -> Result { - let name = name.into(); + let type_id = self.assignments_type(name)?; - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; + let types = self.type_system(); + let sem_id = self + .schema + .owned_types + .get(&type_id) + .expect("schema-interface inconsistence") + .sem_id; + let value = types.typify(value, sem_id)?; + let data = types + .strict_serialize_type::<{ confinement::U16 }>(&value)? + .to_strict_serialized()?; + + let mut state = State::from(StateData::from(data)); + state.attach = attach; + self.add_owned_state_raw(type_id, seal, state) + } + + fn serialize_owned_state( + self, + name: impl Into, + seal: impl Into>, + value: &impl StrictSerialize, + attach: Option, + ) -> Result { + let type_id = self.assignments_type(name)?; - self.add_owned_state_raw(type_id, seal, State::from_serialized(value)) + let mut state = State::from_serialized(value)?; + state.attach = attach; + self.add_owned_state_raw(type_id, seal, state) } fn complete(self) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments, TypeSystem) { diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 273af067..2793c156 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -885,7 +885,7 @@ impl Stock { #[allow(clippy::result_large_err)] pub fn compose( &self, - invoice: &RgbInvoice, + invoice: RgbInvoice, prev_outputs: impl IntoIterator>, method: CloseMethod, beneficiary_vout: Option>, @@ -908,7 +908,7 @@ impl Stock { #[allow(clippy::too_many_arguments, clippy::result_large_err)] pub fn compose_deterministic( &self, - invoice: &RgbInvoice, + invoice: RgbInvoice, prev_outputs: impl IntoIterator>, method: CloseMethod, beneficiary_vout: Option>, @@ -917,11 +917,8 @@ impl Stock { seal_blinder: impl Fn(ContractId, AssignmentType) -> u64, ) -> Result> { let layer1 = invoice.layer1(); - let invoice_state = invoice - .owned_state - .state() - .ok_or(ComposeError::NoInvoiceState)? - .clone(); + let state_data = invoice.state.ok_or(ComposeError::NoInvoiceState)?; + let state = rgb::State::from(state_data); // TODO: Take account attachements when they will be supported by invoices let prev_outputs = prev_outputs .into_iter() .map(|o| o.into()) @@ -970,9 +967,7 @@ impl Stock { .or_else(|| main_builder.default_assignment().ok()) .ok_or(BuilderError::NoDefaultAssignment)? .clone(); - let assignment_id = main_builder - .assignments_type(&assignment_name) - .ok_or(BuilderError::InvalidStateField(assignment_name.clone()))?; + let assignment_id = main_builder.assignments_type(assignment_name)?; // If there are inputs which are using different seal closing method from our // wallet (and thus main state transition) we need to put them aside and @@ -1019,9 +1014,9 @@ impl Stock { if opout.ty != assignment_id { let seal = output_for_assignment(contract_id, opout.ty)?; if output.method() == method { - main_builder = main_builder.add_owned_state_raw(opout.ty, seal, state)?; + main_builder = main_builder.add_owned_state_blank(opout.ty, seal, state)?; } else { - alt_builder = alt_builder.add_owned_state_raw(opout.ty, seal, state)?; + alt_builder = alt_builder.add_owned_state_blank(opout.ty, seal, state)?; } } } @@ -1029,7 +1024,7 @@ impl Stock { // Add payments to beneficiary let (builder, partial_state) = - main_builder.fulfill_owned_state(assignment_id, beneficiary, invoice_state)?; + main_builder.fulfill_owned_state(assignment_id, beneficiary, state)?; main_builder = builder; if let Some(partial_state) = partial_state { let (builder, remaining_state) = @@ -1080,12 +1075,12 @@ impl Stock { Method::TapretFirst => { blank_builder_tapret = blank_builder_tapret .add_input(opout, state.clone())? - .add_owned_state_raw(opout.ty, seal, state)? + .add_owned_state_blank(opout.ty, seal, state)? } Method::OpretFirst => { blank_builder_opret = blank_builder_opret .add_input(opout, state.clone())? - .add_owned_state_raw(opout.ty, seal, state)? + .add_owned_state_blank(opout.ty, seal, state)? } } } From bc455d70d168deb56551ad67885c498f6f27d2b4 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 16:52:57 +0200 Subject: [PATCH 10/70] iface: use updated state serialization APIs --- Cargo.lock | 5 +- Cargo.toml | 1 + src/interface/builder.rs | 195 +++++++++++++++++++++++++++----------- src/interface/contract.rs | 8 +- 4 files changed, 145 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2420f764..60158c23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -668,7 +668,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.9" -source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#b59f1ca4c13c62ce53152f7f4c34094e435a1be4" +source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#e92e5b176886b3f04d8cfbb41714ab8f7d0b8046" dependencies = [ "aluvm", "amplify", @@ -906,8 +906,7 @@ dependencies = [ [[package]] name = "strict_types" version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3188d65ee78a90da3545df762a1363b5b4f9c3b845f182a18fc40ae991c235ce" +source = "git+https://github.com/strict-types/strict-types?branch=develop#729a4f86d25dfcea15ed15bbeb1e027473401c58" dependencies = [ "amplify", "ascii-armor", diff --git a/Cargo.toml b/Cargo.toml index e4200e51..3837c078 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,7 @@ features = ["all"] [patch.crates-io] commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } +strict_types = { git = "https://github.com/strict-types/strict-types", branch = "develop" } aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "develop" } bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } diff --git a/src/interface/builder.rs b/src/interface/builder.rs index 5f444a82..4905aca1 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -28,11 +28,10 @@ use chrono::Utc; use rgb::validation::Scripts; use rgb::{ validation, AltLayer1, AltLayer1Set, AssignmentType, Assignments, AttachId, ContractId, - ExposedSeal, Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Input, Layer1, - MetadataError, Opout, Schema, State, StateData, Transition, TransitionType, TypedAssigns, - XChain, XOutpoint, + ExposedSeal, Genesis, GenesisSeal, GlobalState, GlobalStateSchema, GlobalStateType, GraphSeal, + Identity, Input, Layer1, MetaType, Metadata, MetadataError, Opout, Schema, State, StateData, + Transition, TransitionType, TypedAssigns, ValencyType, XChain, XOutpoint, STATE_DATA_MAX_LEN, }; -use rgbcore::{GlobalStateSchema, GlobalStateType, MetaType, Metadata, ValencyType}; use strict_encoding::{FieldName, SerializeError, StrictSerialize}; use strict_types::{decode, typify, SemId, StrictVal, TypeSystem}; @@ -203,26 +202,44 @@ impl ContractBuilder { self.builder.valency_name(type_id) } - #[inline] pub fn add_metadata( mut self, name: impl Into, - value: impl StrictSerialize, + value: StrictVal, ) -> Result { self.builder = self.builder.add_metadata(name, value)?; Ok(self) } #[inline] + pub fn serialize_metadata( + mut self, + name: impl Into, + value: &impl StrictSerialize, + ) -> Result { + self.builder = self.builder.serialize_metadata(name, value)?; + Ok(self) + } + pub fn add_global_state( mut self, name: impl Into, - value: impl StrictSerialize, + value: StrictVal, ) -> Result { self.builder = self.builder.add_global_state(name, value)?; Ok(self) } + #[inline] + pub fn serialize_global_state( + mut self, + name: impl Into, + value: &impl StrictSerialize, + ) -> Result { + self.builder = self.builder.serialize_global_state(name, value)?; + Ok(self) + } + pub fn add_owned_state_raw( mut self, type_id: AssignmentType, @@ -400,39 +417,31 @@ impl TransitionBuilder { pub fn transition_type(&self) -> TransitionType { self.transition_type } - pub fn set_nonce(mut self, nonce: u64) -> Self { - self.nonce = nonce; - self + #[inline] + pub fn global_type(&self, name: impl Into) -> Result { + self.builder.global_type(name) } #[inline] - pub fn add_metadata( - mut self, + pub fn assignments_type( + &self, name: impl Into, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_metadata(name, value)?; - Ok(self) + ) -> Result { + self.builder.assignments_type(name) } #[inline] - pub fn add_global_state( - mut self, - name: impl Into, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_global_state(name, value)?; - Ok(self) + pub fn valency_type(&self, name: impl Into) -> Result { + self.builder.valency_type(name) } - pub fn add_input(mut self, opout: Opout, state: State) -> Result { - if let Some(calc) = &mut self.calc { - calc.reg_input(opout.ty, &state)?; - } - self.inputs.insert(Input::with(opout), state)?; - Ok(self) + #[inline] + pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { + self.builder.valency_name(type_id) } + pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } + pub fn default_assignment(&self) -> Result<&FieldName, BuilderError> { self.builder .transition_iface(self.transition_type) @@ -441,31 +450,57 @@ impl TransitionBuilder { .ok_or(BuilderError::NoDefaultAssignment) } - #[inline] - pub fn assignments_type( - &self, + pub fn set_nonce(mut self, nonce: u64) -> Self { + self.nonce = nonce; + self + } + + pub fn add_input(mut self, opout: Opout, state: State) -> Result { + if let Some(calc) = &mut self.calc { + calc.reg_input(opout.ty, &state)?; + } + self.inputs.insert(Input::with(opout), state)?; + Ok(self) + } + + pub fn add_metadata( + mut self, name: impl Into, - ) -> Result { - self.builder.assignments_type(name) + value: StrictVal, + ) -> Result { + self.builder = self.builder.add_metadata(name, value)?; + Ok(self) } #[inline] - pub fn global_type(&self, name: impl Into) -> Result { - self.builder.global_type(name) + pub fn serialize_metadata( + mut self, + name: impl Into, + value: &impl StrictSerialize, + ) -> Result { + self.builder = self.builder.serialize_metadata(name, value)?; + Ok(self) } - #[inline] - pub fn valency_type(&self, name: impl Into) -> Result { - self.builder.valency_type(name) + pub fn add_global_state( + mut self, + name: impl Into, + value: StrictVal, + ) -> Result { + self.builder = self.builder.add_global_state(name, value)?; + Ok(self) } #[inline] - pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { - self.builder.valency_name(type_id) + pub fn serialize_global_state( + mut self, + name: impl Into, + value: &impl StrictSerialize, + ) -> Result { + self.builder = self.builder.serialize_global_state(name, value)?; + Ok(self) } - pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - // TODO: We won't need this once we will have Blank Transition builder /// NB: This does not process the state with VM pub fn add_owned_state_blank( @@ -610,8 +645,9 @@ impl OperationBuilder { } #[inline] - fn meta_schema(&self, type_id: MetaType) -> &SemId { - self.schema + fn meta_schema(&self, type_id: MetaType) -> SemId { + *self + .schema .meta_types .get(&type_id) .expect("schema should match interface: must be checked by the constructor") @@ -625,29 +661,78 @@ impl OperationBuilder { .expect("schema should match interface: must be checked by the constructor") } - pub fn add_metadata( + fn add_metadata( mut self, name: impl Into, - value: impl StrictSerialize, + value: StrictVal, + ) -> Result { + let type_id = self.meta_type(name)?; + + let types = self.type_system(); + let sem_id = *self + .schema + .meta_types + .get(&type_id) + .expect("schema-interface inconsistency"); + let value = types.typify(value, sem_id)?; + let data = types.strict_serialize_value::(&value)?; + + self.meta.add_value(type_id, data.into())?; + Ok(self) + } + + fn serialize_metadata( + mut self, + name: impl Into, + value: &impl StrictSerialize, ) -> Result { let type_id = self.meta_type(name)?; let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; let sem_id = self.meta_schema(type_id); - self.types.strict_deserialize_type(*sem_id, &serialized)?; + + #[cfg(debug_assertions)] + self.types + .strict_deserialize_type(sem_id, &serialized) + .expect("failed deserialization"); + self.meta.add_value(type_id, serialized.into())?; Ok(self) } - pub fn add_global_state( + fn add_global_state( mut self, name: impl Into, - value: impl StrictSerialize, + value: StrictVal, + ) -> Result { + let type_id = self.global_type(name)?; + + let types = self.type_system(); + let sem_id = self + .schema + .global_types + .get(&type_id) + .expect("schema-interface inconsistency") + .sem_id; + let value = types.typify(value, sem_id)?; + let data = types.strict_serialize_value::(&value)?; + + self.global.add_state(type_id, data.into())?; + Ok(self) + } + + fn serialize_global_state( + mut self, + name: impl Into, + value: &impl StrictSerialize, ) -> Result { let type_id = self.global_type(name)?; let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; - // Check value matches type requirements let sem_id = self.global_schema(type_id).sem_id; - self.types.strict_deserialize_type(sem_id, &serialized)?; + + #[cfg(debug_assertions)] + self.types + .strict_deserialize_type(sem_id, &serialized) + .expect("failed deserialization"); self.global.add_state(type_id, serialized.into())?; @@ -687,12 +772,10 @@ impl OperationBuilder { .schema .owned_types .get(&type_id) - .expect("schema-interface inconsistence") + .expect("schema-interface inconsistency") .sem_id; let value = types.typify(value, sem_id)?; - let data = types - .strict_serialize_type::<{ confinement::U16 }>(&value)? - .to_strict_serialized()?; + let data = types.strict_serialize_value::(&value)?; let mut state = State::from(StateData::from(data)); state.attach = attach; diff --git a/src/interface/contract.rs b/src/interface/contract.rs index 075fafb1..2f92e710 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -22,13 +22,12 @@ use std::borrow::Borrow; use std::collections::{BTreeSet, HashMap, HashSet}; -use amplify::confinement; use rgb::validation::Scripts; use rgb::{ AssignmentType, AttachId, ContractId, OpId, Opout, Schema, State, StateData, XOutputSeal, - XWitnessId, + XWitnessId, STATE_DATA_MAX_LEN, }; -use strict_encoding::{FieldName, SerializeError, StrictSerialize}; +use strict_encoding::{FieldName, SerializeError}; use strict_types::{typify, SemId, StrictVal, TypeSystem}; use crate::contract::{Allocation, WitnessInfo}; @@ -189,8 +188,7 @@ impl ContractIface { let t = self.types.typify(value, self.assignment_sem_id(ty))?; let value = self .types - .strict_serialize_type::<{ confinement::U16 }>(&t)? - .to_strict_serialized()?; + .strict_serialize_value::(&t)?; Ok(value.into()) } From 0bc16ef093a99b16c61f09a5e82ca9eb594d9511 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 18:47:26 +0200 Subject: [PATCH 11/70] iface: improve AssignIface APIs --- src/interface/iface.rs | 57 +++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/src/interface/iface.rs b/src/interface/iface.rs index 684cfc1c..84dfec26 100644 --- a/src/interface/iface.rs +++ b/src/interface/iface.rs @@ -208,25 +208,58 @@ pub struct AssignIface { } impl AssignIface { - pub fn public(state_ty: Option, attach: Option, req: Req) -> Self { + pub fn optional() -> Self { AssignIface { - state_ty, - attach, - public: true, - required: req.is_required(), - multiple: req.is_multiple(), + state_ty: None, + attach: None, + public: false, + required: false, + multiple: false, } } - - pub fn private(state_ty: Option, attach: Option, req: Req) -> Self { + pub fn required() -> Self { AssignIface { - state_ty, - attach, + state_ty: None, + attach: None, public: false, - required: req.is_required(), - multiple: req.is_multiple(), + required: true, + multiple: false, + } + } + pub fn none_or_many() -> Self { + AssignIface { + state_ty: None, + attach: None, + public: false, + required: false, + multiple: true, } } + pub fn one_or_many() -> Self { + AssignIface { + state_ty: None, + attach: None, + public: false, + required: true, + multiple: true, + } + } + pub fn public(mut self) -> Self { + self.public = true; + self + } + pub fn rights(mut self) -> Self { + self.state_ty = Some(SemId::default()); + self + } + pub fn typed(mut self, sem_id: SemId) -> Self { + self.state_ty = Some(sem_id); + self + } + pub fn attachments(mut self, require: bool) -> Self { + self.attach = Some(require); + self + } } pub type ArgMap = TinyOrdMap; From 9240917a44e4ba5a3e44da5acac3a0ad9c1498df Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 19:12:31 +0200 Subject: [PATCH 12/70] iface: add add_rights convenience method to builder --- Cargo.lock | 2 +- src/interface/builder.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 60158c23..040ef4f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -668,7 +668,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.9" -source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#e92e5b176886b3f04d8cfbb41714ab8f7d0b8046" +source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#9c6f3fee4ac573380c0ed8658d644fc5a7cfc533" dependencies = [ "aluvm", "amplify", diff --git a/src/interface/builder.rs b/src/interface/builder.rs index 4905aca1..76eff309 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -252,6 +252,16 @@ impl ContractBuilder { Ok(self) } + pub fn add_rights( + mut self, + name: impl Into, + seal: impl Into>, + attach: Option, + ) -> Result { + self.builder = self.builder.add_rights(name, seal, attach)?; + Ok(self) + } + pub fn add_owned_state( mut self, name: impl Into, @@ -513,6 +523,16 @@ impl TransitionBuilder { Ok(self) } + pub fn add_rights( + mut self, + name: impl Into, + seal: impl Into>, + attach: Option, + ) -> Result { + self.builder = self.builder.add_rights(name, seal, attach)?; + Ok(self) + } + pub fn fulfill_owned_state( mut self, type_id: AssignmentType, @@ -758,6 +778,18 @@ impl OperationBuilder { Ok(self) } + fn add_rights( + self, + name: impl Into, + seal: impl Into>, + attach: Option, + ) -> Result { + let type_id = self.assignments_type(name)?; + let mut state = State::default(); + state.attach = attach; + self.add_owned_state_raw(type_id, seal, state) + } + fn add_owned_state( self, name: impl Into, From 0bf8c97606d081b65a6d74f21f854c997246bf8d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 20:25:51 +0200 Subject: [PATCH 13/70] iface: add ContractIface::outputs_typed method --- src/interface/contract.rs | 61 +++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/src/interface/contract.rs b/src/interface/contract.rs index 2f92e710..37d18fd1 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -22,12 +22,14 @@ use std::borrow::Borrow; use std::collections::{BTreeSet, HashMap, HashSet}; +use amplify::confinement::SmallBlob; +use amplify::Wrapper; use rgb::validation::Scripts; use rgb::{ AssignmentType, AttachId, ContractId, OpId, Opout, Schema, State, StateData, XOutputSeal, XWitnessId, STATE_DATA_MAX_LEN, }; -use strict_encoding::{FieldName, SerializeError}; +use strict_encoding::{FieldName, SerializeError, StrictDeserialize}; use strict_types::{typify, SemId, StrictVal, TypeSystem}; use crate::contract::{Allocation, WitnessInfo}; @@ -58,14 +60,27 @@ pub enum ContractError { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase") )] -pub struct Output { +pub struct Output { pub opout: Opout, pub seal: XOutputSeal, - pub state: StrictVal, + pub state: T, pub attach_id: Option, pub witness: Option, } +impl From for Output { + fn from(a: Allocation) -> Self { + Output { + opout: a.opout, + seal: a.seal, + state: T::from_strict_serialized(a.state.data.to_inner()) + .expect("data in stash are not valid"), + attach_id: a.state.attach, + witness: a.witness, + } + } +} + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] #[cfg_attr( feature = "serde", @@ -205,8 +220,7 @@ impl ContractIface { /// # Panics /// - /// If data are corrupted and contract schema doesn't match interface - /// implementations. + /// If data are corrupted and contract schema doesn't match interface implementations. pub fn global( &self, name: impl Into, @@ -227,12 +241,34 @@ impl ContractIface { .expect("schema doesn't match interface") .map(|data| { self.types - .strict_deserialize_type(global_schema.sem_id, data.borrow().as_slice()) + .strict_deserialize_type(global_schema.sem_id, data.borrow()) .expect("unvalidated contract data in stash") .unbox() })) } + /// # Panics + /// + /// If data are corrupted and contract schema doesn't match interface implementations. + pub fn global_typed( + &self, + name: impl Into, + ) -> Result + '_, ContractError> { + let name = name.into(); + let type_id = self + .iface + .global_type(&name) + .ok_or(ContractError::FieldNameUnknown(name))?; + Ok(self + .state + .global(type_id) + .expect("schema doesn't match interface") + .map(|data| { + let data = SmallBlob::from_slice_checked(data.borrow()); + T::from_strict_serialized(data).expect("unvalidated contract data in stash") + })) + } + pub fn allocations<'c>( &'c self, filter: impl AssignmentsFilter + 'c, @@ -286,6 +322,19 @@ impl ContractIface { .map(|a| self.allocation_to_output(a))) } + pub fn outputs_typed<'c, T: StrictDeserialize + 'c>( + &'c self, + name: impl Into, + filter: impl AssignmentsFilter + 'c, + ) -> Result> + 'c, ContractError> { + let type_id = self.assignment_type(name)?; + Ok(self + .allocations(filter) + .filter(move |a| a.opout.ty == type_id) + .cloned() + .map(Output::from)) + } + pub fn history( &self, filter_outpoints: impl AssignmentsFilter, From 50a76079864c35fc8229bb861f17ad8c6e45f566 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 17 Oct 2024 20:25:51 +0200 Subject: [PATCH 14/70] chore: remove outdated IfaceStd.con --- stl/IfaceStd.con | 252 ----------------------------------------------- 1 file changed, 252 deletions(-) delete mode 100644 stl/IfaceStd.con diff --git a/stl/IfaceStd.con b/stl/IfaceStd.con deleted file mode 100644 index 37380a20..00000000 --- a/stl/IfaceStd.con +++ /dev/null @@ -1,252 +0,0 @@ -@version(1) -@timestamp(1711405444) -interface NamedAsset - global spec: RGBContract.AssetSpec - global terms: RGBContract.AssetTerms - - genesis: abstract - globals: spec, terms - - -@version(1) -@timestamp(1711405444) -interface RenameableAsset - - public updateRight: Rights - - genesis: override - assigns: updateRight - - transition rename: required, final - globals: spec - assigns: updateRight(?) - default: updateRight - inputs: updateRight - - -@version(1) -@timestamp(1711405444) -interface FungibleAsset - global issuedSupply: RGBContract.Amount - - owned assetOwner(*): Zk64 - - error nonEqualAmounts - "the sum of spent assets doesn't equal to the sum of assets in outputs" - error supplyMismatch - "supply specified as a global parameter doesn't match the issued supply allocated to the asset owners" - - genesis: override - errors: insufficientReserves, invalidProof, supplyMismatch - globals: issuedSupply - assigns: assetOwner(*) - - transition transfer: required, default, abstract - errors: nonEqualAmounts - assigns: assetOwner(+) - default: assetOwner - inputs: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface FixedAsset - - owned assetOwner(+): Zk64 - - genesis: override - errors: insufficientReserves, invalidProof, supplyMismatch - assigns: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface BurnableAsset - global burnedSupply(*): RGBContract.Amount - - public burnRight(+): Rights - - error insufficientCoverage - "the claimed amount of burned assets is not covered by the assets in the operation inputs" - - genesis: override - assigns: burnRight(+) - - transition burn: required, final - errors: insufficientCoverage, invalidProof, supplyMismatch - meta: RGBContract.BurnMeta - globals: burnedSupply - assigns: burnRight(*) - inputs: burnRight - - -@version(1) -@timestamp(1711405444) -interface InflatableAsset - global issuedSupply(+): RGBContract.Amount - - public inflationAllowance(*): Zk64 - - error issueExceedsAllowance - "you try to issue more assets than allowed by the contract terms" - - genesis: override - assigns: inflationAllowance(+) - - transition issue: required, abstract - errors: issueExceedsAllowance, supplyMismatch - globals: issuedSupply - assigns: assetOwner(*), inflationAllowance(*) - default: assetOwner - inputs: inflationAllowance(+) - - -@version(1) -@timestamp(1711405444) -interface ReplaceableAsset - global burnedSupply(*): RGBContract.Amount - global replacedSupply(*): RGBContract.Amount - - public burnEpoch(+): Rights - public burnRight(*): Rights - - error insufficientCoverage - "the claimed amount of burned assets is not covered by the assets in the operation inputs" - - genesis: override - assigns: burnEpoch - - transition burn: required, final - errors: insufficientCoverage, invalidProof, supplyMismatch - meta: RGBContract.BurnMeta - globals: burnedSupply - assigns: burnRight(?) - inputs: burnRight - - transition openEpoch: required, final - assigns: burnEpoch(?), burnRight - default: burnRight - inputs: burnEpoch - - transition replace: required, final - errors: insufficientCoverage, invalidProof, nonEqualAmounts, supplyMismatch - meta: RGBContract.BurnMeta - globals: replacedSupply - assigns: assetOwner(*), burnRight(?) - default: assetOwner - inputs: burnRight - - -@version(1) -@timestamp(1711405444) -interface ReservableAsset - - error insufficientReserves - "reserve is insufficient to cover the issued assets" - error invalidProof - "the provided proof is invalid" - - genesis: override - errors: insufficientReserves, invalidProof - meta: RGBContract.IssueMeta - - transition issue: override - errors: insufficientReserves, invalidProof - meta: RGBContract.IssueMeta - default: assetOwner - inputs: - - -@version(1) -@timestamp(1711405444) -interface NonFungibleToken - global attachmentTypes(*): RGB21.AttachmentType - global tokens(*): RGB21.TokenData - - owned assetOwner(*): RGB21.Allocation - - error fractionOverflow - "the amount of fractional token in outputs exceeds 1" - error invalidAttachmentType - "attachment has a type which is not allowed for the token" - error nonEqualValues - "the sum of spent token fractions doesn't equal to the sum of token fractions in outputs" - error nonFractionalToken - "attempt to transfer a fraction of non-fractionable token" - - genesis: override - errors: fractionOverflow, invalidAttachmentType - globals: attachmentTypes(*), tokens(*) - assigns: assetOwner(*) - - transition transfer: required, default, final - errors: fractionOverflow, nonEqualValues, nonFractionalToken - assigns: assetOwner(+) - default: assetOwner - inputs: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface EngravableNft - global engravings(*): RGB21.EngravingData - - error nonEngravableToken - "attempt to engrave on a token which prohibit engraving" - - genesis: override - - transition engrave: required, final - errors: fractionOverflow, nonEngravableToken, nonEqualValues, nonFractionalToken - globals: engravings - assigns: assetOwner(+) - default: assetOwner - inputs: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface UniqueNft - global attachmentTypes: RGB21.AttachmentType - global tokens: RGB21.TokenData - - owned assetOwner(+): RGB21.Allocation - - genesis: override - globals: attachmentTypes, tokens - assigns: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface LimitedNft - global attachmentTypes(+): RGB21.AttachmentType - global tokens(+): RGB21.TokenData - - owned assetOwner(+): RGB21.Allocation - - genesis: override - globals: attachmentTypes(+), tokens(+) - assigns: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface IssuableNft - - public inflationAllowance(+): RGB21.ItemsCount - - error issueExceedsAllowance - "you try to issue more assets than allowed by the contract terms" - - genesis: override - assigns: inflationAllowance(+) - - transition issue: required, abstract - errors: fractionOverflow, insufficientReserves, invalidAttachmentType, invalidProof, issueExceedsAllowance - globals: attachmentTypes(*), tokens(*) - assigns: assetOwner(*), inflationAllowance(*) - default: assetOwner - inputs: inflationAllowance(+) - - From ee649c6f71edd66175c158fe6d47bf154129933c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 19 Oct 2024 11:01:37 +0200 Subject: [PATCH 15/70] chore: update aluvm --- Cargo.lock | 18 +++++++++--------- src/interface/builder.rs | 2 +- src/interface/calc.rs | 10 ++++------ src/interface/contract.rs | 2 +- src/interface/iimpl.rs | 2 +- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 040ef4f6..e5000e05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "aluvm" version = "0.11.0-beta.9" -source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#7adf61dbe4a3b39834bc3d665800024d66658e9c" +source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#bedd86c160bab2398c07901728fd06b6bab13ddc" dependencies = [ "amplify", "ascii-armor", @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "log" @@ -619,9 +619,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -668,7 +668,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.9" -source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#9c6f3fee4ac573380c0ed8658d644fc5a7cfc533" +source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#78ee97123665b5da312336f52d56485153af1673" dependencies = [ "aluvm", "amplify", @@ -810,9 +810,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "67d42a0bd4ac281beff598909bb56a86acaf979b84483e1c79c10dcaf98f8cf3" dependencies = [ "itoa", "memchr", @@ -906,7 +906,7 @@ dependencies = [ [[package]] name = "strict_types" version = "2.7.1" -source = "git+https://github.com/strict-types/strict-types?branch=develop#729a4f86d25dfcea15ed15bbeb1e027473401c58" +source = "git+https://github.com/strict-types/strict-types?branch=develop#9a2041a9b1988b17608564725d47b39f442e5062" dependencies = [ "amplify", "ascii-armor", diff --git a/src/interface/builder.rs b/src/interface/builder.rs index 76eff309..5b2f08b4 100644 --- a/src/interface/builder.rs +++ b/src/interface/builder.rs @@ -631,7 +631,7 @@ impl OperationBuilder { fn assignments_type(&self, name: impl Into) -> Result { let name = name.into(); self.iimpl - .assignments_type(&name) + .assignment_type(&name) .ok_or(BuilderError::AssignmentNotFound(name)) } diff --git a/src/interface/calc.rs b/src/interface/calc.rs index 2932f775..077b2fd5 100644 --- a/src/interface/calc.rs +++ b/src/interface/calc.rs @@ -21,7 +21,7 @@ use aluvm::data::ByteStr; use aluvm::library::{LibId, LibSite}; -use aluvm::reg::{Reg16, Reg32, RegA, RegR, RegS}; +use aluvm::reg::{Reg16, Reg32, RegA, RegR}; use amplify::num::{u256, u4}; use amplify::{ByteArray, Wrapper}; use rgb::validation::Scripts; @@ -91,7 +91,7 @@ impl StateCalc { fn run(&mut self, site: LibSite) -> Result<(), String> { if !self.vm.exec(site, |id| self.scripts.get(&id), &()) { - if let Some(err) = self.vm.registers.get_s(RegS::from(15)).cloned() { + if let Some(err) = self.vm.registers.s16(15).cloned() { return Err(err.to_string()); } } @@ -104,9 +104,7 @@ impl StateCalc { .set_n(RegA::A16, Reg32::Reg0, Some(ty.to_inner())); assert_eq!(state.reserved, none!()); self.vm.registers.set_n(RegA::A8, Reg32::Reg0, Some(0u8)); - self.vm - .registers - .set_s(RegS::from(0), Some(ByteStr::with(&state.data))); + self.vm.registers.set_s16(0, ByteStr::with(&state.data)); self.vm.registers.set_n( RegR::R256, Reg32::Reg0, @@ -119,7 +117,7 @@ impl StateCalc { ty: AssignmentType, idx: Reg16, ) -> Result, StateCalcError> { - let Some(data) = self.vm.registers.get_s(RegS::from(u4::from(idx))) else { + let Some(data) = self.vm.registers.s16(u4::from(idx)) else { return Ok(None); }; let reserved = self diff --git a/src/interface/contract.rs b/src/interface/contract.rs index 37d18fd1..e027b43c 100644 --- a/src/interface/contract.rs +++ b/src/interface/contract.rs @@ -157,7 +157,7 @@ impl ContractIface { fn assignment_type(&self, name: impl Into) -> Result { let name = name.into(); self.iface - .assignments_type(&name) + .assignment_type(&name) .ok_or(ContractError::FieldNameUnknown(name)) } diff --git a/src/interface/iimpl.rs b/src/interface/iimpl.rs index 69f9eb76..5644aa36 100644 --- a/src/interface/iimpl.rs +++ b/src/interface/iimpl.rs @@ -256,7 +256,7 @@ impl IfaceImpl { .map(|nt| nt.id) } - pub fn assignments_type(&self, name: &FieldName) -> Option { + pub fn assignment_type(&self, name: &FieldName) -> Option { self.assignments .iter() .find(|nt| &nt.name == name) From 355b9516c3c3bfe69208d33ecea7fed0acb20d17 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 19 Oct 2024 11:06:06 +0200 Subject: [PATCH 16/70] containers: add Suppl::with deterministic constructor --- Cargo.lock | 4 ++-- src/containers/suppl.rs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5000e05..a3fdd9ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,9 +307,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.30" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "shlex", ] diff --git a/src/containers/suppl.rs b/src/containers/suppl.rs index 5da0ea8b..a98aa3ed 100644 --- a/src/containers/suppl.rs +++ b/src/containers/suppl.rs @@ -221,6 +221,19 @@ impl Supplement { } } + pub fn with( + content: impl Into, + creator: impl Into, + timestamp: i64, + ) -> Self { + Supplement { + content_id: content.into(), + timestamp, + creator: creator.into(), + annotations: none!(), + } + } + pub fn get_default_opt( &self, sub: SupplSub, From 48428bafccbc8fd3a52216fe476f25af3531fdae Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 26 Nov 2024 15:38:26 +0100 Subject: [PATCH 17/70] reboot repo --- Cargo.lock | 543 +++++---- Cargo.toml | 73 +- LICENSE | 25 - MANIFEST.yml | 14 - asset/armored_contract.default | 13 - asset/armored_kit.default | 9 - asset/armored_transfer.default | 13 - asset/contract.default | Bin 145 -> 0 bytes asset/kit.default | Bin 18 -> 0 bytes asset/transfer.default | Bin 145 -> 0 bytes cli/Cargo.toml | 22 + cli/src/cmd.rs | 223 ++++ cli/src/main.rs | 33 + doc/seals.md | 28 - examples/token.rs | 90 ++ invoice/Cargo.toml | 34 - invoice/src/builder.rs | 147 --- invoice/src/invoice.rs | 225 ---- invoice/src/lib.rs | 41 - invoice/src/parse.rs | 793 ------------- src/bp/anchor.rs | 39 + src/bp/mod.rs | 26 + src/{containers/seal.rs => bp/seals.rs} | 29 +- src/containers/anchors.rs | 505 -------- src/containers/consignment.rs | 582 --------- src/containers/disclosure.rs | 23 - src/containers/file.rs | 440 ------- src/containers/indexed.rs | 147 --- src/containers/kit.rs | 333 ------ src/containers/mod.rs | 77 -- src/containers/partials.rs | 394 ------- src/containers/seals.md | 29 - src/containers/suppl.rs | 368 ------ src/containers/util.rs | 137 --- src/contract/allocation.rs | 149 --- src/contract/merge_reveal.rs | 211 ---- src/contract/mod.rs | 91 -- src/info.rs | 319 ----- src/interface/builder.rs | 834 ------------- src/interface/calc.rs | 194 --- src/interface/contract.rs | 439 ------- src/interface/contractum.rs | 341 ------ src/interface/filter.rs | 132 --- src/interface/iface.rs | 698 ----------- src/interface/iimpl.rs | 564 --------- src/interface/inheritance.rs | 725 ------------ src/interface/mod.rs | 66 -- src/interface/resolver.rs | 38 - src/lib.rs | 63 +- src/mound.rs | 79 ++ src/persistence/fs.rs | 93 -- src/persistence/index.rs | 368 ------ src/persistence/memory.rs | 1424 ----------------------- src/persistence/mod.rs | 70 -- src/persistence/stash.rs | 802 ------------- src/persistence/state.rs | 310 ----- src/persistence/stock.rs | 1405 ---------------------- src/pile.rs | 97 ++ src/resolvers.rs | 54 - src/stl.rs | 29 +- src/stockpile.rs | 106 ++ src/wallet.rs | 85 ++ stl/Cargo.toml | 23 - stl/RGBStd@0.11.0.sta | 300 ----- stl/RGBStd@0.11.0.stl | Bin 18172 -> 0 bytes stl/RGBStd@0.11.0.sty | 389 ------- stl/RGBStorage@0.11.0.sta | 199 ---- stl/RGBStorage@0.11.0.stl | Bin 11571 -> 0 bytes stl/RGBStorage@0.11.0.sty | 234 ---- stl/Transfer.vesper | 764 ------------ stl/src/main.rs | 133 --- 71 files changed, 1178 insertions(+), 16105 deletions(-) delete mode 100644 MANIFEST.yml delete mode 100644 asset/armored_contract.default delete mode 100644 asset/armored_kit.default delete mode 100644 asset/armored_transfer.default delete mode 100644 asset/contract.default delete mode 100644 asset/kit.default delete mode 100644 asset/transfer.default create mode 100644 cli/Cargo.toml create mode 100644 cli/src/cmd.rs create mode 100644 cli/src/main.rs delete mode 100644 doc/seals.md create mode 100644 examples/token.rs delete mode 100644 invoice/Cargo.toml delete mode 100644 invoice/src/builder.rs delete mode 100644 invoice/src/invoice.rs delete mode 100644 invoice/src/lib.rs delete mode 100644 invoice/src/parse.rs create mode 100644 src/bp/anchor.rs create mode 100644 src/bp/mod.rs rename src/{containers/seal.rs => bp/seals.rs} (82%) delete mode 100644 src/containers/anchors.rs delete mode 100644 src/containers/consignment.rs delete mode 100644 src/containers/disclosure.rs delete mode 100644 src/containers/file.rs delete mode 100644 src/containers/indexed.rs delete mode 100644 src/containers/kit.rs delete mode 100644 src/containers/mod.rs delete mode 100644 src/containers/partials.rs delete mode 100644 src/containers/seals.md delete mode 100644 src/containers/suppl.rs delete mode 100644 src/containers/util.rs delete mode 100644 src/contract/allocation.rs delete mode 100644 src/contract/merge_reveal.rs delete mode 100644 src/contract/mod.rs delete mode 100644 src/info.rs delete mode 100644 src/interface/builder.rs delete mode 100644 src/interface/calc.rs delete mode 100644 src/interface/contract.rs delete mode 100644 src/interface/contractum.rs delete mode 100644 src/interface/filter.rs delete mode 100644 src/interface/iface.rs delete mode 100644 src/interface/iimpl.rs delete mode 100644 src/interface/inheritance.rs delete mode 100644 src/interface/mod.rs delete mode 100644 src/interface/resolver.rs create mode 100644 src/mound.rs delete mode 100644 src/persistence/fs.rs delete mode 100644 src/persistence/index.rs delete mode 100644 src/persistence/memory.rs delete mode 100644 src/persistence/mod.rs delete mode 100644 src/persistence/stash.rs delete mode 100644 src/persistence/state.rs delete mode 100644 src/persistence/stock.rs create mode 100644 src/pile.rs delete mode 100644 src/resolvers.rs create mode 100644 src/stockpile.rs create mode 100644 src/wallet.rs delete mode 100644 stl/Cargo.toml delete mode 100644 stl/RGBStd@0.11.0.sta delete mode 100644 stl/RGBStd@0.11.0.stl delete mode 100644 stl/RGBStd@0.11.0.sty delete mode 100644 stl/RGBStorage@0.11.0.sta delete mode 100644 stl/RGBStorage@0.11.0.stl delete mode 100644 stl/RGBStorage@0.11.0.sty delete mode 100644 stl/Transfer.vesper delete mode 100644 stl/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index a3fdd9ee..1089c2b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,31 +4,26 @@ version = 3 [[package]] name = "aluvm" -version = "0.11.0-beta.9" -source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#bedd86c160bab2398c07901728fd06b6bab13ddc" +version = "0.12.0-beta.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24cbb8887879db8e58ad1aada824eabe4aaa8a90b0b3fbd992e9e001625673a0" dependencies = [ "amplify", - "ascii-armor", "baid64", - "blake3", + "commit_verify", "getrandom", - "half", "paste", - "ripemd", "serde", - "sha2", "strict_encoding", - "strict_types", "wasm-bindgen", ] [[package]] name = "amplify" -version = "4.7.0" +version = "4.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7147b742325842988dd6c793d55f58df3ae36bccf7d9b6e07db10ab035be343d" +checksum = "448cf0c3afc71439b5f837aac5399a1ef2b223f5f38324dbfb4343deec3b80cc" dependencies = [ - "amplify_apfloat", "amplify_derive", "amplify_num", "amplify_syn", @@ -38,17 +33,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "amplify_apfloat" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695e433882668b55b3d7fb0ba22bf9be66a91abe30d7ca1f1a774f8b90b4db4c" -dependencies = [ - "amplify_num", - "bitflags 2.6.0", - "wasm-bindgen", -] - [[package]] name = "amplify_derive" version = "4.0.1" @@ -98,10 +82,59 @@ dependencies = [ ] [[package]] -name = "arrayref" -version = "0.3.9" +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arrayvec" @@ -120,9 +153,9 @@ dependencies = [ [[package]] name = "ascii-armor" -version = "0.7.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4966ac403dc4a666d8131dfe4df684f45acc68d4c7e768db89c463aa5617910" +checksum = "0269eb842ec952b027df0fc33184b6a0dea5ea473160b36992274eb53758461e" dependencies = [ "amplify", "baid64", @@ -139,9 +172,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "baid64" -version = "0.2.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95dabc2759e01e2c382968639868a701f384a18890934f9e75d4feb4d6623794" +checksum = "6cb4a8b2f1afee4ef00a190b260ad871842b93206177b59631fecd325d48d538" dependencies = [ "amplify", "base64", @@ -164,17 +197,11 @@ dependencies = [ "thiserror", ] -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "bitcoin-io" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin_hashes" @@ -186,31 +213,6 @@ dependencies = [ "hex-conservative", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "blake3" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -222,8 +224,8 @@ dependencies = [ [[package]] name = "bp-consensus" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" +version = "0.12.0-beta.2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" dependencies = [ "amplify", "chrono", @@ -236,8 +238,8 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" +version = "0.12.0-beta.2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" dependencies = [ "amplify", "bp-consensus", @@ -254,8 +256,8 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" +version = "0.12.0-beta.2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" dependencies = [ "amplify", "base85", @@ -266,21 +268,10 @@ dependencies = [ "strict_encoding", ] -[[package]] -name = "bp-invoice" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-std?branch=develop#b83739dc1ee3299a85f4cb040e061597dd9be2db" -dependencies = [ - "amplify", - "bech32", - "bp-consensus", - "commit_verify", -] - [[package]] name = "bp-seals" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#0f591b4bcbd16d4bab3c9fe7134b9eaf8d397023" +version = "0.12.0-beta.2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" dependencies = [ "amplify", "baid64", @@ -307,9 +298,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.31" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "shlex", ] @@ -335,10 +326,57 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "commit_encoding_derive" -version = "0.11.0-beta.9" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" +version = "0.12.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137f212bdbb4abf7bb648ba73feed1d981a4f4681821b15d79a37bfdbc206070" dependencies = [ "amplify", "amplify_syn", @@ -349,8 +387,9 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0-beta.9" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" +version = "0.12.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef304002218b4136632abe4145a168d8b8f95e4d5443d377240ab2b1868a52a" dependencies = [ "amplify", "commit_encoding_derive", @@ -363,22 +402,6 @@ dependencies = [ "vesper-lang", ] -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -387,19 +410,13 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - [[package]] name = "crypto-common" version = "0.1.6" @@ -426,15 +443,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "fluent-uri" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -458,21 +466,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -489,6 +487,25 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hypersonic" +version = "0.12.0-beta.1" +source = "git+https://github.com/AluVM/sonic#90d37d566a13510e2634adb19e25d6eba017c166" +dependencies = [ + "aluvm", + "amplify", + "commit_verify", + "getrandom", + "indexmap", + "serde", + "serde_yaml", + "sonic-api", + "strict_encoding", + "strict_types", + "ultrasonic", + "wasm-bindgen", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -514,35 +531,42 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.161" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "log" @@ -558,9 +582,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minicov" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", @@ -572,15 +596,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b8f3a258db515d5e91a904ce4ae3f73e091149b90cadbdb93d210bee07f63b" -[[package]] -name = "nonasync" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1005555d351f593bf72ffc3a89a0d42e243df004d2c4ded17699f10b562b98" -dependencies = [ - "amplify", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -602,12 +617,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - [[package]] name = "ppv-lite86" version = "0.2.20" @@ -619,9 +628,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -667,60 +676,30 @@ dependencies = [ [[package]] name = "rgb-core" -version = "0.11.0-beta.9" -source = "git+https://github.com/RGB-WG/rgb-core?branch=feat/fungible-nonconf#78ee97123665b5da312336f52d56485153af1673" +version = "0.12.0-beta.3" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#059dc252372f4f01b6ab7a7dfed939095fdd886e" dependencies = [ - "aluvm", "amplify", - "baid64", - "base64", - "bp-core", - "chrono", "commit_verify", "getrandom", - "serde", "single_use_seals", - "strict_encoding", - "strict_types", + "ultrasonic", "wasm-bindgen", ] -[[package]] -name = "rgb-invoice" -version = "0.11.0-beta.9" -dependencies = [ - "amplify", - "baid64", - "bp-core", - "bp-invoice", - "fluent-uri", - "indexmap", - "percent-encoding", - "rand", - "rgb-core", - "serde", - "strict_encoding", -] - [[package]] name = "rgb-std" -version = "0.11.0-beta.9" +version = "0.12.0-alpha.1" dependencies = [ - "aluvm", "amplify", - "ascii-armor", - "baid64", - "base85", "bp-core", - "chrono", "commit_verify", "getrandom", - "indexmap", - "nonasync", + "hypersonic", "rand", "rgb-core", - "rgb-invoice", "serde", + "single_use_seals", "strict_encoding", "strict_types", "wasm-bindgen", @@ -728,13 +707,18 @@ dependencies = [ ] [[package]] -name = "rgb-stl" -version = "0.11.0-beta.9" +name = "rgbx" +version = "0.12.0-alpha.1" dependencies = [ "amplify", - "commit_verify", + "anyhow", + "bp-core", + "clap", + "hypersonic", "rgb-std", - "strict_types", + "serde", + "serde_yaml", + "strict_encoding", ] [[package]] @@ -790,29 +774,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.131" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d42a0bd4ac281beff598909bb56a86acaf979b84483e1c79c10dcaf98f8cf3" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -871,20 +855,35 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0-beta.9" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" +version = "0.12.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa1f0140117847f5470c5ab2e68f7645bfe6fe27933b9160de63832ecaf0f3d2" + +[[package]] +name = "sonic-api" +version = "0.12.0-beta.1" +source = "git+https://github.com/AluVM/sonic#90d37d566a13510e2634adb19e25d6eba017c166" dependencies = [ - "amplify_derive", + "aluvm", + "amplify", + "baid64", + "chrono", + "commit_verify", + "getrandom", + "serde", + "strict_encoding", + "strict_types", + "ultrasonic", + "wasm-bindgen", ] [[package]] name = "strict_encoding" -version = "2.7.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69b4893cf054e129d5288a565102124520d7b94eb9589d1e78202abc7e2092d" +checksum = "8fd36b71bb44ca146be0b2185ed6c6deb3684cc0d5c3a94284e97fe7fa6a642f" dependencies = [ "amplify", - "half", "serde", "strict_encoding_derive", "wasm-bindgen", @@ -892,9 +891,9 @@ dependencies = [ [[package]] name = "strict_encoding_derive" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4f9b678862372f8e439bcaafc27df7610ea93b06d2deb6244dec0af4259ce6" +checksum = "34e3bc6e4a2450420b4dbfb6929d9ce005e8c36cf73bf215db99f0d09c9fa79f" dependencies = [ "amplify_syn", "heck", @@ -905,13 +904,13 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.7.1" -source = "git+https://github.com/strict-types/strict-types?branch=develop#9a2041a9b1988b17608564725d47b39f442e5062" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e208d1bd29a0f70d7ee90a91d76446b8bb7b1b8212d06e031e396d52e2fe891" dependencies = [ "amplify", "ascii-armor", "baid64", - "half", "indexmap", "serde", "serde_json", @@ -933,6 +932,12 @@ dependencies = [ "serde_str_helpers", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -946,9 +951,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -957,22 +962,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1015,11 +1020,26 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ultrasonic" +version = "0.12.0-beta.2" +source = "git+https://github.com/AluVM/ultrasonic#69ccba97ed9347db5a7b8ff680e3e1179dcd13e0" +dependencies = [ + "amplify", + "baid64", + "commit_verify", + "getrandom", + "serde", + "strict_encoding", + "wasm-bindgen", + "zk-aluvm", +] + [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unsafe-libyaml" @@ -1027,6 +1047,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version_check" version = "0.9.5" @@ -1035,9 +1061,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vesper-lang" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f72ebd3b32f16ee8ace2bd3058c2bfa0f4820992bd4ea86e73ba228bb13dd2b0" +checksum = "cd2b7e3e27aeb0524204e58042f6e4531a720745d1b1a3978d3a084f1885f63d" dependencies = [ "amplify", "strict_encoding", @@ -1061,9 +1087,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -1072,36 +1098,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1109,30 +1135,29 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-bindgen-test" -version = "0.3.45" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" +checksum = "c61d44563646eb934577f2772656c7ad5e9c90fac78aa8013d776fcdaf24625d" dependencies = [ - "console_error_panic_hook", "js-sys", "minicov", "scoped-tls", @@ -1143,20 +1168,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.45" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" +checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -1280,5 +1305,19 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", +] + +[[package]] +name = "zk-aluvm" +version = "0.12.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f06b3c7a5e4ddf056024c9028004c34b0a0a1b575b2dc2abe4e31ae9f9073ec" +dependencies = [ + "aluvm", + "amplify", + "getrandom", + "serde", + "strict_encoding", + "wasm-bindgen", ] diff --git a/Cargo.toml b/Cargo.toml index 3837c078..529f45d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,10 @@ [workspace] -members = [ - ".", - "invoice", - "stl" -] -default-members = [ - ".", - "invoice" -] +members = [".", "cli"] +default-members = ["."] resolver = "2" [workspace.package] -version = "0.11.0-beta.9" +version = "0.12.0-alpha.1" authors = ["Dr Maxim Orlovsky "] homepage = "https://github.com/RGB-WG" repository = "https://github.com/RGB-WG/rgb-std" @@ -22,23 +15,21 @@ edition = "2021" license = "Apache-2.0" [workspace.dependencies] -amplify = "4.7.0" -nonasync = "0.1.0" -ascii-armor = "0.7.2" -baid64 = "0.2.2" -strict_encoding = "2.7.0" -strict_types = "2.7.1" -commit_verify = { version = "0.11.0-beta.9", features = ["stl"] } -bp-core = { version = "0.11.0-beta.9", features = ["stl"] } -bp-invoice = { version = "0.11.0-beta.9" } -rgb-core = { version = "0.11.0-beta.9", features = ["stl"] } -indexmap = "2.4.0" -serde_crate = { package = "serde", version = "1", features = ["derive"] } +amplify = "4.8.0" +strict_encoding = "2.8.1" +strict_types = "2.8.1" +commit_verify = "0.12.0-beta.1" +single_use_seals = "0.12.0-beta.1" +hypersonic = "0.12.0-beta.1" +rgb-std = { version = "0.12.0-alpha.1", path = "." } +bp-core = "0.12.0-beta.2" +rgb-core = "0.12.0-beta.3" +serde = { package = "serde", version = "1", features = ["derive"] } [package] name = "rgb-std" version = { workspace = true } -description = "RGB standard library for working with smart contracts on Bitcoin & Lightning" +description = "Standard Library for RGB smart contracts" keywords = { workspace = true } categories = { workspace = true } authors = { workspace = true } @@ -55,37 +46,31 @@ crate-type = ["cdylib", "rlib"] # We need this for WASM [dependencies] amplify = { workspace = true } -nonasync = { workspace = true } -ascii-armor = { workspace = true } -baid64 = { workspace = true } strict_encoding = { workspace = true } strict_types = { workspace = true } commit_verify = { workspace = true } +single_use_seals = { workspace = true } +hypersonic = { workspace = true } bp-core = { workspace = true } rgb-core = { workspace = true } -rgb-invoice = { version = "0.11.0-beta.9", path = "invoice" } -aluvm = "0.11.0-beta.9" -base85 = "=2.0.0" -chrono = "0.4.38" -indexmap = { workspace = true } -serde_crate = { workspace = true, optional = true } -rand = "0.8.5" +serde = { workspace = true, optional = true } [features] default = [] all = ["fs", "serde"] serde = [ - "serde_crate", - "chrono/serde", + "dep:serde", "amplify/serde", "strict_encoding/serde", "strict_types/serde", "commit_verify/serde", "bp-core/serde", "rgb-core/serde", - "rgb-invoice/serde" ] -fs = [] +stl = [ + "bp-core/stl", "commit_verify/stl" +] +fs = ["hypersonic/persist-file"] [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" @@ -99,13 +84,7 @@ wasm-bindgen-test = "0.3" features = ["all"] [patch.crates-io] -commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } -single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } -strict_types = { git = "https://github.com/strict-types/strict-types", branch = "develop" } -aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "develop" } -bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "feat/fungible-nonconf" } +ultrasonic = { git = "https://github.com/AluVM/ultrasonic" } +hypersonic = { git = "https://github.com/AluVM/sonic" } +bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.12" } diff --git a/LICENSE b/LICENSE index 5987cb5c..d9a10c0d 100644 --- a/LICENSE +++ b/LICENSE @@ -174,28 +174,3 @@ of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2019-2024 LNP/BP Standards Association, Switzerland - - 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. diff --git a/MANIFEST.yml b/MANIFEST.yml deleted file mode 100644 index 6e84d0f4..00000000 --- a/MANIFEST.yml +++ /dev/null @@ -1,14 +0,0 @@ -Name: rgbwallet -Type: Library -Kind: Free software -License: Apache-2.0 -Language: Rust -Compiler: 1.77 -Author: Maxim Orlovsky -Maintained: LNP/BP Standards Association, Switzerland -Maintainers: - Maxim Orlovsky: - GitHub: @dr-orlovsky - GPG: EAE730CEC0C663763F028A5860094BAF18A26EC9 - SSH: BoSGFzbyOKC7Jm28MJElFboGepihCpHop60nS8OoG/A - EMail: dr@orlovsky.ch diff --git a/asset/armored_contract.default b/asset/armored_contract.default deleted file mode 100644 index 4944ab6e..00000000 --- a/asset/armored_contract.default +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:mK5KaBwW-ht!iR1o-5qi3fe7-gIHhBiL-t80Tud5-Wi2Jo4A#bikini-binary-table -Version: 2 -Type: contract -Contract: rgb:5M7hTCP5-or5y2Bp-xPPIYez-WEsey5D-e2GhCpV-HlsK7jI -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: 181748dae0c83cbb44f6ccfdaddf6faca0bc4122a9f35fef47bab9aea023e4a1 - -0ssI2000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#nj! -0000000000000000000000d59ZDjxe00000000dDb8~4rVQz13d2MfXa{vGU00000000000000000000 -0000000000000 - ------END RGB CONSIGNMENT----- diff --git a/asset/armored_kit.default b/asset/armored_kit.default deleted file mode 100644 index 7a10425d..00000000 --- a/asset/armored_kit.default +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RGB KIT----- -Id: rgb:kit:e1jW6Rgc-2$JzXDg-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel -Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da - -0ssI2000000000 - ------END RGB KIT----- diff --git a/asset/armored_transfer.default b/asset/armored_transfer.default deleted file mode 100644 index e1cb27e8..00000000 --- a/asset/armored_transfer.default +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:H58AX9qS-4IFd5aQ-tx9Exr$-DzCvDDW-luMVTFJ-GqEnZ3k#avenue-educate-finland -Version: 2 -Type: transfer -Contract: rgb:5M7hTCP5-or5y2Bp-xPPIYez-WEsey5D-e2GhCpV-HlsK7jI -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: 562a944631243e23a8de1d2aa2a5621be13351fc6f4d9aa8127c12ac4fb54d97 - -0s#O3000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#nj! -0000000000000000000000d59ZDjxe00000000dDb8~4rVQz13d2MfXa{vGU00000000000000000000 -0000000000000 - ------END RGB CONSIGNMENT----- diff --git a/asset/contract.default b/asset/contract.default deleted file mode 100644 index 33e2bd7135ba82e199e19512612bc503a87edbbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145 wcmWG?cVck%_hVup3Ggx$7iU@}=H=&A=H{0cW6{gvmzbLh6DO=3rjmgH0M|SYK>z>% diff --git a/asset/kit.default b/asset/kit.default deleted file mode 100644 index 67d729f7a135b27f782b34c9ecab0947f4b5f14f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18 RcmWG?cVh7N3}Iq`0{|L=0mc9T diff --git a/asset/transfer.default b/asset/transfer.default deleted file mode 100644 index 5685f5e9a3e3155df8b77b179518b100bfecf734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145 xcmWG?cVY-}3u0nqAO-L;6c=Y&CFbSlRp#cG7Gu%M;+L443KJ)+9Hx?i0RY}&4o(07 diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 00000000..b11893df --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rgbx" +version.workspace = true +authors.workspace = true +repository.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true + +[dependencies] +amplify.workspace = true +strict_encoding.workspace = true +hypersonic = { workspace = true, features = ["persist-file"] } +bp-core.workspace = true +rgb-std = { workspace = true, features = ["fs"] } +serde.workspace = true +serde_yaml = "0.9.34" +anyhow = "1.0.93" +clap = { version = "4.5.21", features = ["derive"] } diff --git a/cli/src/cmd.rs b/cli/src/cmd.rs new file mode 100644 index 00000000..bc15f6ea --- /dev/null +++ b/cli/src/cmd.rs @@ -0,0 +1,223 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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; +use std::fs::File; +use std::path::{Path, PathBuf}; + +use bp::dbc::opret::OpretProof; +use bp::dbc::tapret::TapretProof; +use bp::seals::TxoSeal; +use hypersonic::{ + Articles, AuthToken, CallParams, ContractId, IssueParams, Schema, Stock, +}; +use rgbstd::{FilePile, Mound, Stockpile}; +use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictReader, StrictWriter}; + +pub const WALLET_ENV: &str = "RGB_WALLET"; + +pub const DATA_DIR_ENV: &str = "RGB_DATA_DIR"; +#[cfg(target_os = "linux")] +pub const DATA_DIR: &str = "~/.rgb"; +#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] +pub const DATA_DIR: &str = "~/.rgb"; +#[cfg(target_os = "macos")] +pub const DATA_DIR: &str = "~/Library/Application Support/RGB Smart Contracts"; +#[cfg(target_os = "windows")] +pub const DATA_DIR: &str = "~\\AppData\\Local\\RGB Smart Contracts"; +#[cfg(target_os = "ios")] +pub const DATA_DIR: &str = "~/Documents"; +#[cfg(target_os = "android")] +pub const DATA_DIR: &str = "."; + +#[derive(Parser)] +pub struct Args { + /// Location of the data directory + #[clap( + short, + long, + global = true, + default_value = DATA_DIR, + env = DATA_DIR_ENV, + value_hint = ValueHint::DirPath + )] + pub data_dir: PathBuf, + + /// Command to execute + #[clap(subcommand)] + pub command: Cmd, +} + +#[derive(Parser)] +pub enum Cmd { + /// Issue a new RGB contract + #[clap(alias = "i")] + Issue { + /// Schema used to issue the contract + schema: PathBuf, + + /// Parameters and data for the contract + params: PathBuf, + }, + + /// Import contract articles + Import { + /// Contract articles to process + articles: PathBuf, + }, + + /// Export contract articles + Export { + /// Path to export articles to + articles: PathBuf, + }, + + /// Create a new wallet + Create { descriptor: String }, + + /// Print out a contract state + #[clap(alias = "s")] + State { + /// Present all the state, not just the one owned by the wallet + #[clap(short, long, global = true)] + all: bool, + + /// Contract directory + contract: ContractId, + }, + + /// Make a contract call + #[clap(aliases = ["e", "exec"])] + Execute { + /// YAML file with a script to execute + script: PathBuf, + }, + + /// Create a consignment transferring part of a contract state to another peer + #[clap(alias = "c")] + Consign { + /// List of tokens of authority which should serve as a contract terminals. + #[clap(short, long)] + terminals: Vec, + + /// Location to save the consignment file to + output: PathBuf, + }, + + /// Verify and accept a consignment + #[clap(alias = "a")] + Accept { + /// File with consignment to accept + input: PathBuf, + }, +} + +pub enum Treasure { + Opret(Stockpile, FilePile>, FilePersistence>), + Tapret(Stockpile, FilePile>, FilePersistence>), +} + +pub struct Barrow(BTreeMap); + +impl Args { + pub fn exec(&self) -> anyhow::Result<()> { + let mound = Mound::excavate(&self.data_dir); + match &self.command { + Cmd::Issue { schema, params } => todo!(), + Cmd::Import { .. } => todo!(), + Cmd::Export { .. } => todo!(), + Cmd::Create { .. } => todo!(), + Cmd::State { .. } => todo!(), + Cmd::Execute { .. } => todo!(), + Cmd::Consign { .. } => todo!(), + Cmd::Accept { .. } => todo!(), + } + Ok(()) + } +} + +impl Barrow { + pub fn issue(&self, schema: &Path, form: &Path, output: Option<&Path>) -> anyhow::Result<()> { + let schema = Schema::load(schema)?; + let file = File::open(form)?; + let params = serde_yaml::from_reader::<_, IssueParams>(file)?; + + let path = output.unwrap_or(form); + let output = path.with_file_name(&format!("{}.articles", params.name)); + + let articles = schema.issue::(params); + articles.save(output)?; + + Ok(()) + } +} + +fn process(articles: &Path, stock: Option<&Path>) -> anyhow::Result<()> { + let path = stock.unwrap_or(articles); + + let articles = Articles::::load(articles)?; + Stock::new(articles, path); + + Ok(()) +} + +fn state(path: &Path) { + let stock = Stock::::load(path); + let val = serde_yaml::to_string(&stock.state().main).expect("unable to generate YAML"); + println!("{val}"); +} + +fn call(stock: &Path, form: &Path) -> anyhow::Result<()> { + let mut stock = Stock::::load(stock); + let file = File::open(form)?; + let call = serde_yaml::from_reader::<_, CallParams>(file)?; + let opid = stock.call(call); + println!("Operation ID: {opid}"); + Ok(()) +} + +fn export<'a>( + stock: &Path, + terminals: impl IntoIterator, + output: &Path, +) -> anyhow::Result<()> { + let mut stock = Stock::::load(stock); + let file = File::create_new(output)?; + let writer = StrictWriter::with(StreamWriter::new::<{ usize::MAX }>(file)); + stock.export(terminals, writer)?; + Ok(()) +} + +fn accept(stock: &Path, input: &Path) -> anyhow::Result<()> { + let mut stock = Stock::::load(stock); + let file = File::open(input)?; + let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); + + let articles = Articles::::strict_decode(&mut reader)?; + if articles.contract_id() != stock.contract_id() { + return Err("Contract ID mismatch".into()); + } + + stock.consume() +} diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 00000000..31609d9c --- /dev/null +++ b/cli/src/main.rs @@ -0,0 +1,33 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +#[macro_use] +extern crate clap; + +mod cmd; + +use clap::Parser; +use cmd::Cmd; + +fn main() -> anyhow::Result<()> { Cmd::parse().exec() } diff --git a/doc/seals.md b/doc/seals.md deleted file mode 100644 index 0c066771..00000000 --- a/doc/seals.md +++ /dev/null @@ -1,28 +0,0 @@ -# Single-use-seal API specific for RGB implementation - -Based on LNP/BP client-side-validation single-use-seals API (see -`single_use_seals` crate). RGB single-use-seal implementation differs in the fact -that seals are organized into a graph; thus a seal may be defined as -pointing witness transaction closing some other seal, which is meaningless -with LNP/BP seals. - -Single-use-seals in RGB are used for holding assigned state, i.e. *state* + -*seal definition* = *assignment*. Closing of the single-use-seal invalidates -the assigned state. - -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 | - -[`Outpoint`]: bp::Outpoint -[`BlindSeal`]: bp::seals::txout::blind::BlindSeal -[`ExplicitSeal`]: bp::seals::txout::ExplicitSeal diff --git a/examples/token.rs b/examples/token.rs new file mode 100644 index 00000000..c8ecde75 --- /dev/null +++ b/examples/token.rs @@ -0,0 +1,90 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +#[macro_use] +extern crate amplify; +#[macro_use] +extern crate strict_types; + +use hypersonic::Schema; +use rgbstd::Stockpile; + +fn main() { + let mut alice = Wallet::load(""); + + let seal1 = alice.next_seal_pub(); + + let schema = Schema::load("").expect("unable to load schema"); + // Contract is articles object + let articles = schema + .start_issue("firstIssue") + .append("ticker", svnum!(0u64), Some(ston!(ticker "TICK", name "Token"))) + .assign("tokenOwners", seal1, svnum!(100_0000), None) + .finish::("TokenContract", 1732529307); + + let mut stockpile = Stockpile::new(articles, "examples/token/data"); + + let bob = Wallet::load(""); + let seal2 = bob.next_seal_pub(); + let seal_change = alice.next_seal_priv(); + // The seal can be also vout-based, use `next_seal_vout` for that purpose + + // Instead of keeping the whole contract ops in the memory, this can be actually done + // using state combined with APIs! + let op = stockpile + .start_deed("transfer") + .using(seal1, ston!()) + .append("tokenOwners", seal2, svnum!(10_0000), None) + .append("tokenOwners", seal_change, svnum!(90_0000), None) + .commit(); + + // PSBT constructor analyses both inputs and outputs of the operation, detecting and checking + // relevant seals (for instance, vout-based). + let psbt = alice.construct_psbt(op); + //let alice_balances = stockpile.select_unspent(alice.utxos(), svnum!(10_0000)); + + for contract_id in alice.affected(psbt) { + // TODO: We need to do blank transitions as well + } + + let anchor = psbt.extract_anchor(stockpile.contract_id()); + // TODO: We need to extract an anchor per each contract + // This adds information about UTXOs to the wallet + let tx = alice.finalize_psbt(); + + // Ensuring Alice's contract is updated + stockpile.append_witness(tx, anchor); + + stockpile.consign_to_file([seal2], "examples/token/transfer.rgb"); + tx.broadcast(); + alice.save(""); + + // Bob's site: + // let diff = Deeds::diff("", transfer); + // let transitions = state.accept(diff); // This also does the verification + // Trace::extend("", transitions); + // Deeds::extend("", diff); + + // Locker, token (stash) and trace are append-only logs + // Only state, wallet (alice) must persist in memory +} diff --git a/invoice/Cargo.toml b/invoice/Cargo.toml deleted file mode 100644 index 60607596..00000000 --- a/invoice/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "rgb-invoice" -version = { workspace = true } -description = "Invoicing library for RGB smart contracts" -keywords = { workspace = true } -categories = { workspace = true } -readme = "../README.md" -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -rust-version = { workspace = true } -edition = { workspace = true } -license = { workspace = true } - -[lib] -name = "rgbinvoice" - -[dependencies] -amplify = { workspace = true } -baid64 = { workspace = true } -strict_encoding = { workspace = true } -bp-core = { workspace = true } -bp-invoice = { workspace = true } -rgb-core = { workspace = true } -indexmap = { workspace = true } -fluent-uri = "0.1.4" -percent-encoding = "2.3.1" -serde_crate = { workspace = true, optional = true } -rand = "0.8.5" - -[features] -default = [] -serde = ["serde_crate"] -# TODO: Separate URL with a feature gate diff --git a/invoice/src/builder.rs b/invoice/src/builder.rs deleted file mode 100644 index 9d84fb61..00000000 --- a/invoice/src/builder.rs +++ /dev/null @@ -1,147 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::str::FromStr; - -use rgb::{ContractId, StateData}; -use strict_encoding::{FieldName, SerializeError, StrictSerialize, TypeName}; - -use crate::{Beneficiary, RgbInvoice, RgbTransport, TransportParseError, XChainNet}; - -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct RgbInvoiceBuilder(RgbInvoice); - -#[allow(clippy::result_large_err)] -impl RgbInvoiceBuilder { - pub fn new(beneficiary: impl Into>) -> Self { - Self(RgbInvoice { - transports: vec![RgbTransport::UnspecifiedMeans], - contract: None, - iface: None, - operation: None, - assignment: None, - beneficiary: beneficiary.into(), - state: None, - expiry: None, - unknown_query: none!(), - }) - } - - pub fn with(contract_id: ContractId, beneficiary: impl Into>) -> Self { - Self::new(beneficiary).set_contract(contract_id) - } - - pub fn set_contract(mut self, contract_id: ContractId) -> Self { - self.0.contract = Some(contract_id); - self - } - - /// Sets interface for the invoice. Interface can be a concrete interface (name or id), or a - /// name of an interface standard, like `RGB20`, `RGB21` etc. - pub fn set_interface(mut self, name: impl Into) -> Self { - self.0.iface = Some(name.into()); - self - } - - pub fn set_operation(mut self, name: impl Into) -> Self { - self.0.operation = Some(name.into()); - self - } - - pub fn set_assignment(mut self, name: impl Into) -> Self { - self.0.assignment = Some(name.into()); - self - } - - /// Add state data to the invoice. - /// - /// See also [`Self::serialize_state_data`], which adds state data by serializing them from a - /// state object. - pub fn set_state(mut self, data: StateData) -> Self { - self.0.state = Some(data); - self - } - - /// Add state data to the invoice by strict-serializing the provided object. - /// - /// Use the function carefully, since the common pitfall here is to perform double serialization - /// of an already serialized data type, like `SmallBlob`. This produces an invalid state object - /// which can't be properly parsed later. See also [`Self::set_state`], which sets state data - /// directly with no serialization. - pub fn serialize_state_data( - mut self, - data: &impl StrictSerialize, - ) -> Result { - self.0.state = Some(StateData::from_serialized(data)?); - Ok(self) - } - - pub fn set_expiry_timestamp(mut self, expiry: i64) -> Self { - self.0.expiry = Some(expiry); - self - } - - fn drop_unspecified_transport(&mut self) { - if self.0.transports.len() == 1 && self.0.transports[0] == RgbTransport::UnspecifiedMeans { - self.0.transports = vec![]; - } - } - - pub fn add_transport(self, transport: &str) -> Result { - let transport = match RgbTransport::from_str(transport) { - Err(err) => return Err((self, err)), - Ok(transport) => transport, - }; - Ok(self.add_transport_raw(transport)) - } - - pub fn add_transport_raw(mut self, transport: RgbTransport) -> Self { - self.drop_unspecified_transport(); - self.0.transports.push(transport); - self - } - - pub fn add_transports<'a>( - self, - transports: impl IntoIterator, - ) -> Result { - let res = transports - .into_iter() - .map(RgbTransport::from_str) - .collect::, TransportParseError>>(); - let transports = match res { - Err(err) => return Err((self, err)), - Ok(transports) => transports, - }; - Ok(self.add_transports_raw(transports)) - } - - pub fn add_transports_raw( - mut self, - transports: impl IntoIterator, - ) -> Self { - self.drop_unspecified_transport(); - self.0.transports.extend(transports); - self - } - - pub fn finish(self) -> RgbInvoice { self.0 } -} diff --git a/invoice/src/invoice.rs b/invoice/src/invoice.rs deleted file mode 100644 index 41f1720d..00000000 --- a/invoice/src/invoice.rs +++ /dev/null @@ -1,225 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 amplify::{ByteArray, Bytes32}; -use bp::seals::txout::CloseMethod; -use bp::{InvalidPubkey, OutputPk, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; -use indexmap::IndexMap; -use invoice::{AddressNetwork, AddressPayload, Network}; -use rgb::{ContractId, Layer1, SecretSeal, StateData}; -use strict_encoding::{FieldName, TypeName}; - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum RgbTransport { - JsonRpc { tls: bool, host: String }, - RestHttp { tls: bool, host: String }, - WebSockets { tls: bool, host: String }, - Storm {/* todo */}, - UnspecifiedMeans, -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[non_exhaustive] -pub enum ChainNet { - #[display("bc")] - BitcoinMainnet, - #[display("tb")] - BitcoinTestnet, - #[display("sb")] - BitcoinSignet, - #[display("bcrt")] - BitcoinRegtest, - #[display("lq")] - LiquidMainnet, - #[display("tl")] - LiquidTestnet, -} - -impl ChainNet { - pub fn layer1(&self) -> Layer1 { - match self { - ChainNet::BitcoinMainnet - | ChainNet::BitcoinTestnet - | ChainNet::BitcoinSignet - | ChainNet::BitcoinRegtest => Layer1::Bitcoin, - ChainNet::LiquidMainnet | ChainNet::LiquidTestnet => Layer1::Liquid, - } - } - - pub fn is_prod(&self) -> bool { - match self { - ChainNet::BitcoinMainnet | ChainNet::LiquidMainnet => true, - - ChainNet::BitcoinTestnet - | ChainNet::BitcoinSignet - | ChainNet::BitcoinRegtest - | ChainNet::LiquidTestnet => false, - } - } - - pub fn address_network(&self) -> AddressNetwork { - match self { - ChainNet::BitcoinMainnet => AddressNetwork::Mainnet, - ChainNet::BitcoinTestnet | ChainNet::BitcoinSignet => AddressNetwork::Testnet, - ChainNet::BitcoinRegtest => AddressNetwork::Regtest, - ChainNet::LiquidMainnet => AddressNetwork::Mainnet, - ChainNet::LiquidTestnet => AddressNetwork::Testnet, - } - } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -#[non_exhaustive] -pub enum XChainNet { - BitcoinMainnet(T), - BitcoinTestnet(T), - BitcoinSignet(T), - BitcoinRegtest(T), - LiquidMainnet(T), - LiquidTestnet(T), -} - -impl XChainNet { - pub fn with(cn: ChainNet, data: T) -> Self { - match cn { - ChainNet::BitcoinMainnet => XChainNet::BitcoinMainnet(data), - ChainNet::BitcoinTestnet => XChainNet::BitcoinTestnet(data), - ChainNet::BitcoinSignet => XChainNet::BitcoinSignet(data), - ChainNet::BitcoinRegtest => XChainNet::BitcoinRegtest(data), - ChainNet::LiquidMainnet => XChainNet::LiquidMainnet(data), - ChainNet::LiquidTestnet => XChainNet::LiquidTestnet(data), - } - } - - pub fn bitcoin(network: Network, data: T) -> Self { - match network { - Network::Mainnet => Self::BitcoinMainnet(data), - Network::Testnet3 => Self::BitcoinTestnet(data), - Network::Testnet4 => Self::BitcoinTestnet(data), - Network::Signet => Self::BitcoinSignet(data), - Network::Regtest => Self::BitcoinRegtest(data), - } - } - - pub fn chain_network(&self) -> ChainNet { - match self { - XChainNet::BitcoinMainnet(_) => ChainNet::BitcoinMainnet, - XChainNet::BitcoinTestnet(_) => ChainNet::BitcoinTestnet, - XChainNet::BitcoinSignet(_) => ChainNet::BitcoinSignet, - XChainNet::BitcoinRegtest(_) => ChainNet::BitcoinRegtest, - XChainNet::LiquidMainnet(_) => ChainNet::LiquidMainnet, - XChainNet::LiquidTestnet(_) => ChainNet::LiquidTestnet, - } - } - - pub fn into_inner(self) -> T { - match self { - XChainNet::BitcoinMainnet(inner) - | XChainNet::BitcoinTestnet(inner) - | XChainNet::BitcoinSignet(inner) - | XChainNet::BitcoinRegtest(inner) - | XChainNet::LiquidMainnet(inner) - | XChainNet::LiquidTestnet(inner) => inner, - } - } - - pub fn layer1(&self) -> Layer1 { self.chain_network().layer1() } - pub fn address_network(&self) -> AddressNetwork { self.chain_network().address_network() } - pub fn is_prod(&self) -> bool { self.chain_network().is_prod() } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum Pay2VoutError { - /// invalid close method byte {0:#04x}. - InvalidMethod(u8), - /// unexpected address type byte {0:#04x}. - InvalidAddressType(u8), - /// invalid taproot output key; specifically {0}. - InvalidTapkey(InvalidPubkey<32>), -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, From)] -pub struct Pay2Vout { - pub method: CloseMethod, - pub address: AddressPayload, -} - -impl Pay2Vout { - pub(crate) const P2PKH: u8 = 1; - pub(crate) const P2SH: u8 = 2; - pub(crate) const P2WPKH: u8 = 3; - pub(crate) const P2WSH: u8 = 4; - pub(crate) const P2TR: u8 = 5; -} - -impl TryFrom<[u8; 34]> for Pay2Vout { - type Error = Pay2VoutError; - - fn try_from(data: [u8; 34]) -> Result { - let method = - CloseMethod::try_from(data[0]).map_err(|e| Pay2VoutError::InvalidMethod(e.1))?; - let address = match data[1] { - Self::P2PKH => AddressPayload::Pkh(PubkeyHash::from_slice_unsafe(&data[2..22])), - Self::P2SH => AddressPayload::Sh(ScriptHash::from_slice_unsafe(&data[2..22])), - Self::P2WPKH => AddressPayload::Wpkh(WPubkeyHash::from_slice_unsafe(&data[2..22])), - Self::P2WSH => AddressPayload::Wsh(WScriptHash::from_slice_unsafe(&data[2..])), - Self::P2TR => AddressPayload::Tr( - OutputPk::from_byte_array(Bytes32::from_slice_unsafe(&data[2..34]).to_byte_array()) - .map_err(Pay2VoutError::InvalidTapkey)?, - ), - wrong => return Err(Pay2VoutError::InvalidAddressType(wrong)), - }; - Ok(Self { method, address }) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, From)] -pub enum Beneficiary { - #[from] - BlindedSeal(SecretSeal), - #[from] - WitnessVout(Pay2Vout), -} - -#[derive(Clone, Eq, PartialEq, Debug)] -#[non_exhaustive] -pub struct RgbInvoice { - pub transports: Vec, - pub contract: Option, - pub iface: Option, - pub operation: Option, - pub assignment: Option, - pub beneficiary: XChainNet, - pub state: Option, - /// UTC unix timestamp - pub expiry: Option, - // Attachment requirements should go here - pub unknown_query: IndexMap, -} - -impl RgbInvoice { - pub fn chain_network(&self) -> ChainNet { self.beneficiary.chain_network() } - pub fn address_network(&self) -> AddressNetwork { self.beneficiary.address_network() } - pub fn layer1(&self) -> Layer1 { self.beneficiary.layer1() } - pub fn is_prod(&self) -> bool { self.beneficiary.is_prod() } -} diff --git a/invoice/src/lib.rs b/invoice/src/lib.rs deleted file mode 100644 index 9ffe2999..00000000 --- a/invoice/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -#[macro_use] -extern crate amplify; -extern crate rgbcore as rgb; -#[cfg(feature = "serde")] -extern crate serde_crate as serde; - -/// Re-exporting BP invoice data types. -pub use ::invoice::*; - -#[allow(clippy::module_inception)] -mod invoice; -mod parse; -mod builder; - -pub use builder::RgbInvoiceBuilder; -pub use parse::{InvoiceParseError, TransportParseError}; - -pub use crate::invoice::{ - Beneficiary, ChainNet, Pay2Vout, Pay2VoutError, RgbInvoice, RgbTransport, XChainNet, -}; diff --git a/invoice/src/parse.rs b/invoice/src/parse.rs deleted file mode 100644 index 3ae6b546..00000000 --- a/invoice/src/parse.rs +++ /dev/null @@ -1,793 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::fmt::{self, Debug, Display, Formatter}; -use std::io::{Cursor, Write}; -use std::num::ParseIntError; -use std::str::FromStr; - -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use fluent_uri::enc::EStr; -use fluent_uri::Uri; -use indexmap::IndexMap; -use invoice::{AddressPayload, UnknownNetwork}; -use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; -use rgb::{ContractId, SecretSeal, StateData, StateParseError}; -use strict_encoding::{InvalidRString, TypeName}; - -use crate::invoice::{Beneficiary, ChainNet, Pay2Vout, RgbInvoice, RgbTransport, XChainNet}; - -const OMITTED: &str = "~"; -const EXPIRY: &str = "expiry"; -const ENDPOINTS: &str = "endpoints"; -const TRANSPORT_SEP: char = ','; -const TRANSPORT_HOST_SEP: &str = "://"; -const QUERY_ENCODE: &AsciiSet = &CONTROLS - .add(b' ') - .add(b'"') - .add(b'#') - .add(b'<') - .add(b'>') - .add(b'[') - .add(b']') - .add(b'&') - .add(b'='); - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(inner)] -pub enum TransportParseError { - #[display(doc_comments)] - /// invalid transport {0}. - InvalidTransport(String), - - #[display(doc_comments)] - /// invalid transport host {0}. - InvalidTransportHost(String), -} - -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum InvoiceParseError { - #[from] - #[display(inner)] - Uri(fluent_uri::ParseError), - - /// absent invoice URI scheme name. - AbsentScheme, - - /// invalid invoice scheme {0}. - InvalidScheme(String), - - /// RGB invoice must not contain any URI authority data, including empty - /// one. - Authority, - - /// contract id is missed from the invoice. - ContractMissed, - - /// interface information is missed from the invoice. - IfaceMissed, - - /// assignment data is missed from the invoice. - AssignmentMissed, - - #[from] - #[display(inner)] - InvalidState(StateParseError), - - /// no invoice transport has been provided. - NoTransport, - - /// invalid invoice: contract ID present but no contract interface provided. - ContractIdNoIface, - - /// invalid contract ID. - InvalidContractId(String), - - /// invalid interface {0}. - InvalidIface(String), - - /// invalid expiration timestamp {0}. - InvalidExpiration(String), - - #[display(inner)] - #[from] - InvalidNetwork(UnknownNetwork), - - /// invalid query parameter {0}. - InvalidQueryParam(String), - - #[from] - #[display(inner)] - Id(Baid64ParseError), - - /// can't recognize beneficiary "{0}": it should be either a bitcoin address - /// or a blinded UTXO seal. - Beneficiary(String), - - #[from] - #[display(inner)] - Num(ParseIntError), - - #[from] - /// invalid interface name. - IfaceName(InvalidRString), -} - -impl RgbInvoice { - fn has_params(&self) -> bool { - self.expiry.is_some() - || self.transports != vec![RgbTransport::UnspecifiedMeans] - || !self.unknown_query.is_empty() - } - - fn query_params(&self) -> IndexMap { - let mut query_params: IndexMap = IndexMap::new(); - if let Some(expiry) = self.expiry { - query_params.insert(EXPIRY.to_string(), expiry.to_string()); - } - if self.transports != vec![RgbTransport::UnspecifiedMeans] { - let mut transports: Vec = vec![]; - for transport in self.transports.clone() { - transports.push(transport.to_string()); - } - query_params.insert(ENDPOINTS.to_string(), transports.join(&TRANSPORT_SEP.to_string())); - } - query_params.extend(self.unknown_query.clone()); - query_params - } -} - -impl Display for RgbTransport { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - RgbTransport::JsonRpc { tls, host } => { - let s = if *tls { "s" } else { "" }; - write!(f, "rpc{s}{TRANSPORT_HOST_SEP}{}", host)?; - } - RgbTransport::RestHttp { tls, host } => { - let s = if *tls { "s" } else { "" }; - write!(f, "http{s}{TRANSPORT_HOST_SEP}{}", host)?; - } - RgbTransport::WebSockets { tls, host } => { - let s = if *tls { "s" } else { "" }; - write!(f, "ws{s}{TRANSPORT_HOST_SEP}{}", host)?; - } - RgbTransport::Storm {} => { - write!(f, "storm{TRANSPORT_HOST_SEP}_/")?; - } - RgbTransport::UnspecifiedMeans => {} - }; - Ok(()) - } -} - -impl FromStr for RgbTransport { - type Err = TransportParseError; - - fn from_str(s: &str) -> Result { - let tokens = s.split_once(TRANSPORT_HOST_SEP); - if tokens.is_none() { - return Err(TransportParseError::InvalidTransport(s.to_string())); - } - let (trans_type, host) = tokens.unwrap(); - if host.is_empty() { - return Err(TransportParseError::InvalidTransportHost(host.to_string())); - } - let host = host.to_string(); - let transport = match trans_type { - "rpc" => RgbTransport::JsonRpc { tls: false, host }, - "rpcs" => RgbTransport::JsonRpc { tls: true, host }, - "http" => RgbTransport::RestHttp { tls: false, host }, - "https" => RgbTransport::RestHttp { tls: true, host }, - "ws" => RgbTransport::WebSockets { tls: false, host }, - "wss" => RgbTransport::WebSockets { tls: true, host }, - "storm" => RgbTransport::Storm {}, - _ => return Err(TransportParseError::InvalidTransport(s.to_string())), - }; - Ok(transport) - } -} - -impl Display for XChainNet { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}:", self.chain_network())?; - match self.into_inner() { - Beneficiary::BlindedSeal(seal) => Display::fmt(&seal, f), - Beneficiary::WitnessVout(payload) => payload.fmt_baid64(f), - } - } -} - -impl FromStr for ChainNet { - type Err = InvoiceParseError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase() { - x if ChainNet::BitcoinMainnet.to_string() == x => Ok(ChainNet::BitcoinMainnet), - x if ChainNet::BitcoinTestnet.to_string() == x => Ok(ChainNet::BitcoinTestnet), - x if ChainNet::BitcoinSignet.to_string() == x => Ok(ChainNet::BitcoinSignet), - x if ChainNet::BitcoinRegtest.to_string() == x => Ok(ChainNet::BitcoinRegtest), - x if ChainNet::LiquidMainnet.to_string() == x => Ok(ChainNet::BitcoinMainnet), - x if ChainNet::LiquidTestnet.to_string() == x => Ok(ChainNet::LiquidTestnet), - _ => Err(InvoiceParseError::Beneficiary(s.to_owned())), - } - } -} - -impl DisplayBaid64<34> for Pay2Vout { - const HRI: &'static str = "wvout"; - const CHUNKING: bool = true; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = true; - const MNEMONIC: bool = false; - - fn to_baid64_payload(&self) -> [u8; 34] { - let mut payload = [0u8; 34]; - // tmp stack array to store the tr payload to resolve lifetime issue - let schnorr_pk: [u8; 32]; - payload[0] = self.method as u8; - let (addr_type, spk) = match &self.address { - AddressPayload::Pkh(pkh) => (Self::P2PKH, pkh.as_ref()), - AddressPayload::Sh(sh) => (Self::P2SH, sh.as_ref()), - AddressPayload::Wpkh(wpkh) => (Self::P2WPKH, wpkh.as_ref()), - AddressPayload::Wsh(wsh) => (Self::P2WSH, wsh.as_ref()), - AddressPayload::Tr(tr) => { - schnorr_pk = tr.to_byte_array(); - (Self::P2TR, &schnorr_pk[..]) - } - }; - payload[1] = addr_type; - Cursor::new(&mut payload[2..]) - .write_all(spk) - .expect("address payload always less than 32 bytes"); - payload - } -} - -impl Display for Pay2Vout { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} -impl FromBaid64Str<34> for Pay2Vout {} -impl FromStr for Pay2Vout { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} - -impl FromStr for XChainNet { - type Err = InvoiceParseError; - - fn from_str(s: &str) -> Result { - let Some((cn, beneficiary)) = s.split_once(':') else { - return Err(InvoiceParseError::Beneficiary(s.to_owned())); - }; - let cn = ChainNet::from_str(cn)?; - if let Ok(seal) = SecretSeal::from_str(beneficiary) { - return Ok(XChainNet::with(cn, Beneficiary::BlindedSeal(seal))); - } - - let payload = Pay2Vout::from_str(beneficiary)?; - Ok(XChainNet::with(cn, Beneficiary::WitnessVout(payload))) - } -} - -impl Display for RgbInvoice { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - // TODO: Support attachment through invoice params - if let Some(contract) = self.contract { - let id = if f.alternate() { - contract.to_string().replace('-', "") - } else { - contract.to_string() - }; - write!(f, "{id}/")?; - } else { - write!(f, "rgb:{OMITTED}/")?; - } - if let Some(iface) = self.iface.clone() { - write!(f, "{iface}/")?; - } else { - write!(f, "{OMITTED}/")?; - } - if let Some(ref op) = self.operation { - write!(f, "{op}/")?; - } - if let Some(ref assignment_name) = self.assignment { - write!(f, "{assignment_name}/")?; - } - if let Some(state) = self.state.as_ref() { - write!(f, "{state}+")?; - } - let beneficiary = if f.alternate() { - self.beneficiary.to_string().replace('-', "") - } else { - self.beneficiary.to_string() - }; - f.write_str(&beneficiary)?; - if self.has_params() { - f.write_str("?")?; - } - let query_params = self.query_params(); - for (key, val) in query_params.iter().take(1) { - write!( - f, - "{}={}", - utf8_percent_encode(key, QUERY_ENCODE), - utf8_percent_encode(val, QUERY_ENCODE) - )?; - } - for (key, val) in query_params.iter().skip(1) { - write!( - f, - "&{}={}", - utf8_percent_encode(key, QUERY_ENCODE), - utf8_percent_encode(val, QUERY_ENCODE) - )?; - } - Ok(()) - } -} - -impl FromStr for RgbInvoice { - type Err = InvoiceParseError; - - fn from_str(s: &str) -> Result { - // TODO: Support attachment through invoice params - let uri = Uri::parse(s)?; - - let scheme = uri.scheme().ok_or(InvoiceParseError::AbsentScheme)?; - if scheme.as_str() != "rgb" { - return Err(InvoiceParseError::InvalidScheme(scheme.to_string())); - } - - let path = uri.path(); - if path.is_absolute() || uri.authority().is_some() { - return Err(InvoiceParseError::Authority); - } - - let mut path = path.segments(); - - let Some(contract_id_str) = path.next() else { - return Err(InvoiceParseError::ContractMissed); - }; - let contract = match ContractId::from_str(contract_id_str.as_str()) { - Ok(cid) => Some(cid), - Err(_) if contract_id_str.as_str() == OMITTED => None, - Err(_) => { - return Err(InvoiceParseError::InvalidContractId(contract_id_str.to_string())); - } - }; - - let Some(iface_str) = path.next() else { - return Err(InvoiceParseError::IfaceMissed); - }; - let iface = match TypeName::try_from(iface_str.to_string()) { - Ok(i) => Some(i), - Err(_) if iface_str.as_str() == OMITTED => None, - Err(_) => return Err(InvoiceParseError::InvalidIface(iface_str.to_string())), - }; - if contract.is_some() && iface.is_none() { - return Err(InvoiceParseError::ContractIdNoIface); - } - - let Some(assignment) = path.next() else { - return Err(InvoiceParseError::AssignmentMissed); - }; - let (state, beneficiary) = assignment - .as_str() - .split_once('+') - .map(|(a, b)| (Some(a), Some(b))) - .unwrap_or((Some(assignment.as_str()), None)); - let (beneficiary_str, state) = match (beneficiary, state) { - (Some(b), Some(a)) => (b, Some(StateData::from_str(a)?)), - (None, Some(b)) => (b, None), - _ => unreachable!(), - }; - - let beneficiary = XChainNet::::from_str(beneficiary_str)?; - let mut query_params = map_query_params(&uri)?; - - let transports = if let Some(endpoints) = query_params.shift_remove(ENDPOINTS) { - let tokens = endpoints.split(TRANSPORT_SEP); - let mut transport_vec: Vec = vec![]; - for token in tokens { - transport_vec.push( - RgbTransport::from_str(token) - .map_err(|e| InvoiceParseError::InvalidQueryParam(e.to_string()))?, - ); - } - transport_vec - } else { - vec![RgbTransport::UnspecifiedMeans] - }; - - let mut expiry = None; - if let Some(exp) = query_params.shift_remove(EXPIRY) { - let timestamp = exp - .parse::() - .map_err(|e| InvoiceParseError::InvalidExpiration(e.to_string()))?; - expiry = Some(timestamp); - } - - Ok(RgbInvoice { - transports, - contract, - iface, - operation: None, - assignment: None, - beneficiary, - state, - expiry, - unknown_query: query_params, - }) - } -} - -fn percent_decode(estr: &EStr) -> Result { - Ok(estr - .decode() - .into_string() - .map_err(|e| InvoiceParseError::InvalidQueryParam(e.to_string()))? - .to_string()) -} - -fn map_query_params(uri: &Uri<&str>) -> Result, InvoiceParseError> { - let mut map: IndexMap = IndexMap::new(); - if let Some(q) = uri.query() { - let params = q.split('&'); - for p in params { - if let Some((k, v)) = p.split_once('=') { - map.insert(percent_decode(k)?, percent_decode(v)?); - } else { - return Err(InvoiceParseError::InvalidQueryParam(p.to_string())); - } - } - } - Ok(map) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn parse() { - // rgb20/rgb25 parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.state, Some(StateData::from_checked(vec![100, 0, 0, 0, 0, 0, 0, 0]))); - assert_eq!(invoice.to_string(), invoice_str); - - // rgb21 parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB21/\ - -p----p---------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!( - invoice.state, - Some(StateData::from_checked(vec![1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0])) - ); - assert_eq!(invoice.to_string(), invoice_str); - - // no amount - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // no allocation - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB21/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // no contract ID - let invoice_str = - "rgb:~/RGB20/bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // no contract ID nor iface - let invoice_str = "rgb:~/~/bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // contract ID provided but no iface - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/~/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::ContractIdNoIface))); - - // invalid contract ID - let invalid_contract_id = "invalid"; - let invoice_str = format!( - "rgb:{invalid_contract_id}/RGB20/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F" - ); - let result = RgbInvoice::from_str(&invoice_str); - assert!(matches!(result, - Err(InvoiceParseError::InvalidContractId(c)) if c == invalid_contract_id)); - - // with expiration - let invoice_str = - "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry=1682086371"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // bad expiration - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry=six"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidExpiration(_)))); - - // with bad query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); - - // with an unknown query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?unknown=new"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // with two unknown query parameters - let invoice_str = - "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?unknown=new&another=new"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // with expiration and an unknown query parameter - let invoice_str = - "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry=1682086371&unknown=new"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.to_string(), invoice_str); - - // with an unknown query parameter containing percent-encoded text - let invoice_base = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?"; - let query_key_encoded = ":@-%20%23"; - let query_key_decoded = ":@- #"; - let query_val_encoded = "?/.%26%3D"; - let query_val_decoded = "?/.&="; - let invoice = - RgbInvoice::from_str(&format!("{invoice_base}{query_key_encoded}={query_val_encoded}")) - .unwrap(); - let query_params = invoice.query_params(); - assert_eq!(query_params[query_key_decoded], query_val_decoded); - assert_eq!( - invoice.to_string(), - format!("{invoice_base}{query_key_encoded}={query_val_encoded}") - ); - - // no scheme - let invoice_str = "2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/~/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::AbsentScheme))); - - // invalid scheme - let invoice_str = "bad:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/~/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidScheme(_)))); - - // empty transport endpoint specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints="; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); - - // invalid transport endpoint specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=bad"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); - - // invalid transport variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpca:/\ - /host.example.com"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); - - // rgb-rpc variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://\ - host.example.com"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.transports, vec![RgbTransport::JsonRpc { - tls: false, - host: "host.example.com".to_string() - }]); - assert_eq!(invoice.to_string(), invoice_str); - - // rgb-rpc variant, host containing authentication, "-" characters and port - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs:/\ - /user:pass@host-1.ex-ample.com:1234"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.transports, vec![RgbTransport::JsonRpc { - tls: true, - host: "user:pass@host-1.ex-ample.com:1234".to_string() - }]); - assert_eq!(invoice.to_string(), invoice_str); - - // rgb-rpc variant, IPv6 host - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs:/\ - /%5B2001:db8::1%5D:1234"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.transports, vec![RgbTransport::JsonRpc { - tls: true, - host: "[2001:db8::1]:1234".to_string() - }]); - assert_eq!(invoice.to_string(), invoice_str); - - // rgb-rpc variant with missing host - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); - - // rgb-rpc variant with invalid separator - let invoice_str = - "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc/host.example.com"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); - - // rgb-rpc variant with invalid transport host specification - let invoice_str = - "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://ho]t"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::Uri(_)))); - - // rgb+http variant - let invoice_str = "rgb:\ - 11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=https://\ - host.example.com"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - let transports = vec![RgbTransport::RestHttp { - tls: true, - host: "host.example.com".to_string(), - }]; - assert_eq!(invoice.transports, transports); - assert_eq!(invoice.to_string(), invoice_str); - - // rgb+ws variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=wss://\ - host.example.com"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - let transports = vec![RgbTransport::WebSockets { - tls: true, - host: "host.example.com".to_string(), - }]; - assert_eq!(invoice.transports, transports); - assert_eq!(invoice.to_string(), invoice_str); - - // TODO: rgb+storm variant - - // multiple transports - let invoice_str = "rgb:\ - 11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - y----------+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs://\ - host1.example.com,http://host2.example.com,ws://host3.example.com"; - let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - let transports = vec![ - RgbTransport::JsonRpc { - tls: true, - host: "host1.example.com".to_string(), - }, - RgbTransport::RestHttp { - tls: false, - host: "host2.example.com".to_string(), - }, - RgbTransport::WebSockets { - tls: false, - host: "host3.example.com".to_string(), - }, - ]; - assert_eq!(invoice.transports, transports); - assert_eq!(invoice.to_string(), invoice_str); - - // empty transport parse error - let result = RgbTransport::from_str(""); - assert!(matches!(result, Err(TransportParseError::InvalidTransport(_)))); - - // invalid transport parse error - let result = RgbTransport::from_str("bad"); - assert!(matches!(result, Err(TransportParseError::InvalidTransport(_)))); - - // invalid transport variant parse error - let result = RgbTransport::from_str("rpca://host.example.com"); - assert!(matches!(result, Err(TransportParseError::InvalidTransport(_)))); - - // rgb-rpc variant with missing host parse error - let result = RgbTransport::from_str("rpc://"); - assert!(matches!(result, Err(TransportParseError::InvalidTransportHost(_)))); - - // rgb-rpc variant with invalid separator parse error - let result = RgbTransport::from_str("rpc/host.example.com"); - assert!(matches!(result, Err(TransportParseError::InvalidTransport(_)))); - } - - #[test] - fn pay2vout_parse() { - let p = Pay2Vout { - method: bp::dbc::Method::OpretFirst, - address: AddressPayload::Pkh([0xff; 20].into()), - }; - assert_eq!(Pay2Vout::from_str(&p.to_string()).unwrap(), p); - - let p = Pay2Vout { - method: bp::dbc::Method::OpretFirst, - address: AddressPayload::Sh([0xff; 20].into()), - }; - assert_eq!(Pay2Vout::from_str(&p.to_string()).unwrap(), p); - - let p = Pay2Vout { - method: bp::dbc::Method::OpretFirst, - address: AddressPayload::Wpkh([0xff; 20].into()), - }; - assert_eq!(Pay2Vout::from_str(&p.to_string()).unwrap(), p); - - let p = Pay2Vout { - method: bp::dbc::Method::OpretFirst, - address: AddressPayload::Wsh([0xff; 32].into()), - }; - assert_eq!(Pay2Vout::from_str(&p.to_string()).unwrap(), p); - - let p = Pay2Vout { - method: bp::dbc::Method::OpretFirst, - address: AddressPayload::Tr( - bp::OutputPk::from_byte_array([ - 0x85, 0xa6, 0x42, 0x59, 0x8b, 0xfe, 0x2e, 0x42, 0xa3, 0x78, 0xcb, 0xb5, 0x3b, - 0xf1, 0x4a, 0xbe, 0x77, 0xf8, 0x1a, 0xef, 0xed, 0xf7, 0x3b, 0x66, 0x7b, 0x42, - 0x85, 0xaf, 0x7c, 0xf1, 0xc8, 0xa3, - ]) - .unwrap(), - ), - }; - assert_eq!(Pay2Vout::from_str(&p.to_string()).unwrap(), p); - } -} diff --git a/src/bp/anchor.rs b/src/bp/anchor.rs new file mode 100644 index 00000000..e8216856 --- /dev/null +++ b/src/bp/anchor.rs @@ -0,0 +1,39 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 amplify::confinement::SmallOrdMap; +use rgb::ContractId; + +pub struct SubAnchor { + pub mmb_proof: mmb::BundleProof, + #[cfg_attr(feature = "serde", serde(skip))] + // TODO: This should become an option once fallback proofs are ready + pub fallback_proof: ReservedBytes<1>, +} + +pub struct SuperAnchor { + pub mpc_proof: mpc::MerkleBlock, + pub dbc_proof: D, + pub contracts: SmallOrdMap, +} diff --git a/src/bp/mod.rs b/src/bp/mod.rs new file mode 100644 index 00000000..6f061482 --- /dev/null +++ b/src/bp/mod.rs @@ -0,0 +1,26 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +mod anchor; +pub mod seals; diff --git a/src/containers/seal.rs b/src/bp/seals.rs similarity index 82% rename from src/containers/seal.rs rename to src/bp/seals.rs index 6e044604..95c5009c 100644 --- a/src/containers/seal.rs +++ b/src/bp/seals.rs @@ -1,23 +1,26 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning +// Standard Library for RGB smart contracts // // SPDX-License-Identifier: Apache-2.0 // -// Written in 2019-2024 by -// Dr Maxim Orlovsky +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky // -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 +// 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 +// 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. +// 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. #![doc = include_str!("seals.md")] diff --git a/src/containers/anchors.rs b/src/containers/anchors.rs deleted file mode 100644 index 0a346a0c..00000000 --- a/src/containers/anchors.rs +++ /dev/null @@ -1,505 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::cmp::Ordering; -use std::vec; - -use amplify::ByteArray; -use bp::dbc::opret::OpretProof; -use bp::dbc::tapret::TapretProof; -use bp::dbc::{anchor, Anchor}; -use bp::{dbc, Tx, Txid}; -use commit_verify::mpc; -use rgb::validation::{DbcProof, EAnchor}; -use rgb::{ - BundleId, DiscloseHash, OpId, Operation, Transition, TransitionBundle, XChain, XGraphSeal, - XWitnessId, -}; -use strict_encoding::StrictDumb; - -use crate::containers::Dichotomy; -use crate::{MergeReveal, MergeRevealError, LIB_NAME_RGB_STD}; - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error)] -#[display("state transition {0} is not a part of the bundle.")] -pub struct UnrelatedTransition(OpId, Transition); - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum AnchoredBundleMismatch { - /// witness bundle for witness id {0} already has both opret and tapret information. - AlreadyDouble(XWitnessId), - /// the combined anchored bundles for witness id {0} are of the same type. - SameBundleType(XWitnessId), -} - -#[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 SealWitness { - pub public: XPubWitness, - pub anchors: AnchorSet, -} - -impl SealWitness { - pub fn new(witness: XPubWitness, anchors: AnchorSet) -> Self { - SealWitness { - public: witness, - anchors, - } - } - - pub fn witness_id(&self) -> XWitnessId { self.public.to_witness_id() } -} - -pub type XPubWitness = XChain; - -pub trait ToWitnessId { - fn to_witness_id(&self) -> XWitnessId; -} - -impl ToWitnessId for XPubWitness { - fn to_witness_id(&self) -> XWitnessId { self.map_ref(|w| w.txid()) } -} - -impl MergeReveal for XPubWitness { - fn merge_reveal(self, other: Self) -> Result { - match (self, other) { - (XChain::Bitcoin(one), XChain::Bitcoin(two)) => { - one.merge_reveal(two).map(XChain::Bitcoin) - } - (XChain::Liquid(one), XChain::Liquid(two)) => one.merge_reveal(two).map(XChain::Liquid), - (XChain::Bitcoin(bitcoin), XChain::Liquid(liquid)) - | (XChain::Liquid(liquid), XChain::Bitcoin(bitcoin)) => { - Err(MergeRevealError::ChainMismatch { - bitcoin: bitcoin.txid(), - liquid: liquid.txid(), - }) - } - _ => unreachable!(), - } - } -} - -#[derive(Clone, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom, dumb = Self::Txid(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum PubWitness { - #[strict_type(tag = 0x00)] - Txid(Txid), - #[strict_type(tag = 0x01)] - Tx(Tx), /* TODO: Consider using `UnsignedTx` here - * TODO: Add SPV as an option here */ -} - -impl PartialEq for PubWitness { - fn eq(&self, other: &Self) -> bool { self.txid() == other.txid() } -} - -impl Ord for PubWitness { - fn cmp(&self, other: &Self) -> Ordering { self.txid().cmp(&other.txid()) } -} - -impl PartialOrd for PubWitness { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl PubWitness { - pub fn new(txid: Txid) -> Self { Self::Txid(txid) } - - pub fn with(tx: Tx) -> Self { Self::Tx(tx) } - - pub fn txid(&self) -> Txid { - match self { - PubWitness::Txid(txid) => *txid, - PubWitness::Tx(tx) => tx.txid(), - } - } - - pub fn tx(&self) -> Option<&Tx> { - match self { - PubWitness::Txid(_) => None, - PubWitness::Tx(tx) => Some(tx), - } - } - - pub fn merge_reveal(self, other: Self) -> Result { - match (self, other) { - (Self::Txid(txid1), Self::Txid(txid2)) if txid1 == txid2 => Ok(Self::Txid(txid1)), - (Self::Txid(txid), Self::Tx(tx)) | (Self::Txid(txid), Self::Tx(tx)) - if txid == tx.txid() => - { - Ok(Self::Tx(tx)) - } - // TODO: tx1 and tx2 may differ on their witness data; take the one having most of the - // witness - (Self::Tx(tx1), Self::Tx(tx2)) if tx1.txid() == tx2.txid() => Ok(Self::Tx(tx1)), - (a, b) => Err(MergeRevealError::TxidMismatch(a.txid(), b.txid())), - } - } -} - -#[derive(Clone, Eq, 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") -)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = DiscloseHash)] -pub struct WitnessBundle { - pub pub_witness: XPubWitness, - pub anchored_bundles: AnchoredBundles, -} - -impl PartialEq for WitnessBundle { - fn eq(&self, other: &Self) -> bool { self.pub_witness == other.pub_witness } -} - -impl Ord for WitnessBundle { - fn cmp(&self, other: &Self) -> Ordering { self.pub_witness.cmp(&other.pub_witness) } -} - -impl PartialOrd for WitnessBundle { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl WitnessBundle { - #[inline] - pub fn with(pub_witness: XPubWitness, anchored_bundle: ClientBundle) -> Self { - Self { - pub_witness, - anchored_bundles: AnchoredBundles::from(anchored_bundle), - } - } - - pub fn into_double(mut self, other: ClientBundle) -> Result { - match (self.anchored_bundles, other.dbc_proof) { - (AnchoredBundles::Double { .. }, _) => { - return Err(AnchoredBundleMismatch::AlreadyDouble( - self.pub_witness.to_witness_id(), - )); - } - (AnchoredBundles::Opret(opret), DbcProof::Tapret(tapret)) => { - self.anchored_bundles = AnchoredBundles::Double { - tapret: ClientBundle::new(other.mpc_proof, tapret, other.bundle), - opret, - } - } - (AnchoredBundles::Tapret(tapret), DbcProof::Opret(opret)) => { - self.anchored_bundles = AnchoredBundles::Double { - opret: ClientBundle::new(other.mpc_proof, opret, other.bundle), - tapret, - } - } - _ => { - return Err(AnchoredBundleMismatch::SameBundleType( - self.pub_witness.to_witness_id(), - )); - } - } - Ok(self) - } - - pub fn witness_id(&self) -> XWitnessId { self.pub_witness.to_witness_id() } - - pub fn reveal_seal(&mut self, bundle_id: BundleId, seal: XGraphSeal) -> bool { - let bundle = match &mut self.anchored_bundles { - AnchoredBundles::Tapret(tapret) | AnchoredBundles::Double { tapret, .. } - if tapret.bundle.bundle_id() == bundle_id => - { - Some(&mut tapret.bundle) - } - AnchoredBundles::Opret(opret) | AnchoredBundles::Double { opret, .. } - if opret.bundle.bundle_id() == bundle_id => - { - Some(&mut opret.bundle) - } - _ => None, - }; - let Some(bundle) = bundle else { - return false; - }; - bundle - .known_transitions - .values_mut() - .flat_map(|t| t.assignments.values_mut()) - .for_each(|a| a.reveal_seal(seal)); - - true - } - - pub fn anchored_bundles(&self) -> impl Iterator { - self.anchored_bundles.iter() - } - - #[inline] - pub fn known_transitions(&self) -> impl Iterator { - self.anchored_bundles - .bundles() - .flat_map(|bundle| bundle.known_transitions.values()) - } -} - -/// Keeps client-side data - a combination of client-side witness (anchor) and state (transition -/// bundle). Ensures that transition bundle uses the same DBC close method as used by the -/// client-side witness (anchor). -#[derive(Clone, PartialEq, Eq, 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 ClientBundle { - mpc_proof: mpc::MerkleProof, - dbc_proof: D, - bundle: TransitionBundle, -} - -impl ClientBundle { - /// # Panics - /// - /// Panics if DBC proof and bundle have different closing methods - pub fn new(mpc_proof: mpc::MerkleProof, dbc_proof: D, bundle: TransitionBundle) -> Self { - assert_eq!(dbc_proof.method(), bundle.close_method); - Self { - mpc_proof, - dbc_proof, - bundle, - } - } - - #[inline] - pub fn bundle_id(&self) -> BundleId { self.bundle.bundle_id() } - - pub fn reveal_transition( - &mut self, - transition: Transition, - ) -> Result { - let opid = transition.id(); - if self.bundle.input_map.values().all(|id| *id != opid) { - return Err(UnrelatedTransition(opid, transition)); - } - if self.bundle.known_transitions.contains_key(&opid) { - return Ok(false); - } - self.bundle - .known_transitions - .insert(opid, transition) - .expect("same size as input map"); - Ok(true) - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum AnchoredBundles { - #[strict_type(tag = 0x01)] - Tapret(ClientBundle), - #[strict_type(tag = 0x02)] - Opret(ClientBundle), - #[strict_type(tag = 0x03)] - Double { - tapret: ClientBundle, - opret: ClientBundle, - }, -} - -impl StrictDumb for AnchoredBundles { - fn strict_dumb() -> Self { Self::Opret(strict_dumb!()) } -} - -impl From for AnchoredBundles { - fn from(ab: ClientBundle) -> Self { - match ab.dbc_proof { - DbcProof::Opret(proof) => { - Self::Opret(ClientBundle::::new(ab.mpc_proof, proof, ab.bundle)) - } - DbcProof::Tapret(proof) => { - Self::Tapret(ClientBundle::::new(ab.mpc_proof, proof, ab.bundle)) - } - } - } -} - -impl AnchoredBundles { - pub fn bundles(&self) -> impl Iterator { - match self { - AnchoredBundles::Tapret(tapret) => Dichotomy::single(&tapret.bundle), - AnchoredBundles::Opret(opret) => Dichotomy::single(&opret.bundle), - AnchoredBundles::Double { tapret, opret } => { - Dichotomy::double(&tapret.bundle, &opret.bundle) - } - } - .into_iter() - } - - pub fn into_bundles(self) -> impl Iterator { - match self { - AnchoredBundles::Tapret(tapret) => Dichotomy::single(tapret.bundle), - AnchoredBundles::Opret(opret) => Dichotomy::single(opret.bundle), - AnchoredBundles::Double { tapret, opret } => { - Dichotomy::double(tapret.bundle, opret.bundle) - } - } - .into_iter() - } - - pub fn iter(&self) -> impl Iterator { - match self { - AnchoredBundles::Tapret(tapret) => { - let anchor = - EAnchor::new(tapret.mpc_proof.clone(), tapret.dbc_proof.clone().into()); - Dichotomy::single((anchor, &tapret.bundle)) - } - AnchoredBundles::Opret(opret) => { - let anchor = EAnchor::new(opret.mpc_proof.clone(), opret.dbc_proof.into()); - Dichotomy::single((anchor, &opret.bundle)) - } - AnchoredBundles::Double { tapret, opret } => { - let tapret_anchor = - EAnchor::new(tapret.mpc_proof.clone(), tapret.dbc_proof.clone().into()); - let opret_anchor = EAnchor::new(opret.mpc_proof.clone(), opret.dbc_proof.into()); - Dichotomy::double((tapret_anchor, &tapret.bundle), (opret_anchor, &opret.bundle)) - } - } - .into_iter() - } -} - -impl IntoIterator for AnchoredBundles { - type Item = (EAnchor, TransitionBundle); - type IntoIter = vec::IntoIter<(EAnchor, TransitionBundle)>; - - fn into_iter(self) -> Self::IntoIter { - match self { - AnchoredBundles::Tapret(tapret) => { - let anchor = EAnchor::new(tapret.mpc_proof, tapret.dbc_proof.into()); - Dichotomy::single((anchor, tapret.bundle)) - } - AnchoredBundles::Opret(opret) => { - let anchor = EAnchor::new(opret.mpc_proof, opret.dbc_proof.into()); - Dichotomy::single((anchor, opret.bundle)) - } - AnchoredBundles::Double { tapret, opret } => { - let tapret_anchor = EAnchor::new(tapret.mpc_proof, tapret.dbc_proof.into()); - let opret_anchor = EAnchor::new(opret.mpc_proof, opret.dbc_proof.into()); - Dichotomy::double((tapret_anchor, tapret.bundle), (opret_anchor, opret.bundle)) - } - } - .into_iter() - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum AnchorSet { - #[strict_type(tag = 0x01)] - Tapret(Anchor), - #[strict_type(tag = 0x02)] - Opret(Anchor), - #[strict_type(tag = 0x03)] - Double { - tapret: Anchor, - opret: Anchor, - }, -} - -impl StrictDumb for AnchorSet { - fn strict_dumb() -> Self { Self::Opret(strict_dumb!()) } -} - -impl AnchorSet { - pub fn known_bundle_ids(&self) -> impl Iterator { - let map = match self { - AnchorSet::Tapret(tapret) => tapret.mpc_proof.to_known_message_map().release(), - AnchorSet::Opret(opret) => opret.mpc_proof.to_known_message_map().release(), - AnchorSet::Double { tapret, opret } => { - let mut map = tapret.mpc_proof.to_known_message_map().release(); - map.extend(opret.mpc_proof.to_known_message_map().release()); - map - } - }; - map.into_values() - .map(|msg| BundleId::from_byte_array(msg.to_byte_array())) - } - - pub fn has_tapret(&self) -> bool { matches!(self, Self::Tapret(_) | Self::Double { .. }) } - - pub fn has_opret(&self) -> bool { matches!(self, Self::Opret(_) | Self::Double { .. }) } - - pub fn merge_reveal(self, other: Self) -> Result { - match (self, other) { - (Self::Tapret(anchor), Self::Tapret(a)) => Ok(Self::Tapret(anchor.merge_reveal(a)?)), - (Self::Opret(anchor), Self::Opret(a)) => Ok(Self::Opret(anchor.merge_reveal(a)?)), - (Self::Tapret(tapret), Self::Opret(opret)) - | (Self::Opret(opret), Self::Tapret(tapret)) => Ok(Self::Double { tapret, opret }), - - (Self::Double { tapret, opret }, Self::Tapret(t)) - | (Self::Tapret(t), Self::Double { tapret, opret }) => Ok(Self::Double { - tapret: tapret.merge_reveal(t)?, - opret, - }), - - (Self::Double { tapret, opret }, Self::Opret(o)) - | (Self::Opret(o), Self::Double { tapret, opret }) => Ok(Self::Double { - tapret, - opret: opret.merge_reveal(o)?, - }), - ( - Self::Double { tapret, opret }, - Self::Double { - tapret: t, - opret: o, - }, - ) => Ok(Self::Double { - tapret: tapret.merge_reveal(t)?, - opret: opret.merge_reveal(o)?, - }), - } - } -} diff --git a/src/containers/consignment.rs b/src/containers/consignment.rs deleted file mode 100644 index f76d4162..00000000 --- a/src/containers/consignment.rs +++ /dev/null @@ -1,582 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::BTreeSet; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::ops::Deref; -use std::str::FromStr; - -use aluvm::library::Lib; -use amplify::confinement::{ - Confined, LargeOrdSet, MediumBlob, SmallOrdMap, SmallOrdSet, TinyOrdMap, TinyOrdSet, -}; -use amplify::{ByteArray, Bytes32}; -use armor::{ArmorHeader, AsciiArmor, StrictArmor, StrictArmorError}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use commit_verify::{CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::validation::{ResolveWitness, Validator, Validity, Warning, CONSIGNMENT_MAX_LIBS}; -use rgb::{ - impl_serde_baid64, validation, AttachId, BundleId, ContractId, Extension, Genesis, GraphSeal, - Operation, Schema, SchemaId, XChain, -}; -use rgbcore::validation::ConsignmentApi; -use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize}; -use strict_types::TypeSystem; - -use super::{ - ContainerVer, ContentId, ContentSigs, IndexedConsignment, Supplement, WitnessBundle, - 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}; -use crate::resolvers::ConsignmentResolver; -use crate::{SecretSeal, LIB_NAME_RGB_STD}; - -pub type Transfer = Consignment; -pub type Contract = Consignment; - -pub trait ConsignmentExt { - fn contract_id(&self) -> ContractId; - fn schema_id(&self) -> SchemaId; - fn schema(&self) -> &Schema; - fn genesis(&self) -> &Genesis; - fn extensions(&self) -> impl Iterator; - fn bundled_witnesses(&self) -> impl Iterator; -} - -impl ConsignmentExt for &C { - #[inline] - fn contract_id(&self) -> ContractId { (*self).contract_id() } - - #[inline] - fn schema_id(&self) -> SchemaId { (*self).schema_id() } - - #[inline] - fn schema(&self) -> &Schema { (*self).schema() } - - #[inline] - fn genesis(&self) -> &Genesis { (*self).genesis() } - - #[inline] - fn extensions(&self) -> impl Iterator { (*self).extensions() } - - #[inline] - fn bundled_witnesses(&self) -> impl Iterator { - (*self).bundled_witnesses() - } -} - -/// Interface identifier. -/// -/// Interface identifier commits to all the interface data. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -pub struct ConsignmentId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for ConsignmentId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for ConsignmentId { - const TAG: &'static str = "urn:lnp-bp:rgb:consignment#2024-03-11"; -} - -impl DisplayBaid64 for ConsignmentId { - const HRI: &'static str = "rgb:csg"; - const CHUNKING: bool = true; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = true; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for ConsignmentId {} -impl FromStr for ConsignmentId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for ConsignmentId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(ConsignmentId); - -impl ConsignmentId { - pub const fn from_array(id: [u8; 32]) -> Self { Self(Bytes32::from_array(id)) } -} - -pub type ValidContract = ValidConsignment; -pub type ValidTransfer = ValidConsignment; - -#[derive(Clone, Debug, Display)] -#[display("{consignment}")] -pub struct ValidConsignment { - /// Status of the latest validation. - validation_status: validation::Status, - consignment: Consignment, -} - -impl ValidConsignment { - pub fn validation_status(&self) -> &validation::Status { &self.validation_status } - - pub fn into_consignment(self) -> Consignment { self.consignment } - - pub fn into_validation_status(self) -> validation::Status { self.validation_status } - - pub fn split(self) -> (Consignment, validation::Status) { - (self.consignment, self.validation_status) - } -} - -impl Deref for ValidConsignment { - type Target = Consignment; - - fn deref(&self) -> &Self::Target { &self.consignment } -} - -/// Consignment represents contract-specific data, always starting with genesis, -/// which must be valid under client-side-validation rules (i.e. internally -/// consistent and properly committed into the commitment layer, like bitcoin -/// blockchain or current state of the lightning channel). -/// -/// All consignments-related procedures, including validation or merging -/// consignments data into stash or schema-specific data storage, must start -/// with `endpoints` and process up to the genesis. -#[derive(Clone, Debug, Display)] -#[display(AsciiArmor::to_ascii_armored_string)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode, PartialEq)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Consignment { - /// Version. - pub version: ContainerVer, - - /// Specifies whether the consignment contains information about state - /// transfer (true), or it is just a consignment with an information about a - /// contract. - pub transfer: bool, - - /// Set of secret seals which are history terminals. - pub terminals: SmallOrdMap>, - - /// Genesis data. - pub genesis: Genesis, - - /// All state extensions contained in the consignment. - pub extensions: LargeOrdSet, - - /// All bundled state transitions contained in the consignment, together - /// with their witness data. - pub bundles: LargeOrdSet, - - /// Schema (plus root schema, if any) under which contract is issued. - pub schema: Schema, - - /// Interfaces supported by the contract. - pub ifaces: TinyOrdMap, - - /// Known supplements. - pub supplements: TinyOrdSet, - - /// Type system covering all types used in schema, interfaces and - /// implementations. - pub types: TypeSystem, - - /// Collection of scripts used across consignment. - pub scripts: Confined, 0, CONSIGNMENT_MAX_LIBS>, - - /// Data containers coming with this consignment. For the purposes of - /// in-memory consignments we are restricting the size of the containers to - /// 24 bit value (RGB allows containers up to 32-bit values in size). - pub attachments: SmallOrdMap, - - /// Signatures on the pieces of content which are the part of the - /// consignment. - pub signatures: TinyOrdMap, -} - -impl StrictSerialize for Consignment {} -impl StrictDeserialize for Consignment {} - -impl CommitEncode for Consignment { - type CommitmentId = ConsignmentId; - - fn commit_encode(&self, e: &mut CommitEngine) { - e.commit_to_serialized(&self.version); - e.commit_to_serialized(&self.transfer); - - e.commit_to_serialized(&self.contract_id()); - e.commit_to_serialized(&self.genesis.disclose_hash()); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.ifaces.values().map(|iimpl| iimpl.impl_id()), - )); - - e.commit_to_set(&LargeOrdSet::from_iter_checked( - self.bundles.iter().map(WitnessBundle::commit_id), - )); - e.commit_to_set(&LargeOrdSet::from_iter_checked( - self.extensions.iter().map(Extension::disclose_hash), - )); - e.commit_to_map(&self.terminals); - - e.commit_to_set(&SmallOrdSet::from_iter_checked(self.attachments.keys().copied())); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.supplements.iter().map(|suppl| suppl.suppl_id()), - )); - - e.commit_to_serialized(&self.types.id()); - e.commit_to_set(&SmallOrdSet::from_iter_checked(self.scripts.iter().map(|lib| lib.id()))); - - e.commit_to_map(&self.signatures); - } -} - -impl ConsignmentExt for Consignment { - #[inline] - fn contract_id(&self) -> ContractId { self.genesis.contract_id() } - - #[inline] - fn schema_id(&self) -> SchemaId { self.schema.schema_id() } - - #[inline] - fn schema(&self) -> &Schema { &self.schema } - - #[inline] - fn genesis(&self) -> &Genesis { &self.genesis } - - #[inline] - fn extensions(&self) -> impl Iterator { self.extensions.iter() } - - #[inline] - fn bundled_witnesses(&self) -> impl Iterator { self.bundles.iter() } -} - -impl Consignment { - #[inline] - pub fn consignment_id(&self) -> ConsignmentId { self.commit_id() } - - #[inline] - pub fn schema_id(&self) -> SchemaId { self.schema.schema_id() } - - 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 witness_bundle in self.bundles { - for (bundle_id, secret) in &self.terminals { - if let Some(seal) = f(*secret)? { - witness_bundle.reveal_seal(*bundle_id, seal); - } - } - bundles.push(witness_bundle).ok(); - } - self.bundles = bundles; - Ok(self) - } - - pub fn into_contract(self) -> Contract { - Contract { - version: self.version, - transfer: false, - schema: self.schema, - ifaces: self.ifaces, - supplements: self.supplements, - types: self.types, - genesis: self.genesis, - terminals: self.terminals, - bundles: self.bundles, - extensions: self.extensions, - attachments: self.attachments, - signatures: self.signatures, - scripts: self.scripts, - } - } - - pub fn validate( - self, - resolver: &impl ResolveWitness, - // TODO: Add sig validator - //_: &impl SigValidator, - testnet: bool, - ) -> Result, (validation::Status, Consignment)> { - let index = IndexedConsignment::new(&self); - let resolver = ConsignmentResolver { - consignment: &index, - fallback: resolver, - }; - let mut status = Validator::, _, _>::validate( - &index, - &resolver, - testnet, - (&self.schema, self.contract_id()), - ); - - let validity = status.validity(); - - if self.transfer != TRANSFER { - status.add_warning(Warning::Custom(s!("invalid consignment type"))); - } - // check ifaceid match implementation - for (iface, iimpl) in self.ifaces.iter() { - if iface.iface_id() != iimpl.iface_id { - status.add_warning(Warning::Custom(format!( - "implementation {} targets different interface {} than expected {}", - iimpl.impl_id(), - iimpl.iface_id, - iface.iface_id() - ))); - } - } - - // check bundle ids listed in terminals are present in the consignment - for bundle_id in self.terminals.keys() { - if !index.bundle_ids().any(|id| id == *bundle_id) { - status.add_warning(Warning::Custom(format!( - "terminal bundle id {bundle_id} is not present in the consignment" - ))); - } - } - // TODO: check attach ids from data containers are present in operations - // TODO: validate sigs and remove untrusted - // TODO: Check that all extensions present in the consignment are used by state - // transitions - - if validity != Validity::Valid { - Err((status, self)) - } else { - Ok(ValidConsignment { - validation_status: status, - consignment: self, - }) - } - } -} - -impl StrictArmor for Consignment { - type Id = ConsignmentId; - const PLATE_TITLE: &'static str = "RGB CONSIGNMENT"; - - fn armor_id(&self) -> Self::Id { self.commit_id() } - fn armor_headers(&self) -> Vec { - let mut headers = vec![ - ArmorHeader::new(ASCII_ARMOR_VERSION, format!("{:#}", self.version)), - ArmorHeader::new( - ASCII_ARMOR_CONSIGNMENT_TYPE, - if self.transfer { s!("transfer") } else { s!("contract") }, - ), - ArmorHeader::new(ASCII_ARMOR_CONTRACT, self.contract_id().to_string()), - ArmorHeader::new(ASCII_ARMOR_SCHEMA, self.schema.schema_id().to_string()), - ]; - if !self.ifaces.is_empty() { - headers.push(ArmorHeader::with( - ASCII_ARMOR_IFACE, - self.ifaces.keys().map(|iface| iface.name.to_string()), - )); - } - if !self.terminals.is_empty() { - headers.push(ArmorHeader::with( - ASCII_ARMOR_TERMINAL, - self.terminals.keys().map(BundleId::to_string), - )); - } - headers - } - fn parse_armor_headers(&mut self, headers: Vec) -> Result<(), StrictArmorError> { - // TODO: Check remaining headers - terminals, version, iface, contract, schema - if let Some(header) = headers - .iter() - .find(|header| header.title == ASCII_ARMOR_CONSIGNMENT_TYPE) - { - if self.transfer && header.values.len() != 1 && header.values[0] != "transfer" { - // TODO: Add header-specific errors to StrictArmorError - // return Err(Strict) - } - } - Ok(()) - } -} - -// TODO: Remove after header-specific variants are added to StrictArmorError -#[derive(Debug, Display, Error, From)] -pub enum ConsignmentParseError { - #[display(inner)] - #[from] - Armor(armor::StrictArmorError), - - #[display("required consignment type doesn't match the actual type")] - Type, -} - -impl FromStr for Consignment { - type Err = ConsignmentParseError; - fn from_str(s: &str) -> Result { - let consignment = Self::from_ascii_armored_str(s)?; - - if consignment.transfer != TRANSFER { - return Err(ConsignmentParseError::Type); - } - - Ok(consignment) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn contract_str_round_trip() { - let s = include_str!("../../asset/armored_contract.default"); - let mut contract = Contract::from_str(s).unwrap(); - assert_eq!(contract.to_string(), s.replace('\r', ""), "contract string round trip fails"); - contract.transfer = true; - eprintln!("{contract}"); - } - - #[test] - fn error_contract_strs() { - Contract::from_str(include_str!("../../asset/armored_contract.default")).unwrap(); - - // Wrong Id - Contract::from_str( - r#"-----BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:aaaaaaaa-aaaaaaa-aaaaaaa-aaaaaaa-aaaaaaa-aaaaaaa#guide-campus-arctic -Version: 2 -Type: contract -Contract: rgb:qm7P!06T-uuBQT56-ovwOLzx-9Gka7Nb-84Nwo8g-blLb8kw -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: 181748dae0c83cbb44f6ccfdaddf6faca0bc4122a9f35fef47bab9aea023e4a1 - -0ssI2000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#nj! -0000000000000000000000d59ZDjxe00000000dDb8~4rVQz13d2MfXa{vGU00000000000000000000 -0000000000000 - ------END RGB CONSIGNMENT-----"#, - ) - .unwrap_err(); - - // Wrong checksum - Contract::from_str( - r#"-----BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:poAMvm9j-NdapxqA-MJ!5dwP-d!IIt2A-T!5OiXE-Tl54Yew#guide-campus-arctic -Version: 2 -Type: contract -Contract: rgb:qm7P!06T-uuBQT56-ovwOLzx-9Gka7Nb-84Nwo8g-blLb8kw -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - -0ssI2000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#nj! -0000000000000000000000d59ZDjxe00000000dDb8~4rVQz13d2MfXa{vGU00000000000000000000 -0000000000000 - ------END RGB CONSIGNMENT-----"#, - ) - .unwrap_err(); - } - - #[test] - fn transfer_str_round_trip() { - let s = include_str!("../../asset/armored_transfer.default"); - let transfer = Transfer::from_str(s).unwrap(); - assert_eq!(transfer.to_string(), s.replace('\r', ""), "transfer string round trip fails"); - } - - #[test] - fn error_transfer_strs() { - let s = include_str!("../../asset/armored_transfer.default"); - Transfer::from_str(s).unwrap(); - - // Wrong Id - Transfer::from_str( - r#"-----BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:aaaaaaaa-aaaaaaa-aaaaaaa-aaaaaaa-aaaaaaa-aaaaaaa#guide-campus-arctic -Version: 2 -Type: transfer -Contract: rgb:T24t0N1D-eiInTgb-BXlrrXz-$7OgV6n-WJWHPUD-BWNuqZw -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: 562a944631243e23a8de1d2aa2a5621be13351fc6f4d9aa8127c12ac4fb54d97 - -0s#O3000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#nj! -0000000000000000000000d59ZDjxe00000000dDb8~4rVQz13d2MfXa{vGU00000000000000000000 -0000000000000 - ------END RGB CONSIGNMENT-----"#, - ) - .unwrap_err(); - - // Wrong checksum - - Transfer::from_str( - r#"-----BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:9jMKgkmP-alPghZC-bu65ctP-GT5tKgM-cAbaTLT-rhu8xQo#urban-athena-adam -Version: 2 -Type: transfer -Contract: rgb:T24t0N1D-eiInTgb-BXlrrXz-$7OgV6n-WJWHPUD-BWNuqZw -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - -0s#O3000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#nj! -0000000000000000000000d59ZDjxe00000000dDb8~4rVQz13d2MfXa{vGU00000000000000000000 -0000000000000 - ------END RGB CONSIGNMENT-----"#, - ) - .unwrap_err(); - - // Wrong type - // TODO: Uncomment once ASCII headers get checked - /*assert!(matches!( - Transfer::from_str( - r#"-----BEGIN RGB CONSIGNMENT----- - Id: rgb:csg:9jMKgkmP-alPghZC-bu65ctP-GT5tKgM-cAbaTLT-rhu8xQo#urban-athena-adam - Version: 2 - Type: contract - Contract: rgb:T24t0N1D-eiInTgb-BXlrrXz-$7OgV6n-WJWHPUD-BWNuqZw - Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe - Check-SHA256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - - 0s#O3000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#nj! - 0000000000000000000000d59ZDjxe00000000dDb8~4rVQz13d2MfXa{vGU00000000000000000000 - 0000000000000 - - -----END RGB CONSIGNMENT-----"# - ), - Err(ConsignmentParseError::Type) - ));*/ - assert!(matches!( - Transfer::from_str(include_str!("../../asset/armored_contract.default")), - Err(ConsignmentParseError::Type) - )); - } -} diff --git a/src/containers/disclosure.rs b/src/containers/disclosure.rs deleted file mode 100644 index b81f83c9..00000000 --- a/src/containers/disclosure.rs +++ /dev/null @@ -1,23 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -// TODO: Implement disclosures -pub struct Disclosure; diff --git a/src/containers/file.rs b/src/containers/file.rs deleted file mode 100644 index 02a567b8..00000000 --- a/src/containers/file.rs +++ /dev/null @@ -1,440 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::fmt::{self, Debug, Display, Formatter}; -use std::io::{self, Read, Write}; - -use amplify::confinement::U32 as FILE_MAX_LEN; -use armor::{AsciiArmor, StrictArmor}; -use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictEncode}; - -use crate::containers::{Contract, Kit, Transfer}; - -const RGB_PREFIX: [u8; 4] = *b"RGB\x00"; -const MAGIC_LEN: usize = 3; - -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum LoadError { - /// invalid file data. - InvalidMagic, - - #[display(inner)] - #[from] - #[from(io::Error)] - Decode(strict_encoding::DecodeError), - - #[display(inner)] - #[from] - Armor(armor::StrictArmorError), -} - -pub trait FileContent: StrictArmor { - /// Magic bytes used in saving/restoring container from a file. - const MAGIC: [u8; MAGIC_LEN]; - - fn load(mut data: impl Read) -> Result { - let mut rgb = [0u8; 4]; - let mut magic = [0u8; MAGIC_LEN]; - data.read_exact(&mut rgb)?; - data.read_exact(&mut magic)?; - if rgb != RGB_PREFIX || magic != Self::MAGIC { - return Err(LoadError::InvalidMagic); - } - - let reader = StreamReader::new::(data); - let me = Self::strict_read(reader)?; - - Ok(me) - } - - fn save(&self, mut writer: impl Write) -> Result<(), io::Error> { - writer.write_all(&RGB_PREFIX)?; - writer.write_all(&Self::MAGIC)?; - - let writer = StreamWriter::new::(writer); - self.strict_write(writer)?; - - Ok(()) - } - - #[cfg(feature = "fs")] - fn load_file(path: impl AsRef) -> Result { - let file = std::fs::File::open(path)?; - Self::load(file) - } - - #[cfg(feature = "fs")] - fn save_file(&self, path: impl AsRef) -> Result<(), io::Error> { - let file = std::fs::File::create(path)?; - self.save(file) - } - - #[cfg(feature = "fs")] - fn load_armored(path: impl AsRef) -> Result { - let armor = std::fs::read_to_string(path)?; - let content = Self::from_ascii_armored_str(&armor)?; - Ok(content) - } - - #[cfg(feature = "fs")] - fn save_armored(&self, path: impl AsRef) -> Result<(), io::Error> { - std::fs::write(path, self.to_ascii_armored_string()) - } -} - -impl FileContent for Kit { - const MAGIC: [u8; MAGIC_LEN] = *b"KIT"; -} - -impl FileContent for Contract { - const MAGIC: [u8; MAGIC_LEN] = *b"CON"; -} - -impl FileContent for Transfer { - const MAGIC: [u8; MAGIC_LEN] = *b"TFR"; -} - -// TODO: Add disclosure -// TODO: Add batch and fascia - -#[derive(Clone, Debug, From)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "type") -)] -pub enum UniversalFile { - #[from] - Kit(Kit), - - #[from] - Contract(Contract), - - #[from] - Transfer(Transfer), - // TODO: Add disclosure - // TODO: Add batch and fascia -} - -impl UniversalFile { - pub fn load(mut data: impl Read) -> Result { - let mut rgb = [0u8; 4]; - let mut magic = [0u8; MAGIC_LEN]; - data.read_exact(&mut rgb)?; - data.read_exact(&mut magic)?; - if rgb != RGB_PREFIX { - return Err(LoadError::InvalidMagic); - } - let mut reader = StreamReader::new::(data); - Ok(match magic { - x if x == Kit::MAGIC => Kit::strict_read(&mut reader)?.into(), - x if x == Contract::MAGIC => Contract::strict_read(&mut reader)?.into(), - x if x == Transfer::MAGIC => Transfer::strict_read(&mut reader)?.into(), - _ => return Err(LoadError::InvalidMagic), - }) - } - - pub fn save(&self, mut writer: impl Write) -> Result<(), io::Error> { - writer.write_all(&RGB_PREFIX)?; - let magic = match self { - UniversalFile::Kit(_) => Kit::MAGIC, - UniversalFile::Contract(_) => Contract::MAGIC, - UniversalFile::Transfer(_) => Transfer::MAGIC, - }; - writer.write_all(&magic)?; - - let writer = StreamWriter::new::(writer); - - match self { - UniversalFile::Kit(content) => content.strict_write(writer), - UniversalFile::Contract(content) => content.strict_write(writer), - UniversalFile::Transfer(content) => content.strict_write(writer), - } - } - - #[cfg(feature = "fs")] - pub fn load_file(path: impl AsRef) -> Result { - let file = std::fs::File::open(path)?; - Self::load(file) - } - - #[cfg(feature = "fs")] - pub fn save_file(&self, path: impl AsRef) -> Result<(), io::Error> { - let file = std::fs::File::create(path)?; - self.save(file) - } -} - -impl Display for UniversalFile { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - UniversalFile::Kit(content) => Display::fmt(&content.display_ascii_armored(), f), - UniversalFile::Contract(content) => Display::fmt(&content.display_ascii_armored(), f), - UniversalFile::Transfer(content) => Display::fmt(&content.display_ascii_armored(), f), - } - } -} - -#[cfg(test)] -mod test { - use std::fs::OpenOptions; - use std::str::FromStr; - - use super::*; - static DEFAULT_KIT_PATH: &str = "asset/kit.default"; - #[cfg(feature = "fs")] - static ARMORED_KIT_PATH: &str = "asset/armored_kit.default"; - - static DEFAULT_CONTRACT_PATH: &str = "asset/contract.default"; - #[cfg(feature = "fs")] - static ARMORED_CONTRACT_PATH: &str = "asset/armored_contract.default"; - - static DEFAULT_TRANSFER_PATH: &str = "asset/transfer.default"; - #[cfg(feature = "fs")] - static ARMORED_TRANSFER_PATH: &str = "asset/armored_transfer.default"; - - #[test] - fn kit_save_load_round_trip() { - let mut kit_file = OpenOptions::new() - .read(true) - .open(DEFAULT_KIT_PATH) - .unwrap(); - let kit = Kit::load(kit_file).expect("fail to load kit.default"); - let default_kit = Kit::default(); - assert_eq!(kit, default_kit, "kit default is not same as before"); - - kit_file = OpenOptions::new() - .write(true) - .open(DEFAULT_KIT_PATH) - .unwrap(); - default_kit.save(kit_file).expect("fail to export kit"); - - kit_file = OpenOptions::new() - .read(true) - .open(DEFAULT_KIT_PATH) - .unwrap(); - let kit = Kit::load(kit_file).expect("fail to load kit.default"); - assert_eq!(kit, default_kit, "kit roudtrip does not work"); - } - - #[cfg(feature = "fs")] - #[test] - fn armored_kit_save_load_round_trip() { - let kit_file = OpenOptions::new() - .read(true) - .open(DEFAULT_KIT_PATH) - .unwrap(); - let kit = Kit::load(kit_file).expect("fail to load kit.default"); - let unarmored_kit = - Kit::load_armored(ARMORED_KIT_PATH).expect("fail to export armored kit"); - assert_eq!(kit, unarmored_kit, "kit unarmored is not the same"); - - let default_kit = Kit::default(); - default_kit - .save_armored(ARMORED_KIT_PATH) - .expect("fail to save armored kit"); - let kit = Kit::load_armored(ARMORED_KIT_PATH).expect("fail to export armored kit"); - assert_eq!(kit, default_kit, "armored kit roudtrip does not work"); - } - - // A contract with almost default fields - fn almost_default_contract() -> Contract { - Contract { - version: Default::default(), - transfer: Default::default(), - terminals: Default::default(), - genesis: rgb::Genesis { - ffv: Default::default(), - schema_id: rgb::SchemaId::from_str( - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#distant-history-exotic", - ) - .unwrap(), - flags: Default::default(), - timestamp: Default::default(), - issuer: Default::default(), - testnet: Default::default(), - alt_layers1: Default::default(), - metadata: Default::default(), - globals: Default::default(), - assignments: Default::default(), - valencies: Default::default(), - validator: Default::default(), - }, - extensions: Default::default(), - bundles: Default::default(), - schema: rgb::Schema { - ffv: Default::default(), - flags: Default::default(), - name: strict_encoding::TypeName::from_str("Name").unwrap(), - timestamp: Default::default(), - developer: Default::default(), - meta_types: Default::default(), - global_types: Default::default(), - owned_types: Default::default(), - valency_types: Default::default(), - genesis: Default::default(), - extensions: Default::default(), - transitions: Default::default(), - reserved: Default::default(), - }, - ifaces: Default::default(), - supplements: Default::default(), - types: Default::default(), - scripts: Default::default(), - attachments: Default::default(), - signatures: Default::default(), - } - } - - #[test] - fn contract_save_load_round_trip() { - let mut contract_file = OpenOptions::new() - .read(true) - .open(DEFAULT_CONTRACT_PATH) - .unwrap(); - let contract = Contract::load(contract_file).expect("fail to load contract.default"); - - let default_contract = almost_default_contract(); - assert_eq!(&contract, &default_contract, "contract default is not same as before"); - - contract_file = OpenOptions::new() - .write(true) - .open(DEFAULT_CONTRACT_PATH) - .unwrap(); - default_contract - .save(contract_file) - .expect("fail to export contract"); - - contract_file = OpenOptions::new() - .read(true) - .open(DEFAULT_CONTRACT_PATH) - .unwrap(); - let contract = Contract::load(contract_file).expect("fail to load contract.default"); - assert_eq!(&contract, &default_contract, "contract roudtrip does not work"); - } - - #[cfg(feature = "fs")] - #[test] - fn armored_contract_save_load_round_trip() { - let contract_file = OpenOptions::new() - .read(true) - .open(DEFAULT_CONTRACT_PATH) - .unwrap(); - let contract = Contract::load(contract_file).expect("fail to load contract.default"); - let unarmored_contract = - Contract::load_armored(ARMORED_CONTRACT_PATH).expect("fail to export armored contract"); - assert_eq!(contract, unarmored_contract, "contract unarmored is not the same"); - - let default_contract = almost_default_contract(); - default_contract - .save_armored(ARMORED_CONTRACT_PATH) - .expect("fail to save armored contract"); - let contract = - Contract::load_armored(ARMORED_CONTRACT_PATH).expect("fail to export armored contract"); - assert_eq!(contract, default_contract, "armored contract roudtrip does not work"); - } - - // A transfer with almost default fields - fn almost_default_transfer() -> Transfer { - Transfer { - version: Default::default(), - transfer: true, - terminals: Default::default(), - genesis: rgb::Genesis { - ffv: Default::default(), - schema_id: rgb::SchemaId::from_str( - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#distant-history-exotic", - ) - .unwrap(), - flags: Default::default(), - timestamp: Default::default(), - issuer: Default::default(), - testnet: Default::default(), - alt_layers1: Default::default(), - metadata: Default::default(), - globals: Default::default(), - assignments: Default::default(), - valencies: Default::default(), - validator: Default::default(), - }, - extensions: Default::default(), - bundles: Default::default(), - schema: rgb::Schema { - ffv: Default::default(), - flags: Default::default(), - name: strict_encoding::TypeName::from_str("Name").unwrap(), - timestamp: Default::default(), - developer: Default::default(), - meta_types: Default::default(), - global_types: Default::default(), - owned_types: Default::default(), - valency_types: Default::default(), - genesis: Default::default(), - extensions: Default::default(), - transitions: Default::default(), - reserved: Default::default(), - }, - ifaces: Default::default(), - supplements: Default::default(), - types: Default::default(), - scripts: Default::default(), - attachments: Default::default(), - signatures: Default::default(), - } - } - - #[cfg(feature = "fs")] - #[test] - fn transfer_save_load_round_trip() { - let transfer = - Transfer::load_file(DEFAULT_TRANSFER_PATH).expect("fail to load transfer.default"); - - let default_transfer = almost_default_transfer(); - assert_eq!(&transfer, &default_transfer, "transfer default is not same as before"); - - default_transfer - .save_file(DEFAULT_TRANSFER_PATH) - .expect("fail to export transfer"); - - let transfer = - Transfer::load_file(DEFAULT_TRANSFER_PATH).expect("fail to load transfer.default"); - assert_eq!(&transfer, &default_transfer, "transfer roudtrip does not work"); - } - - #[cfg(feature = "fs")] - #[test] - fn armored_transfer_save_load_round_trip() { - let transfer = - Transfer::load_file(DEFAULT_TRANSFER_PATH).expect("fail to load transfer.default"); - let unarmored_transfer = - Transfer::load_armored(ARMORED_TRANSFER_PATH).expect("fail to export armored transfer"); - assert_eq!(transfer, unarmored_transfer, "transfer unarmored is not the same"); - - let default_transfer = almost_default_transfer(); - default_transfer - .save_armored(ARMORED_TRANSFER_PATH) - .expect("fail to save armored transfer"); - let transfer = - Transfer::load_armored(ARMORED_TRANSFER_PATH).expect("fail to export armored transfer"); - assert_eq!(transfer, default_transfer, "armored transfer roudtrip does not work"); - } -} diff --git a/src/containers/indexed.rs b/src/containers/indexed.rs deleted file mode 100644 index 355d8c28..00000000 --- a/src/containers/indexed.rs +++ /dev/null @@ -1,147 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 rgb::validation::{ConsignmentApi, EAnchor, OpRef, Scripts}; -use rgb::{ - BundleId, Extension, Genesis, OpId, Operation, Schema, Transition, TransitionBundle, XWitnessId, -}; -use strict_types::TypeSystem; - -use super::{Consignment, XPubWitness}; -use crate::containers::anchors::ToWitnessId; - -// TODO: Transform consignment into this type instead of composing over it -#[derive(Clone, Debug)] -pub struct IndexedConsignment<'c, const TRANSFER: bool> { - consignment: &'c Consignment, - scripts: Scripts, - anchor_idx: BTreeMap, - bundle_idx: BTreeMap, - op_witness_idx: BTreeMap, - op_bundle_idx: BTreeMap, - extension_idx: BTreeMap, - witness_idx: BTreeMap, -} - -impl<'c, const TRANSFER: bool> Deref for IndexedConsignment<'c, TRANSFER> { - type Target = Consignment; - - fn deref(&self) -> &Self::Target { self.consignment } -} - -impl<'c, const TRANSFER: bool> IndexedConsignment<'c, TRANSFER> { - pub fn new(consignment: &'c Consignment) -> Self { - let mut anchor_idx = BTreeMap::new(); - let mut bundle_idx = BTreeMap::new(); - let mut op_witness_idx = BTreeMap::new(); - let mut op_bundle_idx = BTreeMap::new(); - let mut extension_idx = BTreeMap::new(); - let mut witness_idx = BTreeMap::new(); - for witness_bundle in &consignment.bundles { - witness_idx - .insert(witness_bundle.pub_witness.to_witness_id(), &witness_bundle.pub_witness); - let witness_id = witness_bundle.pub_witness.to_witness_id(); - for (anchor, bundle) in witness_bundle.anchored_bundles() { - let bundle_id = bundle.bundle_id(); - bundle_idx.insert(bundle_id, bundle); - anchor_idx.insert(bundle_id, (witness_id, anchor)); - for opid in bundle.known_transitions.keys() { - op_witness_idx.insert(*opid, witness_id); - op_bundle_idx.insert(*opid, bundle_id); - } - } - } - for extension in &consignment.extensions { - extension_idx.insert(extension.id(), extension); - } - let scripts = Scripts::from_iter_checked( - consignment - .scripts - .iter() - .map(|lib| (lib.id(), lib.clone())), - ); - Self { - consignment, - scripts, - anchor_idx, - bundle_idx, - op_witness_idx, - op_bundle_idx, - extension_idx, - witness_idx, - } - } - - fn extension(&self, opid: OpId) -> Option<&Extension> { self.extension_idx.get(&opid).copied() } - - fn transition(&self, opid: OpId) -> Option<&Transition> { - self.op_bundle_idx - .get(&opid) - .and_then(|id| self.bundle_idx.get(id)) - .and_then(|bundle| bundle.known_transitions.get(&opid)) - } - - pub fn pub_witness(&self, id: XWitnessId) -> Option<&XPubWitness> { - self.witness_idx.get(&id).copied() - } -} - -impl<'c, const TRANSFER: bool> ConsignmentApi for IndexedConsignment<'c, TRANSFER> { - fn schema(&self) -> &Schema { &self.schema } - - fn types(&self) -> &TypeSystem { &self.types } - - fn scripts(&self) -> &Scripts { &self.scripts } - - fn operation(&self, opid: OpId) -> Option { - if opid == self.genesis.id() { - return Some(OpRef::Genesis(&self.genesis)); - } - self.transition(opid) - .map(OpRef::Transition) - .or_else(|| self.extension(opid).map(OpRef::Extension)) - } - - fn genesis(&self) -> &Genesis { &self.genesis } - - fn bundle_ids<'iter>(&self) -> impl Iterator + 'iter { - self.bundle_idx - .keys() - .copied() - .collect::>() - .into_iter() - } - - fn bundle(&self, bundle_id: BundleId) -> Option<&TransitionBundle> { - self.bundle_idx.get(&bundle_id).copied() - } - - fn anchor(&self, bundle_id: BundleId) -> Option<(XWitnessId, &EAnchor)> { - self.anchor_idx.get(&bundle_id).map(|(id, set)| (*id, set)) - } - - fn op_witness_id(&self, opid: OpId) -> Option { - self.op_witness_idx.get(&opid).copied() - } -} diff --git a/src/containers/kit.rs b/src/containers/kit.rs deleted file mode 100644 index 4316f83c..00000000 --- a/src/containers/kit.rs +++ /dev/null @@ -1,333 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::fmt; -use std::fmt::{Display, Formatter}; -use std::ops::Deref; -use std::str::FromStr; - -use aluvm::library::Lib; -use amplify::confinement::{SmallOrdSet, TinyOrdMap, TinyOrdSet}; -use amplify::{ByteArray, Bytes32}; -use armor::{ArmorHeader, AsciiArmor, StrictArmor}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use commit_verify::{CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::{validation, Schema}; -use strict_encoding::{StrictDeserialize, StrictSerialize}; -use strict_types::TypeSystem; - -use super::{ - ContentRef, Supplement, ASCII_ARMOR_IFACE, ASCII_ARMOR_IIMPL, ASCII_ARMOR_SCHEMA, - ASCII_ARMOR_SCRIPT, ASCII_ARMOR_TYPE_SYSTEM, ASCII_ARMOR_VERSION, -}; -use crate::containers::{ContainerVer, ContentId, ContentSigs}; -use crate::interface::{Iface, IfaceImpl}; -use crate::LIB_NAME_RGB_STD; - -/// Kit identifier. -/// -/// Kit identifier commits to all data provided within the kit. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -pub struct KitId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for KitId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for KitId { - const TAG: &'static str = "urn:lnp-bp:rgb:kit#2024-04-09"; -} - -impl DisplayBaid64 for KitId { - const HRI: &'static str = "rgb:kit"; - const CHUNKING: bool = true; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = false; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for KitId {} -impl FromStr for KitId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for KitId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(KitId); - -impl KitId { - pub const fn from_array(id: [u8; 32]) -> Self { KitId(Bytes32::from_array(id)) } -} - -#[derive(Clone, Debug, Display)] -#[display("{kit}")] -pub struct ValidKit { - /// Status of the latest validation. - validation_status: validation::Status, - kit: Kit, -} - -impl ValidKit { - pub fn validation_status(&self) -> &validation::Status { &self.validation_status } - - pub fn into_kit(self) -> Kit { self.kit } - - pub fn into_validation_status(self) -> validation::Status { self.validation_status } - - pub fn split(self) -> (Kit, validation::Status) { (self.kit, self.validation_status) } -} - -impl Deref for ValidKit { - type Target = Kit; - - fn deref(&self) -> &Self::Target { &self.kit } -} - -#[derive(Clone, Default, Debug, Display, PartialEq)] -#[display(AsciiArmor::to_ascii_armored_string)] -#[derive(StrictType, 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 Kit { - /// Version. - pub version: ContainerVer, - - pub ifaces: TinyOrdSet, - - pub schemata: TinyOrdSet, - - pub iimpls: TinyOrdSet, - - pub supplements: TinyOrdSet, - - /// Type system covering all types used in schema, interfaces and - /// implementations. - pub types: TypeSystem, - - /// Collection of scripts used across kit data. - pub scripts: SmallOrdSet, - - /// Signatures on the pieces of content which are the part of the kit. - pub signatures: TinyOrdMap, -} - -impl StrictSerialize for Kit {} -impl StrictDeserialize for Kit {} - -impl CommitEncode for Kit { - type CommitmentId = KitId; - - fn commit_encode(&self, e: &mut CommitEngine) { - e.commit_to_serialized(&self.version); - - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.ifaces.iter().map(|iface| iface.iface_id()), - )); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.schemata.iter().map(|schema| schema.schema_id()), - )); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.iimpls.iter().map(|iimpl| iimpl.impl_id()), - )); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.supplements.iter().map(|suppl| suppl.suppl_id()), - )); - - e.commit_to_serialized(&self.types.id()); - e.commit_to_set(&SmallOrdSet::from_iter_checked(self.scripts.iter().map(|lib| lib.id()))); - - e.commit_to_map(&self.signatures); - } -} - -impl Kit { - #[inline] - pub fn kit_id(&self) -> KitId { self.commit_id() } - - pub fn validate( - self, - // TODO: Add sig validator - //_: &impl SigValidator, - ) -> Result { - let status = validation::Status::new(); - // TODO: - // - Verify integrity for each interface - // - Verify implementations against interfaces - // - Check schema integrity - // - Validate content sigs and remove untrusted ones - Ok(ValidKit { - validation_status: status, - kit: self, - }) - } -} - -impl StrictArmor for Kit { - type Id = KitId; - const PLATE_TITLE: &'static str = "RGB KIT"; - - fn armor_id(&self) -> Self::Id { self.kit_id() } - fn armor_headers(&self) -> Vec { - let mut headers = - vec![ArmorHeader::new(ASCII_ARMOR_VERSION, format!("{:#}", self.version))]; - for schema in &self.schemata { - let mut header = ArmorHeader::new(ASCII_ARMOR_SCHEMA, schema.name.to_string()); - let id = schema.schema_id(); - header.params.push((s!("id"), format!("{id:-}"))); - header - .params - .push((s!("dev"), schema.developer.to_string())); - if let Some(suppl) = self - .supplements - .iter() - .find(|s| s.content_id == ContentRef::Schema(id)) - { - header - .params - .push((s!("suppl"), format!("{:-}", suppl.suppl_id()))); - } - headers.push(header); - } - for iface in &self.ifaces { - let mut header = ArmorHeader::new(ASCII_ARMOR_IFACE, iface.name.to_string()); - let id = iface.iface_id(); - header.params.push((s!("id"), format!("{id:-}"))); - header.params.push((s!("dev"), iface.developer.to_string())); - if let Some(suppl) = self - .supplements - .iter() - .find(|s| s.content_id == ContentRef::Iface(id)) - { - header - .params - .push((s!("suppl"), format!("{:-}", suppl.suppl_id()))); - } - headers.push(header); - } - for iimpl in &self.iimpls { - let id = iimpl.impl_id(); - let mut header = ArmorHeader::new(ASCII_ARMOR_IIMPL, format!("{id:-}")); - header - .params - .push((s!("interface"), format!("{:-}", iimpl.iface_id))); - header - .params - .push((s!("schema"), format!("{:-}", iimpl.schema_id))); - header.params.push((s!("dev"), iimpl.developer.to_string())); - if let Some(suppl) = self - .supplements - .iter() - .find(|s| s.content_id == ContentRef::IfaceImpl(id)) - { - header - .params - .push((s!("suppl"), format!("{:-}", suppl.suppl_id()))); - } - headers.push(header); - } - headers.push(ArmorHeader::new(ASCII_ARMOR_TYPE_SYSTEM, self.types.id().to_string())); - for lib in &self.scripts { - headers.push(ArmorHeader::new(ASCII_ARMOR_SCRIPT, lib.id().to_string())); - } - headers - } -} - -impl FromStr for Kit { - type Err = armor::StrictArmorError; - fn from_str(s: &str) -> Result { Self::from_ascii_armored_str(s) } -} - -#[cfg(test)] -mod test { - use super::*; - #[test] - fn kit_str_round_trip() { - let kit = Kit::from_str(include_str!("../../asset/armored_kit.default")) - .expect("kit from str should work"); - - let hardcoded = include_str!("../../asset/armored_kit.default").replace('\r', ""); - assert_eq!(kit.to_string(), hardcoded, "kit string round trip fails"); - - assert_eq!( - kit.validate().unwrap().to_string(), - hardcoded, - "validated kit string round trip fails" - ); - } - - #[test] - fn error_kit_strs() { - assert!(Kit::from_str( - r#"-----BEGIN RGB KIT----- -Id: rgb:kit:e1jW6Rgc-2$JzXDg-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel -Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da - -0ssI2000000000 - ------END RGB KIT-----"# - ) - .is_ok()); - - // Wrong Id - assert!(Kit::from_str( - r#"-----BEGIN RGB KIT----- -Id: rgb:kit:11111111-2222222-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel -Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da - -0ssI2000000000 - ------END RGB KIT-----"# - ) - .is_err()); - - // wrong checksum - assert!(Kit::from_str( - r#"-----BEGIN RGB KIT----- -Id: rgb:kit:e1jW6Rgc-2$JzXDg-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel -Check-SHA256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - -0ssI2000000000 - ------END RGB KIT-----"# - ) - .is_err()); - } -} diff --git a/src/containers/mod.rs b/src/containers/mod.rs deleted file mode 100644 index 76ed6377..00000000 --- a/src/containers/mod.rs +++ /dev/null @@ -1,77 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -//! RGB containers are data packages which can be transferred between smart -//! contract users. There are two main types of containers: -//! 1. [`Consignment`]s, containing information about partial state of a *single contract*, -//! extending from its genesis up to certain contract endpoints. -//! 2. [`Disclosure`]s, containing extracts from (possibly) independent state transitions and -//! extensions under multiple contracts. Useful fro disclosing the concealed state for some other -//! parties, and also for performing "change" operations on inventory during state transfers. - -mod seal; -mod anchors; -mod consignment; -mod disclosure; -mod util; -mod partials; -mod indexed; -mod file; -mod kit; -mod suppl; - -pub use anchors::{ - AnchorSet, AnchoredBundleMismatch, AnchoredBundles, ClientBundle, PubWitness, SealWitness, - ToWitnessId, UnrelatedTransition, WitnessBundle, XPubWitness, -}; -pub use consignment::{ - Consignment, ConsignmentExt, ConsignmentId, ConsignmentParseError, Contract, Transfer, - ValidConsignment, ValidContract, ValidTransfer, -}; -pub use disclosure::Disclosure; -pub use file::{FileContent, LoadError, UniversalFile}; -pub use indexed::IndexedConsignment; -pub use kit::{Kit, KitId, ValidKit}; -pub use partials::{ - Batch, BundleDichotomy, CloseMethodSet, Dichotomy, Fascia, TransitionDichotomy, TransitionInfo, - TransitionInfoError, -}; -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, TrustLevel, -}; - -pub const ASCII_ARMOR_NAME: &str = "Name"; -pub const ASCII_ARMOR_IFACE: &str = "Interface"; -pub const ASCII_ARMOR_IIMPL: &str = "Implementation"; -pub const ASCII_ARMOR_SCHEMA: &str = "Schema"; -pub const ASCII_ARMOR_CONTRACT: &str = "Contract"; -pub const ASCII_ARMOR_VERSION: &str = "Version"; -pub const ASCII_ARMOR_TERMINAL: &str = "Terminal"; -pub const ASCII_ARMOR_SUPPL: &str = "Supplement"; -pub const ASCII_ARMOR_SCRIPT: &str = "Alu-Lib"; -pub const ASCII_ARMOR_TYPE_SYSTEM: &str = "Type-System"; -pub const ASCII_ARMOR_CONSIGNMENT_TYPE: &str = "Type"; diff --git a/src/containers/partials.rs b/src/containers/partials.rs deleted file mode 100644 index ed2d6ee9..00000000 --- a/src/containers/partials.rs +++ /dev/null @@ -1,394 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::cmp::Ordering; -use std::collections::BTreeSet; -use std::hash::{Hash, Hasher}; -use std::ops::{BitOr, BitOrAssign}; -use std::{iter, vec}; - -use amplify::confinement::{Confined, NonEmptyOrdMap, U24}; -use bp::seals::txout::CloseMethod; -use rgb::{ - ContractId, OpId, Operation, Transition, TransitionBundle, TxoSeal, XOutpoint, XOutputSeal, - XWitnessId, -}; -use strict_encoding::{ - DecodeError, ReadStruct, StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, - StrictProduct, StrictSerialize, StrictStruct, StrictType, TypedRead, TypedWrite, WriteStruct, -}; - -use crate::containers::{AnchorSet, XPubWitness}; -use crate::LIB_NAME_RGB_STD; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum CloseMethodSet { - #[strict_type(dumb)] - TapretFirst = 0x01, - OpretFirst = 0x02, - Both = 0x03, -} - -impl BitOr> for CloseMethodSet { - type Output = Self; - fn bitor(mut self, rhs: Option) -> Self::Output { - if let Some(m) = rhs { - self |= m - }; - self - } -} - -impl BitOrAssign> for CloseMethodSet { - fn bitor_assign(&mut self, rhs: Option) { - if let Some(m) = rhs { - *self |= m - }; - } -} - -impl BitOr for Option { - type Output = CloseMethodSet; - fn bitor(self, mut rhs: CloseMethodSet) -> Self::Output { - if let Some(m) = self { - rhs |= m - }; - rhs - } -} - -impl BitOrAssign for Option { - fn bitor_assign(&mut self, rhs: CloseMethodSet) { *self = Some(rhs | *self) } -} - -impl> BitOr for CloseMethodSet { - type Output = Self; - fn bitor(self, rhs: T) -> Self::Output { - if self == rhs.into() { - self - } else { - Self::Both - } - } -} - -impl> BitOrAssign for CloseMethodSet { - fn bitor_assign(&mut self, rhs: T) { *self = self.bitor(rhs.into()); } -} - -impl From for CloseMethodSet { - fn from(seal: XOutputSeal) -> Self { seal.method().into() } -} - -impl From for CloseMethodSet { - fn from(method: CloseMethod) -> Self { - match method { - CloseMethod::OpretFirst => CloseMethodSet::OpretFirst, - CloseMethod::TapretFirst => CloseMethodSet::TapretFirst, - } - } -} - -impl CloseMethodSet { - pub fn has_tapret_first(self) -> bool { matches!(self, Self::TapretFirst | Self::Both) } - pub fn has_opret_first(self) -> bool { matches!(self, Self::OpretFirst | Self::Both) } -} - -#[derive(Clone, Eq, Debug)] -#[derive(StrictType, 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 TransitionInfo { - pub id: OpId, - pub inputs: Confined, 1, U24>, - pub transition: Transition, - pub method: CloseMethod, -} - -impl StrictDumb for TransitionInfo { - fn strict_dumb() -> Self { Self::new(strict_dumb!(), [strict_dumb!()]).unwrap() } -} - -impl PartialEq for TransitionInfo { - fn eq(&self, other: &Self) -> bool { self.id.eq(&other.id) } -} - -impl Ord for TransitionInfo { - fn cmp(&self, other: &Self) -> Ordering { self.id.cmp(&other.id) } -} - -impl PartialOrd for TransitionInfo { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Hash for TransitionInfo { - fn hash(&self, state: &mut H) { state.write(self.id.as_slice()) } -} - -impl TransitionInfo { - pub fn new( - transition: Transition, - seals: impl AsRef<[XOutputSeal]>, - ) -> Result { - let id = transition.id(); - let seals = seals.as_ref(); - let inputs = Confined::, 1, U24>::try_from_iter( - seals.iter().copied().map(XOutpoint::from), - ) - .map_err(|_| TransitionInfoError::TooMany(id))?; - let method = seals.first().expect("one item guaranteed").method(); - if seals.iter().any(|s| s.method() != method) { - return Err(TransitionInfoError::CloseMethodDivergence(id)); - } - Ok(TransitionInfo { - id, - inputs, - transition, - method, - }) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum TransitionInfoError { - /// the operation produces too many state transitions which can't fit the - /// container requirements. - TooMany(OpId), - - /// transition {0} contains inputs with different seal closing methods, - /// which is not allowed. - CloseMethodDivergence(OpId), -} - -/// A batch of state transitions under different contracts which are associated -/// with some specific transfer and will be anchored within a single layer 1 -/// transaction. -#[derive(Clone, PartialEq, Eq, Hash, 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 Batch { - pub main: TransitionDichotomy, - pub blanks: Confined, 0, { U24 - 1 }>, -} - -impl StrictSerialize for Batch {} -impl StrictDeserialize for Batch {} - -impl IntoIterator for Batch { - type Item = TransitionInfo; - type IntoIter = iter::FlatMap< - vec::IntoIter>, - vec::IntoIter, - fn(Dichotomy) -> as IntoIterator>::IntoIter, - >; - - fn into_iter(self) -> Self::IntoIter { - let mut vec = self.blanks.release(); - vec.push(self.main); - vec.into_iter().flat_map(TransitionDichotomy::into_iter) - } -} - -impl Batch { - pub fn close_method_set(&self) -> CloseMethodSet { - let mut methods = CloseMethodSet::from(self.main.first.method); - if let Some(info) = &self.main.second { - methods |= info.method; - } - self.blanks.iter().for_each(|i| methods |= i.first.method); - self.blanks - .iter() - .filter_map(|i| i.second.as_ref()) - .for_each(|i| methods |= i.method); - methods - } - - pub fn set_priority(&mut self, priority: u64) { - self.main.first.transition.nonce = priority; - if let Some(info) = &mut self.main.second { - info.transition.nonce = priority; - } - for info in &mut self.blanks { - info.first.transition.nonce = priority; - if let Some(info) = &mut info.second { - info.transition.nonce = priority; - } - } - } -} - -pub type BundleDichotomy = Dichotomy; -pub type TransitionDichotomy = Dichotomy; - -// TODO: Move to amplify -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Dichotomy { - pub first: T, - pub second: Option, -} - -impl StrictType for Dichotomy { - const STRICT_LIB_NAME: &'static str = LIB_NAME_RGB_STD; -} -impl StrictProduct for Dichotomy {} -impl StrictStruct for Dichotomy { - const ALL_FIELDS: &'static [&'static str] = &["first", "second"]; -} -impl StrictEncode for Dichotomy { - fn strict_encode(&self, writer: W) -> std::io::Result { - writer.write_struct::(|w| { - Ok(w.write_field(fname!("first"), &self.first)? - .write_field(fname!("second"), &self.second)? - .complete()) - }) - } -} -impl StrictDecode for Dichotomy { - fn strict_decode(reader: &mut impl TypedRead) -> Result { - reader.read_struct(|r| { - Ok(Self { - first: r.read_field(fname!("first"))?, - second: r.read_field(fname!("second"))?, - }) - }) - } -} -impl StrictDumb for Dichotomy { - fn strict_dumb() -> Self { - Self { - first: T::strict_dumb(), - second: None, - } - } -} - -impl FromIterator for Dichotomy { - fn from_iter>(iter: I) -> Self { - let mut iter = iter.into_iter(); - let first = iter.next().expect("iterator must have at least one item"); - let second = iter.next(); - assert!(iter.next().is_none(), "iterator must have at most two items"); - Self { first, second } - } -} - -impl IntoIterator for Dichotomy { - type Item = T; - type IntoIter = vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - let mut vec = Vec::with_capacity(2); - vec.push(self.first); - if let Some(s) = self.second { - vec.push(s) - } - vec.into_iter() - } -} - -impl Dichotomy { - pub fn single(first: T) -> Self { - Self { - first, - second: None, - } - } - - pub fn double(first: T, second: T) -> Self { - Self { - first, - second: Some(second), - } - } - - pub fn with(first: T, second: Option) -> Self { Self { first, second } } - - pub fn iter(&self) -> vec::IntoIter<&T> { - let mut vec = Vec::with_capacity(2); - vec.push(&self.first); - if let Some(ref s) = self.second { - vec.push(s) - } - vec.into_iter() - } -} - -/// Structure exported from a PSBT for merging into the stash. It contains a set -/// of finalized state transitions (under multiple contracts), packed into -/// bundles, and anchored to a single layer 1 transaction. -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, 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 Fascia { - pub witness: XPubWitness, - pub anchor: AnchorSet, - pub bundles: NonEmptyOrdMap, -} - -impl StrictDumb for Fascia { - fn strict_dumb() -> Self { - Fascia { - witness: strict_dumb!(), - anchor: strict_dumb!(), - bundles: NonEmptyOrdMap::with_key_value(strict_dumb!(), strict_dumb!()), - } - } -} -impl StrictSerialize for Fascia {} -impl StrictDeserialize for Fascia {} - -impl Fascia { - pub fn witness_id(&self) -> XWitnessId { self.witness.map_ref(|w| w.txid()) } - - pub fn into_bundles(self) -> impl IntoIterator { - self.bundles - .into_iter() - .flat_map(|(id, d)| d.into_iter().map(move |b| (id, b))) - } -} diff --git a/src/containers/seals.md b/src/containers/seals.md deleted file mode 100644 index 3136a22f..00000000 --- a/src/containers/seals.md +++ /dev/null @@ -1,29 +0,0 @@ -# Single-use-seal API specific for RGB implementation - -Based on LNP/BP client-side-validation single-use-seals API (see -`single_use_seals` crate). RGB single-use-seal implementation differs in the fact -that seals are organized into a graph; thus a seal may be defined as -pointing witness transaction closing some other seal, which is meaningless -with LNP/BP seals. - -Single-use-seals in RGB are used for holding assigned state, i.e. *state* + -*seal definition* = *assignment*. Closing of the single-use-seal invalidates -the assigned state. - -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 | - -[`Outpoint`]: bp::Outpoint - -[`BlindSeal`]: bp::seals::txout::blind::BlindSeal - -[`ExplicitSeal`]: bp::seals::txout::ExplicitSeal diff --git a/src/containers/suppl.rs b/src/containers/suppl.rs deleted file mode 100644 index a98aa3ed..00000000 --- a/src/containers/suppl.rs +++ /dev/null @@ -1,368 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::fmt; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; - -use amplify::confinement::{SmallBlob, TinyOrdMap}; -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use chrono::Utc; -use commit_verify::{CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::{AssignmentType, ContractId, GlobalStateType, Identity, SchemaId}; -use strict_encoding::stl::{AlphaCaps, AlphaNumDash}; -use strict_encoding::{ - DeserializeError, FieldName, RString, SerializeError, StrictDeserialize, StrictSerialize, - TypeName, VariantName, -}; -use strict_types::value; - -use crate::interface::{IfaceId, ImplId}; -use crate::LIB_NAME_RGB_STD; - -pub const SUPPL_ANNOT_VELOCITY: &str = "Velocity"; -pub const SUPPL_ANNOT_IFACE_CLASS: &str = "Standard"; -pub const SUPPL_ANNOT_IFACE_FEATURES: &str = "Features"; - -/// Contract supplement identifier. -/// -/// Contract supplement identifier commits to all of the supplement data. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -pub struct SupplId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for SupplId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for SupplId { - const TAG: &'static str = "urn:lnp-bp:rgb:suppl#2024-03-11"; -} - -impl DisplayBaid64 for SupplId { - const HRI: &'static str = "rgb:sup"; - const CHUNKING: bool = false; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = false; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for SupplId {} -impl FromStr for SupplId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for SupplId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(SupplId); - -impl SupplId { - pub const fn from_array(id: [u8; 32]) -> Self { Self(Bytes32::from_array(id)) } -} - -#[derive(Wrapper, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Display)] -#[wrapper(Deref, FromStr)] -#[display(inner)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AnnotationName(RString); - -impl From<&'static str> for AnnotationName { - fn from(s: &'static str) -> Self { Self(RString::from(s)) } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, From)] -#[display(inner)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order, dumb = ContentRef::Schema(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum ContentRef { - #[from] - Schema(SchemaId), - #[from] - Genesis(ContractId), - #[from] - Iface(IfaceId), - #[from] - IfaceImpl(ImplId), -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum SupplSub { - #[default] - Itself = 0, - Meta = 1, - Global, - Owned, - Valency, - Assignment, - Genesis, - Transition, - Extension, - Exception, -} - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum SupplItem { - #[default] - #[strict_type(tag = 0)] - Default, - #[strict_type(tag = 1)] - TypeNo(u16), - #[strict_type(tag = 0x11)] - TypeName(TypeName), - #[strict_type(tag = 0x12)] - FieldName(FieldName), - #[strict_type(tag = 0x13)] - VariantName(VariantName), -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct SupplMap(TinyOrdMap); - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct Annotations(TinyOrdMap); - -/// Contract supplement, providing non-consensus information about standard -/// way of working with the contract data. Each contract can have only a single -/// valid supplement; the supplement is attached to the contract via trusted -/// provider signature (providers are ordered by the priority). -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = SupplId)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Supplement { - pub content_id: ContentRef, - pub timestamp: i64, - pub creator: Identity, - /// Strict-encoded custom fields. - pub annotations: TinyOrdMap, -} - -impl StrictSerialize for Supplement {} -impl StrictDeserialize for Supplement {} - -impl Supplement { - pub fn suppl_id(&self) -> SupplId { self.commit_id() } - - pub fn new(content: impl Into, creator: impl Into) -> Self { - Supplement { - content_id: content.into(), - timestamp: Utc::now().timestamp(), - creator: creator.into(), - annotations: none!(), - } - } - - pub fn with( - content: impl Into, - creator: impl Into, - timestamp: i64, - ) -> Self { - Supplement { - content_id: content.into(), - timestamp, - creator: creator.into(), - annotations: none!(), - } - } - - pub fn get_default_opt( - &self, - sub: SupplSub, - name: impl Into, - ) -> Option { - self.get_default(sub, name).transpose().ok().flatten() - } - - pub fn get_default( - &self, - sub: SupplSub, - name: impl Into, - ) -> Option> { - let annotation = self - .annotations - .get(&sub)? - .get(&SupplItem::Default)? - .get(&name.into())?; - Some(T::from_strict_serialized(annotation.clone())) - } - - pub fn get( - &self, - sub: SupplSub, - item: SupplItem, - name: impl Into, - ) -> Option> { - let annotation = self.annotations.get(&sub)?.get(&item)?.get(&name.into())?; - Some(T::from_strict_serialized(annotation.clone())) - } - - pub fn annotate_itself( - &mut self, - name: impl Into, - data: &impl StrictSerialize, - ) -> Result { - self.annotate_default(SupplSub::Itself, name, data) - } - - pub fn annotate_default( - &mut self, - sub: SupplSub, - name: impl Into, - data: &impl StrictSerialize, - ) -> Result { - self.annotate(sub, SupplItem::Default, name, data) - } - - pub fn annotate( - &mut self, - sub: SupplSub, - item: SupplItem, - name: impl Into, - data: &impl StrictSerialize, - ) -> Result { - let mut a = self - .annotations - .remove(&sub) - .expect("zero items allowed") - .unwrap_or_default(); - let mut b = a - .remove(&item) - .expect("zero items allowed") - .unwrap_or_default(); - let prev = b.insert(name.into(), data.to_strict_serialized()?)?; - a.insert(item, b)?; - self.annotations.insert(sub, a)?; - Ok(prev.is_some()) - } -} - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum TickerSuppl { - #[strict_type(tag = 0, dumb)] - Absent, - #[strict_type(tag = 1)] - Global(GlobalStateType, value::Path), - #[strict_type(tag = 2)] - Owned(AssignmentType, value::Path), -} - -impl StrictSerialize for TickerSuppl {} -impl StrictDeserialize for TickerSuppl {} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = repr, try_from_u8, into_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(lowercase)] -#[repr(u8)] -pub enum VelocityHint { - #[default] - Unspecified = 0, - /// Should be used for thinks like secondary issuance for tokens which do - /// not inflate very often. - Seldom = 15, - /// Should be used for digital identity revocations. - Episodic = 31, - /// Should be used for digital art, shares, bonds etc. - Regular = 63, - /// Should be used for fungible tokens. - Frequent = 127, - /// Should be used for stablecoins and money. - HighFrequency = 255, -} - -impl StrictSerialize for VelocityHint {} -impl StrictDeserialize for VelocityHint {} - -impl VelocityHint { - pub fn with_value(value: &u8) -> Self { - match *value { - 0 => VelocityHint::Unspecified, - 1..=15 => VelocityHint::Seldom, - 16..=31 => VelocityHint::Episodic, - 32..=63 => VelocityHint::Regular, - 64..=127 => VelocityHint::Frequent, - 128..=255 => VelocityHint::HighFrequency, - } - } -} diff --git a/src/containers/util.rs b/src/containers/util.rs deleted file mode 100644 index 92b68043..00000000 --- a/src/containers/util.rs +++ /dev/null @@ -1,137 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::btree_map; - -use amplify::confinement::{NonEmptyBlob, NonEmptyOrdMap}; -use commit_verify::StrictHash; -use rgb::{ContractId, Identity, SchemaId}; -use strict_encoding::StrictDumb; - -use super::SupplId; -use crate::interface::{IfaceId, ImplId}; -use crate::LIB_NAME_RGB_STD; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[non_exhaustive] -#[repr(u8)] -pub enum ContainerVer { - // V0 and V1 was a previous version before v0.11, currently not supported. - #[default] - #[display("v2", alt = "2")] - V2 = 2, -} - -pub trait SigValidator { - fn validate_sig(&self, identity: &Identity, sig: SigBlob) -> bool; -} - -pub struct DumbValidator; -impl SigValidator for DumbValidator { - fn validate_sig(&self, _: &Identity, _: SigBlob) -> bool { false } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] -#[display(lowercase)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum TrustLevel { - Malicious = 0x10, - #[default] - Unknown = 0x20, - Untrusted = 0x40, - Trusted = 0x80, - Ultimate = 0xC0, -} - -impl TrustLevel { - pub fn should_accept(self) -> bool { self >= Self::Unknown } - pub fn should_use(self) -> bool { self >= Self::Trusted } - pub fn must_use(self) -> bool { self >= Self::Ultimate } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order, dumb = ContentId::Schema(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum ContentId { - Schema(SchemaId), - Genesis(ContractId), - Iface(IfaceId), - IfaceImpl(ImplId), - Suppl(SupplId), -} - -#[derive(Wrapper, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Display)] -#[wrapper(Deref, AsSlice, BorrowSlice, Hex)] -#[display(LowerHex)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct SigBlob(NonEmptyBlob<4096>); - -impl Default for SigBlob { - fn default() -> Self { SigBlob(NonEmptyBlob::with(0)) } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Debug, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct ContentSigs(NonEmptyOrdMap); - -impl StrictDumb for ContentSigs { - fn strict_dumb() -> Self { - Self(NonEmptyOrdMap::with_key_value(strict_dumb!(), SigBlob::default())) - } -} - -impl IntoIterator for ContentSigs { - type Item = (Identity, SigBlob); - type IntoIter = btree_map::IntoIter; - - fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } -} diff --git a/src/contract/allocation.rs b/src/contract/allocation.rs deleted file mode 100644 index cb3cdc64..00000000 --- a/src/contract/allocation.rs +++ /dev/null @@ -1,149 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::cmp::Ordering; -use std::collections::HashMap; -use std::fmt::Debug; -use std::hash::Hash; - -use rgb::vm::WitnessOrd; -use rgb::{AssignmentType, ExposedSeal, OpId, Opout, State, XChain, XOutputSeal, XWitnessId}; -use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; - -use crate::LIB_NAME_RGB_STD; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, 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 WitnessInfo { - pub id: XWitnessId, - pub ord: WitnessOrd, -} - -/// Allocation is an owned state assignment, equipped with information about the operation defining -/// the assignment and the witness id, containing the commitment to the operation. -#[allow(clippy::derived_hash_with_manual_eq)] -#[derive(Clone, Eq, Hash, 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 Allocation { - pub opout: Opout, - pub seal: XOutputSeal, - pub state: State, - pub witness: Option, -} - -impl PartialEq for Allocation { - fn eq(&self, other: &Self) -> bool { - // We ignore difference in witness transactions, state and seal definitions here - // in order to support updates from the ephemeral state of the lightning - // channels. See - // for the details. - let res = self.opout == other.opout && self.seal == other.seal; - #[cfg(debug_assertions)] - if res { - debug_assert_eq!(self.state, other.state); - } - res - } -} - -impl PartialOrd for Allocation { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for Allocation { - fn cmp(&self, other: &Self) -> Ordering { - if self == other { - return Ordering::Equal; - } - match self.opout.cmp(&other.opout) { - Ordering::Equal => self.seal.cmp(&other.seal), - ordering => ordering, - } - } -} - -impl Allocation { - /// # Panics - /// - /// If the processing is done on invalid stash data, the seal is - /// witness-based and the anchor chain doesn't match the seal chain. - pub fn with_witness( - seal: XChain, - witness_id: XWitnessId, - state: State, - opid: OpId, - ty: AssignmentType, - no: u16, - ) -> Self { - Allocation { - opout: Opout::new(opid, ty, no), - seal: seal.try_to_output_seal(witness_id).expect( - "processing contract from unverified/invalid stash: witness seal chain doesn't \ - match anchor's chain", - ), - state, - witness: witness_id.into(), - } - } - - /// # Panics - /// - /// If the processing is done on invalid stash data, the seal is - /// witness-based and the anchor chain doesn't match the seal chain. - pub fn with_no_witness( - seal: XChain, - state: State, - opid: OpId, - ty: AssignmentType, - no: u16, - ) -> Self { - Allocation { - opout: Opout::new(opid, ty, no), - seal: seal.to_output_seal().expect( - "processing contract from unverified/invalid stash: seal must have txid \ - information since it comes from genesis or extension", - ), - state, - witness: None, - } - } - - pub fn check_witness(&self, filter: &HashMap) -> bool { - match self.witness { - None => true, - Some(witness_id) => { - !matches!(filter.get(&witness_id), None | Some(WitnessOrd::Archived)) - } - } - } -} diff --git a/src/contract/merge_reveal.rs b/src/contract/merge_reveal.rs deleted file mode 100644 index a8975f24..00000000 --- a/src/contract/merge_reveal.rs +++ /dev/null @@ -1,211 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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; - -use amplify::confinement::{Confined, NonEmptyVec}; -use amplify::Wrapper; -use bp::Txid; -use commit_verify::{mpc, Conceal}; -use rgb::{ - Assign, Assignments, BundleId, ExposedSeal, Extension, Genesis, OpId, Operation, Transition, - TransitionBundle, TypedAssigns, -}; - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum MergeRevealError { - /// operations {0} and {1} has different commitment ids and can't be - /// merge-revealed. This usually means internal application business logic - /// error which should be reported to the software vendor. - OperationMismatch(OpId, OpId), - - /// mismatch in anchor chains: one grip references bitcoin transaction - /// {bitcoin} and the other merged part references liquid transaction - /// {liquid}. - ChainMismatch { bitcoin: Txid, liquid: Txid }, - - /// mismatching transaction id for merge-revealed: {0} and {1}. - TxidMismatch(Txid, Txid), - - /// anchors in anchored bundle are not equal for bundle {0}. - AnchorsNonEqual(BundleId), - - /// the merged bundles contain more transitions than inputs. - InsufficientInputs, - - /// contract id provided for the merge-reveal operation doesn't match - /// multiprotocol commitment. - #[from(mpc::InvalidProof)] - #[from(mpc::LeafNotKnown)] - ContractMismatch, -} - -/// A trait to merge two structures modifying the revealed status -/// of the first one. The merge operation will **consume** both the structures -/// and return a new structure with revealed states. -/// -/// The resulting structure will depend on the reveal status of both of the -/// variant. And the most revealed condition among the two will be selected -/// Usage: prevent hiding already known previous state data by merging -/// incoming new consignment in stash. -/// -/// The following conversion logic is intended by this trait: -/// -/// merge(Revealed, Anything) => Revealed -/// merge(ConfidentialSeal, ConfidentialAmount) => Revealed -/// merge(ConfidentialAmount, ConfidentialSeal) => Revealed -/// merge(Confidential, Anything) => Anything -pub trait MergeReveal: Sized { - // TODO: Take self by mut ref instead of consuming (will remove clones in - // Stash::consume operation). - fn merge_reveal(self, other: Self) -> Result; -} - -/* -pub trait MergeRevealContract: Sized { - fn merge_reveal_contract( - self, - other: Self, - contract_id: ContractId, - ) -> Result; -} - */ - -impl MergeReveal for Assign { - fn merge_reveal(self, other: Self) -> Result { - debug_assert_eq!(self.conceal(), other.conceal()); - match (self, other) { - // Anything + Revealed = Revealed - (_, state @ Assign::Revealed { .. }) | (state @ Assign::Revealed { .. }, _) => { - Ok(state) - } - // Anything + Confidential = Anything - (state, Assign::Confidential { .. }) => Ok(state), - } - } -} - -impl MergeReveal for TypedAssigns { - fn merge_reveal(self, other: Self) -> Result { - let mut result = Vec::with_capacity(self.len()); - for (first, second) in self.into_iter().zip(other.into_iter()) { - result.push(first.merge_reveal(second)?); - } - Ok(TypedAssigns::from(NonEmptyVec::from_checked(result))) - } -} - -impl MergeReveal for Assignments { - fn merge_reveal(self, other: Self) -> Result { - let mut result = BTreeMap::new(); - for (first, second) in self - .into_inner() - .into_iter() - .zip(other.into_inner().into_iter()) - { - debug_assert_eq!(first.0, second.0); - result.insert(first.0, first.1.merge_reveal(second.1)?); - } - Ok(Assignments::from_inner( - Confined::try_from(result).expect("collection of the same size"), - )) - } -} - -impl MergeReveal for TransitionBundle { - fn merge_reveal(mut self, other: Self) -> Result { - debug_assert_eq!(self.bundle_id(), other.bundle_id()); - - let mut self_transitions = self.known_transitions.release(); - for (opid, other_transition) in other.known_transitions { - if let Some(mut transition) = self_transitions.remove(&opid) { - transition = transition.merge_reveal(other_transition)?; - self_transitions.insert(opid, transition); - } - } - self.known_transitions = Confined::from_checked(self_transitions); - - if self.input_map.len() < self.known_transitions.len() { - return Err(MergeRevealError::InsufficientInputs); - } - Ok(self) - } -} - -/* -impl MergeRevealContract for AnchoredBundle { - fn merge_reveal_contract( - self, - other: Self, - contract_id: ContractId, - ) -> Result { - let bundle_id = self.bundle_id(); - let anchor1 = self.anchor.into_merkle_block(contract_id, bundle_id)?; - let anchor2 = other.anchor.into_merkle_block(contract_id, bundle_id)?; - Ok(AnchoredBundle { - anchor: anchor1 - .merge_reveal(anchor2)? - .into_merkle_proof(contract_id)?, - bundle: self.bundle.merge_reveal(other.bundle)?, - }) - } -} - */ - -impl MergeReveal for Genesis { - fn merge_reveal(mut self, other: Self) -> Result { - let self_id = self.id(); - let other_id = other.id(); - if self_id != other_id { - return Err(MergeRevealError::OperationMismatch( - OpId::from_inner(self_id.into_inner()), - OpId::from_inner(other_id.into_inner()), - )); - } - self.assignments = self.assignments.merge_reveal(other.assignments)?; - Ok(self) - } -} - -impl MergeReveal for Transition { - fn merge_reveal(mut self, other: Self) -> Result { - let self_id = self.id(); - let other_id = other.id(); - if self_id != other_id { - return Err(MergeRevealError::OperationMismatch(self_id, other_id)); - } - self.assignments = self.assignments.merge_reveal(other.assignments)?; - Ok(self) - } -} - -impl MergeReveal for Extension { - fn merge_reveal(mut self, other: Self) -> Result { - let self_id = self.id(); - let other_id = other.id(); - if self_id != other_id { - return Err(MergeRevealError::OperationMismatch(self_id, other_id)); - } - self.assignments = self.assignments.merge_reveal(other.assignments)?; - Ok(self) - } -} diff --git a/src/contract/mod.rs b/src/contract/mod.rs deleted file mode 100644 index cc0c48f2..00000000 --- a/src/contract/mod.rs +++ /dev/null @@ -1,91 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -mod allocation; -mod merge_reveal; - -pub use allocation::{Allocation, WitnessInfo}; -pub use merge_reveal::{MergeReveal, MergeRevealError}; -use rgb::vm::OrdOpRef; -use rgb::{ExtensionType, OpId, TransitionType, XWitnessId}; - -use crate::LIB_NAME_RGB_STD; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum OpWitness { - #[strict_type(dumb)] - Genesis, - Transition(XWitnessId, TransitionType), - Extension(XWitnessId, ExtensionType), -} - -impl From> for OpWitness { - fn from(aor: OrdOpRef) -> Self { - match aor { - OrdOpRef::Genesis(_) => OpWitness::Genesis, - OrdOpRef::Transition(op, witness_id, ..) => { - OpWitness::Transition(witness_id, op.transition_type) - } - OrdOpRef::Extension(op, witness_id, ..) => { - OpWitness::Extension(witness_id, op.extension_type) - } - } - } -} - -impl OpWitness { - #[inline] - pub fn witness_id(&self) -> Option { - match self { - OpWitness::Genesis => None, - OpWitness::Transition(witness_id, _) | OpWitness::Extension(witness_id, _) => { - Some(*witness_id) - } - } - } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, 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 GlobalOut { - pub opid: OpId, - pub nonce: u64, - pub index: u16, - pub op_witness: OpWitness, -} - -impl GlobalOut { - #[inline] - pub fn witness_id(&self) -> Option { self.op_witness.witness_id() } -} diff --git a/src/info.rs b/src/info.rs deleted file mode 100644 index 261d890d..00000000 --- a/src/info.rs +++ /dev/null @@ -1,319 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::HashMap; -use std::fmt::{self, Debug, Display, Formatter, Write}; -use std::str::FromStr; - -use amplify::confinement::TinyOrdSet; -use chrono::{DateTime, TimeZone, Utc}; -use rgb::{AltLayer1Set, ContractId, Genesis, Identity, Operation, SchemaId}; -use strict_encoding::stl::{AlphaCapsLodash, AlphaNumLodash}; -use strict_encoding::{FieldName, RString, StrictDeserialize, StrictSerialize, TypeName}; - -use crate::containers::{ - SupplSub, Supplement, SUPPL_ANNOT_IFACE_CLASS, SUPPL_ANNOT_IFACE_FEATURES, -}; -use crate::interface::{Iface, IfaceId, IfaceImpl, IfaceRef, ImplId, VerNo}; -use crate::persistence::SchemaIfaces; -use crate::LIB_NAME_RGB_STD; - -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] -#[wrapper(Deref, Display, FromStr)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct IfaceClassName(RString); - -impl_ident_type!(IfaceClassName); -impl_ident_subtype!(IfaceClassName); -impl_strict_newtype!(IfaceClassName, LIB_NAME_RGB_STD); - -impl StrictSerialize for IfaceClassName {} -impl StrictDeserialize for IfaceClassName {} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct FeatureList(TinyOrdSet); - -impl StrictSerialize for FeatureList {} -impl StrictDeserialize for FeatureList {} - -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct IfaceInfo { - pub id: IfaceId, - pub version: VerNo, - pub name: TypeName, - pub standard: Option, - pub features: FeatureList, - pub developer: Identity, - pub created_at: DateTime, - pub inherits: Vec, - pub default_op: Option, -} - -impl IfaceInfo { - pub fn new( - iface: &Iface, - names: &HashMap, - suppl: Option<&Supplement>, - ) -> Self { - let mut standard = None; - let mut features = none!(); - if let Some(suppl) = suppl { - standard = - suppl.get_default_opt::(SupplSub::Itself, SUPPL_ANNOT_IFACE_CLASS); - if let Some(list) = - suppl.get_default_opt::(SupplSub::Itself, SUPPL_ANNOT_IFACE_FEATURES) - { - features = list - }; - } - Self::with(iface, standard, features, names) - } - - pub fn with( - iface: &Iface, - standard: Option, - features: FeatureList, - names: &HashMap, - ) -> Self { - IfaceInfo { - id: iface.iface_id(), - version: iface.version, - name: iface.name.clone(), - standard, - features, - developer: iface.developer.clone(), - created_at: Utc - .timestamp_opt(iface.timestamp, 0) - .single() - .unwrap_or_else(Utc::now), - inherits: iface - .inherits - .iter() - .map(|id| { - names - .get(id) - .cloned() - .map(IfaceRef::Name) - .unwrap_or(IfaceRef::Id(*id)) - }) - .collect(), - default_op: iface.default_operation.clone(), - } - } -} - -impl Display for IfaceInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!( - f, - "{}\t", - self.standard - .as_ref() - .map(IfaceClassName::to_string) - .unwrap_or_else(|| s!("~")) - )?; - write!(f, "{: <40}\t", self.name.to_string())?; - write!(f, "{}\t", self.created_at.format("%Y-%m-%d"))?; - write!(f, "{}\t", self.version)?; - writeln!(f, "{}", self.id)?; - - writeln!( - f, - " Features: {}", - self.features - .iter() - .map(FieldName::to_string) - .collect::>() - .join(", ") - )?; - - writeln!( - f, - " Defaults to: {}", - self.default_op - .as_ref() - .map(FieldName::to_string) - .unwrap_or_else(|| s!("~")) - )?; - - writeln!(f, " Developer: {}", self.developer)?; - - writeln!( - f, - " Inherits: {}", - self.inherits - .iter() - .map(|f| format!("{:#}", f)) - .collect::>() - .chunks(5) - .map(|chunk| chunk.join(", ")) - .collect::>() - .join("\n ") - ) - } -} - -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct SchemaInfo { - pub id: SchemaId, - pub name: TypeName, - pub developer: Identity, - pub created_at: DateTime, - pub implements: Vec, -} - -impl SchemaInfo { - pub fn with(schema_ifaces: &SchemaIfaces) -> Self { - let schema = &schema_ifaces.schema; - SchemaInfo { - id: schema.schema_id(), - name: schema.name.clone(), - developer: schema.developer.clone(), - created_at: Utc - .timestamp_opt(schema.timestamp, 0) - .single() - .unwrap_or_else(Utc::now), - implements: schema_ifaces - .iimpls - .iter() - .map(|(name, iimpl)| ImplInfo::with(name.clone(), iimpl)) - .collect(), - } - } -} - -impl Display for SchemaInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{: <24}", self.name.to_string())?; - write!(f, "\t{: <80}", self.id.to_string())?; - write!(f, "\t{}", self.created_at.format("%Y-%m-%d"))?; - writeln!(f, "\t{}", self.developer)?; - for info in &self.implements { - write!(f, " {info}")?; - } - Ok(()) - } -} - -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ImplInfo { - pub id: ImplId, - pub iface_id: IfaceId, - pub iface_name: TypeName, - pub developer: Identity, - pub created_at: DateTime, -} - -impl ImplInfo { - pub fn with(iface_name: TypeName, iimpl: &IfaceImpl) -> Self { - ImplInfo { - id: iimpl.impl_id(), - iface_id: iimpl.iface_id, - iface_name, - developer: iimpl.developer.clone(), - created_at: Utc - .timestamp_opt(iimpl.timestamp, 0) - .single() - .unwrap_or_else(Utc::now), - } - } -} - -impl Display for ImplInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{: <24}", self.iface_name.to_string())?; - write!(f, "\t{: <80}", self.id.to_string())?; - write!(f, "\t{}", self.created_at.format("%Y-%m-%d"))?; - writeln!(f, "\t{}", self.developer) - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ContractInfo { - pub id: ContractId, - pub schema_id: SchemaId, - pub issuer: Identity, - pub issued_at: DateTime, - pub testnet: bool, - pub alt_layers1: AltLayer1Set, -} - -impl ContractInfo { - pub fn with(genesis: &Genesis) -> Self { - ContractInfo { - id: genesis.contract_id(), - schema_id: genesis.schema_id, - issuer: genesis.issuer.clone(), - issued_at: Utc - .timestamp_opt(genesis.timestamp, 0) - .single() - .unwrap_or_else(Utc::now), - testnet: genesis.testnet, - alt_layers1: genesis.alt_layers1.clone(), - } - } -} - -impl Display for ContractInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.id)?; - write!( - f, - "\tbitcoin{: <12}", - self.alt_layers1.iter().fold(s!(""), |mut acc, layer| { - write!(acc, ", {layer}").ok(); - acc - }) - )?; - write!(f, "\t{}", self.issued_at.format("%Y-%m-%d"))?; - writeln!(f, "\t{: <80}", self.schema_id.to_string())?; - writeln!(f, " Developer: {}", self.issuer) - } -} diff --git a/src/interface/builder.rs b/src/interface/builder.rs deleted file mode 100644 index 5b2f08b4..00000000 --- a/src/interface/builder.rs +++ /dev/null @@ -1,834 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -#![allow(clippy::result_large_err)] - -use std::collections::btree_map::Entry; - -use amplify::confinement::{self, Confined, SmallOrdSet, TinyOrdMap}; -use chrono::Utc; -use rgb::validation::Scripts; -use rgb::{ - validation, AltLayer1, AltLayer1Set, AssignmentType, Assignments, AttachId, ContractId, - ExposedSeal, Genesis, GenesisSeal, GlobalState, GlobalStateSchema, GlobalStateType, GraphSeal, - Identity, Input, Layer1, MetaType, Metadata, MetadataError, Opout, Schema, State, StateData, - Transition, TransitionType, TypedAssigns, ValencyType, XChain, XOutpoint, STATE_DATA_MAX_LEN, -}; -use strict_encoding::{FieldName, SerializeError, StrictSerialize}; -use strict_types::{decode, typify, SemId, StrictVal, TypeSystem}; - -use crate::containers::{BuilderSeal, ContainerVer, Contract, ValidConsignment}; -use crate::interface::resolver::DumbResolver; -use crate::interface::{Iface, IfaceImpl, StateCalc, StateCalcError, TransitionIface}; -use crate::Outpoint; - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum BuilderError { - /// contract already has too many layers1. - TooManyLayers1, - - /// metadata `{0}` are not known to the schema - MetadataNotFound(FieldName), - - #[from] - #[display(inner)] - MetadataInvalid(MetadataError), - - /// global state `{0}` is not known to the schema. - GlobalNotFound(FieldName), - - /// assignment `{0}` is not known to the schema. - AssignmentNotFound(FieldName), - - /// valency `{0}` is not known to the schema. - ValencyNotFound(FieldName), - - /// transition `{0}` is not known to the schema. - TransitionNotFound(FieldName), - - /// interface doesn't specify default operation name, thus an explicit - /// operation type must be provided with `set_operation_type` method. - NoOperationSubtype, - - /// interface doesn't have a default assignment type. - NoDefaultAssignment, - - /// {0} is not supported by the contract genesis. - InvalidLayer1(Layer1), - - #[from] - #[display(inner)] - Calc(StateCalcError), - - #[from] - #[display(inner)] - StrictEncode(SerializeError), - - #[from] - #[display(inner)] - Reify(decode::Error), - - #[from] - #[display(inner)] - Typify(typify::Error), - - #[from] - #[display(inner)] - Confinement(confinement::Error), - - #[from] - #[display(inner)] - ContractInconsistency(validation::Status), -} - -mod private { - pub trait Sealed {} -} - -pub trait TxOutpoint: Copy + Eq + private::Sealed { - fn is_liquid(&self) -> bool; - fn is_bitcoin(&self) -> bool; - fn map_to_xchain(self, f: impl FnOnce(Outpoint) -> U) -> XChain; -} - -impl private::Sealed for Outpoint {} -impl private::Sealed for XOutpoint {} -impl TxOutpoint for Outpoint { - fn is_liquid(&self) -> bool { false } - fn is_bitcoin(&self) -> bool { true } - fn map_to_xchain(self, f: impl FnOnce(Outpoint) -> U) -> XChain { - XChain::Bitcoin(f(self)) - } -} -impl TxOutpoint for XOutpoint { - fn is_liquid(&self) -> bool { XChain::is_liquid(self) } - fn is_bitcoin(&self) -> bool { XChain::is_bitcoin(self) } - fn map_to_xchain(self, f: impl FnOnce(Outpoint) -> U) -> XChain { self.map(f) } -} - -#[derive(Clone, Debug)] -pub struct ContractBuilder { - builder: OperationBuilder, - testnet: bool, - alt_layers1: AltLayer1Set, - scripts: Scripts, - issuer: Identity, -} - -impl ContractBuilder { - pub fn with( - issuer: Identity, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - scripts: Scripts, - ) -> Self { - Self { - builder: OperationBuilder::with(iface, schema, iimpl, types), - testnet: true, - alt_layers1: none!(), - scripts, - issuer, - } - } - - pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } - - pub fn set_mainnet(mut self) -> Self { - self.testnet = false; - self - } - - pub fn has_layer1(&self, layer1: Layer1) -> bool { - match layer1 { - Layer1::Bitcoin => true, - Layer1::Liquid => self.alt_layers1.contains(&AltLayer1::Liquid), - } - } - pub fn check_layer1(&self, layer1: Layer1) -> Result<(), BuilderError> { - if !self.has_layer1(layer1) { - return Err(BuilderError::InvalidLayer1(layer1)); - } - Ok(()) - } - - pub fn add_layer1(mut self, layer1: AltLayer1) -> Result { - self.alt_layers1 - .push(layer1) - .map_err(|_| BuilderError::TooManyLayers1)?; - Ok(self) - } - - #[inline] - pub fn meta_type(&self, name: impl Into) -> Result { - self.builder.meta_type(name) - } - - #[inline] - pub fn global_type(&self, name: impl Into) -> Result { - self.builder.global_type(name) - } - - #[inline] - pub fn valency_type(&self, name: impl Into) -> Result { - self.builder.valency_type(name) - } - - #[inline] - pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - - #[inline] - pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { - self.builder.valency_name(type_id) - } - - pub fn add_metadata( - mut self, - name: impl Into, - value: StrictVal, - ) -> Result { - self.builder = self.builder.add_metadata(name, value)?; - Ok(self) - } - - #[inline] - pub fn serialize_metadata( - mut self, - name: impl Into, - value: &impl StrictSerialize, - ) -> Result { - self.builder = self.builder.serialize_metadata(name, value)?; - Ok(self) - } - - pub fn add_global_state( - mut self, - name: impl Into, - value: StrictVal, - ) -> Result { - self.builder = self.builder.add_global_state(name, value)?; - Ok(self) - } - - #[inline] - pub fn serialize_global_state( - mut self, - name: impl Into, - value: &impl StrictSerialize, - ) -> Result { - self.builder = self.builder.serialize_global_state(name, value)?; - Ok(self) - } - - pub fn add_owned_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: State, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; - Ok(self) - } - - pub fn add_rights( - mut self, - name: impl Into, - seal: impl Into>, - attach: Option, - ) -> Result { - self.builder = self.builder.add_rights(name, seal, attach)?; - Ok(self) - } - - pub fn add_owned_state( - mut self, - name: impl Into, - seal: impl Into>, - state: StrictVal, - attach: Option, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self.builder.add_owned_state(name, seal, state, attach)?; - Ok(self) - } - - pub fn serialize_owned_state( - mut self, - name: impl Into, - seal: impl Into>, - value: &impl StrictSerialize, - attach: Option, - ) -> Result { - let seal = seal.into(); - self.check_layer1(seal.layer1())?; - self.builder = self - .builder - .serialize_owned_state(name, seal, value, attach)?; - Ok(self) - } - - pub fn issue_contract(self) -> Result, BuilderError> { - self.issue_contract_raw(Utc::now().timestamp()) - } - - pub fn issue_contract_det( - self, - timestamp: i64, - ) -> Result, BuilderError> { - self.issue_contract_raw(timestamp) - } - - fn issue_contract_raw(self, timestamp: i64) -> Result, BuilderError> { - let (schema, iface, iimpl, global, assignments, types) = self.builder.complete(); - - let genesis = Genesis { - ffv: none!(), - schema_id: schema.schema_id(), - flags: none!(), - timestamp, - testnet: self.testnet, - alt_layers1: self.alt_layers1, - metadata: empty!(), - globals: global, - assignments, - valencies: none!(), - issuer: self.issuer, - validator: none!(), - }; - - let ifaces = tiny_bmap! { iface => iimpl }; - let scripts = Confined::from_iter_checked(self.scripts.into_values()); - - let contract = Contract { - version: ContainerVer::V2, - transfer: false, - terminals: none!(), - genesis, - extensions: none!(), - bundles: none!(), - schema, - ifaces, - attachments: none!(), // TODO: Add support for attachment files - - types, - scripts, - - supplements: none!(), // TODO: Add supplements - signatures: none!(), // TODO: Add signatures - }; - - let valid_contract = contract - .validate(&DumbResolver, self.testnet) - .map_err(|(status, _)| status)?; - - Ok(valid_contract) - } -} - -#[derive(Debug)] -pub struct TransitionBuilder { - contract_id: ContractId, - builder: OperationBuilder, - nonce: u64, - transition_type: TransitionType, - inputs: TinyOrdMap, - // TODO: Remove option once we have blank builder - calc: Option, -} - -impl TransitionBuilder { - pub fn blank_transition( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - ) -> Self { - Self::with(contract_id, iface, schema, iimpl, TransitionType::BLANK, types, None) - } - - pub fn default_transition( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - scripts: Scripts, - ) -> Result { - let transition_type = iface - .default_operation - .as_ref() - .and_then(|name| iimpl.transition_type(name)) - .ok_or(BuilderError::NoOperationSubtype)?; - let calc = StateCalc::new(scripts, iimpl.state_abi); - Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types, Some(calc))) - } - - pub fn named_transition( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_name: impl Into, - types: TypeSystem, - scripts: Scripts, - ) -> Result { - let transition_name = transition_name.into(); - let transition_type = iimpl - .transition_type(&transition_name) - .ok_or(BuilderError::TransitionNotFound(transition_name))?; - let calc = StateCalc::new(scripts, iimpl.state_abi); - Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types, Some(calc))) - } - - fn with( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_type: TransitionType, - types: TypeSystem, - calc: Option, - ) -> Self { - Self { - contract_id, - builder: OperationBuilder::with(iface, schema, iimpl, types), - nonce: u64::MAX, - transition_type, - inputs: none!(), - calc, - } - } - - pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } - - pub fn transition_type(&self) -> TransitionType { self.transition_type } - - #[inline] - pub fn global_type(&self, name: impl Into) -> Result { - self.builder.global_type(name) - } - - #[inline] - pub fn assignments_type( - &self, - name: impl Into, - ) -> Result { - self.builder.assignments_type(name) - } - - #[inline] - pub fn valency_type(&self, name: impl Into) -> Result { - self.builder.valency_type(name) - } - - #[inline] - pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { - self.builder.valency_name(type_id) - } - - pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - - pub fn default_assignment(&self) -> Result<&FieldName, BuilderError> { - self.builder - .transition_iface(self.transition_type) - .default_assignment - .as_ref() - .ok_or(BuilderError::NoDefaultAssignment) - } - - pub fn set_nonce(mut self, nonce: u64) -> Self { - self.nonce = nonce; - self - } - - pub fn add_input(mut self, opout: Opout, state: State) -> Result { - if let Some(calc) = &mut self.calc { - calc.reg_input(opout.ty, &state)?; - } - self.inputs.insert(Input::with(opout), state)?; - Ok(self) - } - - pub fn add_metadata( - mut self, - name: impl Into, - value: StrictVal, - ) -> Result { - self.builder = self.builder.add_metadata(name, value)?; - Ok(self) - } - - #[inline] - pub fn serialize_metadata( - mut self, - name: impl Into, - value: &impl StrictSerialize, - ) -> Result { - self.builder = self.builder.serialize_metadata(name, value)?; - Ok(self) - } - - pub fn add_global_state( - mut self, - name: impl Into, - value: StrictVal, - ) -> Result { - self.builder = self.builder.add_global_state(name, value)?; - Ok(self) - } - - #[inline] - pub fn serialize_global_state( - mut self, - name: impl Into, - value: &impl StrictSerialize, - ) -> Result { - self.builder = self.builder.serialize_global_state(name, value)?; - Ok(self) - } - - // TODO: We won't need this once we will have Blank Transition builder - /// NB: This does not process the state with VM - pub fn add_owned_state_blank( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: State, - ) -> Result { - self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; - Ok(self) - } - - pub fn add_rights( - mut self, - name: impl Into, - seal: impl Into>, - attach: Option, - ) -> Result { - self.builder = self.builder.add_rights(name, seal, attach)?; - Ok(self) - } - - pub fn fulfill_owned_state( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: State, - ) -> Result<(Self, Option), BuilderError> { - let calc = self - .calc - .as_mut() - .expect("you must not call fulfill_owned_state for the blank transition builder"); - let state = calc.calc_output(type_id, &state)?; - self.builder = self - .builder - .add_owned_state_raw(type_id, seal, state.sufficient)?; - Ok((self, state.insufficient)) - } - - pub fn add_owned_state_change( - mut self, - type_id: AssignmentType, - seal: impl Into>, - ) -> Result { - let calc = self - .calc - .as_mut() - .expect("you must not call add_owned_state_change for the blank transition builder"); - if let Some(state) = calc.calc_change(type_id)? { - self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; - } - Ok(self) - } - - pub fn has_inputs(&self) -> bool { !self.inputs.is_empty() } - - pub fn complete_transition(self) -> Result { - let (_, _, _, global, assignments, _) = self.builder.complete(); - - let transition = Transition { - ffv: none!(), - contract_id: self.contract_id, - nonce: self.nonce, - transition_type: self.transition_type, - metadata: empty!(), - globals: global, - inputs: SmallOrdSet::from_iter_checked(self.inputs.into_keys()).into(), - assignments, - valencies: none!(), - witness: none!(), - validator: none!(), - }; - - // TODO: Validate against schema - - Ok(transition) - } -} - -#[derive(Clone, Debug)] -pub struct OperationBuilder { - // TODO: use references instead of owned values - schema: Schema, - iface: Iface, - iimpl: IfaceImpl, - - global: GlobalState, - meta: Metadata, - assignments: Assignments, - // TODO: add valencies - types: TypeSystem, -} - -impl OperationBuilder { - fn with(iface: Iface, schema: Schema, iimpl: IfaceImpl, types: TypeSystem) -> Self { - OperationBuilder { - schema, - iface, - iimpl, - - global: none!(), - assignments: none!(), - meta: none!(), - types, - } - } - - fn type_system(&self) -> &TypeSystem { &self.types } - - fn transition_iface(&self, ty: TransitionType) -> &TransitionIface { - let transition_name = self.iimpl.transition_name(ty).expect("reverse type"); - self.iface - .transitions - .get(transition_name) - .expect("internal inconsistency") - } - - fn assignments_type(&self, name: impl Into) -> Result { - let name = name.into(); - self.iimpl - .assignment_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name)) - } - - fn meta_type(&self, name: impl Into) -> Result { - let name = name.into(); - self.iimpl - .meta_type(&name) - .ok_or(BuilderError::MetadataNotFound(name)) - } - - fn meta_name(&self, ty: MetaType) -> &FieldName { - self.iimpl.meta_name(ty).expect("internal inconsistency") - } - - fn global_type(&self, name: impl Into) -> Result { - let name = name.into(); - self.iimpl - .global_type(&name) - .ok_or(BuilderError::GlobalNotFound(name)) - } - - fn valency_type(&self, name: impl Into) -> Result { - let name = name.into(); - self.iimpl - .valency_type(&name) - .ok_or(BuilderError::ValencyNotFound(name)) - } - - fn valency_name(&self, ty: ValencyType) -> &FieldName { - self.iimpl.valency_name(ty).expect("internal inconsistency") - } - - #[inline] - fn meta_schema(&self, type_id: MetaType) -> SemId { - *self - .schema - .meta_types - .get(&type_id) - .expect("schema should match interface: must be checked by the constructor") - } - - #[inline] - fn global_schema(&self, type_id: GlobalStateType) -> &GlobalStateSchema { - self.schema - .global_types - .get(&type_id) - .expect("schema should match interface: must be checked by the constructor") - } - - fn add_metadata( - mut self, - name: impl Into, - value: StrictVal, - ) -> Result { - let type_id = self.meta_type(name)?; - - let types = self.type_system(); - let sem_id = *self - .schema - .meta_types - .get(&type_id) - .expect("schema-interface inconsistency"); - let value = types.typify(value, sem_id)?; - let data = types.strict_serialize_value::(&value)?; - - self.meta.add_value(type_id, data.into())?; - Ok(self) - } - - fn serialize_metadata( - mut self, - name: impl Into, - value: &impl StrictSerialize, - ) -> Result { - let type_id = self.meta_type(name)?; - let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; - let sem_id = self.meta_schema(type_id); - - #[cfg(debug_assertions)] - self.types - .strict_deserialize_type(sem_id, &serialized) - .expect("failed deserialization"); - - self.meta.add_value(type_id, serialized.into())?; - Ok(self) - } - - fn add_global_state( - mut self, - name: impl Into, - value: StrictVal, - ) -> Result { - let type_id = self.global_type(name)?; - - let types = self.type_system(); - let sem_id = self - .schema - .global_types - .get(&type_id) - .expect("schema-interface inconsistency") - .sem_id; - let value = types.typify(value, sem_id)?; - let data = types.strict_serialize_value::(&value)?; - - self.global.add_state(type_id, data.into())?; - Ok(self) - } - - fn serialize_global_state( - mut self, - name: impl Into, - value: &impl StrictSerialize, - ) -> Result { - let type_id = self.global_type(name)?; - let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; - let sem_id = self.global_schema(type_id).sem_id; - - #[cfg(debug_assertions)] - self.types - .strict_deserialize_type(sem_id, &serialized) - .expect("failed deserialization"); - - self.global.add_state(type_id, serialized.into())?; - - Ok(self) - } - - fn add_owned_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: State, - ) -> Result { - let assignment = seal.into().assignment(state); - - match self.assignments.entry(type_id)? { - Entry::Vacant(entry) => { - entry.insert(TypedAssigns::with(assignment)); - } - Entry::Occupied(mut entry) => { - entry.get_mut().push(assignment)?; - } - } - Ok(self) - } - - fn add_rights( - self, - name: impl Into, - seal: impl Into>, - attach: Option, - ) -> Result { - let type_id = self.assignments_type(name)?; - let mut state = State::default(); - state.attach = attach; - self.add_owned_state_raw(type_id, seal, state) - } - - fn add_owned_state( - self, - name: impl Into, - seal: impl Into>, - value: StrictVal, - attach: Option, - ) -> Result { - let type_id = self.assignments_type(name)?; - - let types = self.type_system(); - let sem_id = self - .schema - .owned_types - .get(&type_id) - .expect("schema-interface inconsistency") - .sem_id; - let value = types.typify(value, sem_id)?; - let data = types.strict_serialize_value::(&value)?; - - let mut state = State::from(StateData::from(data)); - state.attach = attach; - self.add_owned_state_raw(type_id, seal, state) - } - - fn serialize_owned_state( - self, - name: impl Into, - seal: impl Into>, - value: &impl StrictSerialize, - attach: Option, - ) -> Result { - let type_id = self.assignments_type(name)?; - - let mut state = State::from_serialized(value)?; - state.attach = attach; - self.add_owned_state_raw(type_id, seal, state) - } - - fn complete(self) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments, TypeSystem) { - (self.schema, self.iface, self.iimpl, self.global, self.assignments, self.types) - } -} diff --git a/src/interface/calc.rs b/src/interface/calc.rs deleted file mode 100644 index 077b2fd5..00000000 --- a/src/interface/calc.rs +++ /dev/null @@ -1,194 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 aluvm::data::ByteStr; -use aluvm::library::{LibId, LibSite}; -use aluvm::reg::{Reg16, Reg32, RegA, RegR}; -use amplify::num::{u256, u4}; -use amplify::{ByteArray, Wrapper}; -use rgb::validation::Scripts; -use rgb::{AssignmentType, AttachId, StateData}; - -use crate::LIB_NAME_RGB_STD; - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum StateCalcError { - /// reserved byte value {0} is not 0x00 for assignment type {1}. - InvalidReserved(AssignmentType, u8), - /// error registering input state of type {0} - {1}. - InputReg(AssignmentType, String), - /// error registering output state of type {0} - {1}. - OutputReg(AssignmentType, String), - /// error computing output state of type {0} - {1}. - OutputCalc(AssignmentType, String), - /// error computing change state of type {0} - {1}. - ChangeCalc(AssignmentType, String), - /// failed script for calculating output state of type {0}; please update interface - /// implementation for the schema - InsufficientState(AssignmentType), -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, 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 StateAbi { - pub reg_input: LibSite, - pub reg_output: LibSite, - pub calc_output: LibSite, - pub calc_change: LibSite, -} - -impl StateAbi { - pub fn lib_ids(&self) -> impl Iterator { - [self.reg_input, self.reg_output, self.calc_output, self.calc_change] - .into_iter() - .map(|site| site.lib) - } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct AllocatedState { - pub sufficient: rgb::State, - pub insufficient: Option, -} - -#[derive(Clone, Debug)] -pub struct StateCalc { - vm: aluvm::Vm, - abi: StateAbi, - scripts: Scripts, -} - -impl StateCalc { - pub fn new(scripts: Scripts, abi: StateAbi) -> Self { - let vm = aluvm::Vm::new(); - Self { vm, abi, scripts } - } - - fn run(&mut self, site: LibSite) -> Result<(), String> { - if !self.vm.exec(site, |id| self.scripts.get(&id), &()) { - if let Some(err) = self.vm.registers.s16(15).cloned() { - return Err(err.to_string()); - } - } - Ok(()) - } - - fn put_state(&mut self, ty: AssignmentType, state: &rgb::State) { - self.vm - .registers - .set_n(RegA::A16, Reg32::Reg0, Some(ty.to_inner())); - assert_eq!(state.reserved, none!()); - self.vm.registers.set_n(RegA::A8, Reg32::Reg0, Some(0u8)); - self.vm.registers.set_s16(0, ByteStr::with(&state.data)); - self.vm.registers.set_n( - RegR::R256, - Reg32::Reg0, - state.attach.map(|a| u256::from_le_bytes(a.to_byte_array())), - ); - } - - fn fetch_state( - &self, - ty: AssignmentType, - idx: Reg16, - ) -> Result, StateCalcError> { - let Some(data) = self.vm.registers.s16(u4::from(idx)) else { - return Ok(None); - }; - let reserved = self - .vm - .registers - .get_n(RegA::A8, idx) - .map(|n| u8::from(n)) - .unwrap_or_default(); - let attach = self - .vm - .registers - .get_n(RegR::R256, idx) - .map(|n| AttachId::from_byte_array(u256::from(n).to_le_bytes())); - if reserved != 0x00 { - return Err(StateCalcError::InvalidReserved(ty, reserved)); - } - Ok(Some(rgb::State { - reserved: none!(), - data: StateData::from_checked(data.to_vec()), - attach, - })) - } - - pub fn reg_input( - &mut self, - ty: AssignmentType, - state: &rgb::State, - ) -> Result<(), StateCalcError> { - self.put_state(ty, state); - self.run(self.abi.reg_input) - .map_err(|err| StateCalcError::InputReg(ty, err)) - } - - pub fn reg_output( - &mut self, - ty: AssignmentType, - state: &rgb::State, - ) -> Result<(), StateCalcError> { - self.put_state(ty, state); - self.run(self.abi.reg_output) - .map_err(|err| StateCalcError::OutputReg(ty, err)) - } - - pub fn calc_output( - &mut self, - ty: AssignmentType, - state: &rgb::State, - ) -> Result { - self.put_state(ty, state); - self.run(self.abi.calc_output) - .map_err(|err| StateCalcError::OutputCalc(ty, err))?; - let Some(sufficient) = self.fetch_state(ty, Reg16::Reg0)? else { - return Err(StateCalcError::InsufficientState(ty)); - }; - let insufficient = self.fetch_state(ty, Reg16::Reg1)?; - Ok(AllocatedState { - sufficient, - insufficient, - }) - } - - pub fn calc_change( - &mut self, - ty: AssignmentType, - ) -> Result, StateCalcError> { - self.run(self.abi.calc_change) - .map_err(|err| StateCalcError::ChangeCalc(ty, err))?; - self.fetch_state(ty, Reg16::Reg0) - } - - pub fn is_sufficient_for(&self, ty: AssignmentType, state: &rgb::State) -> bool { - self.clone().calc_output(ty, state).is_ok() - } -} diff --git a/src/interface/contract.rs b/src/interface/contract.rs deleted file mode 100644 index e027b43c..00000000 --- a/src/interface/contract.rs +++ /dev/null @@ -1,439 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::borrow::Borrow; -use std::collections::{BTreeSet, HashMap, HashSet}; - -use amplify::confinement::SmallBlob; -use amplify::Wrapper; -use rgb::validation::Scripts; -use rgb::{ - AssignmentType, AttachId, ContractId, OpId, Opout, Schema, State, StateData, XOutputSeal, - XWitnessId, STATE_DATA_MAX_LEN, -}; -use strict_encoding::{FieldName, SerializeError, StrictDeserialize}; -use strict_types::{typify, SemId, StrictVal, TypeSystem}; - -use crate::contract::{Allocation, WitnessInfo}; -use crate::info::ContractInfo; -use crate::interface::{AssignmentsFilter, IfaceImpl, StateCalc}; -use crate::persistence::ContractStateRead; - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum ContractError { - /// field name {0} is unknown to the contract interface - FieldNameUnknown(FieldName), - - /// the provided state object is invalid; {0} - #[from] - Typify(typify::Error), - - /// the provided state exceeds maximum allowed length when serialized. - #[from] - Strict(SerializeError), -} - -/// Allocation is an owned state assignment, equipped with information about the operation defining -/// the assignment and the witness id, containing the commitment to the operation. -#[derive(Clone, PartialEq, Eq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Output { - pub opout: Opout, - pub seal: XOutputSeal, - pub state: T, - pub attach_id: Option, - pub witness: Option, -} - -impl From for Output { - fn from(a: Allocation) -> Self { - Output { - opout: a.opout, - seal: a.seal, - state: T::from_strict_serialized(a.state.data.to_inner()) - .expect("data in stash are not valid"), - attach_id: a.state.attach, - witness: a.witness, - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(lowercase)] -pub enum OpDirection { - Issued, - Received, - Sent, -} - -#[derive(Clone, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ContractOp { - pub direction: OpDirection, - pub ty: AssignmentType, - pub opids: BTreeSet, - pub state: StrictVal, - pub attach_id: Option, - pub to: BTreeSet, - pub witness: Option, -} - -impl ContractOp { - fn new( - direction: OpDirection, - assignment: Allocation, - value: StrictVal, - witness: Option, - ) -> Self { - Self { - direction, - ty: assignment.opout.ty, - opids: bset![assignment.opout.op], - state: value, - attach_id: assignment.state.attach, - to: bset![assignment.seal], - witness, - } - } - - fn issued(assignment: Allocation, value: StrictVal) -> Self { - Self::new(OpDirection::Issued, assignment, value, None) - } - - fn received(assignment: Allocation, value: StrictVal, witness: WitnessInfo) -> Self { - Self::new(OpDirection::Received, assignment, value, Some(witness)) - } - - fn sent(assignment: Allocation, value: StrictVal, witness: WitnessInfo) -> Self { - Self::new(OpDirection::Sent, assignment, value, Some(witness)) - } -} - -/// Contract state is an in-memory structure providing API to read structured -/// data from the [`rgb::ContractHistory`]. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct ContractIface { - pub state: S, - pub schema: Schema, - pub iface: IfaceImpl, - pub types: TypeSystem, - pub scripts: Scripts, - pub info: ContractInfo, -} - -impl ContractIface { - fn assignment_type(&self, name: impl Into) -> Result { - let name = name.into(); - self.iface - .assignment_type(&name) - .ok_or(ContractError::FieldNameUnknown(name)) - } - - fn assignment_sem_id(&self, ty: AssignmentType) -> SemId { - self.schema - .owned_types - .get(&ty) - .expect("invalid contract state") - .sem_id - } - - fn allocation_to_output(&self, a: &Allocation) -> Output { - Output { - opout: a.opout, - seal: a.seal, - state: self.value_from_state_raw(a.opout.ty, &a.state), - attach_id: a.state.attach, - witness: a.witness, - } - } - - pub fn value_from_state_raw(&self, ty: AssignmentType, state: &State) -> StrictVal { - self.types - .strict_deserialize_type(self.assignment_sem_id(ty), state.data.as_slice()) - .expect("invalid contract state") - .unbox() - } - - pub fn value_from_state( - &self, - name: impl Into, - state: &State, - ) -> Result { - let type_id = self.assignment_type(name)?; - Ok(self.value_from_state_raw(type_id, state)) - } - - pub fn value_to_state_raw( - &self, - ty: AssignmentType, - value: StrictVal, - ) -> Result { - let t = self.types.typify(value, self.assignment_sem_id(ty))?; - let value = self - .types - .strict_serialize_value::(&t)?; - Ok(value.into()) - } - - pub fn value_to_state( - &self, - name: impl Into, - value: StrictVal, - ) -> Result { - let type_id = self.assignment_type(name)?; - self.value_to_state_raw(type_id, value) - } - - pub fn contract_id(&self) -> ContractId { self.state.contract_id() } - - /// # Panics - /// - /// If data are corrupted and contract schema doesn't match interface implementations. - pub fn global( - &self, - name: impl Into, - ) -> Result + '_, ContractError> { - let name = name.into(); - let type_id = self - .iface - .global_type(&name) - .ok_or(ContractError::FieldNameUnknown(name))?; - let global_schema = self - .schema - .global_types - .get(&type_id) - .expect("schema doesn't match interface"); - Ok(self - .state - .global(type_id) - .expect("schema doesn't match interface") - .map(|data| { - self.types - .strict_deserialize_type(global_schema.sem_id, data.borrow()) - .expect("unvalidated contract data in stash") - .unbox() - })) - } - - /// # Panics - /// - /// If data are corrupted and contract schema doesn't match interface implementations. - pub fn global_typed( - &self, - name: impl Into, - ) -> Result + '_, ContractError> { - let name = name.into(); - let type_id = self - .iface - .global_type(&name) - .ok_or(ContractError::FieldNameUnknown(name))?; - Ok(self - .state - .global(type_id) - .expect("schema doesn't match interface") - .map(|data| { - let data = SmallBlob::from_slice_checked(data.borrow()); - T::from_strict_serialized(data).expect("unvalidated contract data in stash") - })) - } - - pub fn allocations<'c>( - &'c self, - filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { - self.state - .assignments() - .filter(move |a| filter.should_include(a.seal, a.witness)) - } - - pub fn outputs<'c>( - &'c self, - filter: impl AssignmentsFilter + 'c, - ) -> impl Iterator + 'c { - self.allocations(filter) - .map(|a| self.allocation_to_output(a)) - } - - pub fn outputs_by_type<'c>( - &'c self, - name: impl Into, - filter: impl AssignmentsFilter + 'c, - ) -> Result + 'c, ContractError> { - let type_id = self.assignment_type(name)?; - Ok(self - .outputs(filter) - .filter(move |outp| outp.opout.ty == type_id)) - } - - pub fn output_selection<'c, K: Ord + 'c>( - &'c self, - name: impl Into, - filter: impl AssignmentsFilter + 'c, - sorting: impl FnMut(&&Allocation) -> K, - state: &'c State, - ) -> Result + 'c, ContractError> { - let type_id = self.assignment_type(name)?; - let mut selected = self - .allocations(filter) - .filter(move |a| a.opout.ty == type_id) - .collect::>(); - selected.sort_by_key(sorting); - let mut calc = StateCalc::new(self.scripts.clone(), self.iface.state_abi); - Ok(selected - .into_iter() - .take_while(move |a| { - if calc.reg_input(a.opout.ty, &a.state).is_err() { - return false; - } - calc.is_sufficient_for(a.opout.ty, state) - }) - .map(|a| self.allocation_to_output(a))) - } - - pub fn outputs_typed<'c, T: StrictDeserialize + 'c>( - &'c self, - name: impl Into, - filter: impl AssignmentsFilter + 'c, - ) -> Result> + 'c, ContractError> { - let type_id = self.assignment_type(name)?; - Ok(self - .allocations(filter) - .filter(move |a| a.opout.ty == type_id) - .cloned() - .map(Output::from)) - } - - pub fn history( - &self, - filter_outpoints: impl AssignmentsFilter, - filter_witnesses: impl AssignmentsFilter, - ) -> Vec { - // get all allocations which ever belonged to this wallet and store them by witness id - let mut allocations_our_outpoint = self - .state - .assignments() - .filter(move |outp| filter_outpoints.should_include(outp.seal, outp.witness)) - .fold(HashMap::<_, HashSet<_>>::new(), |mut map, a| { - map.entry(a.witness).or_default().insert(a.clone()); - map - }); - // get all allocations which has a witness transaction belonging to this wallet - let mut allocations_our_witness = self - .state - .assignments() - .filter(move |outp| filter_witnesses.should_include(outp.seal, outp.witness)) - .fold(HashMap::<_, HashSet<_>>::new(), |mut map, a| { - let witness = a.witness.expect( - "all empty witnesses must be already filtered out by wallet.filter_witness()", - ); - map.entry(witness).or_default().insert(a.clone()); - map - }); - - // gather all witnesses from both sets - let mut witness_ids = allocations_our_witness - .keys() - .cloned() - .collect::>(); - witness_ids.extend(allocations_our_outpoint.keys().filter_map(|x| *x)); - - // reconstruct contract history from the wallet perspective - let mut ops = Vec::with_capacity(witness_ids.len() + 1); - // add allocations with no witness to the beginning of the history - if let Some(genesis_state) = allocations_our_outpoint.remove(&None) { - for assignment in genesis_state { - let value = self.value_from_state_raw(assignment.opout.ty, &assignment.state); - ops.push(ContractOp::issued(assignment, value)) - } - } - for witness_id in witness_ids { - let our_outpoint = allocations_our_outpoint.remove(&Some(witness_id)); - let our_witness = allocations_our_witness.remove(&witness_id); - let witness_info = self.witness_info(witness_id).expect( - "witness id was returned from the contract state above, so it must be there", - ); - match (our_outpoint, our_witness) { - // we own both allocation and witness transaction: these allocations are changes and - // outgoing payments. The difference between the change and the payments are whether - // a specific allocation is listed in the first tuple pattern field. - (Some(our_assignments), Some(all_assignments)) => { - // all_allocations - our_allocations = external payments - let ext_assignments = all_assignments - .difference(&our_assignments) - .cloned() - .collect::>(); - // This was a blank state transition with no external payment - if ext_assignments.is_empty() { - continue; - } - for assignment in ext_assignments { - let value = - self.value_from_state_raw(assignment.opout.ty, &assignment.state); - ops.push(ContractOp::sent(assignment, value, witness_info)) - } - } - // the same as above, but the payment has no change - (None, Some(ext_assignments)) => { - for assignment in ext_assignments { - let value = - self.value_from_state_raw(assignment.opout.ty, &assignment.state); - ops.push(ContractOp::sent(assignment, value, witness_info)) - } - } - // we own allocation but the witness transaction was made by other wallet: - // this is an incoming payment to us. - (Some(our_assignments), None) => { - for assignment in our_assignments { - let value = - self.value_from_state_raw(assignment.opout.ty, &assignment.state); - ops.push(ContractOp::received(assignment, value, witness_info)) - } - } - // these can't get into the `witness_ids` due to the used filters - (None, None) => unreachable!("broken allocation filters"), - }; - } - - ops - } - - pub fn witness_info(&self, witness_id: XWitnessId) -> Option { - let ord = self.state.witness_ord(witness_id)?; - Some(WitnessInfo { - id: witness_id, - ord, - }) - } -} diff --git a/src/interface/contractum.rs b/src/interface/contractum.rs deleted file mode 100644 index 0fa8b927..00000000 --- a/src/interface/contractum.rs +++ /dev/null @@ -1,341 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::HashMap; -use std::fmt; -use std::fmt::{Display, Formatter}; - -use amplify::confinement::TinyOrdSet; -use rgb::Occurrences; -use strict_encoding::{FieldName, TypeName, VariantName}; -use strict_types::{SemId, SymbolicSys}; - -use super::{ArgMap, ExtensionIface, GenesisIface, Iface, IfaceId, Modifier, TransitionIface}; - -struct ArgMapDisplay<'a>(&'a ArgMap); - -impl<'a> Display for ArgMapDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - for (i, (name, occ)) in self.0.iter().enumerate() { - if i > 0 { - f.write_str(", ")? - } - write!(f, "{name}")?; - match occ { - Occurrences::Once => Ok(()), - Occurrences::NoneOrOnce => write!(f, "(?)"), - Occurrences::NoneOrMore => write!(f, "(*)"), - Occurrences::OnceOrMore => write!(f, "(+)"), - Occurrences::NoneOrUpTo(to) => write!(f, "(..{to})"), - Occurrences::OnceOrUpTo(to) => write!(f, "(1..{to})"), - Occurrences::Exactly(v) => write!(f, "({v})"), - Occurrences::Range(r) => write!(f, "({}..{})", r.start(), r.end()), - }?; - } - Ok(()) - } -} - -struct OpIfaceDisplay<'a> { - metadata: &'a TinyOrdSet, - globals: &'a ArgMap, - assignments: &'a ArgMap, - valencies: &'a TinyOrdSet, - errors: &'a TinyOrdSet, -} - -impl<'a> OpIfaceDisplay<'a> { - fn genesis(op: &'a GenesisIface) -> Self { - Self { - metadata: &op.metadata, - globals: &op.globals, - assignments: &op.assignments, - valencies: &op.valencies, - errors: &op.errors, - } - } - - fn transition(op: &'a TransitionIface) -> Self { - Self { - metadata: &op.metadata, - globals: &op.globals, - assignments: &op.assignments, - valencies: &op.valencies, - errors: &op.errors, - } - } - - fn extension(op: &'a ExtensionIface) -> Self { - Self { - metadata: &op.metadata, - globals: &op.globals, - assignments: &op.assignments, - valencies: &op.valencies, - errors: &op.errors, - } - } -} - -impl<'a> Display for OpIfaceDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if !self.errors.is_empty() { - write!(f, "\t\terrors: ")?; - for (i, name) in self.errors.iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - write!(f, "{name}")?; - } - writeln!(f)?; - } - - if !self.metadata.is_empty() { - write!(f, "\t\tmeta: ")?; - for (i, meta) in self.metadata.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{meta}")?; - } - writeln!(f)?; - } - if !self.globals.is_empty() { - writeln!(f, "\t\tglobals: {}", ArgMapDisplay(self.globals))?; - } - if !self.valencies.is_empty() { - write!(f, "\t\tvalencies: ")?; - for (i, name) in self.valencies.iter().enumerate() { - if i > 0 { - f.write_str(", ")? - } - write!(f, "{name}")?; - } - writeln!(f)?; - } - if !self.assignments.is_empty() { - writeln!(f, "\t\tassigns: {}", ArgMapDisplay(self.assignments))?; - } - Ok(()) - } -} - -pub struct IfaceDisplay<'a> { - iface: &'a Iface, - externals: &'a HashMap, - types: &'a SymbolicSys, -} - -impl<'a> IfaceDisplay<'a> { - pub fn new( - iface: &'a Iface, - externals: &'a HashMap, - types: &'a SymbolicSys, - ) -> Self { - Self { - iface, - types, - externals, - } - } -} - -impl<'a> Display for IfaceDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - fn sugar(f: &mut Formatter<'_>, required: bool, multiple: bool) -> fmt::Result { - match (required, multiple) { - (true, true) => write!(f, "(+)"), - (false, false) => write!(f, "(?)"), - (false, true) => write!(f, "(*)"), - _ => Ok(()), - } - } - fn resolve(f: &mut Formatter<'_>, types: &SymbolicSys, id: SemId) -> fmt::Result { - match types.lookup(id) { - Some(fqn) => write!(f, "{fqn}"), - None => write!(f, "{id:-} -- type name unknown"), - } - } - fn opsugar( - f: &mut Formatter<'_>, - pred: &str, - name: Option<&FieldName>, - modifier: Modifier, - optional: bool, - default: bool, - ) -> fmt::Result { - write!(f, "\t{pred}")?; - if let Some(name) = name { - write!(f, " {name}")?; - } - let mut modifiers = vec![]; - if !optional { - modifiers.push("required"); - } - if default { - modifiers.push("default"); - } - match modifier { - Modifier::Final => modifiers.push("final"), - Modifier::Abstract => modifiers.push("abstract"), - Modifier::Override => modifiers.push("override"), - } - - if !modifiers.is_empty() { - f.write_str(": ")?; - } - for (i, name) in modifiers.into_iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - f.write_str(name)?; - } - writeln!(f) - } - - writeln!(f, "@version({:#})", self.iface.version)?; - writeln!(f, "@id({})", self.iface.iface_id())?; - if !self.iface.developer.is_anonymous() { - writeln!(f, "@developer(\"{}\")", self.iface.developer)?; - } - writeln!(f, "@timestamp({})", self.iface.timestamp)?; - write!(f, "interface {}", self.iface.name)?; - if !self.iface.inherits.is_empty() { - f.write_str(": ")?; - for (index, id) in self.iface.inherits.iter().enumerate() { - if index > 0 { - f.write_str(", ")?; - } - match self.externals.get(id) { - Some(name) => write!(f, "{name}")?, - None => writeln!(f, "{id:-}")?, - } - } - } - writeln!(f)?; - - for (fname, semid) in &self.iface.metadata { - write!(f, "\tmeta {fname}: ")?; - match self.types.lookup(*semid) { - Some(fqn) => write!(f, "{fqn}"), - None => write!(f, "{semid} -- type name is unknown"), - }?; - writeln!(f)?; - } - if !self.iface.metadata.is_empty() { - writeln!(f)?; - } - - for (fname, g) in &self.iface.global_state { - write!(f, "\tglobal {fname}")?; - sugar(f, g.required, g.multiple)?; - write!(f, ": ")?; - match g.sem_id { - Some(id) => resolve(f, self.types, id)?, - None => write!(f, "Any")?, - } - writeln!(f)?; - } - writeln!(f)?; - - for (fname, a) in &self.iface.assignments { - write!(f, "\t")?; - match a.public { - true => write!(f, "public ")?, - false => write!(f, "owned ")?, - } - write!(f, "{fname}")?; - sugar(f, a.required, a.multiple)?; - f.write_str(": ")?; - match a.state_ty { - None => write!(f, "T any => T")?, - Some(id) => resolve(f, self.types, id)?, - } - writeln!(f)?; - } - if !self.iface.assignments.is_empty() { - writeln!(f)?; - } - - for (fname, v) in &self.iface.valencies { - write!(f, "\tvalency {fname}")?; - if !v.required { - write!(f, "(?)")?; - } - writeln!(f)?; - } - if !self.iface.valencies.is_empty() { - writeln!(f)?; - } - - for (name, descr) in &self.iface.errors { - writeln!(f, "\terror {name}")?; - writeln!(f, "\t\t\"{descr}\"")?; - } - if !self.iface.errors.is_empty() { - writeln!(f)?; - } - - let op = OpIfaceDisplay::genesis(&self.iface.genesis); - opsugar(f, "genesis", None, self.iface.genesis.modifier, true, false)?; - writeln!(f, "{op}")?; - - for (name, t) in &self.iface.transitions { - let default = self.iface.default_operation.as_ref() == Some(name); - opsugar(f, "transition", Some(name), t.modifier, t.optional, default)?; - - let op = OpIfaceDisplay::transition(t); - write!(f, "{op}")?; - - if let Some(ref d) = t.default_assignment { - writeln!(f, "\t\tdefault: {d}")?; - } - - writeln!(f, "\t\tinputs: {}", ArgMapDisplay(&t.inputs))?; - - writeln!(f)?; - } - - for (name, e) in &self.iface.extensions { - let default = self.iface.default_operation.as_ref() == Some(name); - opsugar(f, "extension", Some(name), e.modifier, e.optional, default)?; - - let op = OpIfaceDisplay::extension(e); - write!(f, "{op}")?; - - if let Some(ref d) = e.default_assignment { - writeln!(f, "\t\tdefault: {d}")?; - } - - write!(f, "\t\tredeems: ")?; - for (i, name) in e.redeems.iter().enumerate() { - if i > 0 { - f.write_str(", ")? - } - write!(f, "{name}")?; - } - writeln!(f)?; - - writeln!(f)?; - } - - Ok(()) - } -} diff --git a/src/interface/filter.rs b/src/interface/filter.rs deleted file mode 100644 index b76ccd65..00000000 --- a/src/interface/filter.rs +++ /dev/null @@ -1,132 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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, HashMap, HashSet}; -use std::ops::Deref; - -use rgb::{XOutpoint, XWitnessId}; - -pub trait AssignmentsFilter { - fn should_include( - &self, - outpoint: impl Into, - witness_id: Option, - ) -> bool; -} - -pub struct FilterIncludeAll; -pub struct FilterExclude(pub T); - -impl AssignmentsFilter for FilterIncludeAll { - fn should_include(&self, _: impl Into, _: Option) -> bool { true } -} - -impl AssignmentsFilter for FilterExclude { - fn should_include( - &self, - outpoint: impl Into, - witness_id: Option, - ) -> bool { - !self.0.should_include(outpoint.into(), witness_id) - } -} - -impl AssignmentsFilter for &T { - fn should_include( - &self, - outpoint: impl Into, - witness_id: Option, - ) -> bool { - (*self).should_include(outpoint, witness_id) - } -} - -impl AssignmentsFilter for &mut T { - fn should_include( - &self, - outpoint: impl Into, - witness_id: Option, - ) -> bool { - self.deref().should_include(outpoint, witness_id) - } -} - -impl AssignmentsFilter for Option { - fn should_include( - &self, - outpoint: impl Into, - witness_id: Option, - ) -> bool { - self.as_ref() - .map(|filter| filter.should_include(outpoint, witness_id)) - .unwrap_or(true) - } -} - -impl AssignmentsFilter for XOutpoint { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - *self == outpoint.into() - } -} - -impl AssignmentsFilter for [XOutpoint; LEN] { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - self.contains(&outpoint.into()) - } -} - -impl AssignmentsFilter for &[XOutpoint] { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - self.contains(&outpoint.into()) - } -} - -impl AssignmentsFilter for Vec { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - self.contains(&outpoint.into()) - } -} - -impl AssignmentsFilter for HashSet { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - self.contains(&outpoint.into()) - } -} - -impl AssignmentsFilter for BTreeSet { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - self.contains(&outpoint.into()) - } -} - -impl AssignmentsFilter for HashMap { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - let outpoint = outpoint.into(); - self.keys().any(|o| *o == outpoint) - } -} - -impl AssignmentsFilter for BTreeMap { - fn should_include(&self, outpoint: impl Into, _: Option) -> bool { - let outpoint = outpoint.into(); - self.keys().any(|o| *o == outpoint) - } -} diff --git a/src/interface/iface.rs b/src/interface/iface.rs deleted file mode 100644 index 84dfec26..00000000 --- a/src/interface/iface.rs +++ /dev/null @@ -1,698 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::cmp::Ordering; -use std::collections::HashMap; -use std::fmt::{self, Debug, Display, Formatter}; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; - -use amplify::confinement::{TinyOrdMap, TinyOrdSet, TinyString, TinyVec}; -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use chrono::{DateTime, TimeZone, Utc}; -use commit_verify::{CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::{ContractId, Identity, Occurrences, SchemaId, XWitnessId}; -use strict_encoding::{ - FieldName, StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, - StrictType, TypeName, VariantName, -}; -use strict_types::{SemId, SymbolicSys, TypeLib}; - -use crate::interface::{ContractIface, IfaceDisplay, IfaceImpl, VerNo}; -use crate::persistence::{ContractStateRead, SchemaIfaces}; -use crate::{WitnessInfo, LIB_NAME_RGB_STD}; - -/// Interface identifier. -/// -/// Interface identifier commits to all the interface data. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -pub struct IfaceId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for IfaceId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for IfaceId { - const TAG: &'static str = "urn:lnp-bp:rgb:interface#2024-02-04"; -} - -impl DisplayBaid64 for IfaceId { - const HRI: &'static str = "rgb:ifc"; - const CHUNKING: bool = true; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = true; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for IfaceId {} -impl FromStr for IfaceId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for IfaceId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(IfaceId); - -impl IfaceId { - pub const fn from_array(id: [u8; 32]) -> Self { IfaceId(Bytes32::from_array(id)) } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, From)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum IfaceRef { - #[from] - #[from(&'static str)] - Name(TypeName), - #[from] - Id(IfaceId), -} - -impl Display for IfaceRef { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - IfaceRef::Name(name) => f.write_str(name.as_str()), - IfaceRef::Id(id) => { - if f.alternate() { - write!(f, "{}", id.to_baid64_mnemonic()) - } else { - write!(f, "{}", id) - } - } - } - } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -pub enum Req { - Optional, - Required, - NoneOrMore, - OneOrMore, -} - -impl Req { - pub fn is_required(self) -> bool { self == Req::Required || self == Req::OneOrMore } - pub fn is_multiple(self) -> bool { self == Req::NoneOrMore || self == Req::OneOrMore } -} - -#[derive(Clone, PartialEq, Eq, Hash, 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 ValencyIface { - pub required: bool, -} - -#[derive(Clone, PartialEq, Eq, Hash, 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 GlobalIface { - pub sem_id: Option, - pub required: bool, - pub multiple: bool, -} - -impl GlobalIface { - pub fn any(req: Req) -> Self { - GlobalIface { - sem_id: None, - required: req.is_required(), - multiple: req.is_multiple(), - } - } - pub fn optional(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: false, - multiple: false, - } - } - pub fn required(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: true, - multiple: false, - } - } - pub fn none_or_many(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: false, - multiple: true, - } - } - pub fn one_or_many(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: true, - multiple: true, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct AssignIface { - pub state_ty: Option, - pub attach: Option, - pub public: bool, - pub required: bool, - pub multiple: bool, -} - -impl AssignIface { - pub fn optional() -> Self { - AssignIface { - state_ty: None, - attach: None, - public: false, - required: false, - multiple: false, - } - } - pub fn required() -> Self { - AssignIface { - state_ty: None, - attach: None, - public: false, - required: true, - multiple: false, - } - } - pub fn none_or_many() -> Self { - AssignIface { - state_ty: None, - attach: None, - public: false, - required: false, - multiple: true, - } - } - pub fn one_or_many() -> Self { - AssignIface { - state_ty: None, - attach: None, - public: false, - required: true, - multiple: true, - } - } - pub fn public(mut self) -> Self { - self.public = true; - self - } - pub fn rights(mut self) -> Self { - self.state_ty = Some(SemId::default()); - self - } - pub fn typed(mut self, sem_id: SemId) -> Self { - self.state_ty = Some(sem_id); - self - } - pub fn attachments(mut self, require: bool) -> Self { - self.attach = Some(require); - self - } -} - -pub type ArgMap = TinyOrdMap; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, into_u8, try_from_u8, tags = repr)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(lowercase)] -#[repr(u8)] -pub enum Modifier { - Abstract = 0, - Override = 1, - #[default] - Final = 0xFF, -} - -#[derive(Clone, PartialEq, Eq, Hash, 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 GenesisIface { - pub modifier: Modifier, - pub metadata: TinyOrdSet, - pub globals: ArgMap, - pub assignments: ArgMap, - pub valencies: TinyOrdSet, - pub errors: TinyOrdSet, -} - -#[derive(Clone, PartialEq, Eq, Hash, 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 ExtensionIface { - pub modifier: Modifier, - /// Defines whence schema may omit providing this operation. - pub optional: bool, - pub metadata: TinyOrdSet, - pub globals: ArgMap, - pub assignments: ArgMap, - pub redeems: TinyOrdSet, - pub valencies: TinyOrdSet, - pub errors: TinyOrdSet, - pub default_assignment: Option, -} - -#[derive(Clone, PartialEq, Eq, Hash, 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 TransitionIface { - pub modifier: Modifier, - /// Defines whence schema may omit providing this operation. - pub optional: bool, - pub metadata: TinyOrdSet, - pub globals: ArgMap, - pub inputs: ArgMap, - pub assignments: ArgMap, - pub valencies: TinyOrdSet, - pub errors: TinyOrdSet, - pub default_assignment: Option, -} - -/// A class of interfaces: one or several interfaces inheriting from each other. -/// -/// Interface standards like RGB20, RGB21 and RGB25 are actually interface -/// classes. -pub trait IfaceClass: Clone + Default { - const IFACE_NAME: &'static str; - const IFACE_IDS: &'static [IfaceId]; - - type Wrapper: IfaceWrapper; - - fn stl(&self) -> TypeLib; - fn iface(&self) -> Iface; - fn iface_id(&self) -> IfaceId; -} - -/// The instances implementing this trait are used as wrappers around -/// [`ContractIface`] object, allowing a simple API matching the interface class -/// requirements. -pub trait IfaceWrapper { - /// Object which represent concise summary about a contract; - type Info: Clone + Eq + Debug; - - fn with(iface: ContractIface) -> Self; - - /// Constructs information object describing a specific class in terms of - /// the interface class. - fn info(&self) -> Self::Info; - - /// Returns contract id. - fn contract_id(&self) -> ContractId; - - /// Returns schema id of the contract. - fn schema_id(&self) -> SchemaId; - - /// Returns information about a witness, if it is known to the contract state. - fn witness_info(&self, witness_id: XWitnessId) -> Option; -} - -/// Interface definition. -#[derive(Clone, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = IfaceId)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Iface { - pub version: VerNo, - pub name: TypeName, - pub inherits: TinyVec, // TODO: Replace with TinyIndexSet - pub timestamp: i64, - pub metadata: TinyOrdMap, - pub global_state: TinyOrdMap, - pub assignments: TinyOrdMap, - pub valencies: TinyOrdMap, - pub genesis: GenesisIface, - pub transitions: TinyOrdMap, - pub extensions: TinyOrdMap, - pub default_operation: Option, - pub errors: TinyOrdMap, - pub developer: Identity, -} - -impl PartialEq for Iface { - fn eq(&self, other: &Self) -> bool { self.iface_id() == other.iface_id() } -} - -impl Ord for Iface { - fn cmp(&self, other: &Self) -> Ordering { self.iface_id().cmp(&other.iface_id()) } -} - -impl PartialOrd for Iface { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Hash for Iface { - fn hash(&self, state: &mut H) { state.write(self.iface_id().as_slice()) } -} - -impl StrictSerialize for Iface {} -impl StrictDeserialize for Iface {} - -impl Iface { - #[inline] - pub fn iface_id(&self) -> IfaceId { self.commit_id() } - - pub fn display<'a>( - &'a self, - externals: &'a HashMap, - sys: &'a SymbolicSys, - ) -> IfaceDisplay<'a> { - IfaceDisplay::new(self, externals, sys) - } - - pub fn types(&self) -> impl Iterator + '_ { - self.metadata - .values() - .copied() - .chain(self.global_state.values().filter_map(|i| i.sem_id)) - .chain(self.assignments.values().filter_map(|i| i.state_ty)) - } - - pub fn find_abstractable_impl<'a>( - &self, - schema_ifaces: &'a SchemaIfaces, - ) -> Option<&'a IfaceImpl> { - schema_ifaces.get(self.iface_id()).or_else(|| { - self.inherits - .iter() - .rev() - .find_map(move |parent| schema_ifaces.get(*parent)) - }) - } - - pub fn check(&self) -> Result<(), Vec> { - let proc_globals = |op_name: &OpName, - globals: &ArgMap, - errors: &mut Vec| { - for (name, occ) in globals { - if let Some(g) = self.global_state.get(name) { - if occ.min_value() > 1 && !g.multiple { - errors.push(IfaceInconsistency::MultipleGlobal( - op_name.clone(), - name.clone(), - )); - } - } else { - errors.push(IfaceInconsistency::UnknownGlobal(op_name.clone(), name.clone())); - } - } - }; - let proc_assignments = - |op_name: &OpName, assignments: &ArgMap, errors: &mut Vec| { - for (name, occ) in assignments { - if let Some(a) = self.assignments.get(name) { - if occ.min_value() > 1 && !a.multiple { - errors.push(IfaceInconsistency::MultipleAssignment( - op_name.clone(), - name.clone(), - )); - } - } else { - errors.push(IfaceInconsistency::UnknownAssignment( - op_name.clone(), - name.clone(), - )); - } - } - }; - let proc_valencies = |op_name: &OpName, - valencies: &TinyOrdSet, - errors: &mut Vec| { - for name in valencies { - if self.valencies.get(name).is_none() { - errors.push(IfaceInconsistency::UnknownValency(op_name.clone(), name.clone())); - } - } - }; - let proc_errors = |op_name: &OpName, - errs: &TinyOrdSet, - errors: &mut Vec| { - for name in errs { - if !self.errors.contains_key(name) { - errors.push(IfaceInconsistency::UnknownError(op_name.clone(), name.clone())); - } - } - }; - - let mut errors = vec![]; - - let now = Utc::now(); - match Utc.timestamp_opt(self.timestamp, 0).single() { - Some(ts) if ts > now => errors.push(IfaceInconsistency::FutureTimestamp(ts)), - None => errors.push(IfaceInconsistency::InvalidTimestamp(self.timestamp)), - _ => {} - } - - for name in &self.genesis.metadata { - if !self.metadata.contains_key(name) { - errors.push(IfaceInconsistency::UnknownMetadata(OpName::Genesis, name.clone())); - } - } - proc_globals(&OpName::Genesis, &self.genesis.globals, &mut errors); - proc_assignments(&OpName::Genesis, &self.genesis.assignments, &mut errors); - proc_valencies(&OpName::Genesis, &self.genesis.valencies, &mut errors); - proc_errors(&OpName::Genesis, &self.genesis.errors, &mut errors); - - for (name, t) in &self.transitions { - let op_name = OpName::Transition(name.clone()); - - for name in &t.metadata { - if !self.metadata.contains_key(name) { - errors.push(IfaceInconsistency::UnknownMetadata(op_name.clone(), name.clone())); - } - } - proc_globals(&op_name, &t.globals, &mut errors); - proc_assignments(&op_name, &t.assignments, &mut errors); - proc_valencies(&op_name, &t.valencies, &mut errors); - proc_errors(&op_name, &t.errors, &mut errors); - - for (name, occ) in &t.inputs { - if let Some(a) = self.assignments.get(name) { - if occ.min_value() > 1 && !a.multiple { - errors.push(IfaceInconsistency::MultipleInputs( - op_name.clone(), - name.clone(), - )); - } - } else { - errors.push(IfaceInconsistency::UnknownInput(op_name.clone(), name.clone())); - } - } - if let Some(ref name) = t.default_assignment { - if t.assignments.get(name).is_none() { - errors - .push(IfaceInconsistency::UnknownDefaultAssignment(op_name, name.clone())); - } - } - } - - for (name, e) in &self.extensions { - let op_name = OpName::Extension(name.clone()); - - for name in &e.metadata { - if !self.metadata.contains_key(name) { - errors.push(IfaceInconsistency::UnknownMetadata(op_name.clone(), name.clone())); - } - } - proc_globals(&op_name, &e.globals, &mut errors); - proc_assignments(&op_name, &e.assignments, &mut errors); - proc_valencies(&op_name, &e.valencies, &mut errors); - proc_errors(&op_name, &e.errors, &mut errors); - - for name in &e.redeems { - if self.valencies.get(name).is_none() { - errors.push(IfaceInconsistency::UnknownRedeem(op_name.clone(), name.clone())); - } - } - if let Some(ref name) = e.default_assignment { - if e.assignments.get(name).is_none() { - errors - .push(IfaceInconsistency::UnknownDefaultAssignment(op_name, name.clone())); - } - } - } - - for name in self.transitions.keys() { - if self.extensions.contains_key(name) { - errors.push(IfaceInconsistency::RepeatedOperationName(name.clone())); - } - } - - if let Some(ref name) = self.default_operation { - if self.transitions.get(name).is_none() && self.extensions.get(name).is_none() { - errors.push(IfaceInconsistency::UnknownDefaultOp(name.clone())); - } - } - - for (name, g) in &self.global_state { - if g.required && self.genesis.globals.get(name).is_none() { - errors.push(IfaceInconsistency::RequiredGlobalAbsent(name.clone())); - } - } - for (name, a) in &self.assignments { - if a.required && self.genesis.assignments.get(name).is_none() { - errors.push(IfaceInconsistency::RequiredAssignmentAbsent(name.clone())); - } - } - for (name, v) in &self.valencies { - if v.required && self.genesis.valencies.get(name).is_none() { - errors.push(IfaceInconsistency::RequiredValencyAbsent(name.clone())); - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - // TODO: Implement checking interface inheritance. - /* - pub fn check_inheritance<'a>(&self, ifaces: impl IntoIterator) -> Result<(), Vec> { - // check for the depth - } - */ - - // TODO: Implement checking types against presence in a type system. - /* - pub fn check_types(&self, sys: &TypeSystem) -> Result<(), Vec> { - for g in self.global_state.values() { - if let Some(id) = g.sem_id { - - } - } - } - */ -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)] -pub enum OpName { - #[display("genesis")] - Genesis, - #[display("transition '{0}'")] - Transition(FieldName), - #[display("extension '{0}'")] - Extension(FieldName), -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum IfaceInconsistency { - /// timestamp is invalid ({0}). - InvalidTimestamp(i64), - /// timestamp in the future ({0}). - FutureTimestamp(DateTime), - /// unknown global state '{1}' referenced from {0}. - UnknownGlobal(OpName, FieldName), - /// unknown valency '{1}' referenced from {0}. - UnknownValency(OpName, FieldName), - /// unknown input '{1}' referenced from {0}. - UnknownRedeem(OpName, FieldName), - /// unknown assignment '{1}' referenced from {0}. - UnknownAssignment(OpName, FieldName), - /// unknown input '{1}' referenced from {0}. - UnknownInput(OpName, FieldName), - /// unknown error '{1}' referenced from {0}. - UnknownError(OpName, VariantName), - /// unknown default assignment '{1}' referenced from {0}. - UnknownDefaultAssignment(OpName, FieldName), - /// unknown default operation '{0}'. - UnknownDefaultOp(FieldName), - /// unknown metadata '{1}' in {0}. - UnknownMetadata(OpName, FieldName), - /// global state '{1}' must have a unique single value, but operation {0} - /// defines multiple global state of this type. - MultipleGlobal(OpName, FieldName), - /// assignment '{1}' must be unique, but operation {0} defines multiple - /// assignments of this type. - MultipleAssignment(OpName, FieldName), - /// assignment '{1}' is unique, but operation {0} defines multiple inputs of - /// this type, which is not possible. - MultipleInputs(OpName, FieldName), - /// operation name '{0}' is used by both state transition and extension. - RepeatedOperationName(FieldName), - /// global state '{0}' is required, but genesis doesn't define it. - RequiredGlobalAbsent(FieldName), - /// assignment '{0}' is required, but genesis doesn't define it. - RequiredAssignmentAbsent(FieldName), - /// valency '{0}' is required, but genesis doesn't define it. - RequiredValencyAbsent(FieldName), -} diff --git a/src/interface/iimpl.rs b/src/interface/iimpl.rs deleted file mode 100644 index 5644aa36..00000000 --- a/src/interface/iimpl.rs +++ /dev/null @@ -1,564 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::HashMap; -use std::fmt::{self, Display, Formatter}; -use std::str::FromStr; - -use amplify::confinement::TinyOrdSet; -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use chrono::{DateTime, TimeZone, Utc}; -use commit_verify::{CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::{ - impl_serde_baid64, AssignmentType, ExtensionType, GlobalStateType, Identity, MetaType, Schema, - SchemaId, TransitionType, ValencyType, -}; -use strict_encoding::{FieldName, StrictDumb, VariantName}; -use strict_types::encoding::{StrictDecode, StrictEncode, StrictType}; - -use crate::interface::iface::IfaceId; -use crate::interface::{Iface, StateAbi, VerNo}; -use crate::{ReservedBytes, LIB_NAME_RGB_STD}; - -pub trait SchemaTypeIndex: - Copy + Eq + Ord + StrictType + StrictDumb + StrictEncode + StrictDecode -{ -} -impl SchemaTypeIndex for u8 {} // Error types -impl SchemaTypeIndex for MetaType {} -impl SchemaTypeIndex for GlobalStateType {} -impl SchemaTypeIndex for AssignmentType {} -impl SchemaTypeIndex for ValencyType {} -impl SchemaTypeIndex for ExtensionType {} -impl SchemaTypeIndex for TransitionType {} - -/// Interface identifier. -/// -/// Interface identifier commits to all the interface data. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -pub struct ImplId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for ImplId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for ImplId { - const TAG: &'static str = "urn:lnp-bp:rgb:iface-impl#2024-02-04"; -} - -impl DisplayBaid64 for ImplId { - const HRI: &'static str = "rgb:imp"; - const CHUNKING: bool = true; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = true; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for ImplId {} -impl FromStr for ImplId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for ImplId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(ImplId); - -impl ImplId { - pub const fn from_array(id: [u8; 32]) -> Self { ImplId(Bytes32::from_array(id)) } -} - -/// Maps certain form of type id (global or owned state or a valency) to a -/// human-readable name. -/// -/// Two distinct [`NamedField`] objects must always have both different state -/// ids and names. -#[derive(Clone, Eq, PartialOrd, Ord, 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 NamedField { - pub id: T, - pub name: FieldName, - /// Reserved bytes for storing information about value transformation - /// procedures - pub reserved: ReservedBytes<4usize>, -} - -impl PartialEq for NamedField -where T: SchemaTypeIndex -{ - fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name } -} - -impl NamedField { - pub fn with(id: T, name: FieldName) -> NamedField { - NamedField { - id, - name, - reserved: default!(), - } - } -} - -/// Maps certain form of type id (global or owned state or a valency) to a -/// human-readable name. -/// -/// Two distinct [`crate::interface::NamedField`] objects must always have both -/// different state ids and names. -#[derive(Clone, Eq, PartialOrd, Ord, 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 NamedVariant { - pub id: T, - pub name: VariantName, - /// Reserved bytes for storing information about value transformation - /// procedures - pub reserved: ReservedBytes<4usize>, -} - -impl PartialEq for NamedVariant -where T: SchemaTypeIndex -{ - fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name } -} - -impl NamedVariant { - pub fn with(id: T, name: VariantName) -> NamedVariant { - NamedVariant { - id, - name, - reserved: default!(), - } - } -} - -/// Maps operation numeric type id to a human-readable name. -/// -/// Two distinct [`NamedType`] objects must always have both different state -/// ids and names. -#[derive(Clone, Eq, PartialOrd, Ord, 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 NamedType { - pub id: T, - pub name: FieldName, - /// Reserved bytes for storing information about adaptor procedures - pub reserved: ReservedBytes<0, 4>, -} - -impl PartialEq for NamedType -where T: SchemaTypeIndex -{ - fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name } -} - -impl NamedType { - pub fn with(id: T, name: impl Into) -> NamedType { - NamedType { - id, - name: name.into(), - reserved: default!(), - } - } -} - -/// Interface implementation for some specific schema. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = ImplId)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct IfaceImpl { - pub version: VerNo, - pub schema_id: SchemaId, - pub iface_id: IfaceId, - pub timestamp: i64, - pub metadata: TinyOrdSet>, - pub global_state: TinyOrdSet>, - pub assignments: TinyOrdSet>, - pub valencies: TinyOrdSet>, - pub transitions: TinyOrdSet>, - pub extensions: TinyOrdSet>, - pub errors: TinyOrdSet>, - pub developer: Identity, - pub state_abi: StateAbi, -} - -impl IfaceImpl { - #[inline] - pub fn impl_id(&self) -> ImplId { self.commit_id() } - - pub fn meta_name(&self, id: MetaType) -> Option<&FieldName> { - self.metadata - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn meta_type(&self, name: &FieldName) -> Option { - self.metadata - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn global_type(&self, name: &FieldName) -> Option { - self.global_state - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn assignment_type(&self, name: &FieldName) -> Option { - self.assignments - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn transition_type(&self, name: &FieldName) -> Option { - self.transitions - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn extension_name(&self, id: ExtensionType) -> Option<&FieldName> { - self.extensions - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn extension_type(&self, name: &FieldName) -> Option { - self.extensions - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn valency_type(&self, name: &FieldName) -> Option { - self.valencies - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn valency_name(&self, id: ValencyType) -> Option<&FieldName> { - self.valencies - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - pub fn global_name(&self, id: GlobalStateType) -> Option<&FieldName> { - self.global_state - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn assignment_name(&self, id: AssignmentType) -> Option<&FieldName> { - self.assignments - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn transition_name(&self, id: TransitionType) -> Option<&FieldName> { - self.transitions - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn error_name(&self, errno: u8) -> Option<&VariantName> { - self.errors - .iter() - .find(|nt| nt.id == errno) - .map(|nt| &nt.name) - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum ImplInconsistency { - /// timestamp is invalid ({0}). - InvalidTimestamp(i64), - /// timestamp in the future ({0}). - FutureTimestamp(DateTime), - - /// interface metadata field '{0}' is not resolved by the implementation. - IfaceMetaAbsent(FieldName), - /// implementation metadata field '{0}' maps to an unknown schema metadata - /// type {1}. - SchemaMetaAbsent(FieldName, MetaType), - - /// interface global state field '{0}' is not resolved by the - /// implementation. - IfaceGlobalAbsent(FieldName), - /// implementation global state field '{0}' maps to an unknown schema global - /// state type {1}. - SchemaGlobalAbsent(FieldName, GlobalStateType), - - /// interface owned state field '{0}' is not resolved by the - /// implementation. - IfaceAssignmentAbsent(FieldName), - /// implementation owned state field '{0}' maps to an unknown schema owned - /// state type {1}. - SchemaAssignmentAbsent(FieldName, AssignmentType), - - /// interface valency field '{0}' is not resolved by the implementation. - IfaceValencyAbsent(FieldName), - /// implementation valency field '{0}' maps to an unknown schema valency - /// {1}. - SchemaValencyAbsent(FieldName, ValencyType), - - /// interface state transition name '{0}' is not resolved by the - /// implementation. - IfaceTransitionAbsent(FieldName), - /// implementation state transition name '{0}' maps to an unknown schema - /// state transition type {1}. - SchemaTransitionAbsent(FieldName, TransitionType), - - /// interface state extension name '{0}' is not resolved by the - /// implementation. - IfaceExtensionAbsent(FieldName), - /// implementation state extension name '{0}' maps to an unknown schema - /// state extension type {1}. - SchemaExtensionAbsent(FieldName, ExtensionType), - - /// implementation references unknown interface error '{0}'. - IfaceErrorAbsent(VariantName), - - /// metadata field '{0}' is repeated {1} times - RepeatedMetaData(FieldName, i32), - - /// global state field '{0}' is repeated {1} times - RepeatedGlobalState(FieldName, i32), - - /// assignments field '{0}' is repeated {1} times - RepeatedAssignments(FieldName, i32), - - /// valencies field '{0}' is repeated {1} times - RepeatedValencies(FieldName, i32), - - /// transition field '{0}' is repeated {1} times - RepeatedTransitions(FieldName, i32), - - /// extension field '{0}' is repeated {1} times - RepeatedExtensions(FieldName, i32), -} - -impl IfaceImpl { - pub fn check(&self, iface: &Iface, schema: &Schema) -> Result<(), Vec> { - let mut errors = vec![]; - let now = Utc::now(); - let mut dup_metadata = HashMap::new(); - let mut dup_global_state = HashMap::new(); - let mut dup_assignments = HashMap::new(); - let mut dup_valencies = HashMap::new(); - let mut dup_transitions = HashMap::new(); - let mut dup_extensions = HashMap::new(); - - match Utc.timestamp_opt(self.timestamp, 0).single() { - Some(ts) if ts > now => errors.push(ImplInconsistency::FutureTimestamp(ts)), - None => errors.push(ImplInconsistency::InvalidTimestamp(self.timestamp)), - _ => {} - } - - for name in iface.metadata.keys() { - if self.metadata.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceMetaAbsent(name.clone())); - } - } - for field in &self.metadata { - dup_metadata - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - if !schema.meta_types.contains_key(&field.id) { - errors.push(ImplInconsistency::SchemaMetaAbsent(field.name.clone(), field.id)); - } - } - - dup_metadata - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedMetaData(field_name.clone(), count)); - }); - - for name in iface.global_state.keys() { - if self.global_state.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceGlobalAbsent(name.clone())); - } - } - for field in &self.global_state { - dup_global_state - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - if !schema.global_types.contains_key(&field.id) { - errors.push(ImplInconsistency::SchemaGlobalAbsent(field.name.clone(), field.id)); - } - } - - dup_global_state - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedGlobalState(field_name.clone(), count)); - }); - - for name in iface.assignments.keys() { - if self.assignments.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceAssignmentAbsent(name.clone())); - } - } - for field in &self.assignments { - dup_assignments - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - if !schema.owned_types.contains_key(&field.id) { - errors - .push(ImplInconsistency::SchemaAssignmentAbsent(field.name.clone(), field.id)); - } - } - - dup_assignments - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedAssignments(field_name.clone(), count)); - }); - - for name in iface.valencies.keys() { - if self.valencies.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceValencyAbsent(name.clone())); - } - } - for field in &self.valencies { - dup_valencies - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - - if !schema.valency_types.contains(&field.id) { - errors.push(ImplInconsistency::SchemaValencyAbsent(field.name.clone(), field.id)); - } - } - dup_valencies - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedValencies(field_name.clone(), count)); - }); - - for name in iface.transitions.keys() { - if self.transitions.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceTransitionAbsent(name.clone())); - } - } - for field in &self.transitions { - dup_transitions - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - - if !schema.transitions.contains_key(&field.id) { - errors - .push(ImplInconsistency::SchemaTransitionAbsent(field.name.clone(), field.id)); - } - } - - dup_transitions - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedTransitions(field_name.clone(), count)); - }); - - for name in iface.extensions.keys() { - if self.extensions.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceExtensionAbsent(name.clone())); - } - } - for field in &self.extensions { - dup_extensions - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - - if !schema.extensions.contains_key(&field.id) { - errors.push(ImplInconsistency::SchemaExtensionAbsent(field.name.clone(), field.id)); - } - } - - dup_extensions - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedExtensions(field_name.clone(), count)); - }); - - for var in &self.errors { - if iface.errors.keys().all(|name| name != &var.name) { - errors.push(ImplInconsistency::IfaceErrorAbsent(var.name.clone())); - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } -} diff --git a/src/interface/inheritance.rs b/src/interface/inheritance.rs deleted file mode 100644 index 2c746494..00000000 --- a/src/interface/inheritance.rs +++ /dev/null @@ -1,725 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 amplify::confinement::{Confined, TinyOrdMap, TinyOrdSet}; -use rgb::{ - AssignmentType, ExtensionType, GlobalStateType, Occurrences, OpFullType, OpSchema, Schema, - TransitionType, ValencyType, -}; -use strict_encoding::{FieldName, TypeName}; - -use crate::interface::{ - ExtensionIface, GenesisIface, Iface, IfaceImpl, Modifier, OpName, TransitionIface, -}; - -#[derive(Clone, PartialEq, Eq, Debug, Display, From)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(doc_comments)] -pub enum InheritanceFailure { - /// invalid schema - no match with root schema requirements for global state - /// type #{0}. - GlobalStateMismatch(GlobalStateType), - /// invalid schema - no match with root schema requirements for assignment - /// type #{0}. - AssignmentTypeMismatch(AssignmentType), - /// invalid schema - no match with root schema requirements for valency - /// type #{0}. - ValencyTypeMismatch(ValencyType), - /// invalid schema - no match with root schema requirements for transition - /// type #{0}. - TransitionTypeMismatch(TransitionType), - /// invalid schema - no match with root schema requirements for extension - /// type #{0}. - ExtensionTypeMismatch(ExtensionType), - - /// invalid schema - no match with root schema requirements for global state - /// type #{1} used in {0}. - OpGlobalStateMismatch(OpFullType, GlobalStateType), - /// invalid schema - no match with root schema requirements for input - /// type #{1} used in {0}. - OpInputMismatch(OpFullType, AssignmentType), - /// invalid schema - no match with root schema requirements for redeem - /// type #{1} used in {0}. - OpRedeemMismatch(OpFullType, ValencyType), - /// invalid schema - no match with root schema requirements for assignment - /// type #{1} used in {0}. - OpAssignmentsMismatch(OpFullType, AssignmentType), - /// invalid schema - no match with root schema requirements for valency - /// type #{1} used in {0}. - OpValencyMismatch(OpFullType, ValencyType), -} - -pub trait CheckInheritance { - fn check_inheritance(&self, root: &Self) -> Result<(), Vec>; -} - -impl CheckInheritance for Schema { - fn check_inheritance(&self, root: &Schema) -> Result<(), Vec> { - let mut status = vec![]; - - for (global_type, data_format) in &self.global_types { - match root.global_types.get(global_type) { - None => status.push(InheritanceFailure::GlobalStateMismatch(*global_type)), - Some(root_data_format) if root_data_format != data_format => { - status.push(InheritanceFailure::GlobalStateMismatch(*global_type)) - } - _ => {} - }; - } - - for (assignments_type, state_schema) in &self.owned_types { - match root.owned_types.get(assignments_type) { - None => status.push(InheritanceFailure::AssignmentTypeMismatch(*assignments_type)), - Some(root_state_schema) if root_state_schema != state_schema => { - status.push(InheritanceFailure::AssignmentTypeMismatch(*assignments_type)) - } - _ => {} - }; - } - - for valencies_type in &self.valency_types { - if !root.valency_types.contains(valencies_type) { - status.push(InheritanceFailure::ValencyTypeMismatch(*valencies_type)); - } - } - - self.genesis - .check_schema_op_inheritance(OpFullType::Genesis, &root.genesis) - .map_err(|e| status.extend(e)) - .ok(); - - for (type_id, transition_schema) in &self.transitions { - if let Some(root_transition_schema) = root.transitions.get(type_id) { - transition_schema - .check_schema_op_inheritance( - OpFullType::StateTransition(*type_id), - root_transition_schema, - ) - .map_err(|e| status.extend(e)) - .ok(); - } else { - status.push(InheritanceFailure::TransitionTypeMismatch(*type_id)); - } - } - for (type_id, extension_schema) in &self.extensions { - if let Some(root_extension_schema) = root.extensions.get(type_id) { - extension_schema - .check_schema_op_inheritance( - OpFullType::StateExtension(*type_id), - root_extension_schema, - ) - .map_err(|e| status.extend(e)) - .ok(); - } else { - status.push(InheritanceFailure::ExtensionTypeMismatch(*type_id)); - } - } - - if status.is_empty() { - Ok(()) - } else { - Err(status) - } - } -} - -/// Trait used for internal schema validation against some root schema -pub(crate) trait CheckSchemaOpInheritance { - fn check_schema_op_inheritance( - &self, - op_type: OpFullType, - root: &Self, - ) -> Result<(), Vec>; -} - -impl CheckSchemaOpInheritance for T -where T: OpSchema -{ - fn check_schema_op_inheritance( - &self, - op_type: OpFullType, - root: &Self, - ) -> Result<(), Vec> { - let mut status = vec![]; - - for (type_id, occ) in self.globals() { - match root.globals().get(type_id) { - None => status.push(InheritanceFailure::OpGlobalStateMismatch(op_type, *type_id)), - Some(root_occ) if occ != root_occ => { - status.push(InheritanceFailure::OpGlobalStateMismatch(op_type, *type_id)) - } - _ => {} - }; - } - - if let Some(inputs) = self.inputs() { - let root_inputs = root.inputs().expect("generic guarantees"); - for (type_id, occ) in inputs { - match root_inputs.get(type_id) { - None => status.push(InheritanceFailure::OpInputMismatch(op_type, *type_id)), - Some(root_occ) if occ != root_occ => { - status.push(InheritanceFailure::OpInputMismatch(op_type, *type_id)) - } - _ => {} - }; - } - } - - for (type_id, occ) in self.assignments() { - match root.assignments().get(type_id) { - None => status.push(InheritanceFailure::OpAssignmentsMismatch(op_type, *type_id)), - Some(root_occ) if occ != root_occ => { - status.push(InheritanceFailure::OpAssignmentsMismatch(op_type, *type_id)) - } - _ => {} - }; - } - - if let Some(redeems) = self.redeems() { - let root_redeems = root.redeems().expect("generic guarantees"); - for type_id in redeems { - if !root_redeems.contains(type_id) { - status.push(InheritanceFailure::OpRedeemMismatch(op_type, *type_id)); - } - } - } - - for type_id in self.valencies() { - if !root.valencies().contains(type_id) { - status.push(InheritanceFailure::OpValencyMismatch(op_type, *type_id)); - } - } - - if status.is_empty() { - Ok(()) - } else { - Err(status) - } - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display("{iface} {err}")] -pub struct InheritError { - err: ExtensionError, - iface: TypeName, -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum ExtensionError { - /// too many metadata fields defined. - MetaOverflow, - /// too many global state types defined. - GlobalOverflow, - /// global state '{0}' has different data type from the parent interface. - GlobalType(FieldName), - /// global state '{0}' has fewer occurrences than in the parent interface. - GlobalOcc(FieldName), - /// too many assignment types defined. - AssignmentOverflow, - /// assignment '{0}' has different data type from the parent interface. - AssignmentType(FieldName), - /// assignment '{0}' has fewer occurrences than in the parent interface. - AssignmentOcc(FieldName), - /// global state '{0}' has lower visibility than in the parent interface. - AssignmentPublic(FieldName), - /// too many valency types defined. - ValencyOverflow, - /// valency '{0}' has fewer occurrences than in the parent interface. - ValencyOcc(FieldName), - /// too many state transitions. - TransitionOverflow, - /// too many state extensions. - ExtensionOverflow, - /// too many error types defined. - ErrorOverflow, - /// inherited interface tries to override the parent default operation. - DefaultOverride, - /// {0} in the parent interface is final and can't be overridden. - OpFinal(OpName), - /// {0} must use `override` keyword to modify the parent version. - OpNoOverride(OpName), - /// too many {1} types defined in {0}. - OpOverflow(OpName, &'static str), - /// {0} tries to override the parent default assignment. - OpDefaultOverride(OpName), - /// {0} tries to override '{2}' {1}. - OpOcc(OpName, &'static str, FieldName), - /// too deep inheritance; it is not allowed for any interface to have more - /// than 255 parents it inherits from, including all grandparents. - InheritanceOverflow, -} - -impl Modifier { - pub fn is_final(self) -> bool { self == Self::Final } - pub fn can_be_overridden_by(self, other: Modifier) -> bool { - matches!((self, other), (Self::Abstract | Self::Override, Self::Override | Self::Final)) - } -} - -impl Iface { - pub fn expect_inherit( - name: impl Into, - ifaces: impl IntoIterator, - ) -> Iface { - let name = name.into(); - match Self::inherit(name.clone(), ifaces) { - Ok(iface) => iface, - Err(msgs) => { - eprintln!("Unable to construct interface {name}:"); - for msg in msgs { - eprintln!("- {msg}") - } - panic!(); - } - } - } - - pub fn inherit( - name: impl Into, - ifaces: impl IntoIterator, - ) -> Result> { - let name = name.into(); - let mut iter = ifaces.into_iter(); - let mut iface = iter - .next() - .expect("at least one interface must be provided for the inheritance"); - for ext in iter { - let ext_name = ext.name.clone(); - iface = iface.extended(ext, name.clone()).map_err(|err| { - err.into_iter() - .map(|e| InheritError { - err: e, - iface: ext_name.clone(), - }) - .collect::>() - })?; - } - Ok(iface) - } - - pub fn expect_extended(self, ext: Iface, name: impl Into) -> Iface { - let prev_name = self.name.clone(); - let ext_name = ext.name.clone(); - match self.extended(ext, name) { - Ok(iface) => iface, - Err(msgs) => { - eprintln!("Unable to extend {prev_name} with {ext_name}:"); - for msg in msgs { - eprintln!("- {msg}") - } - panic!(); - } - } - } - - pub fn extended( - mut self, - ext: Iface, - name: impl Into, - ) -> Result> { - let orig_id = self.iface_id(); - let ext_id = ext.iface_id(); - let name = name.into(); - - let mut errors = vec![]; - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::MetaOverflow)) - .ok(); - - for (name, e) in ext.global_state { - match self.global_state.get_mut(&name) { - None => { - if self - .global_state - .insert(name, e) - .map_err(|_| errors.push(ExtensionError::GlobalOverflow)) - .is_err() - { - break; - } - } - Some(orig) => { - if orig.sem_id.is_some() && e.sem_id != orig.sem_id { - errors.push(ExtensionError::GlobalType(name)); - } else if orig.required & !e.required { - errors.push(ExtensionError::GlobalOcc(name)); - } else { - *orig = e; - } - } - } - } - - for (name, e) in ext.assignments { - match self.assignments.get_mut(&name) { - None => { - if self - .assignments - .insert(name, e) - .map_err(|_| errors.push(ExtensionError::AssignmentOverflow)) - .is_err() - { - break; - } - } - Some(orig) => { - if orig.state_ty.is_some() && orig.state_ty != e.state_ty { - errors.push(ExtensionError::AssignmentType(name)); - } else if orig.required & !e.required { - errors.push(ExtensionError::AssignmentOcc(name)); - } else if orig.public & !e.public { - errors.push(ExtensionError::AssignmentPublic(name)); - } else { - *orig = e; - } - } - } - } - - for (name, e) in ext.valencies { - match self.valencies.get_mut(&name) { - None => { - if self - .valencies - .insert(name, e) - .map_err(|_| errors.push(ExtensionError::ValencyOverflow)) - .is_err() - { - break; - } - } - Some(orig) => { - if orig.required & !e.required { - errors.push(ExtensionError::ValencyOcc(name)); - } else { - *orig = e; - } - } - } - } - - self.clone() - .genesis - .extended(ext.genesis) - .map(|genesis| self.genesis = genesis) - .map_err(|errs| errors.extend(errs)) - .ok(); - - for (name, op) in ext.transitions { - match self.transitions.remove(&name) { - Ok(None) if op.optional => continue, - Ok(None) => { - if self - .transitions - .insert(name, op) - .map_err(|_| errors.push(ExtensionError::TransitionOverflow)) - .is_err() - { - break; - } - } - Ok(Some(orig)) => { - orig.extended(op, name.clone()) - .map(|op| self.transitions.insert(name, op).expect("same size")) - .map_err(|errs| errors.extend(errs)) - .ok(); - } - Err(_) => unreachable!(), - } - } - - for (name, op) in ext.extensions { - match self.extensions.remove(&name) { - Ok(None) if op.optional => continue, - Ok(None) => { - if self - .extensions - .insert(name, op) - .map_err(|_| errors.push(ExtensionError::TransitionOverflow)) - .is_err() - { - break; - } - } - Ok(Some(orig)) => { - orig.extended(op, name.clone()) - .map(|op| self.extensions.insert(name, op).expect("same size")) - .map_err(|errs| errors.extend(errs)) - .ok(); - } - Err(_) => unreachable!(), - } - } - - // We allow replacing error messages - self.errors - .extend(ext.errors) - .map_err(|_| errors.push(ExtensionError::ErrorOverflow)) - .ok(); - - if ext.default_operation.is_some() { - if self.default_operation.is_some() && self.default_operation != ext.default_operation { - errors.push(ExtensionError::DefaultOverride); - } else { - self.default_operation = ext.default_operation - } - } - - self.name = name; - self.inherits - .push(orig_id) - .and_then(|_| self.inherits.extend(ext.inherits)) - .and_then(|_| self.inherits.push(ext_id)) - .map_err(|_| errors.push(ExtensionError::InheritanceOverflow)) - .ok(); - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -fn check_occs( - orig: &mut TinyOrdMap, - ext: impl IntoIterator, - op: OpName, - state: &'static str, - errors: &mut Vec, -) { - for (name, occ) in ext { - match orig.get_mut(&name) { - None => { - if orig - .insert(name, occ) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), state))) - .is_err() - { - break; - } - } - Some(orig) => { - if orig.min_value() > occ.min_value() { - errors.push(ExtensionError::OpOcc(op.clone(), state, name)); - } else { - *orig = occ; - } - } - } - } -} - -fn check_presence( - orig: &mut TinyOrdSet, - ext: impl IntoIterator, - op: OpName, - state: &'static str, - errors: &mut Vec, -) { - for name in ext { - if orig - .push(name) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), state))) - .is_err() - { - break; - } - } -} - -impl GenesisIface { - pub fn extended(mut self, ext: Self) -> Result> { - let mut errors = vec![]; - - let op = OpName::Genesis; - if self.modifier.is_final() { - errors.push(ExtensionError::OpFinal(op.clone())); - } else if !self.modifier.can_be_overridden_by(ext.modifier) { - errors.push(ExtensionError::OpNoOverride(op.clone())); - } - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::OpOverflow(OpName::Genesis, "metadata"))) - .ok(); - check_occs(&mut self.globals, ext.globals, op.clone(), "global", &mut errors); - check_occs(&mut self.assignments, ext.assignments, op.clone(), "assignment", &mut errors); - - check_presence(&mut self.valencies, ext.valencies, op.clone(), "valency", &mut errors); - check_presence(&mut self.errors, ext.errors, op.clone(), "error", &mut errors); - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -impl TransitionIface { - pub fn extended(mut self, ext: Self, op_name: FieldName) -> Result> { - let mut errors = vec![]; - - let op = OpName::Transition(op_name); - if self.modifier.is_final() { - errors.push(ExtensionError::OpFinal(op.clone())); - } else if !self.modifier.can_be_overridden_by(ext.modifier) { - errors.push(ExtensionError::OpNoOverride(op.clone())); - } - self.optional = self.optional.max(ext.optional); - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), "metadata"))) - .ok(); - check_occs(&mut self.globals, ext.globals, op.clone(), "global", &mut errors); - check_occs(&mut self.assignments, ext.assignments, op.clone(), "assignment", &mut errors); - check_occs(&mut self.inputs, ext.inputs, op.clone(), "input", &mut errors); - - check_presence(&mut self.valencies, ext.valencies, op.clone(), "valency", &mut errors); - check_presence(&mut self.errors, ext.errors, op.clone(), "error", &mut errors); - - if ext.default_assignment.is_some() { - if self.default_assignment.is_some() - && self.default_assignment != ext.default_assignment - { - errors.push(ExtensionError::OpDefaultOverride(op.clone())); - } else { - self.default_assignment = ext.default_assignment - } - } - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -impl ExtensionIface { - pub fn extended(mut self, ext: Self, op_name: FieldName) -> Result> { - let mut errors = vec![]; - - let op = OpName::Transition(op_name); - if self.modifier.is_final() { - errors.push(ExtensionError::OpFinal(op.clone())); - } else if !self.modifier.can_be_overridden_by(ext.modifier) { - errors.push(ExtensionError::OpNoOverride(op.clone())); - } - self.optional = self.optional.max(ext.optional); - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), "metadata"))) - .ok(); - check_occs(&mut self.globals, ext.globals, op.clone(), "global", &mut errors); - check_occs(&mut self.assignments, ext.assignments, op.clone(), "assignment", &mut errors); - - check_presence(&mut self.valencies, ext.valencies, op.clone(), "valency", &mut errors); - check_presence(&mut self.redeems, ext.redeems, op.clone(), "input", &mut errors); - check_presence(&mut self.errors, ext.errors, op.clone(), "error", &mut errors); - - if ext.default_assignment.is_some() { - if self.default_assignment.is_some() - && self.default_assignment != ext.default_assignment - { - errors.push(ExtensionError::OpDefaultOverride(op.clone())); - } else { - self.default_assignment = ext.default_assignment - } - } - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -impl IfaceImpl { - pub fn abstracted(mut self, base: &Iface, parent: &Iface) -> Option { - assert_eq!(self.iface_id, base.iface_id()); - let parent_id = parent.iface_id(); - if !base.inherits.contains(&parent_id) { - return None; - } - - self.metadata = Confined::from_iter_checked(base.metadata.keys().filter_map(|name| { - self.metadata - .iter() - .find(|i| parent.metadata.contains_key(name) && &i.name == name) - .cloned() - })); - - self.global_state = - Confined::from_iter_checked(base.global_state.keys().filter_map(|name| { - self.global_state - .iter() - .find(|i| parent.global_state.contains_key(name) && &i.name == name) - .cloned() - })); - - self.assignments = - Confined::from_iter_checked(base.assignments.keys().filter_map(|name| { - self.assignments - .iter() - .find(|i| parent.assignments.contains_key(name) && &i.name == name) - .cloned() - })); - - self.valencies = Confined::from_iter_checked(base.assignments.keys().filter_map(|name| { - self.valencies - .iter() - .find(|i| parent.valencies.contains_key(name) && &i.name == name) - .cloned() - })); - - self.transitions = - Confined::from_iter_checked(base.transitions.keys().filter_map(|name| { - self.transitions - .iter() - .find(|i| parent.transitions.contains_key(name) && &i.name == name) - .cloned() - })); - - self.extensions = Confined::from_iter_checked(base.extensions.keys().filter_map(|name| { - self.extensions - .iter() - .find(|i| parent.extensions.contains_key(name) && &i.name == name) - .cloned() - })); - - self.iface_id = parent_id; - - Some(self) - } -} diff --git a/src/interface/mod.rs b/src/interface/mod.rs deleted file mode 100644 index 7b70ae47..00000000 --- a/src/interface/mod.rs +++ /dev/null @@ -1,66 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -//! RGB contract interface provides a mapping between identifiers of RGB schema- -//! defined contract state and operation types to a human-readable and -//! standardized wallet APIs. - -mod iface; -mod iimpl; -mod contract; -mod builder; -mod filter; -pub(crate) mod resolver; -mod contractum; -mod inheritance; -mod calc; - -pub use builder::{BuilderError, ContractBuilder, TransitionBuilder, TxOutpoint}; -pub use calc::{AllocatedState, StateAbi, StateCalc, StateCalcError}; -pub use contract::{ContractError, ContractIface, ContractOp, OpDirection, Output}; -pub use contractum::IfaceDisplay; -pub use filter::{AssignmentsFilter, FilterExclude, FilterIncludeAll}; -pub use iface::{ - ArgMap, AssignIface, ExtensionIface, GenesisIface, GlobalIface, Iface, IfaceClass, IfaceId, - IfaceInconsistency, IfaceRef, IfaceWrapper, Modifier, OpName, Req, TransitionIface, - ValencyIface, -}; -pub use iimpl::{IfaceImpl, ImplId, NamedField, NamedType, NamedVariant, SchemaTypeIndex}; -pub use inheritance::{CheckInheritance, ExtensionError, InheritanceFailure}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = crate::LIB_NAME_RGB_STD, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -#[non_exhaustive] -pub enum VerNo { - #[display("v0", alt = "0")] - V0 = 0, - - #[default] - #[display("v1", alt = "1")] - V1 = 1, -} diff --git a/src/interface/resolver.rs b/src/interface/resolver.rs deleted file mode 100644 index 7f563820..00000000 --- a/src/interface/resolver.rs +++ /dev/null @@ -1,38 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 rgb::validation::{ResolveWitness, WitnessResolverError}; -use rgb::vm::{WitnessOrd, XWitnessTx}; -use strict_encoding::StrictDumb; - -use crate::XWitnessId; - -pub(crate) struct DumbResolver; - -impl ResolveWitness for DumbResolver { - fn resolve_pub_witness(&self, _: XWitnessId) -> Result { - Ok(XWitnessTx::strict_dumb()) - } - - fn resolve_pub_witness_ord(&self, _: XWitnessId) -> Result { - Ok(WitnessOrd::strict_dumb()) - } -} diff --git a/src/lib.rs b/src/lib.rs index 58f9e507..6cff9d5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,23 +1,26 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning +// Standard Library for RGB smart contracts // // SPDX-License-Identifier: Apache-2.0 // -// Written in 2019-2024 by -// Dr Maxim Orlovsky +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky // -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 +// 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 +// 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. +// 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. #![cfg_attr(docsrs, feature(doc_auto_cfg))] @@ -32,27 +35,19 @@ extern crate commit_verify; extern crate rgbcore as rgb; #[cfg(feature = "serde")] #[macro_use] -extern crate serde_crate as serde; +extern crate serde; -/// Re-exporting all invoice data types (RGB and BP). -pub extern crate rgbinvoice as invoice; - -pub mod stl; -pub mod interface; -pub mod containers; -pub mod persistence; -pub mod resolvers; -mod contract; -pub mod info; +mod pile; +mod stockpile; +mod mound; +mod wallet; +//pub mod stl; pub use bp::{Outpoint, Txid}; -pub use contract::{Allocation, MergeReveal, MergeRevealError, WitnessInfo}; -pub use rgb::prelude::*; -pub use rgb::rgbasm; -pub use stl::{LIB_NAME_RGB_STD, LIB_NAME_RGB_STORAGE}; - -/// BIP32 derivation index for outputs which may contain assigned RGB state. -pub const RGB_NATIVE_DERIVATION_INDEX: u32 = 9; -/// BIP32 derivation index for outputs which are tweaked with Tapret commitment -/// and may also optionally contain assigned RGB state. -pub const RGB_TAPRET_DERIVATION_INDEX: u32 = 10; +pub use mound::Mound; +#[cfg(feature = "fs")] +pub use pile::fs::FilePile; +pub use pile::Pile; +pub use rgb::*; +pub use stockpile::Stockpile; +//pub use stl::{LIB_NAME_RGB_STD, LIB_NAME_RGB_STORAGE}; diff --git a/src/mound.rs b/src/mound.rs new file mode 100644 index 00000000..60f194df --- /dev/null +++ b/src/mound.rs @@ -0,0 +1,79 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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; + +use hypersonic::{CellAddr, ContractId, Supply}; + +use crate::{Pile, Stockpile}; + +pub struct Mound, P: Pile, const CAPS: u32>( + BTreeMap>, +); + +impl, P: Pile, const CAPS: u32> Mound { + pub fn new() -> Self { Self(BTreeMap::new()) } + pub fn excavate(mut loader: impl Excavate) -> Self { + Self(loader.excavate().collect()) + } + + pub fn contract_ids(&self) -> impl Iterator + use<'_, S, P, CAPS> { + self.0.keys().copied() + } + + pub fn contracts(&self) -> impl Iterator)> { + self.0.iter().map(|(id, stock)| (*id, stock)) + } + + pub fn contracts_mut( + &mut self, + ) -> impl Iterator)> { + self.0.iter_mut().map(|(id, stock)| (*id, stock)) + } + + pub fn contract(&self, id: ContractId) -> &Stockpile { + self.0 + .get(&id) + .unwrap_or_else(|| panic!("unknown contract {id}")) + } + + pub fn contract_mut(&mut self, id: ContractId) -> &mut Stockpile { + self.0 + .get_mut(&id) + .unwrap_or_else(|| panic!("unknown contract {id}")) + } + + pub fn select<'seal>( + &self, + seal: &'seal P::Seal, + ) -> impl Iterator + use<'_, 'seal, S, P, CAPS> { + self.0 + .iter() + .filter_map(|(id, stockpile)| stockpile.seal(seal).map(|addr| (*id, addr))) + } +} + +pub trait Excavate, P: Pile, const CAPS: u32> { + fn excavate(&mut self) -> impl Iterator)>; +} diff --git a/src/persistence/fs.rs b/src/persistence/fs.rs deleted file mode 100644 index 600cb217..00000000 --- a/src/persistence/fs.rs +++ /dev/null @@ -1,93 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::path::PathBuf; -use std::{fs, io}; - -use amplify::confinement::U32 as U32MAX; -use nonasync::persistence::{PersistenceError, PersistenceProvider}; -use strict_encoding::{StrictDeserialize, StrictSerialize}; - -use crate::persistence::{MemIndex, MemStash, MemState}; - -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct FsBinStore { - pub stash: PathBuf, - pub state: PathBuf, - pub index: PathBuf, -} - -impl FsBinStore { - pub fn new(path: PathBuf) -> io::Result { - fs::create_dir_all(&path)?; - - let mut stash = path.clone(); - stash.push("stash.dat"); - let mut state = path.clone(); - state.push("state.dat"); - let mut index = path.clone(); - index.push("index.dat"); - - Ok(Self { - stash, - state, - index, - }) - } -} -impl PersistenceProvider for FsBinStore { - fn load(&self) -> Result { - MemStash::strict_deserialize_from_file::(&self.stash) - .map_err(PersistenceError::with) - } - - fn store(&self, object: &MemStash) -> Result<(), PersistenceError> { - object - .strict_serialize_to_file::(&self.stash) - .map_err(PersistenceError::with) - } -} - -impl PersistenceProvider for FsBinStore { - fn load(&self) -> Result { - MemState::strict_deserialize_from_file::(&self.state) - .map_err(PersistenceError::with) - } - - fn store(&self, object: &MemState) -> Result<(), PersistenceError> { - object - .strict_serialize_to_file::(&self.state) - .map_err(PersistenceError::with) - } -} - -impl PersistenceProvider for FsBinStore { - fn load(&self) -> Result { - MemIndex::strict_deserialize_from_file::(&self.index) - .map_err(PersistenceError::with) - } - - fn store(&self, object: &MemIndex) -> Result<(), PersistenceError> { - object - .strict_serialize_to_file::(&self.index) - .map_err(PersistenceError::with) - } -} diff --git a/src/persistence/index.rs b/src/persistence/index.rs deleted file mode 100644 index 2f0ac19e..00000000 --- a/src/persistence/index.rs +++ /dev/null @@ -1,368 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::BTreeSet; -use std::error::Error; -use std::fmt::Debug; - -use amplify::confinement; -use nonasync::persistence::{CloneNoPersistence, Persisting}; -use rgb::{ - Assign, AssignmentType, BundleId, ContractId, Extension, Genesis, GenesisSeal, GraphSeal, OpId, - Operation, Opout, TransitionBundle, XChain, XOutputSeal, XWitnessId, -}; - -use crate::containers::{ConsignmentExt, ToWitnessId, WitnessBundle}; -use crate::persistence::{MemError, StoreTransaction}; -use crate::SecretSeal; - -#[derive(Debug, Display, Error, From)] -#[display(inner)] -pub enum IndexError { - /// Connectivity errors which may be recoverable and temporary. - ReadProvider(

::Error), - - /// Connectivity errors which may be recoverable and temporary. - WriteProvider(

::Error), - - /// {0} - /// - /// It may happen due to RGB standard library bug, or indicate internal - /// stash inconsistency and compromised index storage. - Inconsistency(IndexInconsistency), -} - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(inner)] -pub enum IndexReadError { - #[from] - Inconsistency(IndexInconsistency), - Connectivity(E), -} - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(inner)] -pub enum IndexWriteError { - #[from] - Inconsistency(IndexInconsistency), - Connectivity(E), -} - -impl From::Error>> for IndexError

{ - fn from(err: IndexReadError<

::Error>) -> Self { - match err { - IndexReadError::Inconsistency(e) => IndexError::Inconsistency(e), - IndexReadError::Connectivity(e) => IndexError::ReadProvider(e), - } - } -} - -impl From::Error>> for IndexError

{ - fn from(err: IndexWriteError<

::Error>) -> Self { - match err { - IndexWriteError::Inconsistency(e) => IndexError::Inconsistency(e), - IndexWriteError::Connectivity(e) => IndexError::WriteProvider(e), - } - } -} - -impl From for IndexWriteError { - fn from(err: confinement::Error) -> Self { IndexWriteError::Connectivity(err.into()) } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum IndexInconsistency { - /// contract {0} is unknown. Probably you haven't imported the contract yet. - ContractAbsent(ContractId), - - /// bundle matching state transition {0} is absent in the index. - BundleAbsent(OpId), - - /// outpoint {0} is not part of the contract {1}. - OutpointUnknown(XOutputSeal, ContractId), - - /// index already contains information about bundle {bundle_id} which - /// specifies contract {present} instead of contract {expected}. - DistinctBundleContract { - bundle_id: BundleId, - present: ContractId, - expected: ContractId, - }, - - /// index already contains information about operation {opid} which - /// specifies bundle {present} instead of bundle {expected}. - DistinctBundleOp { - opid: OpId, - present: BundleId, - expected: BundleId, - }, - - /// contract id for bundle {0} is not known. - BundleContractUnknown(BundleId), - - /// absent information about witness for bundle {0}. - BundleWitnessUnknown(BundleId), -} - -#[derive(Debug)] -pub struct Index { - provider: P, -} - -impl CloneNoPersistence for Index

{ - fn clone_no_persistence(&self) -> Self { - Self { - provider: self.provider.clone_no_persistence(), - } - } -} - -impl Default for Index

-where P: Default -{ - fn default() -> Self { - Self { - provider: default!(), - } - } -} - -impl Index

{ - pub(super) fn new(provider: P) -> Self { Self { provider } } - - #[doc(hidden)] - pub fn as_provider(&self) -> &P { &self.provider } - - #[doc(hidden)] - pub(super) fn as_provider_mut(&mut self) -> &mut P { &mut self.provider } - - pub(super) fn index_consignment( - &mut self, - consignment: impl ConsignmentExt, - ) -> Result<(), IndexError

> { - let contract_id = consignment.contract_id(); - - self.provider - .register_contract(contract_id) - .map_err(IndexError::WriteProvider)?; - self.index_genesis(contract_id, consignment.genesis())?; - for extension in consignment.extensions() { - self.index_extension(contract_id, extension)?; - } - for WitnessBundle { - pub_witness, - anchored_bundles, - } in consignment.bundled_witnesses() - { - let witness_id = pub_witness.to_witness_id(); - for bundle in anchored_bundles.bundles() { - self.index_bundle(contract_id, bundle, witness_id)?; - } - } - - Ok(()) - } - - fn index_genesis(&mut self, id: ContractId, genesis: &Genesis) -> Result<(), IndexError

> { - let opid = genesis.id(); - for (type_id, assigns) in genesis.assignments.iter() { - self.provider - .index_genesis_assignments(id, assigns, opid, *type_id)?; - } - Ok(()) - } - - fn index_extension( - &mut self, - id: ContractId, - extension: &Extension, - ) -> Result<(), IndexError

> { - let opid = extension.id(); - for (type_id, assigns) in extension.assignments.iter() { - self.provider - .index_genesis_assignments(id, assigns, opid, *type_id)?; - } - Ok(()) - } - - pub(crate) fn index_bundle( - &mut self, - contract_id: ContractId, - bundle: &TransitionBundle, - witness_id: XWitnessId, - ) -> Result<(), IndexError

> { - let bundle_id = bundle.bundle_id(); - - self.provider - .register_bundle(bundle_id, witness_id, contract_id)?; - - for (opid, transition) in &bundle.known_transitions { - self.provider.register_operation(*opid, bundle_id)?; - for (type_id, assigns) in transition.assignments.iter() { - self.provider.index_transition_assignments( - contract_id, - assigns, - *opid, - *type_id, - witness_id, - )?; - } - } - - Ok(()) - } - - pub(super) fn contracts_assigning( - &self, - outputs: BTreeSet, - ) -> Result + '_, IndexError

> { - self.provider - .contracts_assigning(outputs) - .map_err(IndexError::ReadProvider) - } - - pub(super) fn public_opouts( - &self, - contract_id: ContractId, - ) -> Result, IndexError

> { - Ok(self.provider.public_opouts(contract_id)?) - } - - pub(super) fn opouts_by_outputs( - &self, - contract_id: ContractId, - outputs: impl IntoIterator>, - ) -> Result, IndexError

> { - Ok(self.provider.opouts_by_outputs(contract_id, outputs)?) - } - - pub(super) fn opouts_by_terminals( - &self, - terminals: impl IntoIterator>, - ) -> Result, IndexError

> { - self.provider - .opouts_by_terminals(terminals) - .map_err(IndexError::ReadProvider) - } - - pub(super) fn bundle_id_for_op(&self, opid: OpId) -> Result> { - Ok(self.provider.bundle_id_for_op(opid)?) - } - - pub(super) fn bundle_info( - &self, - bundle_id: BundleId, - ) -> Result<(impl Iterator + '_, ContractId), IndexError

> { - Ok(self.provider.bundle_info(bundle_id)?) - } -} - -impl StoreTransaction for Index

{ - type TransactionErr = IndexError

; - - fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.provider - .begin_transaction() - .map_err(IndexError::WriteProvider) - } - - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.provider - .commit_transaction() - .map_err(IndexError::WriteProvider) - } - - fn rollback_transaction(&mut self) { self.provider.rollback_transaction() } -} - -pub trait IndexProvider: - Debug + CloneNoPersistence + Persisting + IndexReadProvider + IndexWriteProvider -{ -} - -pub trait IndexReadProvider { - type Error: Clone + Eq + Error; - - fn contracts_assigning( - &self, - outputs: BTreeSet, - ) -> Result + '_, Self::Error>; - - fn public_opouts( - &self, - contract_id: ContractId, - ) -> Result, IndexReadError>; - - fn opouts_by_outputs( - &self, - contract_id: ContractId, - outputs: impl IntoIterator>, - ) -> Result, IndexReadError>; - - fn opouts_by_terminals( - &self, - terminals: impl IntoIterator>, - ) -> Result, Self::Error>; - - fn bundle_id_for_op(&self, opid: OpId) -> Result>; - - fn bundle_info( - &self, - bundle_id: BundleId, - ) -> Result<(impl Iterator, ContractId), IndexReadError>; -} - -pub trait IndexWriteProvider: StoreTransaction { - type Error: Error; - - fn register_contract(&mut self, contract_id: ContractId) -> Result; - - fn register_bundle( - &mut self, - bundle_id: BundleId, - witness_id: XWitnessId, - contract_id: ContractId, - ) -> Result>; - - fn register_operation( - &mut self, - opid: OpId, - bundle_id: BundleId, - ) -> Result>; - - fn index_genesis_assignments( - &mut self, - contract_id: ContractId, - vec: &[Assign], - opid: OpId, - type_id: AssignmentType, - ) -> Result<(), IndexWriteError>; - - fn index_transition_assignments( - &mut self, - contract_id: ContractId, - vec: &[Assign], - opid: OpId, - type_id: AssignmentType, - witness_id: XWitnessId, - ) -> Result<(), IndexWriteError>; -} diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs deleted file mode 100644 index 81acbf70..00000000 --- a/src/persistence/memory.rs +++ /dev/null @@ -1,1424 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::borrow::Borrow; -use std::cmp::Ordering; -use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::convert::Infallible; -use std::fmt::{Debug, Formatter}; -use std::num::NonZeroU32; -use std::{iter, mem}; - -use aluvm::library::{Lib, LibId}; -use amplify::confinement::{ - self, Confined, LargeOrdMap, LargeOrdSet, MediumBlob, MediumOrdMap, MediumOrdSet, SmallOrdMap, - TinyOrdMap, TinyOrdSet, -}; -use amplify::num::u24; -use bp::dbc::tapret::TapretCommitment; -use commit_verify::{CommitId, Conceal}; -use nonasync::persistence::{CloneNoPersistence, Persistence, PersistenceError, Persisting}; -use rgb::validation::ResolveWitness; -use rgb::vm::{ - ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, - OrdOpRef, UnknownGlobalStateType, WitnessOrd, -}; -use rgb::{ - Assign, AssignmentType, Assignments, AssignmentsRef, AttachId, BundleId, ContractId, - ExposedSeal, Extension, Genesis, GenesisSeal, GlobalStateType, GraphSeal, Identity, OpId, - Operation, Opout, Schema, SchemaId, SecretSeal, StateData, Transition, TransitionBundle, - XChain, XOutpoint, XOutputSeal, XWitnessId, -}; -use strict_encoding::{StrictDeserialize, StrictSerialize}; -use strict_types::TypeSystem; - -use super::{ - ContractIfaceError, ContractStateRead, ContractStateWrite, IndexInconsistency, IndexProvider, - IndexReadError, IndexReadProvider, IndexWriteError, IndexWriteProvider, SchemaIfaces, - StashInconsistency, StashProvider, StashProviderError, StashReadProvider, StashWriteProvider, - StateInconsistency, StateProvider, StateReadProvider, StateWriteProvider, StoreTransaction, - UpdateRes, -}; -use crate::containers::{ - AnchorSet, ContentId, ContentRef, ContentSigs, SealWitness, SigBlob, Supplement, TrustLevel, -}; -use crate::contract::{Allocation, GlobalOut, OpWitness}; -use crate::interface::{Iface, IfaceClass, IfaceId, IfaceImpl, IfaceRef}; -use crate::LIB_NAME_RGB_STORAGE; - -#[derive(Debug, Display, Error, From)] -#[display(inner)] -pub enum MemError { - #[from] - Persistence(PersistenceError), - - #[from] - Confinement(confinement::Error), -} - -////////// -// STASH -////////// - -/// Hoard is an in-memory stash useful for WASM implementations. -#[derive(Getters, Debug)] -#[getter(prefix = "debug_")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STORAGE, dumb = Self::in_memory())] -pub struct MemStash { - #[getter(skip)] - #[strict_type(skip)] - persistence: Option>, - - schemata: TinyOrdMap, - ifaces: TinyOrdMap, - geneses: TinyOrdMap, - suppl: TinyOrdMap>, - bundles: LargeOrdMap, - extensions: LargeOrdMap, - witnesses: LargeOrdMap, - attachments: SmallOrdMap, - secret_seals: MediumOrdSet>, - type_system: TypeSystem, - identities: SmallOrdMap, - libs: SmallOrdMap, - sigs: SmallOrdMap, -} - -impl StrictSerialize for MemStash {} -impl StrictDeserialize for MemStash {} - -impl MemStash { - pub fn in_memory() -> Self { - Self { - persistence: none!(), - schemata: empty!(), - ifaces: empty!(), - geneses: empty!(), - suppl: empty!(), - bundles: empty!(), - extensions: empty!(), - witnesses: empty!(), - attachments: empty!(), - secret_seals: empty!(), - type_system: none!(), - identities: empty!(), - libs: empty!(), - sigs: empty!(), - } - } -} - -impl CloneNoPersistence for MemStash { - fn clone_no_persistence(&self) -> Self { - Self { - persistence: None, - schemata: self.schemata.clone(), - ifaces: self.ifaces.clone(), - geneses: self.geneses.clone(), - suppl: self.suppl.clone(), - bundles: self.bundles.clone(), - extensions: self.extensions.clone(), - witnesses: self.witnesses.clone(), - attachments: self.attachments.clone(), - secret_seals: self.secret_seals.clone(), - type_system: self.type_system.clone(), - identities: self.identities.clone(), - libs: self.libs.clone(), - sigs: self.sigs.clone(), - } - } -} - -impl Persisting for MemStash { - #[inline] - fn persistence(&self) -> Option<&Persistence> { self.persistence.as_ref() } - #[inline] - fn persistence_mut(&mut self) -> Option<&mut Persistence> { self.persistence.as_mut() } - #[inline] - fn as_mut_persistence(&mut self) -> &mut Option> { &mut self.persistence } -} - -impl StoreTransaction for MemStash { - type TransactionErr = MemError; - #[inline] - fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.mark_dirty(); - Ok(()) - } - #[inline] - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { Ok(self.store()?) } - #[inline] - fn rollback_transaction(&mut self) { unreachable!() } -} - -impl StashProvider for MemStash {} - -impl StashReadProvider for MemStash { - // With in-memory data we have no connectivity or I/O errors - type Error = Infallible; - - fn type_system(&self) -> Result<&TypeSystem, Self::Error> { Ok(&self.type_system) } - - fn lib(&self, id: LibId) -> Result<&Lib, StashProviderError> { - self.libs - .get(&id) - .ok_or_else(|| StashInconsistency::LibAbsent(id).into()) - } - - fn ifaces(&self) -> Result, Self::Error> { - Ok(self.ifaces.values()) - } - - fn iface(&self, iface: impl Into) -> Result<&Iface, StashProviderError> { - let iref = iface.into(); - match iref { - IfaceRef::Name(ref name) => self.ifaces.values().find(|iface| &iface.name == name), - IfaceRef::Id(ref id) => self.ifaces.get(id), - } - .ok_or_else(|| StashInconsistency::IfaceAbsent(iref).into()) - } - - fn schemata(&self) -> Result, Self::Error> { - Ok(self.schemata.values()) - } - fn schemata_by( - &self, - ) -> Result, Self::Error> { - Ok(self - .schemata - .values() - .filter(|schema_ifaces| self.impl_for::(schema_ifaces).is_ok())) - } - - fn impl_for<'a, C: IfaceClass + 'a>( - &'a self, - schema_ifaces: &'a SchemaIfaces, - ) -> Result<&'a IfaceImpl, StashProviderError> { - schema_ifaces - .iimpls - .values() - .find(|iimpl| C::IFACE_IDS.contains(&iimpl.iface_id)) - .or_else(|| { - C::IFACE_IDS.iter().find_map(|id| { - let iface = self.iface(*id).ok()?; - iface.find_abstractable_impl(schema_ifaces) - }) - }) - .ok_or_else(move || { - ContractIfaceError::NoAbstractImpl( - C::IFACE_IDS[0], - schema_ifaces.schema.schema_id(), - ) - .into() - }) - } - - fn schema( - &self, - schema_id: SchemaId, - ) -> Result<&SchemaIfaces, StashProviderError> { - self.schemata - .get(&schema_id) - .ok_or_else(|| StashInconsistency::SchemaAbsent(schema_id).into()) - } - - fn get_trust(&self, identity: &Identity) -> Result { - Ok(self.identities.get(identity).copied().unwrap_or_default()) - } - - fn supplement(&self, content_ref: ContentRef) -> Result, Self::Error> { - Ok(self.suppl.get(&content_ref).and_then(|s| s.first())) - } - - fn supplements( - &self, - content_ref: ContentRef, - ) -> Result, Self::Error> { - Ok(self - .suppl - .get(&content_ref) - .cloned() - .unwrap_or_default() - .into_iter()) - } - - fn sigs_for(&self, content_id: &ContentId) -> Result, Self::Error> { - Ok(self.sigs.get(content_id)) - } - - fn geneses(&self) -> Result, Self::Error> { - Ok(self.geneses.values()) - } - - fn geneses_by(&self) -> Result, Self::Error> { - Ok(self.schemata_by::()?.flat_map(|schema_ifaces| { - self.geneses - .values() - .filter(|genesis| schema_ifaces.schema.schema_id() == genesis.schema_id) - })) - } - - fn genesis( - &self, - contract_id: ContractId, - ) -> Result<&Genesis, StashProviderError> { - self.geneses - .get(&contract_id) - .ok_or(StashInconsistency::ContractAbsent(contract_id).into()) - } - - fn witness_ids(&self) -> Result, Self::Error> { - Ok(self.witnesses.keys().copied()) - } - - fn bundle_ids(&self) -> Result, Self::Error> { - Ok(self.bundles.keys().copied()) - } - - fn bundle( - &self, - bundle_id: BundleId, - ) -> Result<&TransitionBundle, StashProviderError> { - self.bundles - .get(&bundle_id) - .ok_or(StashInconsistency::BundleAbsent(bundle_id).into()) - } - - fn extension_ids(&self) -> Result, Self::Error> { - Ok(self.extensions.keys().copied()) - } - - fn extension(&self, op_id: OpId) -> Result<&Extension, StashProviderError> { - self.extensions - .get(&op_id) - .ok_or(StashInconsistency::OperationAbsent(op_id).into()) - } - - fn witness( - &self, - witness_id: XWitnessId, - ) -> Result<&SealWitness, StashProviderError> { - self.witnesses - .get(&witness_id) - .ok_or(StashInconsistency::WitnessAbsent(witness_id).into()) - } - - fn taprets(&self) -> Result, Self::Error> { - Ok(self - .witnesses - .iter() - .filter_map(|(witness_id, witness)| match &witness.anchors { - AnchorSet::Tapret(anchor) - | AnchorSet::Double { - tapret: anchor, - opret: _, - } => Some((*witness_id, TapretCommitment { - mpc: anchor.mpc_proof.commit_id(), - nonce: anchor.dbc_proof.path_proof.nonce(), - })), - _ => None, - })) - } - - fn seal_secret( - &self, - secret: XChain, - ) -> Result>, Self::Error> { - Ok(self - .secret_seals - .iter() - .find(|s| s.conceal() == secret) - .copied()) - } - - fn secret_seals(&self) -> Result>, Self::Error> { - Ok(self.secret_seals.iter().copied()) - } -} - -impl StashWriteProvider for MemStash { - type Error = MemError; - - fn replace_schema(&mut self, schema: Schema) -> Result { - let schema_id = schema.schema_id(); - if !self.schemata.contains_key(&schema_id) { - self.schemata.insert(schema_id, SchemaIfaces::new(schema))?; - return Ok(true); - } - Ok(false) - } - - fn replace_iface(&mut self, iface: Iface) -> Result { - let iface_id = iface.iface_id(); - if !self.ifaces.contains_key(&iface_id) { - self.ifaces.insert(iface_id, iface)?; - return Ok(true); - } - Ok(false) - } - - fn replace_iimpl(&mut self, iimpl: IfaceImpl) -> Result { - let schema_ifaces = self - .schemata - .get_mut(&iimpl.schema_id) - .expect("unknown schema"); - let iface = self.ifaces.get(&iimpl.iface_id).expect("unknown interface"); - let iface_name = iface.name.clone(); - let present = schema_ifaces.iimpls.contains_key(&iface_name); - schema_ifaces.iimpls.insert(iface_name, iimpl)?; - Ok(!present) - } - - fn set_trust( - &mut self, - identity: Identity, - trust: TrustLevel, - ) -> Result<(), confinement::Error> { - self.identities.insert(identity, trust)?; - Ok(()) - } - - fn add_supplement(&mut self, suppl: Supplement) -> Result<(), Self::Error> { - match self.suppl.get_mut(&suppl.content_id) { - None => { - self.suppl.insert(suppl.content_id, tiny_bset![suppl])?; - } - Some(suppls) => suppls.push(suppl)?, - } - Ok(()) - } - - fn replace_genesis(&mut self, genesis: Genesis) -> Result { - let contract_id = genesis.contract_id(); - let present = self.geneses.insert(contract_id, genesis)?.is_some(); - Ok(!present) - } - - fn replace_extension(&mut self, extension: Extension) -> Result { - let opid = extension.id(); - let present = self.extensions.insert(opid, extension)?.is_some(); - Ok(!present) - } - - fn replace_bundle(&mut self, bundle: TransitionBundle) -> Result { - let bundle_id = bundle.bundle_id(); - let present = self.bundles.insert(bundle_id, bundle)?.is_some(); - Ok(!present) - } - - fn replace_witness(&mut self, witness: SealWitness) -> Result { - let witness_id = witness.witness_id(); - let present = self.witnesses.insert(witness_id, witness)?.is_some(); - Ok(!present) - } - - fn replace_attachment( - &mut self, - id: AttachId, - attach: MediumBlob, - ) -> Result { - let present = self.attachments.insert(id, attach)?.is_some(); - Ok(!present) - } - - fn consume_types(&mut self, types: TypeSystem) -> Result<(), Self::Error> { - Ok(self.type_system.extend(types)?) - } - - fn replace_lib(&mut self, lib: Lib) -> Result { - let present = self.libs.insert(lib.id(), lib)?.is_some(); - Ok(!present) - } - - fn import_sigs(&mut self, content_id: ContentId, sigs: I) -> Result<(), Self::Error> - where I: IntoIterator { - let sigs = sigs.into_iter().filter(|(id, _)| { - match self.identities.get(id) { - Some(level) => *level, - None => { - let level = TrustLevel::default(); - // We ignore if the identities are full - self.identities.insert(id.clone(), level).ok(); - level - } - } - .should_accept() - }); - if let Some(prev_sigs) = self.sigs.get_mut(&content_id) { - prev_sigs.extend(sigs)?; - } else { - let sigs = Confined::try_from_iter(sigs)?; - self.sigs.insert(content_id, ContentSigs::from(sigs)).ok(); - } - Ok(()) - } - - fn add_secret_seal(&mut self, seal: XChain) -> Result { - let present = self.secret_seals.contains(&seal); - self.secret_seals.push(seal)?; - Ok(!present) - } -} - -////////// -// STATE -////////// - -#[derive(Getters, Debug)] -#[getter(prefix = "debug_")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STORAGE, dumb = Self::in_memory())] -pub struct MemState { - #[getter(skip)] - #[strict_type(skip)] - persistence: Option>, - - witnesses: LargeOrdMap, - contracts: TinyOrdMap, -} - -impl StrictSerialize for MemState {} -impl StrictDeserialize for MemState {} - -impl MemState { - pub fn in_memory() -> Self { - Self { - persistence: none!(), - witnesses: empty!(), - contracts: empty!(), - } - } -} - -impl CloneNoPersistence for MemState { - fn clone_no_persistence(&self) -> Self { - Self { - persistence: None, - witnesses: self.witnesses.clone(), - contracts: self.contracts.clone(), - } - } -} - -impl Persisting for MemState { - #[inline] - fn persistence(&self) -> Option<&Persistence> { self.persistence.as_ref() } - #[inline] - fn persistence_mut(&mut self) -> Option<&mut Persistence> { self.persistence.as_mut() } - #[inline] - fn as_mut_persistence(&mut self) -> &mut Option> { &mut self.persistence } -} - -impl StoreTransaction for MemState { - type TransactionErr = MemError; - #[inline] - fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.mark_dirty(); - Ok(()) - } - #[inline] - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { Ok(self.store()?) } - #[inline] - fn rollback_transaction(&mut self) { unreachable!() } -} - -impl StateProvider for MemState {} - -impl StateReadProvider for MemState { - type ContractRead<'a> = MemContract<&'a MemContractState>; - type Error = StateInconsistency; - - fn contract_state( - &self, - contract_id: ContractId, - ) -> Result, Self::Error> { - let unfiltered = self - .contracts - .get(&contract_id) - .ok_or(StateInconsistency::UnknownContract(contract_id))?; - let filter = self - .witnesses - .iter() - .filter(|(id, _)| { - let id = Some(**id); - unfiltered - .global - .values() - .flat_map(|state| state.known.keys()) - .any(|out| out.witness_id() == id) - || unfiltered.owned.iter().any(|a| a.witness == id) - }) - .map(|(id, ord)| (*id, *ord)) - .collect(); - Ok(MemContract { filter, unfiltered }) - } - - fn is_valid_witness(&self, witness_id: XWitnessId) -> Result { - let ord = self - .witnesses - .get(&witness_id) - .ok_or(StateInconsistency::AbsentWitness(witness_id))?; - Ok(ord.is_valid()) - } -} - -impl StateWriteProvider for MemState { - type ContractWrite<'a> = MemContractWriter<'a>; - type Error = MemError; - - fn register_contract( - &mut self, - schema: &Schema, - genesis: &Genesis, - ) -> Result, Self::Error> { - // TODO: Add begin/commit transaction - let contract_id = genesis.contract_id(); - // This crazy construction is caused by a stupidity of rust borrow checker - let contract = if self.contracts.contains_key(&contract_id) { - if let Some(contract) = self.contracts.get_mut(&contract_id) { - contract - } else { - unreachable!(); - } - } else { - self.contracts - .insert(contract_id, MemContractState::new(schema, contract_id))?; - self.contracts.get_mut(&contract_id).expect("just inserted") - }; - let mut writer = MemContractWriter { - writer: Box::new( - |witness_id: XWitnessId, ord: WitnessOrd| -> Result<(), confinement::Error> { - // NB: We do not check the existence of the witness since we have a newer - // version anyway and even if it is known we have to replace it - self.witnesses.insert(witness_id, ord)?; - Ok(()) - }, - ), - contract, - }; - writer.add_genesis(genesis)?; - Ok(writer) - } - - fn update_contract( - &mut self, - contract_id: ContractId, - ) -> Result>, Self::Error> { - // TODO: Add begin/commit transaction - Ok(self - .contracts - .get_mut(&contract_id) - .map(|contract| MemContractWriter { - // We can't move this constructor to a dedicated method due to the rust borrower - // checker - writer: Box::new( - |witness_id: XWitnessId, ord: WitnessOrd| -> Result<(), confinement::Error> { - // NB: We do not check the existence of the witness since we have a newer - // version anyway and even if it is known we have to replace - // it - self.witnesses.insert(witness_id, ord)?; - Ok(()) - }, - ), - contract, - })) - } - - fn update_witnesses( - &mut self, - resolver: impl ResolveWitness, - after_height: u32, - ) -> Result { - let after_height = NonZeroU32::new(after_height).unwrap_or(NonZeroU32::MIN); - let mut succeeded = 0; - let mut failed = map![]; - self.begin_transaction()?; - let mut witnesses = LargeOrdMap::new(); - mem::swap(&mut self.witnesses, &mut witnesses); - let mut witnesses = witnesses.release(); - for (id, ord) in &mut witnesses { - if matches!(ord, WitnessOrd::Mined(pos) if pos.height() < after_height) { - continue; - } - match resolver.resolve_pub_witness_ord(*id) { - Ok(new) => *ord = new, - Err(err) => { - failed.insert(*id, err.to_string()); - } - } - succeeded += 1; - } - let mut witnesses = - LargeOrdMap::try_from(witnesses).inspect_err(|_| self.rollback_transaction())?; - mem::swap(&mut self.witnesses, &mut witnesses); - self.commit_transaction()?; - Ok(UpdateRes { succeeded, failed }) - } -} - -#[derive(Getters, Clone, Eq, PartialEq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STORAGE)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct MemGlobalState { - known: LargeOrdMap, - limit: u24, -} - -impl MemGlobalState { - pub fn new(limit: u24) -> Self { - MemGlobalState { - known: empty!(), - limit, - } - } -} - -/// Contract history accumulates raw data from the contract history, extracted -/// from a series of consignments over the time. It does consensus ordering of -/// the state data, but it doesn't interpret or validates the state against the -/// schema. -/// -/// NB: MemContract provides an in-memory contract state used during contract -/// validation. It does not support filtering by witness transaction validity -/// and thus must not be used in any other cases in its explicit form. Pls see -/// [`MemContract`] instead. -#[derive(Getters, Clone, Eq, PartialEq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STORAGE)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct MemContractState { - #[getter(as_copy)] - schema_id: SchemaId, - #[getter(as_copy)] - contract_id: ContractId, - #[getter(skip)] - global: TinyOrdMap, - owned: LargeOrdSet, -} - -impl MemContractState { - pub fn new(schema: &Schema, contract_id: ContractId) -> Self { - let global = TinyOrdMap::from_iter_checked( - schema - .global_types - .iter() - .map(|(ty, glob)| (*ty, MemGlobalState::new(glob.max_items))), - ); - MemContractState { - schema_id: schema.schema_id(), - contract_id, - global, - owned: empty!(), - } - } - - fn add_operation(&mut self, op: OrdOpRef) { - let opid = op.id(); - - for (ty, state) in op.globals() { - let map = self - .global - .get_mut(ty) - .expect("global map must be initialized from the schema"); - for (idx, s) in state.iter().enumerate() { - let out = GlobalOut { - opid, - nonce: op.nonce(), - index: idx as u16, - op_witness: OpWitness::from(op), - }; - map.known - .insert(out, s.clone()) - .expect("contract global state exceeded 2^32 items, which is unrealistic"); - } - } - - // We skip removing of invalidated state for the cases of re-orgs or unmined - // witness transactions committing to the new state. - // TODO: Expose an API to prune historic state by witness txid - /* - // Remove invalidated state - for input in &op.inputs() { - if let Some(o) = self.rights.iter().find(|r| r.opout == input.prev_out) { - let o = o.clone(); // need this b/c of borrow checker - self.rights - .remove(&o) - .expect("collection allows zero elements"); - } - if let Some(o) = self.fungibles.iter().find(|r| r.opout == input.prev_out) { - let o = o.clone(); - self.fungibles - .remove(&o) - .expect("collection allows zero elements"); - } - if let Some(o) = self.data.iter().find(|r| r.opout == input.prev_out) { - let o = o.clone(); - self.data - .remove(&o) - .expect("collection allows zero elements"); - } - if let Some(o) = self.attach.iter().find(|r| r.opout == input.prev_out) { - let o = o.clone(); - self.attach - .remove(&o) - .expect("collection allows zero elements"); - } - } - */ - - let witness_id = op.witness_id(); - match op.assignments() { - AssignmentsRef::Genesis(assignments) => { - self.add_assignments(witness_id, opid, assignments) - } - AssignmentsRef::Graph(assignments) => { - self.add_assignments(witness_id, opid, assignments) - } - } - } - - fn add_assignments( - &mut self, - witness_id: Option, - opid: OpId, - assignments: &Assignments, - ) { - for (ty, assignments) in assignments.iter() { - for (no, seal, state) in assignments - .iter() - .enumerate() - .filter_map(|(n, a)| a.revealed_seal().map(|seal| (n, seal, a.as_state()))) - { - let assigned_state = match witness_id { - Some(witness_id) => Allocation::with_witness( - seal, - witness_id, - state.clone(), - opid, - *ty, - no as u16, - ), - None => Allocation::with_no_witness(seal, state.clone(), opid, *ty, no as u16), - }; - self.owned - .push(assigned_state) - .expect("contract state exceeded 2^32 items, which is unrealistic"); - } - } - } -} - -pub struct MemContract = MemContractState> { - filter: HashMap, - unfiltered: M, -} - -impl> Debug for MemContract { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_str("MemContractFiltered { .. }") - } -} - -impl> ContractStateAccess for MemContract { - fn global( - &self, - ty: GlobalStateType, - ) -> Result, UnknownGlobalStateType> { - type Src<'a> = &'a BTreeMap; - type FilteredIter<'a> = Box + 'a>; - struct Iter<'a> { - src: Src<'a>, - iter: FilteredIter<'a>, - last: Option<(GlobalOrd, &'a StateData)>, - depth: u24, - constructor: Box) -> FilteredIter<'a> + 'a>, - } - impl<'a> Iter<'a> { - fn swap(&mut self) -> FilteredIter<'a> { - let mut iter = (self.constructor)(self.src); - mem::swap(&mut iter, &mut self.iter); - iter - } - } - impl<'a> GlobalStateIter for Iter<'a> { - type Data = &'a StateData; - fn size(&mut self) -> u24 { - let iter = self.swap(); - // TODO: Consuming iterator just to count items is highly inefficient, but I do - // not know any other way of computing this value - let size = iter.count(); - u24::try_from(size as u32).expect("iterator size must fit u24 due to `take` limit") - } - fn prev(&mut self) -> Option<(GlobalOrd, Self::Data)> { - self.last = self.iter.next(); - self.depth += u24::ONE; - self.last() - } - fn last(&mut self) -> Option<(GlobalOrd, Self::Data)> { self.last } - fn reset(&mut self, depth: u24) { - match self.depth.cmp(&depth) { - Ordering::Less => { - let mut iter = Box::new(iter::empty()) as FilteredIter; - mem::swap(&mut self.iter, &mut iter); - self.iter = Box::new(iter.skip(depth.to_usize() - depth.to_usize())) - } - Ordering::Equal => {} - Ordering::Greater => { - let iter = self.swap(); - self.iter = Box::new(iter.skip(depth.to_usize())); - } - } - } - } - // We need this due to the limitations of the rust compiler to enforce lifetimes - // on closures - fn constrained<'a, F: Fn(Src<'a>) -> FilteredIter<'a>>(f: F) -> F { f } - - let state = self - .unfiltered - .borrow() - .global - .get(&ty) - .ok_or(UnknownGlobalStateType(ty))?; - - let constructor = constrained(move |src: Src<'_>| -> FilteredIter<'_> { - Box::new( - src.iter() - .rev() - .filter_map(|(out, data)| { - let ord = match out.op_witness { - OpWitness::Genesis => GlobalOrd::genesis(out.index), - OpWitness::Transition(id, ty) => { - let ord = self.filter.get(&id)?; - GlobalOrd::transition(out.opid, out.index, ty, out.nonce, *ord) - } - OpWitness::Extension(id, ty) => { - let ord = self.filter.get(&id)?; - GlobalOrd::extension(out.opid, out.index, ty, out.nonce, *ord) - } - }; - Some((ord, data)) - }) - .take(state.limit.to_usize()), - ) - }); - let iter = Iter { - src: state.known.as_unconfined(), - iter: constructor(state.known.as_unconfined()), - depth: u24::ZERO, - last: None, - constructor: Box::new(constructor), - }; - Ok(GlobalContractState::new(iter)) - } - - fn state( - &self, - outpoint: XOutpoint, - ty: AssignmentType, - ) -> impl DoubleEndedIterator> { - self.unfiltered - .borrow() - .owned - .iter() - .filter(move |assignment| { - assignment.seal.to_outpoint() == outpoint && assignment.opout.ty == ty - }) - .filter(|assignment| assignment.check_witness(&self.filter)) - .map(|assignment| &assignment.state) - } -} - -impl ContractStateEvolve for MemContract { - type Context<'ctx> = (&'ctx Schema, ContractId); - - fn init(context: Self::Context<'_>) -> Self { - Self { - filter: empty!(), - unfiltered: MemContractState::new(context.0, context.1), - } - } - - fn evolve_state(&mut self, op: OrdOpRef) -> Result<(), confinement::Error> { - fn writer(me: &mut MemContract) -> MemContractWriter { - MemContractWriter { - writer: Box::new( - |witness_id: XWitnessId, ord: WitnessOrd| -> Result<(), confinement::Error> { - // NB: We do not check the existence of the witness since we have a - // newer version anyway and even if it is - // known we have to replace it - me.filter.insert(witness_id, ord); - Ok(()) - }, - ), - contract: &mut me.unfiltered, - } - } - match op { - OrdOpRef::Genesis(genesis) => { - let mut writer = writer(self); - writer.add_genesis(genesis) - } - OrdOpRef::Transition(transition, witness_id, ord) => { - let mut writer = writer(self); - writer.add_transition(transition, witness_id, ord) - } - OrdOpRef::Extension(extension, witness_id, ord) => { - let mut writer = writer(self); - writer.add_extension(extension, witness_id, ord) - } - } - .map_err(|err| { - // TODO: remove once evolve_state would accept arbitrary errors - match err { - MemError::Persistence(_) => unreachable!("only confinement errors are possible"), - MemError::Confinement(e) => e, - } - })?; - Ok(()) - } -} - -impl> ContractStateRead for MemContract { - #[inline] - fn contract_id(&self) -> ContractId { self.unfiltered.borrow().contract_id } - - #[inline] - fn schema_id(&self) -> SchemaId { self.unfiltered.borrow().schema_id } - - #[inline] - fn witness_ord(&self, witness_id: XWitnessId) -> Option { - self.filter.get(&witness_id).copied() - } - - #[inline] - fn assignments(&self) -> impl Iterator { - self.unfiltered - .borrow() - .owned - .iter() - .filter(|assignment| assignment.check_witness(&self.filter)) - } -} - -pub struct MemContractWriter<'mem> { - writer: Box Result<(), confinement::Error> + 'mem>, - contract: &'mem mut MemContractState, -} - -impl<'mem> ContractStateWrite for MemContractWriter<'mem> { - type Error = MemError; - - /// # Panics - /// - /// If genesis violates RGB consensus rules and wasn't checked against the - /// schema before adding to the history. - fn add_genesis(&mut self, genesis: &Genesis) -> Result<(), Self::Error> { - self.contract.add_operation(OrdOpRef::Genesis(genesis)); - Ok(()) - } - - /// # Panics - /// - /// If state transition violates RGB consensus rules and wasn't checked - /// against the schema before adding to the history. - fn add_transition( - &mut self, - transition: &Transition, - witness_id: XWitnessId, - ord: WitnessOrd, - ) -> Result<(), Self::Error> { - (self.writer)(witness_id, ord)?; - self.contract - .add_operation(OrdOpRef::Transition(transition, witness_id, ord)); - Ok(()) - } - - /// # Panics - /// - /// If state extension violates RGB consensus rules and wasn't checked - /// against the schema before adding to the history. - fn add_extension( - &mut self, - extension: &Extension, - witness_id: XWitnessId, - ord: WitnessOrd, - ) -> Result<(), Self::Error> { - (self.writer)(witness_id, ord)?; - self.contract - .add_operation(OrdOpRef::Extension(extension, witness_id, ord)); - Ok(()) - } -} - -////////// -// INDEX -////////// - -impl From for IndexReadError { - fn from(err: confinement::Error) -> Self { IndexReadError::Connectivity(err) } -} - -impl From for IndexWriteError { - fn from(err: confinement::Error) -> Self { IndexWriteError::Connectivity(err) } -} - -#[derive(Clone, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STORAGE)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ContractIndex { - public_opouts: MediumOrdSet, - outpoint_opouts: MediumOrdMap>, -} - -#[derive(Getters, Debug)] -#[getter(prefix = "debug_")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STORAGE, dumb = Self::in_memory())] -pub struct MemIndex { - #[getter(skip)] - #[strict_type(skip)] - persistence: Option>, - - op_bundle_index: MediumOrdMap, - bundle_contract_index: MediumOrdMap, - bundle_witness_index: MediumOrdMap>, - contract_index: TinyOrdMap, - terminal_index: MediumOrdMap, TinyOrdSet>, -} - -impl StrictSerialize for MemIndex {} -impl StrictDeserialize for MemIndex {} - -impl MemIndex { - pub fn in_memory() -> Self { - Self { - persistence: None, - op_bundle_index: empty!(), - bundle_contract_index: empty!(), - bundle_witness_index: empty!(), - contract_index: empty!(), - terminal_index: empty!(), - } - } -} - -impl CloneNoPersistence for MemIndex { - fn clone_no_persistence(&self) -> Self { - Self { - persistence: None, - op_bundle_index: self.op_bundle_index.clone(), - bundle_contract_index: self.bundle_contract_index.clone(), - bundle_witness_index: self.bundle_witness_index.clone(), - contract_index: self.contract_index.clone(), - terminal_index: self.terminal_index.clone(), - } - } -} - -impl Persisting for MemIndex { - #[inline] - fn persistence(&self) -> Option<&Persistence> { self.persistence.as_ref() } - #[inline] - fn persistence_mut(&mut self) -> Option<&mut Persistence> { self.persistence.as_mut() } - #[inline] - fn as_mut_persistence(&mut self) -> &mut Option> { &mut self.persistence } -} - -impl StoreTransaction for MemIndex { - type TransactionErr = MemError; - #[inline] - fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.mark_dirty(); - Ok(()) - } - #[inline] - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { Ok(self.store()?) } - #[inline] - fn rollback_transaction(&mut self) { unreachable!() } -} - -impl IndexProvider for MemIndex {} - -impl IndexReadProvider for MemIndex { - type Error = Infallible; - - fn contracts_assigning( - &self, - outputs: BTreeSet, - ) -> Result + '_, Self::Error> { - Ok(self - .contract_index - .iter() - .flat_map(move |(contract_id, index)| { - outputs.clone().into_iter().filter_map(|outpoint| { - if index.outpoint_opouts.contains_key(&outpoint) { - Some(*contract_id) - } else { - None - } - }) - })) - } - - fn public_opouts( - &self, - contract_id: ContractId, - ) -> Result, IndexReadError> { - let index = self - .contract_index - .get(&contract_id) - .ok_or(IndexInconsistency::ContractAbsent(contract_id))?; - Ok(index.public_opouts.to_unconfined()) - } - - fn opouts_by_outputs( - &self, - contract_id: ContractId, - outputs: impl IntoIterator>, - ) -> Result, IndexReadError> { - let index = self - .contract_index - .get(&contract_id) - .ok_or(IndexInconsistency::ContractAbsent(contract_id))?; - let mut opouts = BTreeSet::new(); - for output in outputs.into_iter().map(|o| o.into()) { - let set = index - .outpoint_opouts - .get(&output) - .ok_or(IndexInconsistency::OutpointUnknown(output, contract_id))?; - opouts.extend(set) - } - Ok(opouts) - } - - fn opouts_by_terminals( - &self, - terminals: impl IntoIterator>, - ) -> Result, Self::Error> { - let terminals = terminals.into_iter().collect::>(); - Ok(self - .terminal_index - .iter() - .filter(|(seal, _)| terminals.contains(*seal)) - .flat_map(|(_, opout)| opout.iter()) - .copied() - .collect()) - } - - fn bundle_id_for_op(&self, opid: OpId) -> Result> { - self.op_bundle_index - .get(&opid) - .copied() - .ok_or(IndexInconsistency::BundleAbsent(opid).into()) - } - - fn bundle_info( - &self, - bundle_id: BundleId, - ) -> Result<(impl Iterator, ContractId), IndexReadError> { - let witness_id = self - .bundle_witness_index - .get(&bundle_id) - .ok_or(IndexInconsistency::BundleWitnessUnknown(bundle_id))?; - let contract_id = self - .bundle_contract_index - .get(&bundle_id) - .ok_or(IndexInconsistency::BundleContractUnknown(bundle_id))?; - Ok((witness_id.iter().cloned(), *contract_id)) - } -} - -impl IndexWriteProvider for MemIndex { - type Error = MemError; - - fn register_contract(&mut self, contract_id: ContractId) -> Result { - if !self.contract_index.contains_key(&contract_id) { - self.contract_index.insert(contract_id, empty!())?; - Ok(true) - } else { - Ok(false) - } - } - - fn register_bundle( - &mut self, - bundle_id: BundleId, - witness_id: XWitnessId, - contract_id: ContractId, - ) -> Result> { - if let Some(alt) = self - .bundle_contract_index - .get(&bundle_id) - .filter(|alt| *alt != &contract_id) - { - return Err(IndexInconsistency::DistinctBundleContract { - bundle_id, - present: *alt, - expected: contract_id, - } - .into()); - } - self.bundle_witness_index - .entry(bundle_id)? - .or_default() - .push(witness_id)?; - let present2 = self - .bundle_contract_index - .insert(bundle_id, contract_id)? - .is_some(); - Ok(!present2) - } - - fn register_operation( - &mut self, - opid: OpId, - bundle_id: BundleId, - ) -> Result> { - if let Some(alt) = self - .op_bundle_index - .get(&opid) - .filter(|alt| *alt != &bundle_id) - { - return Err(IndexInconsistency::DistinctBundleOp { - opid, - present: *alt, - expected: bundle_id, - } - .into()); - } - let present = self.op_bundle_index.insert(opid, bundle_id)?.is_some(); - Ok(!present) - } - - fn index_genesis_assignments( - &mut self, - contract_id: ContractId, - assignments: &[Assign], - opid: OpId, - type_id: AssignmentType, - ) -> Result<(), IndexWriteError> { - let index = self - .contract_index - .get_mut(&contract_id) - .ok_or(IndexInconsistency::ContractAbsent(contract_id))?; - - for (no, assign) in assignments.iter().enumerate() { - let opout = Opout::new(opid, type_id, no as u16); - if let Assign::Revealed { seal, .. } = assign { - let output = seal - .to_output_seal() - .expect("genesis seals always have outpoint"); - index - .outpoint_opouts - .entry(output)? - .or_default() - .push(opout)?; - } - } - - // We need two cycles due to the borrow checker - self.extend_terminals(assignments, opid, type_id) - } - - fn index_transition_assignments( - &mut self, - contract_id: ContractId, - assignments: &[Assign], - opid: OpId, - type_id: AssignmentType, - witness_id: XWitnessId, - ) -> Result<(), IndexWriteError> { - let index = self - .contract_index - .get_mut(&contract_id) - .ok_or(IndexInconsistency::ContractAbsent(contract_id))?; - - for (no, assign) in assignments.iter().enumerate() { - let opout = Opout::new(opid, type_id, no as u16); - if let Assign::Revealed { seal, .. } = assign { - let output = seal.try_to_output_seal(witness_id).unwrap_or_else(|_| { - panic!( - "chain mismatch between assignment vout seal {seal} and witness \ - transaction {witness_id}", - ) - }); - index - .outpoint_opouts - .entry(output)? - .or_default() - .push(opout)?; - } - } - - // We need two cycles due to the borrow checker - self.extend_terminals(assignments, opid, type_id) - } -} - -impl MemIndex { - fn extend_terminals( - &mut self, - vec: &[Assign], - opid: OpId, - type_id: AssignmentType, - ) -> Result<(), IndexWriteError> { - for (no, assign) in vec.iter().enumerate() { - let opout = Opout::new(opid, type_id, no as u16); - if let Assign::Confidential { seal, .. } = assign { - self.add_terminal(*seal, opout)?; - } - } - Ok(()) - } - - fn add_terminal( - &mut self, - seal: XChain, - opout: Opout, - ) -> Result<(), IndexWriteError> { - match self - .terminal_index - .remove(&seal) - .expect("can have zero elements") - { - Some(mut existing_opouts) => { - existing_opouts.push(opout)?; - let _ = self.terminal_index.insert(seal, existing_opouts); - } - None => { - self.terminal_index.insert(seal, tiny_bset![opout])?; - } - } - Ok(()) - } -} diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs deleted file mode 100644 index c92c389a..00000000 --- a/src/persistence/mod.rs +++ /dev/null @@ -1,70 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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. - -//! Module defines API used by providers of persistent data for RGB contracts. -//! -//! These data include: -//! 1. Stash: a consensus-critical data for client-side-validation which must be preserved and -//! backed up. -//! 2. Contract state, updated with each enclosed consignment and disclosure. -//! 3. Index over stash, which simplifies construction of new consignments. -//! -//! Contract state and index data can be re-computed from the stash in case of -//! loss or corruption, while stash can't be recovered unless it was backed up. - -mod stock; -mod stash; -mod state; -mod index; - -mod memory; -#[cfg(feature = "fs")] -pub mod fs; - -pub use index::{ - Index, IndexError, IndexInconsistency, IndexProvider, IndexReadError, IndexReadProvider, - IndexWriteError, IndexWriteProvider, -}; -pub use memory::{ - MemContract, MemContractState, MemError, MemGlobalState, MemIndex, MemStash, MemState, -}; -pub use stash::{ - ProviderError as StashProviderError, SchemaIfaces, Stash, StashDataError, StashError, - StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, -}; -pub use state::{ - ContractStateRead, ContractStateWrite, State, StateError, StateInconsistency, StateProvider, - StateReadProvider, StateWriteProvider, -}; -pub use stock::{ - ComposeError, ConsignError, ContractIfaceError, FasciaError, InputError as StockInputError, - Stock, StockError, StockErrorAll, StockErrorMem, UpdateRes, -}; - -pub trait StoreTransaction { - type TransactionErr: std::error::Error; - - fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr>; - - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr>; - - fn rollback_transaction(&mut self); -} diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs deleted file mode 100644 index a1c522d4..00000000 --- a/src/persistence/stash.rs +++ /dev/null @@ -1,802 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::error::Error; -use std::fmt::Debug; - -use aluvm::library::{Lib, LibId}; -use amplify::confinement::{Confined, MediumBlob, TinyOrdMap}; -use amplify::{confinement, ByteArray}; -use bp::dbc::anchor::MergeError; -use bp::dbc::tapret::TapretCommitment; -use bp::dbc::Anchor; -use bp::seals::txout::CloseMethod; -use commit_verify::mpc; -use commit_verify::mpc::MerkleBlock; -use nonasync::persistence::{CloneNoPersistence, Persisting}; -use rgb::validation::{DbcProof, Scripts}; -use rgb::{ - AttachId, BundleId, ContractId, Extension, Genesis, GraphSeal, Identity, OpId, Operation, - Schema, SchemaId, TransitionBundle, XChain, XWitnessId, -}; -use strict_encoding::{FieldName, TypeName}; -use strict_types::typesys::UnknownType; -use strict_types::TypeSystem; - -use crate::containers::{ - AnchorSet, Consignment, ConsignmentExt, ContentId, ContentRef, ContentSigs, Kit, SealWitness, - SigBlob, Supplement, TrustLevel, WitnessBundle, -}; -use crate::interface::{ - ContractBuilder, Iface, IfaceClass, IfaceId, IfaceImpl, IfaceRef, TransitionBuilder, -}; -use crate::persistence::{ContractIfaceError, StoreTransaction}; -use crate::{MergeReveal, MergeRevealError, SecretSeal, LIB_NAME_RGB_STD}; - -#[derive(Debug, Display, Error, From)] -#[display(inner)] -pub enum StashError { - /// Connectivity errors which may be recoverable and temporary. - ReadProvider(

::Error), - - /// Connectivity errors which may be recoverable and temporary. - WriteProvider(

::Error), - - /// {0} - /// - /// It may happen due to RGB standard library bug, or indicate internal - /// stash inconsistency and compromised stash data storage. - #[display(doc_comments)] - Inconsistency(StashInconsistency), - - /// Errors caused by invalid input arguments. - #[from] - #[from(UnknownType)] - #[from(MergeError)] - #[from(MergeRevealError)] - #[from(mpc::InvalidProof)] - Data(StashDataError), -} - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(inner)] -pub enum ProviderError { - #[from] - Inconsistency(StashInconsistency), - #[from] - Iface(ContractIfaceError), - Connectivity(E), -} - -impl From::Error>> for StashError

{ - fn from(err: ProviderError<

::Error>) -> Self { - match err { - ProviderError::Inconsistency(e) => StashError::Inconsistency(e), - ProviderError::Connectivity(e) => StashError::ReadProvider(e), - ProviderError::Iface(e) => StashError::Data(StashDataError::NoAbstractIface(e)), - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum StashInconsistency { - /// library {0} is unknown; perhaps you need to import it first. - LibAbsent(LibId), - - /// interface {0} is unknown; perhaps you need to import it first. - IfaceAbsent(IfaceRef), - - /// contract {0} is unknown. Probably you haven't imported the contract yet. - ContractAbsent(ContractId), - - /// schema {0} is unknown. - SchemaAbsent(SchemaId), - - /// interface {0::<0} is not implemented for the schema {1::<0}. - IfaceImplAbsent(IfaceId, SchemaId), - - /// transition {0} is absent. - OperationAbsent(OpId), - - /// information about witness {0} is absent. - WitnessAbsent(XWitnessId), - - /// witness {0} for the bundle {1} misses contract {2} information in {3} anchor. - WitnessMissesContract(XWitnessId, BundleId, ContractId, CloseMethod), - - /// bundle {0} is absent. - BundleAbsent(BundleId), - - /// none of known anchors contain information on bundle {0} under contract - /// {1}. - BundleMissedInAnchors(BundleId, ContractId), -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum StashDataError { - /// schema {0} and related interfaces use too many AluVM libraries. - TooManyLibs(SchemaId), - - #[from] - #[display(inner)] - UnknownType(UnknownType), - - #[from] - #[display(inner)] - Anchor(mpc::InvalidProof), - - #[from] - #[display(inner)] - Merge(MergeError), - - #[from] - #[display(inner)] - MergeReveal(MergeRevealError), - - /// schema {0} doesn't implement interface {1}. - NoIfaceImpl(SchemaId, IfaceId), - - #[from] - #[display(inner)] - NoAbstractIface(ContractIfaceError), -} - -#[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 SchemaIfaces { - pub schema: Schema, - pub iimpls: TinyOrdMap, -} - -impl SchemaIfaces { - pub fn new(schema: Schema) -> Self { - SchemaIfaces { - schema, - iimpls: none!(), - } - } - - pub fn get(&self, id: IfaceId) -> Option<&IfaceImpl> { - self.iimpls.values().find(|iimpl| iimpl.iface_id == id) - } - - pub fn contains(&self, id: IfaceId) -> bool { - self.iimpls.values().any(|iimpl| iimpl.iface_id == id) - } -} - -#[derive(Debug)] -pub struct Stash { - provider: P, -} - -impl CloneNoPersistence for Stash

{ - fn clone_no_persistence(&self) -> Self { - Self { - provider: self.provider.clone_no_persistence(), - } - } -} - -impl Default for Stash

-where P: Default -{ - fn default() -> Self { - Self { - provider: default!(), - } - } -} - -impl Stash

{ - pub(super) fn new(provider: P) -> Self { Self { provider } } - - #[doc(hidden)] - pub fn as_provider(&self) -> &P { &self.provider } - - #[doc(hidden)] - pub(super) fn as_provider_mut(&mut self) -> &mut P { &mut self.provider } - - pub(super) fn ifaces(&self) -> Result + '_, StashError

> { - self.provider.ifaces().map_err(StashError::ReadProvider) - } - pub(super) fn iface(&self, iface: impl Into) -> Result<&Iface, StashError

> { - Ok(self.provider.iface(iface)?) - } - pub(super) fn schemata( - &self, - ) -> Result + '_, StashError

> { - self.provider.schemata().map_err(StashError::ReadProvider) - } - pub(super) fn schema(&self, schema_id: SchemaId) -> Result<&SchemaIfaces, StashError

> { - Ok(self.provider.schema(schema_id)?) - } - pub(super) fn impl_for<'a, C: IfaceClass + 'a>( - &'a self, - schema_ifaces: &'a SchemaIfaces, - ) -> Result<&'a IfaceImpl, StashError

> { - Ok(self.provider.impl_for::(schema_ifaces)?) - } - - pub(super) fn geneses(&self) -> Result + '_, StashError

> { - self.provider.geneses().map_err(StashError::ReadProvider) - } - pub(super) fn geneses_by<'a, C: IfaceClass + 'a>( - &'a self, - ) -> Result + 'a, StashError

> { - self.provider - .geneses_by::() - .map_err(StashError::ReadProvider) - } - pub(super) fn genesis(&self, contract_id: ContractId) -> Result<&Genesis, StashError

> { - Ok(self.provider.genesis(contract_id)?) - } - pub(super) fn bundle(&self, bundle_id: BundleId) -> Result<&TransitionBundle, StashError

> { - Ok(self.provider.bundle(bundle_id)?) - } - pub(super) fn witness(&self, witness_id: XWitnessId) -> Result<&SealWitness, StashError

> { - Ok(self.provider.witness(witness_id)?) - } - - pub(super) fn supplements( - &self, - content_ref: ContentRef, - ) -> Result + '_, StashError

> { - self.provider - .supplements(content_ref) - .map_err(StashError::ReadProvider) - } - - pub(super) fn sigs_for( - &self, - content_id: &ContentId, - ) -> Result, StashError

> { - self.provider - .sigs_for(content_id) - .map_err(StashError::ReadProvider) - } - - pub(super) fn supplement( - &self, - content_ref: ContentRef, - ) -> Result, StashError

> { - self.provider - .supplement(content_ref) - .map_err(StashError::ReadProvider) - } - - pub(super) fn scripts<'a>( - &self, - lib_ids: impl IntoIterator, - ) -> Result> { - let mut scripts = BTreeMap::new(); - for id in lib_ids { - let lib = self.provider.lib(id)?; - scripts.insert(id, lib.clone()); - } - Ok(Scripts::from_checked(scripts)) - } - - pub(super) fn type_system(&self, iface: &Iface) -> Result> { - Ok(self - .provider - .type_system() - .map_err(StashError::ReadProvider)? - .extract(iface.types())?) - } - - pub(super) fn types_scripts<'a>( - &self, - schema: &Schema, - ifaces: impl IntoIterator, - ) -> Result<(TypeSystem, Scripts), StashError

> { - let type_iter = schema - .types() - .into_iter() - .chain(ifaces.into_iter().flat_map(Iface::types)); - let types = self - .provider - .type_system() - .map_err(StashError::ReadProvider)? - .extract(type_iter)?; - - let mut scripts = BTreeMap::new(); - for id in schema.libs() { - let lib = self.provider.lib(id)?; - scripts.insert(id, lib.clone()); - } - // TODO: Make sure we have all the libs including their dependencies - let scripts = Scripts::try_from(scripts) - .map_err(|_| StashDataError::TooManyLibs(schema.schema_id()))?; - - Ok((types, scripts)) - } - - pub(super) fn contract_builder( - &self, - issuer: Identity, - schema_id: SchemaId, - iface: impl Into, - ) -> Result> { - let schema_ifaces = self.schema(schema_id)?; - let iface = self.iface(iface)?; - let iface_id = iface.iface_id(); - let iimpl = schema_ifaces - .get(iface_id) - .ok_or(StashDataError::NoIfaceImpl(schema_id, iface_id))?; - - let (types, scripts) = self.types_scripts(&schema_ifaces.schema, [iface])?; - - let builder = ContractBuilder::with( - issuer, - iface.clone(), - schema_ifaces.schema.clone(), - iimpl.clone(), - types, - scripts, - ); - Ok(builder) - } - - pub(super) fn transition_builder( - &self, - contract_id: ContractId, - iface: impl Into, - transition_name: Option>, - ) -> Result> { - let schema_ifaces = self.provider.contract_schema(contract_id)?; - let iface = self.iface(iface)?; - let schema = &schema_ifaces.schema; - let iimpl = schema_ifaces - .get(iface.iface_id()) - .ok_or(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()))?; - - let types = self.type_system(iface)?; - let scripts = self.scripts(iimpl.state_abi.lib_ids())?; - - let builder = if let Some(transition_name) = transition_name { - TransitionBuilder::named_transition( - contract_id, - iface.clone(), - schema.clone(), - iimpl.clone(), - transition_name.into(), - types, - scripts, - ) - } else { - TransitionBuilder::default_transition( - contract_id, - iface.clone(), - schema.clone(), - iimpl.clone(), - types, - scripts, - ) - } - .expect("internal inconsistency"); - - Ok(builder) - } - - pub(super) fn blank_builder( - &self, - contract_id: ContractId, - iface: impl Into, - ) -> Result> { - let schema_ifaces = self.provider.contract_schema(contract_id)?; - let iface = self.iface(iface)?; - let schema = &schema_ifaces.schema; - if schema_ifaces.iimpls.is_empty() { - return Err(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()).into()); - } - let types = self.type_system(iface)?; - - let builder = if let Some(iimpl) = schema_ifaces.get(iface.iface_id()) { - TransitionBuilder::blank_transition( - contract_id, - iface.clone(), - schema.clone(), - iimpl.clone(), - types, - ) - } else { - let (default_iface_name, default_iimpl) = - schema_ifaces.iimpls.first_key_value().unwrap(); - let default_iface = self.iface(default_iface_name.clone())?; - - TransitionBuilder::blank_transition( - contract_id, - default_iface.clone(), - schema.clone(), - default_iimpl.clone(), - types, - ) - }; - - Ok(builder) - } - - pub(super) fn consume_kit(&mut self, kit: Kit) -> Result<(), StashError

> { - self.provider - .consume_types(kit.types) - .map_err(StashError::WriteProvider)?; - for lib in kit.scripts { - self.provider - .replace_lib(lib) - .map_err(StashError::WriteProvider)?; - } - - // TODO: filter most trusted signers - for schema in kit.schemata { - self.provider - .replace_schema(schema) - .map_err(StashError::WriteProvider)?; - } - for iface in kit.ifaces { - self.provider - .replace_iface(iface) - .map_err(StashError::WriteProvider)?; - } - for iimpl in kit.iimpls { - self.provider - .replace_iimpl(iimpl) - .map_err(StashError::WriteProvider)?; - } - - // TODO: filter out non-trusted signers - for suppl in kit.supplements { - self.provider - .add_supplement(suppl) - .map_err(StashError::WriteProvider)?; - } - - for (content_id, sigs) in kit.signatures { - // TODO: Filter sigs by trust level - // Do not bother if we can't import all the sigs - self.provider.import_sigs(content_id, sigs).ok(); - } - - Ok(()) - } - - pub(super) fn resolve_secrets( - &self, - mut consignment: Consignment, - ) -> Result, StashError

> { - consignment = consignment.reveal_terminal_seals(|secret| { - self.provider - .seal_secret(secret) - .map_err(StashError::ReadProvider) - })?; - Ok(consignment) - } - - pub(super) fn consume_consignment( - &mut self, - consignment: Consignment, - ) -> Result<(), StashError

> { - let contract_id = consignment.contract_id(); - - let genesis = match self.genesis(contract_id) { - Ok(g) => g.clone().merge_reveal(consignment.genesis)?, - Err(_) => consignment.genesis, - }; - self.provider - .replace_genesis(genesis) - .map_err(StashError::WriteProvider)?; - - for extension in consignment.extensions { - let opid = extension.id(); - let extension = match self.provider.extension(opid) { - Ok(e) => e.clone().merge_reveal(extension)?, - Err(_) => extension, - }; - self.provider - .replace_extension(extension) - .map_err(StashError::WriteProvider)?; - } - - for witness_bundles in consignment.bundles { - self.consume_witness_bundle(contract_id, witness_bundles)?; - } - - for (id, attach) in consignment.attachments { - self.provider - .replace_attachment(id, attach) - .map_err(StashError::WriteProvider)?; - } - - let (ifaces, iimpls): (BTreeSet<_>, BTreeSet<_>) = consignment - .ifaces - .release() - .into_iter() - .fold((bset!(), bset!()), |(mut keys, mut values), (k, v)| { - keys.insert(k); - values.insert(v); - (keys, values) - }); - - self.consume_kit(Kit { - version: consignment.version, - ifaces: Confined::from_checked(ifaces), - schemata: tiny_bset![consignment.schema], - iimpls: Confined::from_checked(iimpls), - supplements: consignment.supplements, - types: consignment.types, - scripts: Confined::from_checked(consignment.scripts.release()), - signatures: consignment.signatures, - }) - } - - fn consume_witness_bundle( - &mut self, - contract_id: ContractId, - witness_bundle: WitnessBundle, - ) -> Result<(), StashError

> { - let WitnessBundle { - pub_witness, - anchored_bundles, - } = witness_bundle; - - // TODO: Save pub witness transaction SPVs - - let mut anchors = Vec::with_capacity(2); - for (anchor, bundle) in anchored_bundles.into_iter() { - let bundle_id = bundle.bundle_id(); - self.consume_bundle(bundle)?; - - let proto = mpc::ProtocolId::from_byte_array(contract_id.to_byte_array()); - let msg = mpc::Message::from_byte_array(bundle_id.to_byte_array()); - let merkle_block = MerkleBlock::with(&anchor.mpc_proof, proto, msg)?; - anchors.push(Anchor::new(merkle_block, anchor.dbc_proof)); - } - - let anchors = match (anchors.pop().unwrap(), anchors.pop()) { - ( - Anchor { - dbc_proof: DbcProof::Opret(opret), - mpc_proof, - .. - }, - None, - ) => AnchorSet::Opret(Anchor::new(mpc_proof, opret)), - ( - Anchor { - dbc_proof: DbcProof::Tapret(tapret), - mpc_proof, - .. - }, - None, - ) => AnchorSet::Tapret(Anchor::new(mpc_proof, tapret)), - ( - Anchor { - dbc_proof: DbcProof::Tapret(tapret), - mpc_proof: mpc_proof_tapret, - .. - }, - Some(Anchor { - dbc_proof: DbcProof::Opret(opret), - mpc_proof: mpc_proof_opret, - .. - }), - ) - | ( - Anchor { - dbc_proof: DbcProof::Opret(opret), - mpc_proof: mpc_proof_opret, - .. - }, - Some(Anchor { - dbc_proof: DbcProof::Tapret(tapret), - mpc_proof: mpc_proof_tapret, - .. - }), - ) => AnchorSet::Double { - tapret: Anchor::new(mpc_proof_tapret, tapret), - opret: Anchor::new(mpc_proof_opret, opret), - }, - ( - Anchor { - dbc_proof: DbcProof::Opret(_), - .. - }, - Some(Anchor { - dbc_proof: DbcProof::Opret(_), - .. - }), - ) - | ( - Anchor { - dbc_proof: DbcProof::Tapret(_), - .. - }, - Some(Anchor { - dbc_proof: DbcProof::Tapret(_), - .. - }), - ) => unreachable!( - "these combinations must be prevented at the `AnchoredBundles` structure level" - ), - }; - let witness = SealWitness { - public: pub_witness.clone(), - anchors, - }; - self.consume_witness(witness)?; - - Ok(()) - } - - pub(crate) fn consume_witness(&mut self, witness: SealWitness) -> Result> { - let witness = match self.provider.witness(witness.witness_id()).cloned() { - Ok(mut w) => { - w.public = w.public.clone().merge_reveal(witness.public)?; - w.anchors = w.anchors.clone().merge_reveal(witness.anchors)?; - w - } - Err(_) => witness, - }; - - self.provider - .replace_witness(witness) - .map_err(StashError::WriteProvider) - } - - pub(crate) fn consume_bundle( - &mut self, - bundle: TransitionBundle, - ) -> Result> { - let bundle = match self.provider.bundle(bundle.bundle_id()).cloned() { - Ok(b) => b.merge_reveal(bundle)?, - Err(_) => bundle, - }; - self.provider - .replace_bundle(bundle) - .map_err(StashError::WriteProvider) - } - - pub(crate) fn store_secret_seal( - &mut self, - seal: XChain, - ) -> Result> { - self.begin_transaction()?; - let seal = self - .provider - .add_secret_seal(seal) - .inspect_err(|_| self.rollback_transaction()) - .map_err(StashError::WriteProvider)?; - self.commit_transaction()?; - Ok(seal) - } -} - -impl StoreTransaction for Stash

{ - type TransactionErr = StashError

; - - fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.provider - .begin_transaction() - .map_err(StashError::WriteProvider) - } - - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.provider - .commit_transaction() - .map_err(StashError::WriteProvider) - } - - fn rollback_transaction(&mut self) { self.provider.rollback_transaction() } -} - -pub trait StashProvider: - Debug + CloneNoPersistence + Persisting + StashReadProvider + StashWriteProvider -{ -} - -pub trait StashReadProvider { - /// Error type which must indicate problems on data retrieval. - type Error: Clone + Eq + Error; - - fn type_system(&self) -> Result<&TypeSystem, Self::Error>; - fn lib(&self, id: LibId) -> Result<&Lib, ProviderError>; - - fn ifaces(&self) -> Result, Self::Error>; - fn iface(&self, iface: impl Into) -> Result<&Iface, ProviderError>; - fn schemata(&self) -> Result, Self::Error>; - fn schema(&self, schema_id: SchemaId) -> Result<&SchemaIfaces, ProviderError>; - fn schemata_by( - &self, - ) -> Result, Self::Error>; - fn impl_for<'a, C: IfaceClass + 'a>( - &'a self, - schema_ifaces: &'a SchemaIfaces, - ) -> Result<&'a IfaceImpl, ProviderError>; - fn geneses(&self) -> Result, Self::Error>; - fn geneses_by(&self) -> Result, Self::Error>; - fn genesis(&self, contract_id: ContractId) -> Result<&Genesis, ProviderError>; - - fn contract_schema( - &self, - contract_id: ContractId, - ) -> Result<&SchemaIfaces, ProviderError> { - let genesis = self.genesis(contract_id)?; - self.schema(genesis.schema_id) - } - - fn get_trust(&self, identity: &Identity) -> Result; - fn supplement(&self, content_ref: ContentRef) -> Result, Self::Error>; - fn supplements( - &self, - content_ref: ContentRef, - ) -> Result, Self::Error>; - - fn sigs_for(&self, content_id: &ContentId) -> Result, Self::Error>; - fn witness_ids(&self) -> Result, Self::Error>; - fn bundle_ids(&self) -> Result, Self::Error>; - fn bundle(&self, bundle_id: BundleId) -> Result<&TransitionBundle, ProviderError>; - fn extension_ids(&self) -> Result, Self::Error>; - fn extension(&self, op_id: OpId) -> Result<&Extension, ProviderError>; - fn witness(&self, witness_id: XWitnessId) -> Result<&SealWitness, ProviderError>; - - fn taprets(&self) -> Result, Self::Error>; - fn seal_secret( - &self, - secret: XChain, - ) -> Result>, Self::Error>; - fn secret_seals(&self) -> Result>, Self::Error>; -} - -pub trait StashWriteProvider: StoreTransaction { - type Error: Error; - - fn replace_schema(&mut self, schema: Schema) -> Result; - fn replace_iface(&mut self, iface: Iface) -> Result; - fn replace_iimpl(&mut self, iimpl: IfaceImpl) -> Result; - fn replace_genesis(&mut self, genesis: Genesis) -> Result; - fn replace_extension(&mut self, extension: Extension) -> Result; - fn replace_bundle(&mut self, bundle: TransitionBundle) -> Result; - fn replace_witness(&mut self, witness: SealWitness) -> Result; - fn replace_attachment(&mut self, id: AttachId, attach: MediumBlob) - -> Result; - - fn replace_lib(&mut self, lib: Lib) -> Result; - fn consume_types(&mut self, types: TypeSystem) -> Result<(), Self::Error>; - fn set_trust( - &mut self, - identity: Identity, - trust: TrustLevel, - ) -> Result<(), confinement::Error>; - fn add_supplement(&mut self, suppl: Supplement) -> Result<(), Self::Error>; - fn import_sigs(&mut self, content_id: ContentId, sigs: I) -> Result<(), Self::Error> - where I: IntoIterator; - - fn add_secret_seal(&mut self, seal: XChain) -> Result; -} diff --git a/src/persistence/state.rs b/src/persistence/state.rs deleted file mode 100644 index 216e63df..00000000 --- a/src/persistence/state.rs +++ /dev/null @@ -1,310 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::borrow::Borrow; -use std::collections::BTreeMap; -use std::error::Error; -use std::fmt::Debug; -use std::iter; - -use nonasync::persistence::{CloneNoPersistence, Persisting}; -use rgb::validation::{ResolveWitness, WitnessResolverError}; -use rgb::vm::{ContractStateAccess, WitnessOrd}; -use rgb::{ - ContractId, Extension, Genesis, Operation, Schema, SchemaId, Transition, TransitionBundle, - XWitnessId, -}; - -use crate::containers::{ConsignmentExt, ToWitnessId}; -use crate::contract::Allocation; -use crate::persistence::{StoreTransaction, UpdateRes}; - -#[derive(Debug, Display, Error, From)] -#[display(inner)] -pub enum StateError { - /// Connectivity errors which may be recoverable and temporary. - ReadProvider(

::Error), - - /// Connectivity errors which may be recoverable and temporary. - WriteProvider(

::Error), - - /// witness {0} can't be resolved: {1} - #[display(doc_comments)] - Resolver(XWitnessId, WitnessResolverError), - - /// valid (non-archived) witness is absent in the list of witnesses for a - /// state transition bundle. - AbsentValidWitness, - - /// {0} - /// - /// It may happen due to RGB standard library bug, or indicate internal - /// stash inconsistency and compromised stash data storage. - #[from] - #[display(doc_comments)] - Inconsistency(StateInconsistency), -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum StateInconsistency { - /// contract state {0} is not known. - UnknownContract(ContractId), - /// a witness {0} is absent from the state data. - AbsentWitness(XWitnessId), -} - -#[derive(Debug)] -pub struct State { - provider: P, -} - -impl CloneNoPersistence for State

{ - fn clone_no_persistence(&self) -> Self { - Self { - provider: self.provider.clone_no_persistence(), - } - } -} - -impl Default for State

-where P: Default -{ - fn default() -> Self { - Self { - provider: default!(), - } - } -} - -impl State

{ - pub(super) fn new(provider: P) -> Self { Self { provider } } - - #[doc(hidden)] - pub fn as_provider(&self) -> &P { &self.provider } - - #[doc(hidden)] - pub(super) fn as_provider_mut(&mut self) -> &mut P { &mut self.provider } - - #[inline] - pub fn contract_state( - &self, - contract_id: ContractId, - ) -> Result, StateError

> { - self.provider - .contract_state(contract_id) - .map_err(StateError::ReadProvider) - } - - pub fn select_valid_witness( - &self, - witness_ids: impl IntoIterator>, - ) -> Result> { - for witness_id in witness_ids { - let witness_id = *witness_id.borrow(); - if self - .provider - .is_valid_witness(witness_id) - .map_err(StateError::ReadProvider)? - { - return Ok(witness_id); - } - } - Err(StateError::AbsentValidWitness) - } - - pub fn update_from_bundle( - &mut self, - contract_id: ContractId, - bundle: &TransitionBundle, - witness_id: XWitnessId, - resolver: R, - ) -> Result<(), StateError

> { - let mut updater = self - .as_provider_mut() - .update_contract(contract_id) - .map_err(StateError::WriteProvider)? - .ok_or(StateInconsistency::UnknownContract(contract_id))?; - for transition in bundle.known_transitions.values() { - let ord = resolver - .resolve_pub_witness_ord(witness_id) - .map_err(|e| StateError::Resolver(witness_id, e))?; - updater - .add_transition(transition, witness_id, ord) - .map_err(StateError::WriteProvider)?; - } - Ok(()) - } - - pub fn update_from_consignment( - &mut self, - consignment: impl ConsignmentExt, - resolver: R, - ) -> Result<(), StateError

> { - let mut state = self - .as_provider_mut() - .register_contract(consignment.schema(), consignment.genesis()) - .map_err(StateError::WriteProvider)?; - let mut extension_idx = consignment - .extensions() - .map(Extension::id) - .zip(iter::repeat(false)) - .collect::>(); - let mut ordered_extensions = BTreeMap::new(); - for witness_bundle in consignment.bundled_witnesses() { - for transition in witness_bundle.known_transitions() { - let witness_id = witness_bundle.pub_witness.to_witness_id(); - let witness_ord = resolver - .resolve_pub_witness_ord(witness_id) - .map_err(|e| StateError::Resolver(witness_id, e))?; - - state - .add_transition(transition, witness_id, witness_ord) - .map_err(StateError::WriteProvider)?; - for (id, used) in &mut extension_idx { - if *used { - continue; - } - for input in &transition.inputs { - if input.prev_out.op == *id { - *used = true; - if let Some((_, witness_ord2)) = ordered_extensions.get_mut(id) { - if *witness_ord2 < witness_ord { - *witness_ord2 = witness_ord; - } - } else { - ordered_extensions.insert(*id, (witness_id, witness_ord)); - } - } - } - } - } - } - for extension in consignment.extensions() { - if let Some((witness_id, witness_ord)) = ordered_extensions.get(&extension.id()) { - state - .add_extension(extension, *witness_id, *witness_ord) - .map_err(StateError::WriteProvider)?; - } - // Otherwise consignment includes state extensions which are not - // used in transaction graph. This must not be the case for the - // validated consignments. - } - - Ok(()) - } - - pub fn update_witnesses( - &mut self, - resolver: impl ResolveWitness, - after_height: u32, - ) -> Result> { - self.provider - .update_witnesses(resolver, after_height) - .map_err(StateError::WriteProvider) - } -} - -impl StoreTransaction for State

{ - type TransactionErr = StateError

; - - fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.provider - .begin_transaction() - .map_err(StateError::WriteProvider) - } - - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.provider - .commit_transaction() - .map_err(StateError::WriteProvider) - } - - fn rollback_transaction(&mut self) { self.provider.rollback_transaction() } -} - -pub trait StateProvider: - Debug + CloneNoPersistence + Persisting + StateReadProvider + StateWriteProvider -{ -} - -pub trait StateReadProvider { - type ContractRead<'a>: ContractStateRead - where Self: 'a; - type Error: Clone + Eq + Error; - - fn contract_state( - &self, - contract_id: ContractId, - ) -> Result, Self::Error>; - - fn is_valid_witness(&self, witness_id: XWitnessId) -> Result; -} - -pub trait StateWriteProvider: StoreTransaction { - type ContractWrite<'a>: ContractStateWrite - where Self: 'a; - type Error: Error; - - fn register_contract( - &mut self, - schema: &Schema, - genesis: &Genesis, - ) -> Result, Self::Error>; - - fn update_contract( - &mut self, - contract_id: ContractId, - ) -> Result>, Self::Error>; - - fn update_witnesses( - &mut self, - resolver: impl ResolveWitness, - after_height: u32, - ) -> Result; -} - -pub trait ContractStateRead: ContractStateAccess { - fn contract_id(&self) -> ContractId; - fn schema_id(&self) -> SchemaId; - fn witness_ord(&self, witness_id: XWitnessId) -> Option; - fn assignments(&self) -> impl Iterator; -} - -pub trait ContractStateWrite { - type Error: Error; - - fn add_genesis(&mut self, genesis: &Genesis) -> Result<(), Self::Error>; - - fn add_transition( - &mut self, - transition: &Transition, - witness_id: XWitnessId, - witness_ord: WitnessOrd, - ) -> Result<(), Self::Error>; - - fn add_extension( - &mut self, - extension: &Extension, - witness_id: XWitnessId, - witness_ord: WitnessOrd, - ) -> Result<(), Self::Error>; -} diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs deleted file mode 100644 index 2793c156..00000000 --- a/src/persistence/stock.rs +++ /dev/null @@ -1,1405 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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::btree_map::Entry; -use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; -use std::convert::Infallible; -use std::error::Error; -use std::fmt::Debug; - -use amplify::confinement::{Confined, U24}; -use amplify::Wrapper; -use bp::dbc::Method; -use bp::seals::txout::CloseMethod; -use bp::Vout; -use chrono::Utc; -use invoice::{Beneficiary, RgbInvoice}; -use nonasync::persistence::{CloneNoPersistence, PersistenceError, PersistenceProvider}; -use rgb::validation::{DbcProof, ResolveWitness, WitnessResolverError}; -use rgb::{ - validation, AssignmentType, BundleId, ContractId, GraphSeal, Identity, OpId, Operation, Opout, - SchemaId, SecretSeal, Transition, TxoSeal, XChain, XOutpoint, XOutputSeal, XWitnessId, -}; -use strict_encoding::FieldName; -use strict_types::TypeSystem; - -use super::{ - ContractStateRead, Index, IndexError, IndexInconsistency, IndexProvider, IndexReadProvider, - IndexWriteProvider, MemIndex, MemStash, MemState, SchemaIfaces, Stash, StashDataError, - StashError, StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, State, - StateError, StateInconsistency, StateProvider, StateReadProvider, StateWriteProvider, - StoreTransaction, -}; -use crate::containers::{ - AnchorSet, AnchoredBundleMismatch, Batch, BuilderSeal, ClientBundle, Consignment, ContainerVer, - ContentId, ContentRef, Contract, Fascia, Kit, SealWitness, SupplItem, SupplSub, Transfer, - TransitionDichotomy, TransitionInfo, TransitionInfoError, UnrelatedTransition, - ValidConsignment, ValidContract, ValidKit, ValidTransfer, VelocityHint, WitnessBundle, - SUPPL_ANNOT_VELOCITY, -}; -use crate::info::{ContractInfo, IfaceInfo, SchemaInfo}; -use crate::interface::{ - BuilderError, ContractBuilder, ContractIface, Iface, IfaceClass, IfaceId, IfaceRef, - IfaceWrapper, TransitionBuilder, -}; -use crate::MergeRevealError; - -pub type ContractAssignments = HashMap>; - -#[derive(Debug, Display, Error, From)] -#[display(inner)] -pub enum StockError< - S: StashProvider = MemStash, - H: StateProvider = MemState, - P: IndexProvider = MemIndex, - E: Error = Infallible, -> { - InvalidInput(E), - Resolver(String), - StashRead(::Error), - StashWrite(::Error), - IndexRead(

::Error), - IndexWrite(

::Error), - StateRead(::Error), - StateWrite(::Error), - - #[from] - #[display(doc_comments)] - /// {0} - /// - /// It may happen due to RGB standard library bug, or indicate internal - /// stash inconsistency and compromised stash data storage. - StashInconsistency(StashInconsistency), - - #[from] - #[display(doc_comments)] - /// state for contract {0} is not known. - /// - /// It may happen due to RGB standard library bug, or indicate internal - /// stash inconsistency and compromised stash data storage. - StateInconsistency(StateInconsistency), - - #[from] - #[display(doc_comments)] - /// {0} - /// - /// It may happen due to RGB standard library bug, or indicate internal - /// stash inconsistency and compromised stash data storage. - IndexInconsistency(IndexInconsistency), - - #[from] - StashData(StashDataError), - - /// valid (non-archived) witness is absent in the list of witnesses for a - /// state transition bundle. - AbsentValidWitness, - - /// witness {0} can't be resolved: {1} - WitnessUnresolved(XWitnessId, WitnessResolverError), -} - -impl From> - for StockError -{ - fn from(err: StashError) -> Self { - match err { - StashError::ReadProvider(err) => Self::StashRead(err), - StashError::WriteProvider(err) => Self::StashWrite(err), - StashError::Data(e) => Self::StashData(e), - StashError::Inconsistency(e) => Self::StashInconsistency(e), - } - } -} - -impl From> - for StockError -{ - fn from(err: StateError) -> Self { - match err { - StateError::ReadProvider(err) => Self::StateRead(err), - StateError::WriteProvider(err) => Self::StateWrite(err), - StateError::Inconsistency(e) => Self::StateInconsistency(e), - StateError::Resolver(id, e) => Self::WitnessUnresolved(id, e), - StateError::AbsentValidWitness => Self::AbsentValidWitness, - } - } -} -impl From> - for StockError -{ - fn from(err: IndexError

) -> Self { - match err { - IndexError::ReadProvider(err) => Self::IndexRead(err), - IndexError::WriteProvider(err) => Self::IndexWrite(err), - IndexError::Inconsistency(e) => Self::IndexInconsistency(e), - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum ConsignError { - /// unable to construct consignment: too many signatures provided. - TooManySignatures, - /// unable to construct consignment: too many supplements provided. - TooManySupplements, - - /// unable to construct consignment: too many terminals provided. - TooManyTerminals, - - /// unable to construct consignment: history size too large, resulting in - /// too many transitions. - TooManyBundles, - - #[from] - #[display(inner)] - MergeReveal(MergeRevealError), - - #[from] - #[display(inner)] - Transition(UnrelatedTransition), - - #[from] - #[display(inner)] - AnchoredBundle(AnchoredBundleMismatch), - - /// the spent state from transition {1} inside bundle {0} is concealed. - Concealed(BundleId, OpId), -} - -impl From - for StockError -{ - fn from(err: ConsignError) -> Self { Self::InvalidInput(err) } -} - -impl From - for StockError -{ - fn from(err: MergeRevealError) -> Self { Self::InvalidInput(err.into()) } -} - -impl From - for StockError -{ - fn from(err: UnrelatedTransition) -> Self { Self::InvalidInput(err.into()) } -} - -impl From - for StockError -{ - fn from(err: AnchoredBundleMismatch) -> Self { Self::InvalidInput(err.into()) } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum ComposeError { - /// no outputs available to store state of type {1} with velocity class - /// '{0}'. - NoBlankOrChange(VelocityHint, AssignmentType), - - /// the provided PSBT doesn't pay any sats to the RGB beneficiary address. - NoBeneficiaryOutput, - - /// beneficiary output number is given when secret seal is used. - BeneficiaryVout, - - /// expired invoice. - InvoiceExpired, - - /// the invoice contains no contract information. - NoContract, - - /// the invoice contains no interface information. - NoIface, - - /// the invoice lacks specific state information. - NoInvoiceState, - - /// the invoice requirements can't be fulfilled using available assets or - /// smart contract state. - InsufficientState, - - /// the spent UTXOs contain too many seals which can't fit the state - /// transition input limit. - TooManyInputs, - - #[from] - #[display(inner)] - Transition(TransitionInfoError), - - /// the operation produces too many blank state transitions which can't fit - /// the container requirements. - TooManyBlanks, - - #[from] - #[display(inner)] - Builder(BuilderError), -} - -impl From - for StockError -{ - fn from(err: ComposeError) -> Self { Self::InvalidInput(err) } -} - -impl From - for StockError -{ - fn from(err: BuilderError) -> Self { Self::InvalidInput(err.into()) } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum FasciaError { - /// bundle {1} for contract {0} contains invalid transition input map. - InvalidBundle(ContractId, BundleId), -} - -impl From - for StockError -{ - fn from(err: FasciaError) -> Self { Self::InvalidInput(err) } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum ContractIfaceError { - /// no known implementations of {0::<0} parent interfaces for - /// the schema {1::<0}. - NoAbstractImpl(IfaceId, SchemaId), -} - -impl From - for StockError -{ - fn from(err: ContractIfaceError) -> Self { Self::InvalidInput(err) } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(inner)] -pub enum InputError { - #[from] - Compose(ComposeError), - #[from] - Consign(ConsignError), - #[from] - Fascia(FasciaError), - #[from] - ContractIface(ContractIfaceError), -} - -macro_rules! stock_err_conv { - ($err1:ty, $err2:ty) => { - impl From> - for StockError - { - fn from(err: StockError) -> Self { - match err { - StockError::InvalidInput(e) => StockError::InvalidInput(e.into()), - StockError::Resolver(e) => StockError::Resolver(e), - StockError::StashRead(e) => StockError::StashRead(e), - StockError::StashWrite(e) => StockError::StashWrite(e), - StockError::IndexRead(e) => StockError::IndexRead(e), - StockError::IndexWrite(e) => StockError::IndexWrite(e), - StockError::StateRead(e) => StockError::StateRead(e), - StockError::StateWrite(e) => StockError::StateWrite(e), - StockError::AbsentValidWitness => StockError::AbsentValidWitness, - StockError::StashData(e) => StockError::StashData(e), - StockError::StashInconsistency(e) => StockError::StashInconsistency(e), - StockError::StateInconsistency(e) => StockError::StateInconsistency(e), - StockError::IndexInconsistency(e) => StockError::IndexInconsistency(e), - StockError::WitnessUnresolved(id, e) => StockError::WitnessUnresolved(id, e), - } - } - } - }; -} - -impl From for InputError { - fn from(_: Infallible) -> Self { unreachable!() } -} -impl From for ComposeError { - fn from(_: Infallible) -> Self { unreachable!() } -} -impl From for ConsignError { - fn from(_: Infallible) -> Self { unreachable!() } -} -impl From for FasciaError { - fn from(_: Infallible) -> Self { unreachable!() } -} -impl From for ContractIfaceError { - fn from(_: Infallible) -> Self { unreachable!() } -} - -stock_err_conv!(Infallible, ComposeError); -stock_err_conv!(Infallible, ConsignError); -stock_err_conv!(Infallible, FasciaError); -stock_err_conv!(Infallible, ContractIfaceError); -stock_err_conv!(Infallible, InputError); -stock_err_conv!(ComposeError, InputError); -stock_err_conv!(ConsignError, InputError); -stock_err_conv!(FasciaError, InputError); -stock_err_conv!(ContractIfaceError, InputError); - -pub type StockErrorMem = StockError; -pub type StockErrorAll = StockError; - -#[derive(Debug)] -pub struct Stock< - S: StashProvider = MemStash, - H: StateProvider = MemState, - P: IndexProvider = MemIndex, -> { - stash: Stash, - state: State, - index: Index

, -} - -impl CloneNoPersistence for Stock { - fn clone_no_persistence(&self) -> Self { - Self { - stash: self.stash.clone_no_persistence(), - state: self.state.clone_no_persistence(), - index: self.index.clone_no_persistence(), - } - } -} - -impl Default for Stock -where - S: Default, - H: Default, - P: Default, -{ - fn default() -> Self { - Self { - stash: default!(), - state: default!(), - index: default!(), - } - } -} - -impl Stock { - #[inline] - pub fn in_memory() -> Self { - Self::with(MemStash::in_memory(), MemState::in_memory(), MemIndex::in_memory()) - } -} - -impl Stock { - pub fn load

(provider: P, autosave: bool) -> Result - where P: Clone - + PersistenceProvider - + PersistenceProvider - + PersistenceProvider - + 'static { - let stash = S::load(provider.clone(), autosave)?; - let state = H::load(provider.clone(), autosave)?; - let index = I::load(provider, autosave)?; - Ok(Self::with(stash, state, index)) - } - - pub fn make_persistent

( - &mut self, - provider: P, - autosave: bool, - ) -> Result - where - P: Clone - + PersistenceProvider - + PersistenceProvider - + PersistenceProvider - + 'static, - { - let a = self - .as_stash_provider_mut() - .make_persistent(provider.clone(), autosave)?; - let b = self - .as_state_provider_mut() - .make_persistent(provider.clone(), autosave)?; - let c = self - .as_index_provider_mut() - .make_persistent(provider, autosave)?; - Ok(a && b && c) - } - - pub fn store(&mut self) -> Result<(), PersistenceError> { - // TODO: Revert on failure - - self.as_stash_provider_mut().store()?; - self.as_state_provider_mut().store()?; - self.as_index_provider_mut().store()?; - - Ok(()) - } -} - -impl Stock { - pub fn with(stash_provider: S, state_provider: H, index_provider: P) -> Self { - Stock { - stash: Stash::new(stash_provider), - state: State::new(state_provider), - index: Index::new(index_provider), - } - } - - #[doc(hidden)] - pub fn as_stash_provider(&self) -> &S { self.stash.as_provider() } - #[doc(hidden)] - pub fn as_state_provider(&self) -> &H { self.state.as_provider() } - #[doc(hidden)] - pub fn as_index_provider(&self) -> &P { self.index.as_provider() } - - #[doc(hidden)] - pub fn as_stash_provider_mut(&mut self) -> &mut S { self.stash.as_provider_mut() } - #[doc(hidden)] - pub fn as_state_provider_mut(&mut self) -> &mut H { self.state.as_provider_mut() } - #[doc(hidden)] - pub fn as_index_provider_mut(&mut self) -> &mut P { self.index.as_provider_mut() } - - pub fn ifaces(&self) -> Result + '_, StockError> { - let names = self - .stash - .ifaces()? - .map(|iface| (iface.iface_id(), iface.name.clone())) - .collect::>(); - Ok(self.stash.ifaces()?.map(move |iface| { - let suppl = self - .stash - .supplement(ContentRef::Iface(iface.iface_id())) - .ok() - .flatten(); - IfaceInfo::new(iface, &names, suppl) - })) - } - pub fn iface(&self, iface: impl Into) -> Result<&Iface, StockError> { - Ok(self.stash.iface(iface)?) - } - pub fn type_system(&self, iface: &Iface) -> Result> { - Ok(self.stash.type_system(iface)?) - } - pub fn schemata(&self) -> Result + '_, StockError> { - Ok(self.stash.schemata()?.map(SchemaInfo::with)) - } - pub fn schema(&self, schema_id: SchemaId) -> Result<&SchemaIfaces, StockError> { - Ok(self.stash.schema(schema_id)?) - } - - pub fn contracts( - &self, - ) -> Result + '_, StockError> { - Ok(self.stash.geneses()?.map(ContractInfo::with)) - } - - #[allow(clippy::multiple_bound_locations)] - pub fn contracts_by<'a, C: IfaceClass + 'a>( - &'a self, - ) -> Result< - impl Iterator< - Item = > as IfaceWrapper>>::Info, - > + 'a, - StockError, - > { - Ok(self.stash.geneses_by::()?.filter_map(|genesis| { - self.contract_iface_class::(genesis.contract_id()) - .as_ref() - .map(> as IfaceWrapper>>::info) - .ok() - })) - } - - /// Iterates over ids of all contract assigning state to the provided set of - /// output seals. - pub fn contracts_assigning( - &self, - outputs: impl IntoIterator>, - ) -> Result + '_, StockError> { - let outputs = outputs - .into_iter() - .map(|o| o.into()) - .collect::>(); - Ok(self.index.contracts_assigning(outputs)?) - } - - #[allow(clippy::type_complexity)] - fn contract_raw( - &self, - contract_id: ContractId, - ) -> Result<(&SchemaIfaces, H::ContractRead<'_>, ContractInfo), StockError> { - let state = self.state.contract_state(contract_id)?; - let schema_id = state.schema_id(); - let schema_ifaces = self.stash.schema(schema_id)?; - Ok((schema_ifaces, state, self.contract_info(contract_id)?)) - } - - pub fn contract_info( - &self, - contract_id: ContractId, - ) -> Result> { - Ok(ContractInfo::with(self.stash.genesis(contract_id)?)) - } - - pub fn contract_state( - &self, - contract_id: ContractId, - ) -> Result, StockError> { - self.state - .contract_state(contract_id) - .map_err(StockError::from) - } - - #[allow(clippy::multiple_bound_locations, clippy::type_complexity)] - pub fn contract_iface_class( - &self, - contract_id: ContractId, - ) -> Result>, StockError> { - let (schema_ifaces, state, info) = self.contract_raw(contract_id)?; - let iimpl = self.stash.impl_for::(schema_ifaces)?; - - let iface = self.stash.iface(iimpl.iface_id)?; - let types = self.stash.type_system(iface)?; - - Ok(C::Wrapper::with(ContractIface { - state, - schema: schema_ifaces.schema.clone(), - iface: iimpl.clone(), - scripts: self.stash.scripts(iimpl.state_abi.lib_ids())?, - types, - info, - })) - } - - /// Returns the best matching abstract interface to a contract. - pub fn contract_iface( - &self, - contract_id: ContractId, - iface: impl Into, - ) -> Result>, StockError> { - let (schema_ifaces, state, info) = self.contract_raw(contract_id)?; - let iface = self.stash.iface(iface)?; - let iface_id = iface.iface_id(); - - let iimpl = iface.find_abstractable_impl(schema_ifaces).ok_or_else(|| { - ContractIfaceError::NoAbstractImpl(iface_id, schema_ifaces.schema.schema_id()) - })?; - - let types = self.stash.type_system(iface)?; - - Ok(ContractIface { - state, - schema: schema_ifaces.schema.clone(), - iface: iimpl.clone(), - scripts: self.stash.scripts(iimpl.state_abi.lib_ids())?, - types, - info, - }) - } - - pub fn contract_assignments_for( - &self, - contract_id: ContractId, - outpoints: impl IntoIterator>, - ) -> Result> { - let outputs: BTreeSet = outpoints.into_iter().map(|o| o.into()).collect(); - - let state = self.contract_state(contract_id)?; - - let mut res = - HashMap::>::with_capacity(outputs.len()); - - for item in state.assignments() { - let outpoint = item.seal.into(); - if outputs.contains::(&outpoint) { - res.entry(item.seal) - .or_default() - .insert(item.opout, item.state.clone()); - } - } - - Ok(res) - } - - pub fn contract_builder( - &self, - issuer: impl Into, - schema_id: SchemaId, - iface: impl Into, - ) -> Result> { - Ok(self - .stash - .contract_builder(issuer.into(), schema_id, iface)?) - } - - pub fn transition_builder( - &self, - contract_id: ContractId, - iface: impl Into, - transition_name: Option>, - ) -> Result> { - Ok(self - .stash - .transition_builder(contract_id, iface, transition_name)?) - } - - pub fn blank_builder( - &self, - contract_id: ContractId, - iface: impl Into, - ) -> Result> { - Ok(self.stash.blank_builder(contract_id, iface)?) - } - - pub fn export_schema(&self, schema_id: SchemaId) -> Result> { - let mut kit = Kit::default(); - let schema_ifaces = self.schema(schema_id)?; - kit.schemata - .push(schema_ifaces.schema.clone()) - .expect("single item"); - for name in schema_ifaces.iimpls.keys() { - let iface = self.stash.iface(name.clone())?; - kit.ifaces.push(iface.clone()).expect("type guarantees"); - } - kit.iimpls - .extend(schema_ifaces.iimpls.values().cloned()) - .expect("type guarantees"); - let (types, scripts) = self - .stash - .types_scripts(&schema_ifaces.schema, &kit.ifaces)?; - kit.scripts - .extend(scripts.into_values()) - .expect("type guarantees"); - kit.types = types; - Ok(kit.validate().expect("stock produced invalid kit")) - } - - pub fn export_contract( - &self, - contract_id: ContractId, - ) -> Result> { - let consignment = self.consign::(contract_id, [], None)?; - Ok(consignment) - } - - pub fn transfer( - &self, - contract_id: ContractId, - outputs: impl AsRef<[XOutputSeal]>, - secret_seal: Option>, - ) -> Result> { - let consignment = self.consign(contract_id, outputs, secret_seal)?; - Ok(consignment) - } - - fn consign( - &self, - contract_id: ContractId, - outputs: impl AsRef<[XOutputSeal]>, - secret_seal: Option>, - ) -> Result, StockError> { - let outputs = outputs.as_ref(); - - // Initialize supplements with btree set - let mut supplements = bset![]; - // Initialize signatures with btree map - let mut signatures = bmap! {}; - // Get genesis signature by contract id - self.stash - .sigs_for(&ContentId::Genesis(contract_id))? - .map(|genesis_sig| { - signatures.insert(ContentId::Genesis(contract_id), genesis_sig.clone()) - }); - // Get genesis supplement by contract id - self.stash - .supplement(ContentRef::Genesis(contract_id))? - .map(|genesis_suppl| supplements.insert(genesis_suppl.clone())); - // 1. Collect initial set of anchored bundles - // 1.1. Get all public outputs - let mut opouts = self.index.public_opouts(contract_id)?; - - // 1.2. Add outputs requested by the caller - opouts.extend( - self.index - .opouts_by_outputs(contract_id, outputs.iter().copied())?, - ); - opouts.extend(self.index.opouts_by_terminals(secret_seal.into_iter())?); - - // 1.3. Collect all state transitions assigning state to the provided outpoints - let mut anchored_bundles = BTreeMap::::new(); - let mut transitions = 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 - } - - let transition = self.transition(opout.op)?; - transitions.insert(opout.op, transition.clone()); - - let bundle_id = self.index.bundle_id_for_op(transition.id())?; - // 2. Collect secret seals from terminal transitions to add to the consignment terminals - for typed_assignments in transition.assignments.values() { - for index in 0..typed_assignments.len_u16() { - let seal = typed_assignments.confidential_seals()[index as usize]; - if secret_seal == Some(seal) { - let res = terminals.insert(bundle_id, seal); - assert_eq!(res, None); - } - } - } - - if let Entry::Vacant(entry) = anchored_bundles.entry(bundle_id) { - entry.insert(self.client_bundle(bundle_id)?); - } - } - - // 2. Collect all state transitions between terminals and genesis - let mut ids = vec![]; - for transition in transitions.values() { - ids.extend(transition.inputs().iter().map(|input| input.prev_out.op)); - } - while let Some(id) = ids.pop() { - if id == contract_id { - continue; // we skip genesis since it will be present anywhere - } - let transition = self.transition(id)?; - ids.extend(transition.inputs().iter().map(|input| input.prev_out.op)); - transitions.insert(id, transition.clone()); - let bundle_id = self.index.bundle_id_for_op(transition.id())?; - anchored_bundles - .entry(bundle_id) - .or_insert(self.client_bundle(bundle_id)?.clone()) - .reveal_transition(transition.clone())?; - } - - let genesis = self.stash.genesis(contract_id)?.clone(); - // Get schema signature by schema id - self.stash - .sigs_for(&ContentId::Schema(genesis.schema_id))? - .map(|schema_signature| { - signatures.insert(ContentId::Schema(genesis.schema_id), schema_signature.clone()) - }); - // Get schema supplement by schema id - self.stash - .supplement(ContentRef::Schema(genesis.schema_id))? - .map(|schema_suppl| supplements.insert(schema_suppl.clone())); - - let schema_ifaces = self.stash.schema(genesis.schema_id)?.clone(); - let mut ifaces = BTreeMap::new(); - for (iface_id, iimpl) in schema_ifaces.iimpls { - let iface = self.stash.iface(iface_id)?; - // Get iface and iimpl signatures by iface id and iimpl id - self.stash - .sigs_for(&ContentId::Iface(iface.iface_id()))? - .map(|iface_signature| { - signatures.insert(ContentId::Iface(iface.iface_id()), iface_signature.clone()) - }); - self.stash - .sigs_for(&ContentId::IfaceImpl(iimpl.impl_id()))? - .map(|iimpl_signature| { - signatures - .insert(ContentId::IfaceImpl(iimpl.impl_id()), iimpl_signature.clone()) - }); - // Get iface and iimpl supplement by iface id and iimpl id - self.stash - .supplement(ContentRef::Iface(iface.iface_id()))? - .map(|iface_suppl| supplements.insert(iface_suppl.clone())); - - self.stash - .supplement(ContentRef::IfaceImpl(iimpl.impl_id()))? - .map(|iimpl_suppl| supplements.insert(iimpl_suppl.clone())); - - ifaces.insert(iface.clone(), iimpl); - } - let ifaces = Confined::from_checked(ifaces); - - let mut bundles = BTreeMap::::new(); - for anchored_bundle in anchored_bundles.into_values() { - let witness_ids = self.index.bundle_info(anchored_bundle.bundle_id())?.0; - let witness_id = self.state.select_valid_witness(witness_ids)?; - let pub_witness = self.stash.witness(witness_id)?.public.clone(); - let wb = match bundles.remove(&witness_id) { - Some(bundle) => bundle.into_double(anchored_bundle)?, - None => WitnessBundle::with(pub_witness, anchored_bundle), - }; - let res = bundles.insert(witness_id, wb); - debug_assert!(res.is_none()); - } - let bundles = Confined::try_from_iter(bundles.into_values()) - .map_err(|_| ConsignError::TooManyBundles)?; - let terminals = - Confined::try_from(terminals).map_err(|_| ConsignError::TooManyTerminals)?; - - let (types, scripts) = self - .stash - .types_scripts(&schema_ifaces.schema, ifaces.keys())?; - let scripts = Confined::from_iter_checked(scripts.into_values()); - let supplements = - Confined::try_from(supplements).map_err(|_| ConsignError::TooManySupplements)?; - let signatures = - Confined::try_from(signatures).map_err(|_| ConsignError::TooManySignatures)?; - // TODO: Conceal everything we do not need - // TODO: Add known sigs to the consignment - - Ok(Consignment { - version: ContainerVer::V2, - transfer: TRANSFER, - - schema: schema_ifaces.schema, - ifaces, - genesis, - terminals, - bundles, - extensions: none!(), - attachments: none!(), - - signatures, - supplements, - types, - scripts, - }) - } - - /// Composes a batch of state transitions updating state for the provided - /// set of previous outputs, satisfying requirements of the invoice, paying - /// the change back and including the necessary blank state transitions. - #[allow(clippy::result_large_err)] - pub fn compose( - &self, - invoice: RgbInvoice, - prev_outputs: impl IntoIterator>, - method: CloseMethod, - beneficiary_vout: Option>, - allocator: impl Fn(ContractId, AssignmentType, VelocityHint) -> Option, - ) -> Result> { - self.compose_deterministic( - invoice, - prev_outputs, - method, - beneficiary_vout, - u64::MAX, - allocator, - |_, _| rand::random(), - ) - } - - /// Composes a batch of state transitions updating state for the provided - /// set of previous outputs, satisfying requirements of the invoice, paying - /// the change back and including the necessary blank state transitions. - #[allow(clippy::too_many_arguments, clippy::result_large_err)] - pub fn compose_deterministic( - &self, - invoice: RgbInvoice, - prev_outputs: impl IntoIterator>, - method: CloseMethod, - beneficiary_vout: Option>, - priority: u64, - allocator: impl Fn(ContractId, AssignmentType, VelocityHint) -> Option, - seal_blinder: impl Fn(ContractId, AssignmentType) -> u64, - ) -> Result> { - let layer1 = invoice.layer1(); - let state_data = invoice.state.ok_or(ComposeError::NoInvoiceState)?; - let state = rgb::State::from(state_data); // TODO: Take account attachements when they will be supported by invoices - let prev_outputs = prev_outputs - .into_iter() - .map(|o| o.into()) - .collect::>(); - - #[allow(clippy::type_complexity)] - let output_for_assignment = - |id: ContractId, - assignment_type: AssignmentType| - -> Result, StockError> { - let mut suppl = self.stash.supplements(ContentRef::Genesis(id))?; - let velocity = suppl - .next() - .and_then(|suppl| { - suppl - .get( - SupplSub::Assignment, - SupplItem::TypeNo(assignment_type.to_inner()), - SUPPL_ANNOT_VELOCITY, - ) - .transpose() - .ok() - .flatten() - }) - .unwrap_or_default(); - let vout = allocator(id, assignment_type, velocity) - .ok_or(ComposeError::NoBlankOrChange(velocity, assignment_type))?; - let seal = - GraphSeal::with_blinded_vout(method, vout, seal_blinder(id, assignment_type)); - Ok(BuilderSeal::Revealed(XChain::with(layer1, seal))) - }; - - // 1. Prepare the data - if let Some(expiry) = invoice.expiry { - if expiry < Utc::now().timestamp() { - return Err(ComposeError::InvoiceExpired.into()); - } - } - let contract_id = invoice.contract.ok_or(ComposeError::NoContract)?; - let iface = invoice.iface.as_ref().ok_or(ComposeError::NoIface)?; - let mut main_builder = - self.transition_builder(contract_id, iface.clone(), invoice.operation.clone())?; - let assignment_name = invoice - .assignment - .as_ref() - .or_else(|| main_builder.default_assignment().ok()) - .ok_or(BuilderError::NoDefaultAssignment)? - .clone(); - let assignment_id = main_builder.assignments_type(assignment_name)?; - - // If there are inputs which are using different seal closing method from our - // wallet (and thus main state transition) we need to put them aside and - // allocate a different state transition spending them as a change. - let mut alt_builder = - self.transition_builder(contract_id, iface.clone(), invoice.operation.clone())?; - - let layer1 = invoice.beneficiary.chain_network().layer1(); - let beneficiary = match (invoice.beneficiary.into_inner(), beneficiary_vout) { - (Beneficiary::BlindedSeal(seal), None) => { - BuilderSeal::Concealed(XChain::with(layer1, seal)) - } - (Beneficiary::BlindedSeal(_), Some(_)) => { - return Err(ComposeError::BeneficiaryVout.into()); - } - (Beneficiary::WitnessVout(payload), Some(vout)) => { - let blinding = seal_blinder(contract_id, assignment_id); - let seal = GraphSeal::with_blinded_vout(payload.method, vout, blinding); - BuilderSeal::Revealed(XChain::with(layer1, seal)) - } - (Beneficiary::WitnessVout(_), None) => { - return Err(ComposeError::NoBeneficiaryOutput.into()); - } - }; - - // 2. Prepare transition - let mut main_inputs = Vec::::new(); - let mut alt_inputs = Vec::::new(); - - for (output, list) in - self.contract_assignments_for(contract_id, prev_outputs.iter().copied())? - { - if output.method() == method { - main_inputs.push(output) - } else { - alt_inputs.push(output) - }; - for (opout, state) in list { - if output.method() == method { - main_builder = main_builder.add_input(opout, state.clone())?; - } else { - alt_builder = alt_builder.add_input(opout, state.clone())?; - } - if opout.ty != assignment_id { - let seal = output_for_assignment(contract_id, opout.ty)?; - if output.method() == method { - main_builder = main_builder.add_owned_state_blank(opout.ty, seal, state)?; - } else { - alt_builder = alt_builder.add_owned_state_blank(opout.ty, seal, state)?; - } - } - } - } - - // Add payments to beneficiary - let (builder, partial_state) = - main_builder.fulfill_owned_state(assignment_id, beneficiary, state)?; - main_builder = builder; - if let Some(partial_state) = partial_state { - let (builder, remaining_state) = - alt_builder.fulfill_owned_state(assignment_id, beneficiary, partial_state)?; - alt_builder = builder; - if let Some(_) = remaining_state { - // TODO: Add information about remaining state to the error - return Err(ComposeError::InsufficientState.into()); - } - } - - // Pay change - let change_seal = output_for_assignment(contract_id, assignment_id)?; - main_builder = main_builder.add_owned_state_change(assignment_id, change_seal)?; - alt_builder = alt_builder.add_owned_state_change(assignment_id, change_seal)?; - - // 3. Prepare other transitions - // Enumerate state - let mut spent_state = - HashMap::>>::new(); - for id in self.contracts_assigning(prev_outputs.iter().copied())? { - // Skip current contract - if id == contract_id { - continue; - } - let state = self.contract_assignments_for(id, prev_outputs.iter().copied())?; - let entry = spent_state.entry(id).or_default(); - for (seal, assigns) in state { - entry.entry(seal).or_default().extend(assigns); - } - } - - // Construct blank transitions - let mut blanks = Confined::, 0, { U24 - 1 }>::with_capacity(spent_state.len()); - for (id, list) in spent_state { - let mut blank_builder_tapret = self.blank_builder(id, iface.clone())?; - let mut blank_builder_opret = self.blank_builder(id, iface.clone())?; - let mut outputs_tapret = Vec::with_capacity(list.len()); - let mut outputs_opret = Vec::with_capacity(list.len()); - for (output, assigns) in list { - match output.method() { - Method::TapretFirst => outputs_tapret.push(output), - Method::OpretFirst => outputs_opret.push(output), - } - for (opout, state) in assigns { - let seal = output_for_assignment(id, opout.ty)?; - match output.method() { - Method::TapretFirst => { - blank_builder_tapret = blank_builder_tapret - .add_input(opout, state.clone())? - .add_owned_state_blank(opout.ty, seal, state)? - } - Method::OpretFirst => { - blank_builder_opret = blank_builder_opret - .add_input(opout, state.clone())? - .add_owned_state_blank(opout.ty, seal, state)? - } - } - } - } - - let mut dicho = vec![]; - for (blank_builder, outputs) in - [(blank_builder_tapret, outputs_tapret), (blank_builder_opret, outputs_opret)] - { - if !blank_builder.has_inputs() { - continue; - } - let transition = blank_builder.complete_transition()?; - let info = TransitionInfo::new(transition, outputs).map_err(|e| { - debug_assert!(!matches!(e, TransitionInfoError::CloseMethodDivergence(_))); - ComposeError::TooManyInputs - })?; - dicho.push(info); - } - blanks - .push(TransitionDichotomy::from_iter(dicho)) - .map_err(|_| ComposeError::TooManyBlanks)?; - } - - let (first_builder, second_builder) = - match (main_builder.has_inputs(), alt_builder.has_inputs()) { - (true, true) => (main_builder, Some(alt_builder)), - (true, false) => (main_builder, None), - (false, true) => (alt_builder, None), - (false, false) => return Err(ComposeError::InsufficientState.into()), - }; - let first = TransitionInfo::new(first_builder.complete_transition()?, main_inputs) - .map_err(|e| { - debug_assert!(!matches!(e, TransitionInfoError::CloseMethodDivergence(_))); - ComposeError::TooManyInputs - })?; - let second = if let Some(second_builder) = second_builder { - Some(TransitionInfo::new(second_builder.complete_transition()?, alt_inputs).map_err( - |e| { - debug_assert!(!matches!(e, TransitionInfoError::CloseMethodDivergence(_))); - ComposeError::TooManyInputs - }, - )?) - } else { - None - }; - let mut batch = Batch { - main: TransitionDichotomy::with(first, second), - blanks, - }; - batch.set_priority(priority); - Ok(batch) - } - - fn store_transaction( - &mut self, - f: impl FnOnce( - &mut Stash, - &mut State, - &mut Index

, - ) -> Result<(), StockError>, - ) -> Result<(), StockError> { - self.state.begin_transaction()?; - self.stash - .begin_transaction() - .inspect_err(|_| self.stash.rollback_transaction())?; - self.index.begin_transaction().inspect_err(|_| { - self.state.rollback_transaction(); - self.stash.rollback_transaction(); - })?; - f(&mut self.stash, &mut self.state, &mut self.index)?; - self.index - .commit_transaction() - .map_err(StockError::from) - .and_then(|_| self.state.commit_transaction().map_err(StockError::from)) - .and_then(|_| self.stash.commit_transaction().map_err(StockError::from)) - .inspect_err(|_| { - self.state.rollback_transaction(); - self.stash.rollback_transaction(); - self.index.rollback_transaction(); - }) - } - - pub fn import_kit(&mut self, kit: ValidKit) -> Result> { - let (kit, status) = kit.split(); - self.stash.begin_transaction()?; - self.stash.consume_kit(kit)?; - self.stash.commit_transaction()?; - Ok(status) - } - - pub fn import_contract( - &mut self, - contract: ValidContract, - resolver: R, - ) -> Result> { - self.consume_consignment(contract, resolver) - } - - pub fn accept_transfer( - &mut self, - contract: ValidTransfer, - resolver: R, - ) -> Result> { - self.consume_consignment(contract, resolver) - } - - fn consume_consignment( - &mut self, - consignment: ValidConsignment, - resolver: R, - ) -> Result> { - let (mut consignment, status) = consignment.split(); - - consignment = self.stash.resolve_secrets(consignment)?; - self.store_transaction(move |stash, state, index| { - state.update_from_consignment(&consignment, &resolver)?; - index.index_consignment(&consignment)?; - stash.consume_consignment(consignment)?; - Ok(()) - })?; - - Ok(status) - } - - /// Imports fascia into the stash, index and inventory. - /// - /// Part of the transfer workflow. Called once PSBT is completed and an RGB - /// fascia containing anchor and all state transitions is exported from - /// it. - /// - /// Must be called before the consignment is created, when witness - /// transaction is not yet mined. - pub fn consume_fascia( - &mut self, - fascia: Fascia, - resolver: R, - ) -> Result<(), StockError> { - self.store_transaction(move |stash, state, index| { - let witness_id = fascia.witness_id(); - stash - .consume_witness(SealWitness::new(fascia.witness.clone(), fascia.anchor.clone()))?; - - for (contract_id, bundle) in fascia.into_bundles() { - let ids1 = bundle - .known_transitions - .keys() - .copied() - .collect::>(); - let ids2 = bundle.input_map.values().copied().collect::>(); - if !ids1.is_subset(&ids2) { - return Err(FasciaError::InvalidBundle(contract_id, bundle.bundle_id()).into()); - } - - index.index_bundle(contract_id, &bundle, witness_id)?; - state.update_from_bundle(contract_id, &bundle, witness_id, &resolver)?; - stash.consume_bundle(bundle)?; - } - Ok(()) - }) - } - - fn transition(&self, opid: OpId) -> Result<&Transition, StockError> { - let bundle_id = self.index.bundle_id_for_op(opid)?; - let bundle = self.stash.bundle(bundle_id)?; - bundle - .known_transitions - .get(&opid) - .ok_or(ConsignError::Concealed(bundle_id, opid).into()) - } - - fn client_bundle(&self, bundle_id: BundleId) -> Result> { - let (witness_ids, contract_id) = self.index.bundle_info(bundle_id)?; - - let bundle = self.stash.bundle(bundle_id)?.clone(); - let witness_id = self.state.select_valid_witness(witness_ids)?; - let witness = self.stash.witness(witness_id)?; - let (merkle_block, dbc) = match (bundle.close_method, &witness.anchors) { - ( - CloseMethod::TapretFirst, - AnchorSet::Tapret(tapret) | AnchorSet::Double { tapret, .. }, - ) => (&tapret.mpc_proof, DbcProof::Tapret(tapret.dbc_proof.clone())), - ( - CloseMethod::OpretFirst, - AnchorSet::Opret(opret) | AnchorSet::Double { opret, .. }, - ) => (&opret.mpc_proof, DbcProof::Opret(opret.dbc_proof)), - _ => { - return Err( - StashInconsistency::BundleMissedInAnchors(bundle_id, contract_id).into() - ); - } - }; - let Ok(mpc_proof) = merkle_block.to_merkle_proof(contract_id.into()) else { - return Err(StashInconsistency::WitnessMissesContract( - witness_id, - bundle_id, - contract_id, - CloseMethod::OpretFirst, - ) - .into()); - }; - - // TODO: Conceal all transitions except the one we need - - Ok(ClientBundle::new(mpc_proof, dbc, bundle)) - } - - pub fn store_secret_seal( - &mut self, - seal: XChain, - ) -> Result> { - Ok(self.stash.store_secret_seal(seal)?) - } - - pub fn update_witnesses( - &mut self, - resolver: impl ResolveWitness, - after_height: u32, - ) -> Result> { - Ok(self.state.update_witnesses(resolver, after_height)?) - } -} - -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct UpdateRes { - pub succeeded: usize, - pub failed: HashMap, -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - - use baid64::FromBaid64Str; - use commit_verify::{Conceal, DigestExt, Sha256}; - use strict_encoding::TypeName; - - use super::*; - use crate::containers::ConsignmentExt; - - #[test] - fn test_consign() { - let mut stock = Stock::in_memory(); - let seal = XChain::with( - rgbcore::Layer1::Bitcoin, - GraphSeal::new_random_vout(bp::dbc::Method::OpretFirst, Vout::from_u32(0)), - ); - let secret_seal = seal.conceal(); - - stock.store_secret_seal(seal).unwrap(); - let contract_id = - ContractId::from_baid64_str("rgb:qFuT6DN8-9AuO95M-7R8R8Mc-AZvs7zG-obum1Va-BRnweKk") - .unwrap(); - if let Ok(transfer) = stock.consign::(contract_id, [], Some(secret_seal)) { - println!("{:?}", transfer.supplements) - } - } - - #[test] - fn test_export_contract() { - let stock = Stock::in_memory(); - let contract_id = - ContractId::from_baid64_str("rgb:qFuT6DN8-9AuO95M-7R8R8Mc-AZvs7zG-obum1Va-BRnweKk") - .unwrap(); - if let Ok(contract) = stock.export_contract(contract_id) { - println!("{:?}", contract.contract_id()) - } - } - - #[test] - fn test_export_schema() { - let stock = Stock::in_memory(); - let hasher = Sha256::default(); - let schema_id = SchemaId::from(hasher); - if let Ok(schema) = stock.export_schema(schema_id) { - println!("{:?}", schema.kit_id()) - } - } - - #[test] - fn test_blank_builder_ifaceid() { - let stock = Stock::in_memory(); - let hasher = Sha256::default(); - let iface_id = IfaceId::from(hasher.clone()); - let bytes_hash = hasher.finish(); - let contract_id = ContractId::copy_from_slice(bytes_hash).unwrap(); - if let Ok(builder) = stock.blank_builder(contract_id, IfaceRef::Id(iface_id)) { - println!("{:?}", builder.transition_type()) - } - } - - #[test] - fn test_blank_builder_ifacename() { - let stock = Stock::in_memory(); - let hasher = Sha256::default(); - let bytes_hash = hasher.finish(); - let contract_id = ContractId::copy_from_slice(bytes_hash).unwrap(); - if let Ok(builder) = - stock.blank_builder(contract_id, IfaceRef::Name(TypeName::from_str("RGB20").unwrap())) - { - println!("{:?}", builder.transition_type()) - } - } - - #[test] - fn test_transition_builder() { - let stock = Stock::in_memory(); - let hasher = Sha256::default(); - let iface_id = IfaceId::from(hasher.clone()); - - let bytes_hash = hasher.finish(); - let contract_id = ContractId::copy_from_slice(bytes_hash).unwrap(); - - if let Ok(builder) = stock.transition_builder( - contract_id, - IfaceRef::Id(iface_id), - Some(FieldName::from_str("transfer").unwrap()), - ) { - println!("{:?}", builder.transition_type()) - } - } -} diff --git a/src/pile.rs b/src/pile.rs new file mode 100644 index 00000000..dc61193d --- /dev/null +++ b/src/pile.rs @@ -0,0 +1,97 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 hypersonic::aora::Aora; +use hypersonic::AuthToken; +use single_use_seals::SingleUseSeal; + +pub trait Protocol: SingleUseSeal { + type Id: Ord + From<[u8; 32]> + Into<[u8; 32]>; + fn auth_token(&self) -> AuthToken; +} + +pub trait Pile { + type Seal: Protocol; + type Hoard: Aora; + type Cache: Aora; + + fn hoard(&self) -> &Self::Hoard; + fn cache(&self) -> &Self::Cache; + + fn hoard_mut(&mut self) -> &mut Self::Hoard; + fn cache_mut(&mut self) -> &mut Self::Cache; +} + +#[cfg(feature = "fs")] +pub mod fs { + use std::path::{Path, PathBuf}; + + use hypersonic::aora::file::FileAora; + use strict_encoding::{StrictDecode, StrictEncode}; + + use super::*; + + pub struct FilePile { + path: PathBuf, + hoard: FileAora, + cache: FileAora, + } + + impl FilePile { + pub fn new(name: &str, path: impl AsRef) -> Self { + let mut path = path.as_ref().to_path_buf(); + path.push(name); + + let hoard = FileAora::new(&path, "hoard"); + let cache = FileAora::new(&path, "cache"); + + Self { path, hoard, cache } + } + + pub fn open(path: impl AsRef) -> Self { + let path = path.as_ref().to_path_buf(); + let hoard = FileAora::open(&path, "hoard"); + let cache = FileAora::open(&path, "cache"); + Self { path, hoard, cache } + } + } + + impl Pile for FilePile + where + Seal::CliWitness: StrictEncode + StrictDecode, + Seal::PubWitness: StrictEncode + StrictDecode, + { + type Seal = Seal; + type Hoard = FileAora; + type Cache = FileAora; + + fn hoard(&self) -> &Self::Hoard { todo!() } + + fn cache(&self) -> &Self::Cache { todo!() } + + fn hoard_mut(&mut self) -> &mut Self::Hoard { todo!() } + + fn cache_mut(&mut self) -> &mut Self::Cache { todo!() } + } +} diff --git a/src/resolvers.rs b/src/resolvers.rs deleted file mode 100644 index 76dc5e7b..00000000 --- a/src/resolvers.rs +++ /dev/null @@ -1,54 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 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 rgb::validation::{ResolveWitness, WitnessResolverError}; -use rgb::vm::{WitnessOrd, XWitnessId, XWitnessTx}; - -use crate::containers::IndexedConsignment; - -// TODO: Implement caching witness resolver - -pub(crate) struct ConsignmentResolver<'cons, R: ResolveWitness, const TRANSFER: bool> { - pub consignment: &'cons IndexedConsignment<'cons, TRANSFER>, - pub fallback: R, -} - -impl<'cons, R: ResolveWitness, const TRANSFER: bool> ResolveWitness - for ConsignmentResolver<'cons, R, TRANSFER> -{ - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - self.consignment - .pub_witness(witness_id) - .and_then(|p| p.map_ref(|pw| pw.tx().cloned()).transpose()) - .ok_or(WitnessResolverError::Unknown(witness_id)) - .or_else(|_| self.fallback.resolve_pub_witness(witness_id)) - } - - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result { - self.fallback.resolve_pub_witness_ord(witness_id) - } -} diff --git a/src/stl.rs b/src/stl.rs index d20e7c85..67d819d5 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -1,23 +1,26 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning +// Standard Library for RGB smart contracts // // SPDX-License-Identifier: Apache-2.0 // -// Written in 2019-2024 by -// Dr Maxim Orlovsky +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky // -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 +// 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 +// 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. +// 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 amplify::IoError; use baid64::Baid64ParseError; diff --git a/src/stockpile.rs b/src/stockpile.rs new file mode 100644 index 00000000..c368e40c --- /dev/null +++ b/src/stockpile.rs @@ -0,0 +1,106 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +// Used in strict encoding; once solved there, remove here +use std::io; + +use hypersonic::{Articles, AuthToken, CellAddr, Stock, Supply}; +use single_use_seals::SingleUseSeal; +use strict_encoding::{StrictWriter, WriteRaw}; + +use crate::pile::Protocol; +use crate::Pile; + +pub struct Stockpile, P: Pile, const CAPS: u32> { + stock: Stock, + pile: P, +} + +impl, P: Pile, const CAPS: u32> Stockpile { + pub fn create(articles: Articles, supply: S, pile: P) -> Self { + let stock = Stock::create(articles, supply); + Self { stock, pile } + } + + pub fn open(articles: Articles, supply: S, pile: P) -> Self { + let stock = Stock::open(articles, supply); + Self { stock, pile } + } + + pub fn seal(&self, seal: &P::Seal) -> Option { + let auth = seal.auth_token(); + self.stock.state().raw.auth.get(&auth).copied() + } + + pub fn append_witness( + &mut self, + published: ::PubWitness, + client: ::CliWitness, + ) { + todo!() + } + + pub fn consign<'a>( + &mut self, + terminals: impl IntoIterator, + mut writer: StrictWriter, + ) -> io::Result<()> { + todo!() + } +} + +#[cfg(feature = "fs")] +mod fs { + use std::path::Path; + + use hypersonic::{ContractName, FileSupply}; + use strict_encoding::{StrictDecode, StrictEncode}; + + use super::*; + use crate::FilePile; + + impl Stockpile, CAPS> + where + Seal::CliWitness: StrictEncode + StrictDecode, + Seal::PubWitness: StrictEncode + StrictDecode, + { + pub fn new(articles: Articles, path: impl AsRef) -> Self { + let path = path.as_ref(); + let name = match &articles.contract.meta.name { + ContractName::Unnamed => articles.contract_id().to_string(), + ContractName::Named(name) => name.to_string(), + }; + let pile = FilePile::new(&name, path); + let supply = FileSupply::new(&name, path); + Self::create(articles, supply, pile) + } + + pub fn load(path: impl AsRef) -> Self { + let path = path.as_ref(); + let pile = FilePile::open(path); + let supply = FileSupply::open(path); + Self::open(supply.load_articles(), supply, pile) + } + } +} diff --git a/src/wallet.rs b/src/wallet.rs new file mode 100644 index 00000000..5c8d1381 --- /dev/null +++ b/src/wallet.rs @@ -0,0 +1,85 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 bp::seals::TxoSeal; +use bp::{dbc, Outpoint, Txid, Vout}; +use hypersonic::{AuthToken, CellAddr, ContractId, Operation, Supply}; + +use crate::pile::Protocol; +use crate::{Mound, Pile}; + +pub trait WalletDescriptor {} + +impl Protocol for TxoSeal { + type Id = Txid; + + fn auth_token(&self) -> AuthToken { todo!() } +} + +/// Wallet contains a bunch of RGB contract stockpiles, which are held by a single owner; such that +/// when a new operation under any of the contracts happen it may affect other contracts sharing the +/// same UTXOs. +pub struct Wallet< + W: WalletDescriptor, + D: dbc::Proof, + S: Supply, + P: Pile>, + const CAPS: u32, +> { + pub descriptor: W, + pub unspent: BTreeMap)>>, + pub mound: Mound, +} + +impl< + W: WalletDescriptor, + D: dbc::Proof, + S: Supply, + P: Pile>, + const CAPS: u32, + > Wallet +{ + pub fn assignments( + &self, + outpoint: Outpoint, + ) -> impl Iterator)> { + self.unspent + .get(&outpoint) + .expect("unknown outpoint") + .iter() + .map(|(id, seal)| (*id, seal)) + } + + pub fn new_vout(&mut self, vout: Vout) -> TxoSeal { todo!() } + + pub fn new_seal(&mut self) -> TxoSeal { todo!() } + + pub fn resolve_seal(&self, opout: CellAddr) -> TxoSeal { todo!() } + + pub fn assemble_psbt(&self, op: Operation) { todo!() } +} + +pub trait WalletPersistence {} diff --git a/stl/Cargo.toml b/stl/Cargo.toml deleted file mode 100644 index 801bf9f5..00000000 --- a/stl/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "rgb-stl" -version = { workspace = true } -description = "RGB strict type libraries" -keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] -categories = ["cryptography::cryptocurrencies"] -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -rust-version = { workspace = true } -readme = "../README.md" - -[[bin]] -name = "rgb-stl" -path = "src/main.rs" - -[dependencies] -amplify = { workspace = true } -strict_types = { workspace = true } -commit_verify = { workspace = true } -rgb-std = { version = "0.11.0-beta.4", path = ".." } diff --git a/stl/RGBStd@0.11.0.sta b/stl/RGBStd@0.11.0.sta deleted file mode 100644 index 589d596b..00000000 --- a/stl/RGBStd@0.11.0.sta +++ /dev/null @@ -1,300 +0,0 @@ ------BEGIN STRICT TYPE LIB----- -Id: stl:3QsSNDHr-YPIKTR9-5O!fLuv-xhcxKT2-0LWrO9b-pG15Nvw#mango-inside-shelf -Name: RGBStd -Dependencies: - StrictTypes#century-comrade-chess, - BPCore#austin-story-retro, - AluVM#congo-archive-folio, - CommitVerify#miller-pancake-elastic, - RGBCommit#trident-rover-tape, - Std#ralph-blue-lucky, - Bitcoin#signal-color-cipher -Check-SHA256: d003c3fbc2fb3bbf7c1af3b580825dfbf43f509f0b75adb51c4f3096e33e53f5 - -22w{tQ*>kpMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD*X=8L$d2nTORuk6O)Q5AKbFW;J -EQ>MoHhG*Mzd(pEtONi$rOUxc20~CnZ*pZ~a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjHL2Pwa -O?m?z-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCJaMwZEb0ER%LQ&W_f!)g4$;(NAWquAkw}j-|{|z -I;-FIp1Euir581u{j3R6M?ynyZEb0E$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#15DT%6aZ| -SrJerP1pIOD57`7Ol|-ogQ6Pjg~y>s-v>!^VNPLfWv4Jz0xkJm$nc4yMWR2J-cc#Q6SofWC)gp7L6!Sc -3I$AQVo7AP4Jk3r!|EoW{Zi$060oMN(jLzPuNboiNpoRSWoOdj7+WWC1?EKi+6QrwlvP$n -l8x-M691f9z+~t)>6ivgX<}1lX9hx0LvM0r3IG9o2VDR_OBR)w8yCZ2EylR&t_^>1Sz?kFbz0>alMxYA -VQ_L~bWU$%Wl&*qbZ%vG54IneKN{_;j(f`H9IfkFzO$PGD6U0+e -W+%HuC5$^~^vuG3{`}-8x6fV={eh1!etXz_4^&}ra%FT-VRUFva&K>DF1HXRxo%|^+Itiop&gxXSvq){ -{YhrGf57_P)SQy*22EvjXm4aVKVmL%Q_{#Gkvz+H9iKg9-*)mSRaq_gMnjYqO>G4cRAF#(Wpq+$XJ~Xn -a$#;`XhtWfE>N`F8f<{_M@^MEhcVy#omh=bI-rl&{j_4Y)eb^zX>MdwWnpYocu;h5M^4XN(CAD)cag{3QuryWpq$-Z*OL38SA{&vly$FvzVnzHf7z~rv`86=_Ka^V5yX|y#`JS -Q)OdvWpq?<6X>Jq%0U2$DDaiKPL`@Y=jhu|Vo)3+Q0$Mw; -ks-!CQm`I}1yf~lPHzeskk?c43YBIb6Fc=IN+pl}OUT^`C!`zX1ig-;MydoD@qdC-Hdlhx3aZBNPbr@aHF*SPB$t~%I3sYlqX>fEx -d30rSF}tqlgo$^>um>@6G0l?pFt#Zz&53{9y57aQ#OZ(83shlnPH$voNMUnmHQF5&IUsJk-Q1+ZJ%=&s -@|&mHbl*M5f*>4D7PYw?2uyEdYgB1%WjJ*Nu}gdoMr}u)7e{?0bR>WH17z$yORD!eAooFZYY9_nXH#Qx -X>fF3tl4elKTgFI*|CjhfZ7VH>n$b={WmS6z+ej~gaaD&)?_rinzL -Q&_n0fy*YdyZ9}hJM#rpcu#e7m-W{MLar(^k|jH+P94s~ljFZW({ZtfbA~le%!q<(1XE#jbDdR_th)Kl -;F~x`_=5>?(>Td5ZgsqT;~+(zt2h~^9tT%xbZ%vHbEASn^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1 -Rs>XdX=JE;#(89COl4taR%LR& -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 -ZP9(YH~bairNa{vkf;?xyT5z&Ua -+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 -B=zREie$*y(7k2+*P~cYjR -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 -aaxrgbrDxyH3K7!h3DM#@+#URqY -Cg1WtfjX<-_MW+H5~UY4oBgb0bsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez*ZeeX@0!8YhU)%QM -kO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~atLx|b7gXN -Wn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDP -k{-($PGN0jWJYOaY-C4lZ(?C=Q*>c;WmI`^Wd;KRX=DO>K7!h3DM#@+#URqYCg1WtfjX<-_MW+H5~UY4 -oBgcS?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(vPGN0jWJYOaY-CMk -bYWC^aAgJq0%>Fddp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amxHJkmcb>vO>-_DBy8`Vb0jGrW9$=2qS -MXvL3He1kloHngE|MP07*1hrWn@NaWo%?ra$#@6CZd7@2Wd;KRX=DO>K7!h3 -DM#@+#URqYCg1WtfjX<-_MW+H5~UY4oBgabQV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y)ZeeX@ -0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~ -atLx|b7gXNWn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#; -{6ajG64wDPk{-(yPGN0jWJYOaY-CnpY-Mg^c~p6DWd;KRX=DO>K7!h3DM#@+#URqYCg1WtfjX<-_MW+H -5~UY4oBgat?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNABZeeX@0!8YhU)%QMkO4aJ;_ZeCe;xE! -X<$x_Fs4If6Z`oP*&DQ20rFt3ZOHs70;T-agdg$OP=xIp;K4#IcLF!~atLx|b7gXNWn=<+10COKearHw -cS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(rPGN0jWL9Bv -X<=@3bvOnC0%>Fb009JUVQpmsMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r35LOoBKkGaY9#cS -7Qj{WgyAGcS>>g~&^g7&L0`+VYVk7oBr%DNv -+($;q`HHK!gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1RsjNZcmM?f0`+VY -Vk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3dMUNn!oosZgNI|twmNZeC(lYZa*g7-2eQ3Yy;-pLpZg6#U0%CAAe<9`Lptgpr6F_xjAC6(~TLj#*ewiHf`^rCgHqw;r~cW`-QaCLM7VsJHo -A?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@3^Lq|9zft}OB~jx>)hO73S(hx -V^4K-aCLM7VsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*wg~2q@3^Lq|9zft} -OB~jx>)hO73S(hxV?$_RZf9izVsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4WkGaM+ZSSEb;k|42*w -g~2q@3^Lq|9zft}OB~jx>)hO72UB%$aBN9r1pxpD002NB00~odaByr%bY*P>1po(RWoBV@Y;*ts009Pc -d2nS;ZvX`W0006J2y}UHWlmvjWdH>M0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*;5t>gcQkw -bf~^M){{|8P%hsRk~m~ep32F151Y4WWD*HxX=Q9=PGN0j00jX8Me3tp+xFv-0Xp&G?S=|}9rRaeU`~uM -rbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_6AN}>a%o|1bWUMyWdH>M0!8YhU)%QM -kO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*$IZhiz50p(P||0m=?fQ^Mv6fMp@;h#Lzj#&aRFSj|fwBaByr* -VQ>Wj015$yz}|oy`cC#6Uw2{wE+Sw~);*uMH+9Bf@aCY-RuiZDn*}0S0GmZ(?C=0tIh(Ze?Tx -2XWo~161PWnub7^O8ZDnqB1qWwkZe??6a|Q}@a$#@6CZU+fvcywiMb7^mG2nl6)V`Xr3X>V=` -3R87(aBO95Wo~o^1PNnrZggdCbV+0Z2AHk4+Bm{3x%H=p>4!*u&n~Wpi|4 -ZEyepNC#tbWnpx0asqokg4$;(NAWquAkw}j-|{|zI;-FIp1Euir581u{j9d=fQB3>bs~EXcCXx(drQcb -3B`Fx$)^%va$Ar)C7cUkZfdKHyBH|__hx_vscRWAu^w2r{b^x;wDWyGXd29 -kG60)seH8)H{-R`;$q)jqasX>@6CZb@cgV`T;j -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 diff --git a/stl/RGBStd@0.11.0.sty b/stl/RGBStd@0.11.0.sty deleted file mode 100644 index 1b257773..00000000 --- a/stl/RGBStd@0.11.0.sty +++ /dev/null @@ -1,389 +0,0 @@ -{- - Id: stl:3QsSNDHr-YPIKTR9-5O!fLuv-xhcxKT2-0LWrO9b-pG15Nvw#mango-inside-shelf - Name: RGBStd - Version: 0.11.0 - Description: RGB standard library - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -@context -typelib RGBStd - -import StrictTypes#century-comrade-chess - use VariantName#theory-austin-before - use FieldName#present-flute-herman - use Primitive#deliver-arrow-boxer - use TySemId#popcorn-super-young - use FieldSemId#spiral-road-marco - use TypeName#edgar-carol-mystery - use UnnamedFieldsSemId#freedom-degree-gregory - use SemId#logic-absorb-hilton - use Variant#humor-regard-promise - use Sizing#courage-alien-salon - use NamedFieldsSemId#solar-salad-smoke - use EnumVariants#dispute-natasha-vega - use VariantInfoSemId#museum-edward-mirror - use UnionVariantsSemId#santana-address-pepper - use TypeSystem#adrian-boris-sponsor - -import BPCore#austin-story-retro - use TapretNodePartner#roger-member-educate - use TapretProof#marco-border-sample - use TapretPathProof#kiwi-mirror-paris - use Method#bali-boris-plasma - use TapretRightBranch#miracle-patriot-touch - use BlindSealTxPtr#fortune-iron-salmon - use OpretProof#good-village-flex - use SecretSeal#dollar-iris-wizard - use BlindSealTxid#media-judge-anita - use TxPtr#italian-july-eddie - -import AluVM#congo-archive-folio - use Lib#gate-biology-optimal - use LibSite#ultra-grace-message - use IsaName#taboo-olympic-cloud - use LibId#germany-culture-olivia - use IsaSeg#size-shake-olga - use LibSeg#lemon-philips-horse - -import CommitVerify#miller-pancake-elastic - use MerkleHash#horse-popcorn-bundle - use MerkleProof#price-aloha-grid - use ReservedBytes1#origin-roger-relax - use ReservedBytes2#florida-libra-circus - use ReservedBytes4#young-goblin-academy - use ReservedBytes8#rudolf-tape-adrian - -import RGBCommit#trident-rover-tape - use ExtensionSchema#active-eddie-empty - use BundleId#carmen-farmer-diesel - use MetaValue#split-package-recycle - use InputMap#octavia-north-gram - use GenesisSchema#iron-forbid-hamlet - use AltLayer1Set#flute-flex-bottle - use Genesis#ford-acrobat-border - use AssignBlindSealTxPtr#harbor-charm-nelson - use TransitionType#picture-reflex-brigade - use Occurrences#source-olga-mirage - use ValencyType#aloha-dublin-brush - use GlobalState#mouse-bambino-brigade - use GlobalStateSchema#silk-college-august - use OwnedStateSchema#cover-shampoo-weather - use ExtensionType#apropos-scoop-viva - use State#aroma-sailor-manila - use AssignmentsBlindSealTxid#shelter-declare-chrome - use MetaType#quebec-mission-quota - use TransitionSchema#jumbo-matrix-normal - use StateData#nissan-pattern-inside - use AssignmentsBlindSealTxPtr#clone-mayor-patient - use XChainBlindSealTxid#dynamic-life-brown - use AttachId#factor-hair-everest - use AssignmentType#secret-penguin-limit - use XChainBlindSealTxPtr#senator-limbo-raymond - use Opout#yoga-samba-karma - use SchemaId#ramirez-patron-simon - use OpId#picnic-single-gloria - use Schema#eternal-block-totem - use ContractId#uniform-welcome-papa - use TransitionBundle#rubber-permit-martin - use AssignBlindSealTxid#piano-baker-lola - use Inputs#herman-liberal-galaxy - use XChainPubWitness#carrot-import-nova - use TypedAssignsBlindSealTxPtr#python-baboon-money - use Extension#swing-virgo-wisdom - use Identity#smart-pioneer-nominal - use AltLayer1#edison-survive-nitro - use TypedAssignsBlindSealTxid#algebra-fresh-wedding - use GlobalValues#verona-iris-senator - use Input#actor-minus-multi - use GlobalStateType#yoga-quick-jasmine - use Ffv#pigment-career-hippie - use XChainSecretSeal#alex-griffin-left - use Valencies#light-letter-comet - use Redeemed#mile-lady-perfect - use Transition#economy-ethnic-audio - use Metadata#member-nobody-imitate - -import Std#ralph-blue-lucky - use AlphaCaps#picnic-soprano-aurora - use AsciiPrintable#ultra-sunset-format - use Bool#oxygen-complex-duet - use AlphaNumDash#sponsor-snake-nice - use AlphaCapsNum#aladdin-zebra-marble - use AlphaNumLodash#percent-bingo-caesar - use AlphaCapsLodash#duet-hammer-labor - use AlphaSmallLodash#pioneer-eagle-spell - -import Bitcoin#signal-color-cipher - use SeqNo#copper-verbal-ingrid - use TxIn#slang-cherry-gizmo - use Vout#brush-gloria-heroic - use ScriptBytes#equator-cockpit-gong - use TapNodeHash#paprika-amanda-hunter - use LockTime#lobster-liberal-jump - use SigScript#neptune-spiral-sample - use LeafScript#bison-doctor-oscar - use TxOut#aspect-eddie-message - use Sats#metro-picasso-roger - use Witness#engine-daniel-magnum - use Txid#shallow-light-reverse - use TxVer#nepal-symbol-uniform - use InternalPk#habitat-paprika-oliver - use LeafVer#benefit-carbon-africa - use ScriptPubkey#second-lobster-philips - use ByteStr#royal-anatomy-june - use Tx#radar-salon-page - use Outpoint#logo-alamo-madam - use XOnlyPk#clever-swim-carpet - - -@mnemonic(mayday-rider-diploma) -data AnchoredBundles : tapret#1 ClientBundleTapretProof - | opret ClientBundleOpretProof - | double (tapret ClientBundleTapretProof, opret ClientBundleOpretProof) - -@mnemonic(domino-waiter-orlando) -data AnnotationName : Std.AlphaCaps, [Std.AlphaNumDash ^ ..0xfe] - -@mnemonic(phantom-habitat-pegasus) -data Annotations : {AnnotationName -> ^ ..0xff [Byte]} - -@mnemonic(optic-hippie-isabel) -data AssignIface : stateTy StrictTypes.SemId? - , attach Std.Bool? - , public Std.Bool - , required Std.Bool - , multiple Std.Bool - -@mnemonic(prague-peru-under) -data ClientBundleOpretProof : mpcProof CommitVerify.MerkleProof - , dbcProof BPCore.OpretProof - , bundle RGBCommit.TransitionBundle - -@mnemonic(baron-liberal-burger) -data ClientBundleTapretProof : mpcProof CommitVerify.MerkleProof - , dbcProof BPCore.TapretProof - , bundle RGBCommit.TransitionBundle - -@mnemonic(jordan-episode-duet) -data Consignmentfalse : version ContainerVer - , transfer Std.Bool - , terminals {RGBCommit.BundleId -> RGBCommit.XChainSecretSeal} - , genesis RGBCommit.Genesis - , extensions {RGBCommit.Extension ^ ..0xffffffff} - , bundles {WitnessBundle ^ ..0xffffffff} - , schema RGBCommit.Schema - , ifaces {Iface -> ^ ..0xff IfaceImpl} - , supplements {Supplement ^ ..0xff} - , types StrictTypes.TypeSystem - , scripts {AluVM.Lib ^ ..0x400} - , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} - , signatures {ContentId -> ^ ..0xff ContentSigs} - -@mnemonic(gustav-people-message) -data Consignmenttrue : version ContainerVer - , transfer Std.Bool - , terminals {RGBCommit.BundleId -> RGBCommit.XChainSecretSeal} - , genesis RGBCommit.Genesis - , extensions {RGBCommit.Extension ^ ..0xffffffff} - , bundles {WitnessBundle ^ ..0xffffffff} - , schema RGBCommit.Schema - , ifaces {Iface -> ^ ..0xff IfaceImpl} - , supplements {Supplement ^ ..0xff} - , types StrictTypes.TypeSystem - , scripts {AluVM.Lib ^ ..0x400} - , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} - , signatures {ContentId -> ^ ..0xff ContentSigs} - -@mnemonic(giant-bravo-jacket) -data ContainerVer : v2#2 - - -@mnemonic(dispute-senator-parody) -data ContentId : schema RGBCommit.SchemaId - | genesis RGBCommit.ContractId - | iface IfaceId - | ifaceImpl ImplId - | suppl SupplId - -@mnemonic(reward-sharp-orca) -data ContentRef : schema RGBCommit.SchemaId - | genesis RGBCommit.ContractId - | iface IfaceId - | ifaceImpl ImplId - -@mnemonic(apropos-horizon-couple) -data ContentSigs : {RGBCommit.Identity -> ^ 1..0xa SigBlob} - -@mnemonic(corner-reptile-pagoda) -data ExtensionIface : modifier Modifier - , optional Std.Bool - , metadata {StrictTypes.FieldName ^ ..0xff} - , globals {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , assignments {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , redeems {StrictTypes.FieldName ^ ..0xff} - , valencies {StrictTypes.FieldName ^ ..0xff} - , errors {StrictTypes.VariantName ^ ..0xff} - , defaultAssignment StrictTypes.FieldName? - -@mnemonic(oregano-virus-ringo) -data GenesisIface : modifier Modifier - , metadata {StrictTypes.FieldName ^ ..0xff} - , globals {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , assignments {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , valencies {StrictTypes.FieldName ^ ..0xff} - , errors {StrictTypes.VariantName ^ ..0xff} - -@mnemonic(concert-combat-charm) -data GlobalIface : semId StrictTypes.SemId? - , required Std.Bool - , multiple Std.Bool - -@mnemonic(exodus-rider-garcia) -data Iface : version VerNo - , name StrictTypes.TypeName - , inherits [IfaceId ^ ..0xff] - , timestamp I64 - , metadata {StrictTypes.FieldName -> ^ ..0xff StrictTypes.SemId} - , globalState {StrictTypes.FieldName -> ^ ..0xff GlobalIface} - , assignments {StrictTypes.FieldName -> ^ ..0xff AssignIface} - , valencies {StrictTypes.FieldName -> ^ ..0xff ValencyIface} - , genesis GenesisIface - , transitions {StrictTypes.FieldName -> ^ ..0xff TransitionIface} - , extensions {StrictTypes.FieldName -> ^ ..0xff ExtensionIface} - , defaultOperation StrictTypes.FieldName? - , errors {StrictTypes.VariantName -> ^ ..0xff [Unicode ^ ..0xff]} - , developer RGBCommit.Identity - -@mnemonic(nova-cola-carbon) -data IfaceId : [Byte ^ 32] - -@mnemonic(sphere-emotion-east) -data IfaceImpl : version VerNo - , schemaId RGBCommit.SchemaId - , ifaceId IfaceId - , timestamp I64 - , metadata {NamedFieldMetaType ^ ..0xff} - , globalState {NamedFieldGlobalStateType ^ ..0xff} - , assignments {NamedFieldAssignmentType ^ ..0xff} - , valencies {NamedFieldValencyType ^ ..0xff} - , transitions {NamedFieldTransitionType ^ ..0xff} - , extensions {NamedFieldExtensionType ^ ..0xff} - , errors {NamedVariantu8 ^ ..0xff} - , developer RGBCommit.Identity - , stateAbi StateAbi - -@mnemonic(seminar-data-table) -data ImplId : [Byte ^ 32] - -@mnemonic(polka-neptune-star) -data Kit : version ContainerVer - , ifaces {Iface ^ ..0xff} - , schemata {RGBCommit.Schema ^ ..0xff} - , iimpls {IfaceImpl ^ ..0xff} - , supplements {Supplement ^ ..0xff} - , types StrictTypes.TypeSystem - , scripts {AluVM.Lib} - , signatures {ContentId -> ^ ..0xff ContentSigs} - -@mnemonic(saturn-escort-jordan) -data Modifier : abstract | override | final#255 - - -@mnemonic(origin-caramel-flipper) -data NamedFieldAssignmentType : id RGBCommit.AssignmentType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(tuna-archer-melon) -data NamedFieldExtensionType : id RGBCommit.ExtensionType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(museum-ohio-arizona) -data NamedFieldGlobalStateType : id RGBCommit.GlobalStateType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(prefix-carmen-artist) -data NamedFieldMetaType : id RGBCommit.MetaType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(express-brush-desire) -data NamedFieldTransitionType : id RGBCommit.TransitionType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(invest-apollo-inca) -data NamedFieldValencyType : id RGBCommit.ValencyType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(star-pilgrim-pilgrim) -data NamedVariantu8 : id U8 - , name StrictTypes.VariantName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(paper-visa-storm) -data PubWitness : txid Bitcoin.Txid - | tx Bitcoin.Tx - -@mnemonic(insect-cello-avalon) -data SigBlob : [Byte ^ 1..0x1000] - -@mnemonic(thermos-demo-fragile) -data StateAbi : regInput AluVM.LibSite - , regOutput AluVM.LibSite - , calcOutput AluVM.LibSite - , calcChange AluVM.LibSite - -@mnemonic(pilot-claudia-minute) -data SupplId : [Byte ^ 32] - -@mnemonic(jargon-orchid-forget) -data SupplItem : default () - | typeNo U16 - | typeName#17 StrictTypes.TypeName - | fieldName StrictTypes.FieldName - | variantName StrictTypes.VariantName - -@mnemonic(phone-claudia-kiwi) -data SupplMap : {SupplItem -> ^ ..0xff Annotations} - -@mnemonic(canoe-denmark-short) -data SupplSub : itself | meta | global | owned - | valency | assignment | genesis | transition - | extension | exception - - -@mnemonic(lobster-traffic-flame) -data Supplement : contentId ContentRef - , timestamp I64 - , creator RGBCommit.Identity - , annotations {SupplSub -> ^ ..0xff SupplMap} - -@mnemonic(sigma-rose-cubic) -data TransitionIface : modifier Modifier - , optional Std.Bool - , metadata {StrictTypes.FieldName ^ ..0xff} - , globals {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , inputs {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , assignments {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , valencies {StrictTypes.FieldName ^ ..0xff} - , errors {StrictTypes.VariantName ^ ..0xff} - , defaultAssignment StrictTypes.FieldName? - -@mnemonic(buzzer-holiday-fiber) -data ValencyIface : required Std.Bool - -@mnemonic(textile-next-stretch) -data VerNo : v0 | v1 - - -@mnemonic(storm-left-reflex) -data WitnessBundle : pubWitness RGBCommit.XChainPubWitness, anchoredBundles AnchoredBundles - - diff --git a/stl/RGBStorage@0.11.0.sta b/stl/RGBStorage@0.11.0.sta deleted file mode 100644 index f87233bf..00000000 --- a/stl/RGBStorage@0.11.0.sta +++ /dev/null @@ -1,199 +0,0 @@ ------BEGIN STRICT TYPE LIB----- -Id: stl:dYzM3Ct9-SJ8PljY-C!6hB6y-VlWvDE7-DAtNg3y-zanf6hE#media-fresh-cadet -Name: RGBStorage -Dependencies: - RGBLogic#leonid-melody-quick, - StrictTypes#century-comrade-chess, - BPCore#austin-story-retro, - AluVM#congo-archive-folio, - CommitVerify#miller-pancake-elastic, - RGBCommit#trident-rover-tape, - Std#ralph-blue-lucky, - RGBStd#mango-inside-shelf, - Bitcoin#signal-color-cipher -Check-SHA256: 9253c34c5b44ddbc699161987833ea989bcdcd22aa105c8cf57fbdc138fdbcb6 - -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 -`r;e6DUv<<*U}c>CH184%wsNMHUptBVZ#B!U% -rHo-i1kG~VoNp!e_~i}U4@G!%Wo~n6Z*Eg#Xk~3-1ACLTJsO2B2U!6ncg?mz@CdC==Kxq?gSEg)z2E{| -2tsvkWNc+gWE3Slj!?y>j|%qbz^!%<&Wu0B;HjDvS(4Y;;Uvd1Z1jQ)P4~huszhuS%Gw ->J36#@&i>}*{wKf47Hg5JxV=iU{?qSM`dnhb7^xaG~Qz4rf|COpMQA6DFZhcbS+pFfT9t%(h@vS@2O@K -L349yXKq4lX>MdwWnpYocu;h5G*S<)6P6lYy(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(14peesZgXjLX>V>+ -d2nSm!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4rGOBqCPh(?sa&l#EV`Xzj?dHP>9R0ZFSEMRj;Km4q -fBYZ5UUs>0bg9bqiCNAIR$**qZew{=d2nS)+m9st6L>r`q08+u8T&0^adk?AUH3SUSi3+Wb21AHM{I9m -VQf=$VRU6v5zRxYEK#t?kH-RPfvS1oe0PQO`VOrdl$-fvv-}wmM{I9mVQf=$VRU6vV`ybpR6heI$}l1ygikbY*KE -2S>RllQnv!#Bdhn{LP$;qli}WS_~%;XE5$2GG`b;b8~5DZf#|5baO&%X>MdwWnpYocxhyHV>*V`yb=iRT*14O40w5C%+Pd1Z1jdmmICUpAm* -irZQ3c~xnGW`==N2!6EUgc~Rug%*0A2~%`obY(_oQ7|GShenHHQk6Kc**bJ*e3IRag>U{QO}* -5#AX=b8~5DZf#|5baO&%X>MdwWnpYocu;h5f(#9>YyC6LMnX>Mdw -WnpYocu;h5lMuXsu{2tXFT+?;?hj39&>gq>HOrf1lB-q;n)I5N1y68qb##h5j -^*S;NLvL<$a$#e1No1gfw_qjpC#e%OW}_qta$#@6CZbEf#WNc-q -Ht(`hF}jj5^Xl;{(HZPSTKb&GEytIZbS*TmyWyh~L349yXKq4lX>MdwWnpYocxhy*qIy@8$eYR~OKp92 -)%PJ48iGR>vvBgJ_74J{Jehz7Np5g;baS$EAbXV}DW}urw59q*`|HcZksRt+CA}j9C82<;s1zDhd2nT9 -L349yXKr&sY-w&}Q)OXnRCrKyaV?} -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 ->tON(T2L(qY0=?N-3t;l -G3#LR3QZq*JLk)~{9$tvliNbptnXW-ZFx5Qh8PemXlG!~;@e)_O3H?xO^a~KWeI~0jp}x-Dk@(^00000 -00000|Nj60000002u)>eQ*>c;Wd;HXcWHEPWpi_7a{vkgdp?5NXDLVVImIB-z9!%DK7l%`-}aulY!amx -HJkmciECIT&Bl;lSX#$ms8AQN7m&qY<-*c+r9YqvBlw6d-@{>9 -U*X1+0dl)S$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;Q#;t000000RR90{{R30010DnZgg^CV{~%> -3IcmRg4$;(NAWquAkw}j-|{|zI;-FIp1Euir581u{j8q|EJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22 -Ix+!#bL(f8`U$>X>B)Y_u0zsDWJXxNV$=kC)4@UGUHf+c0000000030000000000 - ------END STRICT TYPE LIB----- - diff --git a/stl/RGBStorage@0.11.0.stl b/stl/RGBStorage@0.11.0.stl deleted file mode 100644 index 314dabd9b729ebe90683305cd9be550b05c02b5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11571 zcmcIqcRbbqzdz6=1G_R4mQV}~5h!3pPZh8;2+%1S9B$u22Lh?GrMNSRR@ zq|&l;Kj$2cZ@+sVr^n;o>mMH;ug~lKe82YiFxi;nf6Q?2taFz^+kIhoG&~){_RB?jmFaKViHq~=ocrnCoDy= z*bvFRzRK~88BV~Vy$SZ=K`6W<_mk1#Wc&sE4Y$nQr<6Xch3D?LuXkMW8a+s(sONzx zqk)Yf7Kic*QjHOxdvWhVO!)O>A^aF^FRuOcf)99l; zpGrf`b$R(&Y3$YEpX-uxqz*k{`M#@dNQT7_8yJWtIHGW9pYTYXxG`UOlcfV~J0Ca6 zOn=fjrcp8dEw3(stB7AUXY(2qxDJKBd$$-i{=%dpiw-u=cJHVOBqi4Uo1EG+WY%hX z0Ij_&9h`uiWad&)TJZeDWVIt)^L0=C1_IBOId1Ue+J{3|1H;ue7|DV}ehuLElKgg{ z#2lJAVPf31da~kfyt8}FGd^8`=vFx)Ca?jT;EhFNpp*+Sg1G2Q?$B~Xoiy6}RqY7_ z#>Hi2?m!sd3hQPYdvK6Z-zz#xv{&GV0-2e6#F;Hqi}l0@DuXP_6DeYP&(RhlPf8Xh zCJ=7$Oi=qUb=Y zuzrUFC#O9k2!|rTut<~* z0!P50aC9RoX$wZglW3^Gt)i>i0w2X$_TjEgT|Bg!?0iX5@+il_u%H06H<|!PAp-2f z&`9<>JF<0!7Awv~cE1w2zTnbSokROF@$>!*LC4QMQ;x8~VX;2kt#CUZ*#;x& z6iweRj~+&U-*_oo+wZ}?c`S8rbmY@0_H9}O!H-P8rYC@7tVvQNLq_Vglt)`PZ*>lA zJ|y%w^&A|ydVTDuta1vi!-)?H<~btz!0}j|6$+@6 zicvS(zrK}Ab<0ax&O~m#pYM3);3)hbFaJ8&PjKPhNVP!4`ReQ<3pLc_SP3Kc&0DG0 zbe?5rs~Z_%OmLJp0Frd4s`lW@q{#6Xo)=rD7L?me_KSe}+UsqDZ37(!5)bt+u>N*? zH1g)0`T-s$^`?(lq5dWj&m!#1%$K8K5V`RCgKI+^;*$*aVStE!_!Ei9$c2#1@3~*F149g^#HVXg5l;yL7Tl1@=xpeAxi_S@? z>{a2H^o?h(7?;!AhnZo-U+5UNmAieCmxULqKk!}D^v<<<*4J2;s)FXP?=mFPJ7S3h z>58v)Ts-{sg$ITYNAeO&f-Pnuhyv~dN~#gVT?%iLnBm?ybP&NHoPfeBHB`PyI1$=b z1y;f-^=5oiyd$sBdm?6{eyXj$^=-^ElChGU!4!e_QymlKJ+KqgFgbCxMLSt({!>oL z7-3qwGj68{jIX9n1Y${29y$=EPNctS5yfU4Xp+Zoa#V^S6|+Kze5Y+uzO1oxS)bq! zg`<5b7!F^17C5I1YvXx#^R#d57*oZ9f(-NKeucv3h^y`g@~xOGQ3xLjX__W7C_Eum zSO&i9WnX*o38Tw!=er+|^~h8=tSIDZeg>p&O(dNEI?8BJxocmBv}P$xw68Vu#eJQj z;G4<#Bvsg><8l7eI@m|!6od@$O)CG&hz)onu z^YQq?ID^kUqk{tlTw|waJoh>duVC3)TSMBK{ah?9=uwV3d+DYL%|tHirj9%S7myLk5)(q2$s-l`LuOiq^#$g70sMj%whK!MeaCnE))C zHpDi3iUc>2c1JY0ll5LNaVRi1ZD~9(hJ9Yv3n93%P~>Jq^zuiAx8nR$Q{@ID9-QwK zJ;Pd%<7JflY5?i}z2j||R!#C!A(&(hK;mqR6u)?X`2YrI9DDtsDpY<4I-3KxPxQe3U)u7c((zt6zGWTuameRSdX zr7<=AGUcY?7gAGFMMLv%a^}`iG*9Y$Ke}VmLuI^IDfvA2SI|H}eTdqrkpU-& zJr0E;`R0dtZgz&J$CME8tzg$IF(Rjvhbm;lKv7UePRrwyrXEq(yq_dID zu{JAQE1#jgHu{)vGI}gync?>8pxD33)qfQ#`#^Mlw2w+Bm(4F%^Rl<%a$1T~5Qg-< zxUpQU^tY8c)(Q55VFVNgkH%u)-hQY+1YKlijkZwY9=&e*gSr!o(IRxMSIHojB!&wE$!YHOCk{HS7Xq#_i^YY0a~ z01?G|!57(6Q=td8|12I{^-g8IWN&_1UgTS$Wxtk&&+Eq_W|$x%!3q&1U^+6?>UQ&P z^4@;G!=oFXMc}g0d*_G#i5B@#)6mVzz-od5d>oCZAeC~mdy0zvnA?3sa=$&7(N52( z!rd|NA1(24fUr!^T`4U30R&4#I0~l(M-gO`C;1p|m}i&Fvl_U5qH}P6c3mCKQj@)< zZLaO>=>!39vzAwx@_JDmRR1wQCaguCZodFQ!I?Mq3TN$OE-jl6Wj;Lmcs$w{^ILKO z@`j2XdnNZdA&*A+4NghjMA#<|b^4fL`ljgu<7a$D%6@G2K*GkO34oAEC9c{7m4da) z$GA%-6=StLsy;p39OJ1PDSVRIg2`i7E)Qq6_Vy;?a43v73U9plss$pldH0pm)m?7S z+aU=t8#|gjLh6DEW!+y-xb!gt5(WsvNqo)6Q>8Yz!?gAl^eie1t}7sdiRSU{%j#*) z4SM2uWoBlR0IU}x08T&vaf7qhuza^|RcC4k?U7^U;WJU8iJ#Zlt_z>dSw&WF2y*^T zOEwI6!Z>uWC{+-wmGIq`wqS| zmLX@{$X3#b$dFM`VcLxOyUR9@G~ig%Db}BsM*{DY{qgC&Gb4^;+1G3DKB#dz>mK=W z88JSxpxLH#R4T)Ufy~)o3~W*-o2eR6)EdM$x6zw>s_?kuCs!6(4qwIhGRnRJ6!iq6 zFa-Q>Izl6fFRfOl`%cjcj~I8Rzd`<=S7 zeu>am%_(tG`=r;+jx}=z4c$))g~7lc}?vc%7*i z!^b^NycX(ag&z^(V5Hb!c^JjKVV~gH?I{12%BiOpbf8H&t9u?QLzvrMQ;c=&ggykmoj5o|JuUG7gKN zc^2j#dn1lJrPR$4WNW#sY|D8lJcg0NEg!PmOrw+bN`2ep1hYic&KqZk{aQ`?gEg^jFz3ZWW(GDPc5g#wlW!Zne7|*8rkkC$CocH*2HB z-BPs=x9pVaGn78hFa0wp_|C|6Ew@vl$Seu@lA*cVMQaDw7kXOLMdqEQ8zt$a z3t}rud4x!6MN;_x?p%N}s(Dp(r_8*UAG;;e?^?*LNNGMBSFE{(%O9WT+=o236Z+HD z@4Sgk5|JZHM6!k4n8=E>=*)t)g`0MjaCzbmrD;m%Ld=kW@1hCeo&Ir=%&te<)9Iyf za}u(t1O076PJWjybjy|Wgtek2p+BShqp%6E=t^?y6UpUN9tWLc3=`r)bxQL0_KvT+ ztZyB)7W^M@qmg|>dILtoHmm;MxUM$vR;PYp)41KY_C9^rc#Q4M`Eo%PN)RL`G5nw} zf1@GS$8XSt_unyAV$5`Ova7Jp28N8?tzAm8=gRpgR{CdaIdb|ige51g_$1hv_PKSx zRlb1#eSftU0kH$Oc^b-J%`%XMKk`0<&FpwJdg%y!5Ny6)Be~LH7c91}rtRp$F!PeP zhyAy3OuEikjxDz{pJPZ`^7@52$Fn%K*wF(lj0KORvUf8emmiJL8T*8cpL7+9_@$rJ79i0bvnHPM-H?mPX50pw&WBRpqi} zIkyzwl=sV`R6S4mg%4IRzFwXyes|<#14f- zp#o9JSvkDLk$D-L<7O-;a;8}mD;ay|~`DBkC8cR5H_j(gzhTFn3G{Ab_`ns_! z>r(IaOR$>ldjUoCc2Dqg3`Glan_!dV-5V}3p4_sUYk0CGPk3Or=>e~AVavC>J3+Br zOxv&6VDY#HgH8dsyHbD3*6M90i4Mk&u_{>KDok*E@3&;^#hD+Z);Q$$C`T5=sA-XL z?X3RuM~m=S%`zQPiF2=T=}UL?QpPnas%+zCn0|p`1oGUN`a^}fuO&%ulTD-h6^@pU z+Ns|^UtGp~)8U^Ya*zOA!4Bmk-oYO@uuD(W%A=$wS$*kx+6|7}8%O~VCiRNHv0W%L z80gJ_F5FAWVtNO?DX+hEHB06`!VyFDTWQxWm=rZKUi8-LYg^=G)5l=2K=KF55YkX* zKbx?Sc4*9A#trRzH#chc^t&ATXL0w*p`C?}_WK&1#IgUOz(V8134LJ;^c zV|niaUaFga*PiST9Va|X%cGuvoznzJOp(TDQ~>hVnB>%(4HO9gg2B7DI zVI7l;E{?g~?lH7MO1AICFr-9zEec-m$?y3*5Ub#)be#8>;C`#-96Q;=?zJ26X^b1M zc=)~bG*BQ+K0A@(%Z=CM$Fo*UFSk$iEVb`p7>i#0GoR2J- ztpd%;SZVHqz==UY0dS%hf-9YM&qEtVu8Tz12)W8fdqUdX*gqD%wJH>eem`SK%cLIw zOmfK9;jKM%qRPU|aaaG{K6RpvjF1;ka8%{zai+&Nef&{cHB4llfPZ5MzRJnXke~(L zi^em{u!t=I{DWD}+7fw0ychhQ;^EjVFqza0iEc&JxZKlicyBJ77nbksXEZ+eRin#B zqEC^b;T$+}n*Wy!ep&;`c7k!D#)Bhct*5m3lKn;MOfN}y+eIOVwV@_(0$h7z{)g5mef{!3LvSZ6`UC{Oy-Ibj> z=Wuc0yd4kCZhVf`N3dnw1Fm0M|53NM_|BzhYtbTPFZVf~cq*tN^a}Ra# zsi5O9`hcU90`$(Uxox6OC}DYK4k{y` zrJN@8g`eWMKvz6<#QG_=I}bj~P2j)8GVOjLo1@^%H^CKLw%DSjMEF$(GP~JfUK`HA zr24T!XsM;SzImO(+_8O8-Oa9_zeKgZc`FXxHZ?Qk3vbct4O^iGV2VFmyVi}v0$VCgB_%GOWt|L;M6E39T*Qf5 zs$~O}SdbsW5D|noZIa~Q^(Nuq#nfbfjNnFWG#}4xbZdq>NqWidqK_ zwDnb<;YbB$17vF_S-$XXXPQr*m4Tfb^0Y-8!wEZ$C~(RcURp2Q?VK%nlN~L-1_ks7tjy3MD5cHIA4hYF%HbFj z%_nO3$>&#DAR2nb6Nz$Q3uXi-GuS>HjtVqG8o@Mi2N#b9iZHCl^yWG8S4WQXsyIAo zcM=QSFTQ9bz(hWqObX|NB=B^_5lWjho@Clu+U%L;%1}qb^18di*mG+AkPuQ%AbWDk zFng7MQdz2RL9f>}3!P!7ftfx4_Gp)Z?64Q;nasIFsSl5iW~@qXnw%A&vka7Y z8NpW?0t0Ug_1MsEsnM1<%FkN7Haowhrd`ramb<46vwCS+FmobDkdYCNjzD94Glpna zb#RfNlj2ud1i;Yqbt8^}{SB?My+MtW<;Im`9OTQ81wcW0UOc{hP{dk)5VB8@OYqQ3 z))y>1)rX?t0qmzN0+DUDEC(^fz-~8KtA{HFk12z*dLQCy0)f zRNhODZ9+4Q50-qpO#uh|V*|I6wRrSxO}RTu)d%m6$EvB=3lIj42i3v*0I>np;Sctd zSB_Q2M>B(SN?{9~GM1SVv9>#WXH?T)ULxkccy}U`f+NKpE85=+w&EpNzLnh7Az@Z zI19KVwUemjO{(IiHUj(;DnkG%(1Jj8K|hcIEbe1@kY$2erxQPoO^@wtxSKd8|J@ z{4Y&_nq+8p599jkz-O-ebP$~OWVl+)1YSczie<8KM&I~`m{vkDz4*|gz@5jix9c&4Rzc5Q`;g)LDpw?ObfcrzXjA+uV z1^*ZEh}xWlDl}@1#h=i?zNGaV85^}cPR-<~dNZ|s-JjSP@T4)vUr3GG-0d$?4z=;f zpVm{32~!G8nqf1O;YEe`&K2Mwis=J8iXNG;G( zbr5Q;|DWiX5#(JNdHeVm%B8k?13^F_z2DCG@ksu?T>yia@jpL_`kMlq+OF-#89$N@ z6X9odPfP79&P{5a0-Cbh0Tu{HpKdMRmu~60NRTLjM|r_)INr!%7EGz zoc{p~_~L*Bj9P(8Z3IM>0kv`EpTM?rDgnhv`+w`0)IKbxwww6{l;S4PA0^Y@7#_9U rMH7Wz@IAK%ZSr{A72Q#3_}CO_?A+uvOdmP)K>vmNdg#y7w;%os2WCX* diff --git a/stl/RGBStorage@0.11.0.sty b/stl/RGBStorage@0.11.0.sty deleted file mode 100644 index 529178e4..00000000 --- a/stl/RGBStorage@0.11.0.sty +++ /dev/null @@ -1,234 +0,0 @@ -{- - Id: stl:dYzM3Ct9-SJ8PljY-C!6hB6y-VlWvDE7-DAtNg3y-zanf6hE#media-fresh-cadet - Name: RGBStorage - Version: 0.11.0 - Description: RGB storage library - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -@context -typelib RGBStorage - -import RGBLogic#leonid-melody-quick - use WitnessPos#cliff-enrico-nominal - use WitnessOrd#frank-ohio-forum - -import StrictTypes#century-comrade-chess - use VariantName#theory-austin-before - use FieldName#present-flute-herman - use Primitive#deliver-arrow-boxer - use TySemId#popcorn-super-young - use FieldSemId#spiral-road-marco - use TypeName#edgar-carol-mystery - use UnnamedFieldsSemId#freedom-degree-gregory - use SemId#logic-absorb-hilton - use Variant#humor-regard-promise - use Sizing#courage-alien-salon - use NamedFieldsSemId#solar-salad-smoke - use EnumVariants#dispute-natasha-vega - use VariantInfoSemId#museum-edward-mirror - use UnionVariantsSemId#santana-address-pepper - use TypeSystem#adrian-boris-sponsor - -import BPCore#austin-story-retro - use TapretNodePartner#roger-member-educate - use ExplicitSealTxid#nova-roger-campus - use TapretProof#marco-border-sample - use TapretPathProof#kiwi-mirror-paris - use Method#bali-boris-plasma - use TapretRightBranch#miracle-patriot-touch - use BlindSealTxPtr#fortune-iron-salmon - use OpretProof#good-village-flex - use AnchorMerkleBlockTapretProof#ventura-palma-trumpet - use AnchorMerkleBlockOpretProof#sheriff-alex-degree - use SecretSeal#dollar-iris-wizard - use BlindSealTxid#media-judge-anita - use TxPtr#italian-july-eddie - -import AluVM#congo-archive-folio - use Lib#gate-biology-optimal - use LibSite#ultra-grace-message - use IsaName#taboo-olympic-cloud - use LibId#germany-culture-olivia - use IsaSeg#size-shake-olga - use LibSeg#lemon-philips-horse - -import CommitVerify#miller-pancake-elastic - use ProtocolId#shadow-eclipse-program - use Message#druid-blitz-rover - use MerkleHash#horse-popcorn-bundle - use MerkleBlock#pegasus-delta-eddie - use ReservedBytes1#origin-roger-relax - use ReservedBytes2#florida-libra-circus - use TreeNode#kansas-scarlet-ricardo - use ReservedBytes4#young-goblin-academy - use ReservedBytes8#rudolf-tape-adrian - -import RGBCommit#trident-rover-tape - use ExtensionSchema#active-eddie-empty - use BundleId#carmen-farmer-diesel - use MetaValue#split-package-recycle - use InputMap#octavia-north-gram - use GenesisSchema#iron-forbid-hamlet - use AltLayer1Set#flute-flex-bottle - use Genesis#ford-acrobat-border - use AssignBlindSealTxPtr#harbor-charm-nelson - use TransitionType#picture-reflex-brigade - use Occurrences#source-olga-mirage - use ValencyType#aloha-dublin-brush - use GlobalState#mouse-bambino-brigade - use GlobalStateSchema#silk-college-august - use OwnedStateSchema#cover-shampoo-weather - use ExtensionType#apropos-scoop-viva - use State#aroma-sailor-manila - use AssignmentsBlindSealTxid#shelter-declare-chrome - use MetaType#quebec-mission-quota - use TransitionSchema#jumbo-matrix-normal - use Layer1#camilla-basket-justin - use StateData#nissan-pattern-inside - use AssignmentsBlindSealTxPtr#clone-mayor-patient - use XChainBlindSealTxid#dynamic-life-brown - use AttachId#factor-hair-everest - use AssignmentType#secret-penguin-limit - use XChainTxid#liquid-river-absorb - use XChainBlindSealTxPtr#senator-limbo-raymond - use Opout#yoga-samba-karma - use SchemaId#ramirez-patron-simon - use OpId#picnic-single-gloria - use Schema#eternal-block-totem - use ContractId#uniform-welcome-papa - use TransitionBundle#rubber-permit-martin - use AssignBlindSealTxid#piano-baker-lola - use Inputs#herman-liberal-galaxy - use TypedAssignsBlindSealTxPtr#python-baboon-money - use Extension#swing-virgo-wisdom - use Identity#smart-pioneer-nominal - use AltLayer1#edison-survive-nitro - use TypedAssignsBlindSealTxid#algebra-fresh-wedding - use GlobalValues#verona-iris-senator - use XChainExplicitSealTxid#acid-nepal-melon - use Input#actor-minus-multi - use GlobalStateType#yoga-quick-jasmine - use Ffv#pigment-career-hippie - use XChainSecretSeal#alex-griffin-left - use Valencies#light-letter-comet - use Redeemed#mile-lady-perfect - use Transition#economy-ethnic-audio - use Metadata#member-nobody-imitate - use XChainPubWitness#figure-gram-wave - -import Std#ralph-blue-lucky - use AlphaCaps#picnic-soprano-aurora - use AsciiPrintable#ultra-sunset-format - use Bool#oxygen-complex-duet - use U5#orbit-graph-sonic - use AlphaNumDash#sponsor-snake-nice - use AlphaCapsNum#aladdin-zebra-marble - use AlphaNumLodash#percent-bingo-caesar - use AlphaCapsLodash#duet-hammer-labor - use AlphaSmallLodash#pioneer-eagle-spell - -import RGBStd#mango-inside-shelf - use PubWitness#paper-visa-storm - use ContentRef#polo-ramirez-parker - use SigBlob#insect-cello-avalon - use AnnotationName#domino-waiter-orlando - use TransitionIface#axiom-parker-pyramid - use NamedFieldTransitionType#express-brush-desire - use ExtensionIface#model-ramirez-mentor - use IfaceId#nova-cola-carbon - use ValencyIface#buzzer-holiday-fiber - use Annotations#spend-linda-romeo - use IfaceImpl#coconut-snake-formula - use VerNo#textile-next-stretch - use NamedFieldValencyType#invest-apollo-inca - use ImplId#seminar-data-table - use SupplSub#canoe-denmark-short - use Allocation#water-poker-tape - use Supplement#caviar-zebra-precise - use SupplId#pilot-claudia-minute - use NamedFieldExtensionType#tuna-archer-melon - use NamedFieldGlobalStateType#museum-ohio-arizona - use GenesisIface#rocket-paradox-press - use SchemaIfaces#popcorn-rider-panel - use AnchorSet#pluto-plasma-diagram - use ContentSigs#oval-sister-triton - use SupplItem#jargon-orchid-forget - use Modifier#saturn-escort-jordan - use NamedFieldAssignmentType#origin-caramel-flipper - use TrustLevel#cobra-script-albino - use AssignIface#optic-hippie-isabel - use StateAbi#thermos-demo-fragile - use NamedFieldMetaType#prefix-carmen-artist - use NamedVariantu8#star-pilgrim-pilgrim - use OpWitness#valid-toronto-gibson - use SealWitness#cotton-lopez-isabel - use GlobalIface#concert-combat-charm - use SupplMap#sailor-observe-bundle - use Iface#citizen-oxford-norway - use ContentId#scarlet-portal-office - use GlobalOut#capital-agatha-bruno - -import Bitcoin#signal-color-cipher - use SeqNo#copper-verbal-ingrid - use TxIn#slang-cherry-gizmo - use Vout#brush-gloria-heroic - use ScriptBytes#equator-cockpit-gong - use TapNodeHash#paprika-amanda-hunter - use LockTime#lobster-liberal-jump - use SigScript#neptune-spiral-sample - use LeafScript#bison-doctor-oscar - use TxOut#aspect-eddie-message - use Sats#metro-picasso-roger - use Witness#engine-daniel-magnum - use Txid#shallow-light-reverse - use TxVer#nepal-symbol-uniform - use InternalPk#habitat-paprika-oliver - use LeafVer#benefit-carbon-africa - use ScriptPubkey#second-lobster-philips - use ByteStr#royal-anatomy-june - use Tx#radar-salon-page - use Outpoint#logo-alamo-madam - use XOnlyPk#clever-swim-carpet - - -@mnemonic(carol-salute-aroma) -data ContractIndex : publicOpouts {RGBCommit.Opout ^ ..0xffffff}, outpointOpouts {RGBCommit.XChainExplicitSealTxid -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xffffff}} - -@mnemonic(fire-domingo-monaco) -data MemContractState : schemaId RGBCommit.SchemaId - , contractId RGBCommit.ContractId - , global {RGBCommit.GlobalStateType -> ^ ..0xff MemGlobalState} - , owned {RGBStd.Allocation ^ ..0xffffffff} - -@mnemonic(mary-mineral-frame) -data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.StateData}, limit U24 - -@mnemonic(savage-joshua-clone) -data MemIndex : opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit.BundleId} - , bundleContractIndex {RGBCommit.BundleId -> ^ ..0xffffff RGBCommit.ContractId} - , bundleWitnessIndex {RGBCommit.BundleId -> ^ ..0xffffff {RGBCommit.XChainTxid ^ ..0xff}} - , contractIndex {RGBCommit.ContractId -> ^ ..0xff ContractIndex} - , terminalIndex {RGBCommit.XChainSecretSeal -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xff}} - -@mnemonic(summer-sardine-disney) -data MemStash : schemata {RGBCommit.SchemaId -> ^ ..0xff RGBStd.SchemaIfaces} - , ifaces {RGBStd.IfaceId -> ^ ..0xff RGBStd.Iface} - , geneses {RGBCommit.ContractId -> ^ ..0xff RGBCommit.Genesis} - , suppl {RGBStd.ContentRef -> ^ ..0xff {RGBStd.Supplement ^ ..0xff}} - , bundles {RGBCommit.BundleId -> ^ ..0xffffffff RGBCommit.TransitionBundle} - , extensions {RGBCommit.OpId -> ^ ..0xffffffff RGBCommit.Extension} - , witnesses {RGBCommit.XChainTxid -> ^ ..0xffffffff RGBStd.SealWitness} - , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} - , secretSeals {RGBCommit.XChainBlindSealTxPtr ^ ..0xffffff} - , typeSystem StrictTypes.TypeSystem - , identities {RGBCommit.Identity -> RGBStd.TrustLevel} - , libs {AluVM.LibId -> AluVM.Lib} - , sigs {RGBStd.ContentId -> RGBStd.ContentSigs} - -@mnemonic(paradox-polka-juliet) -data MemState : witnesses {RGBCommit.XChainTxid -> ^ ..0xffffffff RGBLogic.WitnessOrd}, contracts {RGBCommit.ContractId -> ^ ..0xff MemContractState} - - diff --git a/stl/Transfer.vesper b/stl/Transfer.vesper deleted file mode 100644 index 08cfaa9f..00000000 --- a/stl/Transfer.vesper +++ /dev/null @@ -1,764 +0,0 @@ -{- - Description: RGB Transfer - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -Seals vesper lexicon=types+commitments - -ConsignmentId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:consignment#2024-03-11 - ContainerVer serialized - Bool serialized - ContractId serialized - DiscloseHash serialized - ImplId set len=0..MAX8 - ImplId element - DiscloseHash set len=0..MAX32 - DiscloseHash element - DiscloseHash set len=0..MAX32 - DiscloseHash element - XChainSecretSeal map len=0..MAX16 - BundleId mapKey - XChainSecretSeal mapValue - AttachId set len=0..MAX16 - AttachId element - SupplId set len=0..MAX8 - SupplId element - TypeSysId serialized - LibId set len=0..MAX16 - LibId element - ContentSigs map len=0..MAX8 - ContentId mapKey - ContentSigs mapValue - -Consignmenttrue rec - version enum ContainerVer v2=2 - transfer enum Bool false=0 true=1 - terminals map len=0..MAX16 - value union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - genesis rec Genesis - ffv is U16 aka=Ffv - schemaId bytes len=32 aka=SchemaId - flags bytes len=1 aka=ReservedBytes1 - timestamp is I64 - issuer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - testnet enum Bool false=0 true=1 - altLayers1 set len=0..MAX8 aka=AltLayer1Set - AltLayer1 enum liquid=1 - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=StateData - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxid - key is U16 aka=AssignmentType - value list len=1..MAX16 aka=TypedAssignsBlindSealTxid - AssignBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - extensions set len=0..MAX32 - Extension rec - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - extensionType is U16 aka=ExtensionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=StateData - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxid - key is U16 aka=AssignmentType - value list len=1..MAX16 aka=TypedAssignsBlindSealTxid - AssignBlindSealTxid union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=1 - seal union XChainBlindSealTxid - bitcoin rec BlindSealTxid wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxid wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - redeemed map len=0..MAX8 aka=Redeemed - key is U16 aka=ValencyType - value bytes len=32 aka=OpId - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 - bundles set len=0..MAX32 - WitnessBundle rec - anchoredBundles union AnchoredBundles - tapret rec ClientBundleTapretProof wrapped tag=0 - mpcProof rec MerkleProof - pos is U32 - cofactor is U16 - path list len=0..32 - element bytes len=32 aka=MerkleHash - dbcProof rec TapretProof - pathProof rec TapretPathProof - some union TapretNodePartner option wrapped tag=1 - rightBranch rec TapretRightBranch wrapped tag=2 - nonce is U8 - bundle rec TransitionBundle - closeMethod enum Method opretFirst=0 tapretFirst=1 - inputMap map len=1..MAX16 aka=InputMap - key is U32 aka=Vout - value bytes len=32 aka=OpId - knownTransitions map len=1..MAX16 - key bytes len=32 aka=OpId - value rec Transition - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - transitionType is U16 aka=TransitionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=StateData - inputs set len=0..MAX16 aka=Inputs - Input rec - prevOut rec Opout - op bytes len=32 aka=OpId - ty is U16 aka=AssignmentType - no is U16 - reserved bytes len=2 aka=ReservedBytes2 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr - key is U16 aka=AssignmentType - value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr - AssignBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 - opret rec ClientBundleOpretProof wrapped tag=1 - mpcProof rec MerkleProof - pos is U32 - cofactor is U16 - path list len=0..32 - element bytes len=32 aka=MerkleHash - dbcProof is Unit aka=OpretProof - bundle rec TransitionBundle - closeMethod enum Method opretFirst=0 tapretFirst=1 - inputMap map len=1..MAX16 aka=InputMap - key is U32 aka=Vout - value bytes len=32 aka=OpId - knownTransitions map len=1..MAX16 - key bytes len=32 aka=OpId - value rec Transition - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - transitionType is U16 aka=TransitionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=StateData - inputs set len=0..MAX16 aka=Inputs - Input rec - prevOut rec Opout - op bytes len=32 aka=OpId - ty is U16 aka=AssignmentType - no is U16 - reserved bytes len=2 aka=ReservedBytes2 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr - key is U16 aka=AssignmentType - value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr - AssignBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 - double rec tag=2 - tapret rec ClientBundleTapretProof - mpcProof rec MerkleProof - pos is U32 - cofactor is U16 - path list len=0..32 - element bytes len=32 aka=MerkleHash - dbcProof rec TapretProof - pathProof rec TapretPathProof - some union TapretNodePartner option wrapped tag=1 - rightBranch rec TapretRightBranch wrapped tag=2 - nonce is U8 - bundle rec TransitionBundle - closeMethod enum Method opretFirst=0 tapretFirst=1 - inputMap map len=1..MAX16 aka=InputMap - key is U32 aka=Vout - value bytes len=32 aka=OpId - knownTransitions map len=1..MAX16 - key bytes len=32 aka=OpId - value rec Transition - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - transitionType is U16 aka=TransitionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=StateData - inputs set len=0..MAX16 aka=Inputs - Input rec - prevOut rec Opout - op bytes len=32 aka=OpId - ty is U16 aka=AssignmentType - no is U16 - reserved bytes len=2 aka=ReservedBytes2 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr - key is U16 aka=AssignmentType - value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr - AssignBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 - opret rec ClientBundleOpretProof - mpcProof rec MerkleProof - pos is U32 - cofactor is U16 - path list len=0..32 - element bytes len=32 aka=MerkleHash - dbcProof is Unit aka=OpretProof - bundle rec TransitionBundle - closeMethod enum Method opretFirst=0 tapretFirst=1 - inputMap map len=1..MAX16 aka=InputMap - key is U32 aka=Vout - value bytes len=32 aka=OpId - knownTransitions map len=1..MAX16 - key bytes len=32 aka=OpId - value rec Transition - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - transitionType is U16 aka=TransitionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=StateData - inputs set len=0..MAX16 aka=Inputs - Input rec - prevOut rec Opout - op bytes len=32 aka=OpId - ty is U16 aka=AssignmentType - no is U16 - reserved bytes len=2 aka=ReservedBytes2 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr - key is U16 aka=AssignmentType - value list len=1..MAX16 aka=TypedAssignsBlindSealTxPtr - AssignBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec State - reserved bytes len=1 aka=ReservedBytes1 - data bytes len=0..MAX16 aka=StateData - some bytes len=32 option wrapped aka=AttachId tag=1 - lock bytes len=2 aka=ReservedBytes2 - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 - schema rec Schema - ffv is U16 aka=Ffv - flags bytes len=1 aka=ReservedBytes1 - name ascii aka=TypeName first=AlphaCapsLodash rest=AlphaNumLodash len=1..100 - timestamp is I64 - developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - metaTypes map len=0..MAX8 - key is U16 aka=MetaType - value bytes len=32 aka=SemId - globalTypes map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec GlobalStateSchema - reserved bytes len=1 aka=ReservedBytes1 - semId bytes len=32 aka=SemId - maxItems is U24 - ownedTypes map len=0..MAX8 - key is U16 aka=AssignmentType - value rec OwnedStateSchema - reserved bytes len=1 aka=ReservedBytes1 - semId bytes len=32 aka=SemId - valencyTypes set len=0..MAX8 - element is U16 aka=ValencyType - genesis rec GenesisSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - extensions map len=0..MAX8 - key is U16 aka=ExtensionType - value rec ExtensionSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - redeems set len=0..MAX8 - element is U16 aka=ValencyType - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - transitions map len=0..MAX8 - key is U16 aka=TransitionType - value rec TransitionSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - inputs map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - ifaces map len=0..MAX8 - key rec Iface - version enum VerNo v0=0 v1=1 - name ascii aka=TypeName first=AlphaCapsLodash rest=AlphaNumLodash len=1..100 - inherits list len=0..MAX8 - element bytes len=32 aka=IfaceId - timestamp is I64 - metadata map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value bytes len=32 aka=SemId - globalState map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec GlobalIface - some bytes len=32 option wrapped aka=SemId tag=1 - required enum Bool false=0 true=1 - multiple enum Bool false=0 true=1 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec AssignIface - some bytes len=32 option wrapped aka=SemId tag=1 - some enum Bool option wrapped false=0 true=1 tag=1 - public enum Bool false=0 true=1 - required enum Bool false=0 true=1 - multiple enum Bool false=0 true=1 - valencies map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec ValencyIface - required enum Bool false=0 true=1 - genesis rec GenesisIface - modifier enum Modifier abstract=0 override=1 final=255 - metadata set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - globals map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - errors set len=0..MAX8 - element ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - transitions map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec TransitionIface - modifier enum Modifier abstract=0 override=1 final=255 - optional enum Bool false=0 true=1 - metadata set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - globals map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - inputs map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - errors set len=0..MAX8 - element ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - some ascii option wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=1 - extensions map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec ExtensionIface - modifier enum Modifier abstract=0 override=1 final=255 - optional enum Bool false=0 true=1 - metadata set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - globals map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - redeems set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - valencies set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - errors set len=0..MAX8 - element ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - some ascii option wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=1 - some ascii option wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=1 - errors map len=0..MAX8 - key ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value str len=0..MAX8 - developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - value rec IfaceImpl - version enum VerNo v0=0 v1=1 - schemaId bytes len=32 aka=SchemaId - ifaceId bytes len=32 aka=IfaceId - timestamp is I64 - metadata set len=0..MAX8 - NamedFieldMetaType rec - id is U16 aka=MetaType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - globalState set len=0..MAX8 - NamedFieldGlobalStateType rec - id is U16 aka=GlobalStateType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - assignments set len=0..MAX8 - NamedFieldAssignmentType rec - id is U16 aka=AssignmentType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - valencies set len=0..MAX8 - NamedFieldValencyType rec - id is U16 aka=ValencyType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - transitions set len=0..MAX8 - NamedFieldTransitionType rec - id is U16 aka=TransitionType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - extensions set len=0..MAX8 - NamedFieldExtensionType rec - id is U16 aka=ExtensionType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - errors set len=0..MAX8 - NamedVariantu8 rec - id is U8 - name ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - stateAbi rec StateAbi - regInput rec LibSite - lib bytes len=32 aka=LibId - pos is U16 - regOutput rec LibSite - lib bytes len=32 aka=LibId - pos is U16 - calcOutput rec LibSite - lib bytes len=32 aka=LibId - pos is U16 - calcChange rec LibSite - lib bytes len=32 aka=LibId - pos is U16 - supplements set len=0..MAX8 - Supplement rec - contentId union ContentRef - schema bytes len=32 wrapped aka=SchemaId tag=0 - genesis bytes len=32 wrapped aka=ContractId tag=1 - iface bytes len=32 wrapped aka=IfaceId tag=2 - ifaceImpl bytes len=32 wrapped aka=ImplId tag=3 - timestamp is I64 - creator ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - annotations map len=0..MAX8 - key enum { - SupplSub itself=0 meta=1 global=2 owned=3 valency=4 assignment=5 genesis=6 transition=7 - extension=8 exception=9 - } - value map len=0..MAX8 aka=SupplMap - key union SupplItem - default is Unit tag=0 - typeNo is U16 wrapped tag=1 - typeName ascii wrapped aka=TypeName first=AlphaCapsLodash rest=AlphaNumLodash len=1..100 tag=2 - fieldName ascii wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=3 - variantName ascii wrapped aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=4 - value map len=0..MAX8 aka=Annotations - key ascii aka=AnnotationName first=AlphaCaps rest=AlphaNumDash len=1..MAX8 - value bytes len=0..MAX16 - types map len=0..MAX24 aka=TypeSystem - key bytes len=32 aka=SemId - value union TySemId - primitive is U8 wrapped aka=Primitive tag=0 - unicode is Unit tag=1 - enum set len=1..MAX8 wrapped aka=EnumVariants tag=2 - Variant rec - name ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - tag is U8 - union map len=0..MAX8 wrapped aka=UnionVariantsSemId tag=3 - key is U8 - value rec VariantInfoSemId - name ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - ty bytes len=32 aka=SemId - tuple list len=1..MAX8 wrapped aka=UnnamedFieldsSemId tag=4 - element bytes len=32 aka=SemId - struct list len=1..MAX8 wrapped aka=NamedFieldsSemId tag=5 - FieldSemId rec - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - ty bytes len=32 aka=SemId - array tuple tag=6 - _ bytes len=32 aka=SemId - _ is U16 - list tuple tag=7 - _ bytes len=32 aka=SemId - Sizing rec - min is U64 - max is U64 - set tuple tag=8 - _ bytes len=32 aka=SemId - Sizing rec - min is U64 - max is U64 - map tuple tag=9 - _ bytes len=32 aka=SemId - _ bytes len=32 aka=SemId - Sizing rec - min is U64 - max is U64 - scripts set len=0..1024 - Lib rec - isae set len=0..64 aka=IsaSeg - element ascii aka=IsaName first=AlphaCaps rest=AlphaCapsNum len=2..8 - code bytes len=0..MAX16 - data bytes len=0..MAX16 - libs set len=0..MAX8 aka=LibSeg - element bytes len=32 aka=LibId - attachments map len=0..MAX16 - key bytes len=32 aka=AttachId - value bytes len=0..MAX24 - signatures map len=0..MAX8 - key union ContentId - schema bytes len=32 wrapped aka=SchemaId tag=0 - genesis bytes len=32 wrapped aka=ContractId tag=1 - iface bytes len=32 wrapped aka=IfaceId tag=2 - ifaceImpl bytes len=32 wrapped aka=ImplId tag=3 - suppl bytes len=32 wrapped aka=SupplId tag=4 - value map len=1..10 aka=ContentSigs - key ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - value bytes len=1..4096 aka=SigBlob - diff --git a/stl/src/main.rs b/stl/src/main.rs deleted file mode 100644 index f41e32da..00000000 --- a/stl/src/main.rs +++ /dev/null @@ -1,133 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. 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::fs; -use std::io::Write; - -use commit_verify::CommitmentLayout; -use rgbstd::containers::Transfer; -use rgbstd::stl::{ - aluvm_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, rgb_logic_stl, - rgb_std_stl, rgb_storage_stl, -}; -use strict_types::stl::{std_stl, strict_types_stl}; -use strict_types::{parse_args, StlFormat, SystemBuilder}; - -fn main() { - let (_, dir) = parse_args(); - let dir = dir.unwrap_or_else(|| "./stl".to_owned()); - - let rgb_std = rgb_std_stl(); - rgb_std - .serialize(StlFormat::Binary, Some(&dir), "0.11.0", None) - .expect("unable to write to the file"); - rgb_std - .serialize(StlFormat::Armored, Some(&dir), "0.11.0", None) - .expect("unable to write to the file"); - rgb_std - .serialize( - StlFormat::Source, - Some(&dir), - "0.11.0", - Some( - " - Description: RGB standard library - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0", - ), - ) - .expect("unable to write to the file"); - - let rgb_storage = rgb_storage_stl(); - rgb_storage - .serialize(StlFormat::Binary, Some(&dir), "0.11.0", None) - .expect("unable to write to the file"); - rgb_storage - .serialize(StlFormat::Armored, Some(&dir), "0.11.0", None) - .expect("unable to write to the file"); - rgb_storage - .serialize( - StlFormat::Source, - Some(&dir), - "0.11.0", - Some( - " - Description: RGB storage library - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0", - ), - ) - .expect("unable to write to the file"); - - let std = std_stl(); - let rgb = rgb_std_stl(); - let rgb_commit = rgb_commit_stl(); - let rgb_logic = rgb_logic_stl(); - let tx = bp_tx_stl(); - let bp = bp_core_stl(); - let cv = commit_verify_stl(); - let st = strict_types_stl(); - let vm = aluvm_stl(); - - let sys = SystemBuilder::new() - .import(rgb) - .unwrap() - .import(rgb_logic) - .unwrap() - .import(rgb_commit) - .unwrap() - .import(vm) - .unwrap() - .import(bp) - .unwrap() - .import(tx) - .unwrap() - .import(cv) - .unwrap() - .import(st) - .unwrap() - .import(std) - .unwrap() - .finalize() - .expect("not all libraries present"); - - let mut file = fs::File::create(format!("{dir}/Transfer.vesper")).unwrap(); - writeln!( - file, - "{{- - Description: RGB Transfer - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --}} - -Seals vesper lexicon=types+commitments -" - ) - .unwrap(); - let layout = Transfer::commitment_layout(); - writeln!(file, "{layout}").unwrap(); - let tt = sys.type_tree("RGBStd.Consignmenttrue").unwrap(); - writeln!(file, "{tt}").unwrap(); -} From b114c747e11c8380bb0ad67873ca462eee9eb2f9 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 8 Dec 2024 13:26:33 +0100 Subject: [PATCH 18/70] remove unneeded components --- cli/src/cmd.rs | 7 --- src/bp/anchor.rs | 39 ------------- src/bp/mod.rs | 26 --------- src/bp/seals.rs | 147 ----------------------------------------------- 4 files changed, 219 deletions(-) delete mode 100644 src/bp/anchor.rs delete mode 100644 src/bp/mod.rs delete mode 100644 src/bp/seals.rs diff --git a/cli/src/cmd.rs b/cli/src/cmd.rs index bc15f6ea..480ccb64 100644 --- a/cli/src/cmd.rs +++ b/cli/src/cmd.rs @@ -133,13 +133,6 @@ pub enum Cmd { }, } -pub enum Treasure { - Opret(Stockpile, FilePile>, FilePersistence>), - Tapret(Stockpile, FilePile>, FilePersistence>), -} - -pub struct Barrow(BTreeMap); - impl Args { pub fn exec(&self) -> anyhow::Result<()> { let mound = Mound::excavate(&self.data_dir); diff --git a/src/bp/anchor.rs b/src/bp/anchor.rs deleted file mode 100644 index e8216856..00000000 --- a/src/bp/anchor.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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 amplify::confinement::SmallOrdMap; -use rgb::ContractId; - -pub struct SubAnchor { - pub mmb_proof: mmb::BundleProof, - #[cfg_attr(feature = "serde", serde(skip))] - // TODO: This should become an option once fallback proofs are ready - pub fallback_proof: ReservedBytes<1>, -} - -pub struct SuperAnchor { - pub mpc_proof: mpc::MerkleBlock, - pub dbc_proof: D, - pub contracts: SmallOrdMap, -} diff --git a/src/bp/mod.rs b/src/bp/mod.rs deleted file mode 100644 index 6f061482..00000000 --- a/src/bp/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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. - -mod anchor; -pub mod seals; diff --git a/src/bp/seals.rs b/src/bp/seals.rs deleted file mode 100644 index 95c5009c..00000000 --- a/src/bp/seals.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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. - -#![doc = include_str!("seals.md")] - -use bp::seals::txout::{BlindSeal, CloseMethod, SealTxid}; -use bp::secp256k1::rand::{thread_rng, RngCore}; -use bp::Vout; -use rgb::{Assign, ExposedSeal, GraphSeal, Layer1, SecretSeal, State, XChain}; - -use crate::LIB_NAME_RGB_STD; - -/// Seal definition which re-uses witness transaction id of some other seal, -/// which is not known at the moment of seal construction. Thus, the definition -/// has only information about output number. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)] -#[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 VoutSeal { - /// Commitment to the specific seal close method [`CloseMethod`] which must - /// be used to close this seal. - pub method: CloseMethod, - - /// Tx output number, which should be always known. - pub vout: Vout, - - /// Blinding factor providing confidentiality of the seal definition. - /// Prevents rainbow table bruteforce attack based on the existing - /// blockchain txid set. - pub blinding: u64, -} - -impl VoutSeal { - /// Creates new seal definition for the provided output number and seal - /// closing method. Uses `thread_rng` to initialize blinding factor. - #[inline] - pub fn new(method: CloseMethod, vout: impl Into) -> Self { - VoutSeal::with(method, vout, thread_rng().next_u64()) - } - - /// Creates new opret-seal seal definition for the provided output number - /// and seal closing method. Uses `thread_rng` to initialize blinding - /// factor. - #[inline] - pub fn new_opret(vout: impl Into) -> Self { VoutSeal::new(CloseMethod::OpretFirst, vout) } - - /// Creates new tapret-seal seal definition for the provided output number - /// and seal closing method. Uses `thread_rng` to initialize blinding - /// factor. - #[inline] - pub fn new_tapret(vout: impl Into) -> Self { - VoutSeal::new(CloseMethod::TapretFirst, vout) - } - - /// Reconstructs previously defined opret seal given an output number and a - /// previously generated blinding factor. - #[inline] - pub fn with_opret(vout: impl Into, blinding: u64) -> Self { - VoutSeal::with(CloseMethod::OpretFirst, vout, blinding) - } - - /// Reconstructs previously defined tapret seal given an output number and a - /// previously generated blinding factor. - #[inline] - pub fn with_tapret(vout: impl Into, blinding: u64) -> Self { - VoutSeal::with(CloseMethod::TapretFirst, vout, blinding) - } - - /// Reconstructs previously defined seal given method, an output number and - /// a previously generated blinding factor. - #[inline] - pub fn with(method: CloseMethod, vout: impl Into, blinding: u64) -> Self { - VoutSeal { - method, - vout: vout.into(), - blinding, - } - } -} - -impl From for GraphSeal { - fn from(seal: VoutSeal) -> Self { - Self::with_blinded_vout(seal.method, seal.vout, seal.blinding) - } -} - -/// 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 { - Revealed(XChain), - #[from] - Concealed(XChain), -} - -impl From>> for BuilderSeal> { - fn from(seal: XChain>) -> Self { BuilderSeal::Revealed(seal) } -} - -impl BuilderSeal { - pub fn layer1(&self) -> Layer1 { - match self { - BuilderSeal::Revealed(x) => x.layer1(), - BuilderSeal::Concealed(x) => x.layer1(), - } - } - - pub fn assignment(self, state: State) -> Assign { - match self { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state, - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::Confidential { - seal, - state, - lock: none!(), - }, - } - } -} From 2a96e742e3359abbd2cd6f0fe8972b08d4df8908 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 8 Dec 2024 13:32:52 +0100 Subject: [PATCH 19/70] simplify workspace to a single package --- Cargo.lock | 135 ----------------------------- Cargo.toml | 48 ++--------- cli/Cargo.toml | 22 ----- cli/src/cmd.rs | 216 ---------------------------------------------- cli/src/main.rs | 33 ------- examples/token.rs | 90 ------------------- src/lib.rs | 11 --- 7 files changed, 9 insertions(+), 546 deletions(-) delete mode 100644 cli/Cargo.toml delete mode 100644 cli/src/cmd.rs delete mode 100644 cli/src/main.rs delete mode 100644 examples/token.rs diff --git a/Cargo.lock b/Cargo.lock index 1089c2b7..f18075cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,61 +81,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "anyhow" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" - [[package]] name = "arrayvec" version = "0.7.6" @@ -326,52 +271,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "clap" -version = "4.5.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - [[package]] name = "commit_encoding_derive" version = "0.12.0-beta.1" @@ -540,12 +439,6 @@ dependencies = [ "serde", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - [[package]] name = "itoa" version = "1.0.14" @@ -698,7 +591,6 @@ dependencies = [ "hypersonic", "rand", "rgb-core", - "serde", "single_use_seals", "strict_encoding", "strict_types", @@ -706,21 +598,6 @@ dependencies = [ "wasm-bindgen-test", ] -[[package]] -name = "rgbx" -version = "0.12.0-alpha.1" -dependencies = [ - "amplify", - "anyhow", - "bp-core", - "clap", - "hypersonic", - "rgb-std", - "serde", - "serde_yaml", - "strict_encoding", -] - [[package]] name = "ripemd" version = "0.1.3" @@ -932,12 +809,6 @@ dependencies = [ "serde_str_helpers", ] -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "syn" version = "1.0.109" @@ -1047,12 +918,6 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 529f45d4..c4856c31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,7 @@ -[workspace] -members = [".", "cli"] -default-members = ["."] -resolver = "2" - -[workspace.package] +[package] +name = "rgb-std" version = "0.12.0-alpha.1" +description = "Standard Library for RGB smart contracts" authors = ["Dr Maxim Orlovsky "] homepage = "https://github.com/RGB-WG" repository = "https://github.com/RGB-WG/rgb-std" @@ -13,53 +10,26 @@ categories = ["cryptography::cryptocurrencies"] rust-version = "1.77.0" # Due to use of `rustfix` edition = "2021" license = "Apache-2.0" +readme = "README.md" -[workspace.dependencies] +[lib] +name = "rgbstd" +crate-type = ["cdylib", "rlib"] # We need this for WASM + +[dependencies] amplify = "4.8.0" strict_encoding = "2.8.1" strict_types = "2.8.1" commit_verify = "0.12.0-beta.1" single_use_seals = "0.12.0-beta.1" hypersonic = "0.12.0-beta.1" -rgb-std = { version = "0.12.0-alpha.1", path = "." } bp-core = "0.12.0-beta.2" rgb-core = "0.12.0-beta.3" -serde = { package = "serde", version = "1", features = ["derive"] } - -[package] -name = "rgb-std" -version = { workspace = true } -description = "Standard Library for RGB smart contracts" -keywords = { workspace = true } -categories = { workspace = true } -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -rust-version = { workspace = true } -readme = "README.md" - -[lib] -name = "rgbstd" -crate-type = ["cdylib", "rlib"] # We need this for WASM - -[dependencies] -amplify = { workspace = true } -strict_encoding = { workspace = true } -strict_types = { workspace = true } -commit_verify = { workspace = true } -single_use_seals = { workspace = true } -hypersonic = { workspace = true } -bp-core = { workspace = true } -rgb-core = { workspace = true } -serde = { workspace = true, optional = true } [features] default = [] all = ["fs", "serde"] serde = [ - "dep:serde", "amplify/serde", "strict_encoding/serde", "strict_types/serde", diff --git a/cli/Cargo.toml b/cli/Cargo.toml deleted file mode 100644 index b11893df..00000000 --- a/cli/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "rgbx" -version.workspace = true -authors.workspace = true -repository.workspace = true -homepage.workspace = true -keywords.workspace = true -readme.workspace = true -license.workspace = true -edition.workspace = true -rust-version.workspace = true - -[dependencies] -amplify.workspace = true -strict_encoding.workspace = true -hypersonic = { workspace = true, features = ["persist-file"] } -bp-core.workspace = true -rgb-std = { workspace = true, features = ["fs"] } -serde.workspace = true -serde_yaml = "0.9.34" -anyhow = "1.0.93" -clap = { version = "4.5.21", features = ["derive"] } diff --git a/cli/src/cmd.rs b/cli/src/cmd.rs deleted file mode 100644 index 480ccb64..00000000 --- a/cli/src/cmd.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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; -use std::fs::File; -use std::path::{Path, PathBuf}; - -use bp::dbc::opret::OpretProof; -use bp::dbc::tapret::TapretProof; -use bp::seals::TxoSeal; -use hypersonic::{ - Articles, AuthToken, CallParams, ContractId, IssueParams, Schema, Stock, -}; -use rgbstd::{FilePile, Mound, Stockpile}; -use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictReader, StrictWriter}; - -pub const WALLET_ENV: &str = "RGB_WALLET"; - -pub const DATA_DIR_ENV: &str = "RGB_DATA_DIR"; -#[cfg(target_os = "linux")] -pub const DATA_DIR: &str = "~/.rgb"; -#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] -pub const DATA_DIR: &str = "~/.rgb"; -#[cfg(target_os = "macos")] -pub const DATA_DIR: &str = "~/Library/Application Support/RGB Smart Contracts"; -#[cfg(target_os = "windows")] -pub const DATA_DIR: &str = "~\\AppData\\Local\\RGB Smart Contracts"; -#[cfg(target_os = "ios")] -pub const DATA_DIR: &str = "~/Documents"; -#[cfg(target_os = "android")] -pub const DATA_DIR: &str = "."; - -#[derive(Parser)] -pub struct Args { - /// Location of the data directory - #[clap( - short, - long, - global = true, - default_value = DATA_DIR, - env = DATA_DIR_ENV, - value_hint = ValueHint::DirPath - )] - pub data_dir: PathBuf, - - /// Command to execute - #[clap(subcommand)] - pub command: Cmd, -} - -#[derive(Parser)] -pub enum Cmd { - /// Issue a new RGB contract - #[clap(alias = "i")] - Issue { - /// Schema used to issue the contract - schema: PathBuf, - - /// Parameters and data for the contract - params: PathBuf, - }, - - /// Import contract articles - Import { - /// Contract articles to process - articles: PathBuf, - }, - - /// Export contract articles - Export { - /// Path to export articles to - articles: PathBuf, - }, - - /// Create a new wallet - Create { descriptor: String }, - - /// Print out a contract state - #[clap(alias = "s")] - State { - /// Present all the state, not just the one owned by the wallet - #[clap(short, long, global = true)] - all: bool, - - /// Contract directory - contract: ContractId, - }, - - /// Make a contract call - #[clap(aliases = ["e", "exec"])] - Execute { - /// YAML file with a script to execute - script: PathBuf, - }, - - /// Create a consignment transferring part of a contract state to another peer - #[clap(alias = "c")] - Consign { - /// List of tokens of authority which should serve as a contract terminals. - #[clap(short, long)] - terminals: Vec, - - /// Location to save the consignment file to - output: PathBuf, - }, - - /// Verify and accept a consignment - #[clap(alias = "a")] - Accept { - /// File with consignment to accept - input: PathBuf, - }, -} - -impl Args { - pub fn exec(&self) -> anyhow::Result<()> { - let mound = Mound::excavate(&self.data_dir); - match &self.command { - Cmd::Issue { schema, params } => todo!(), - Cmd::Import { .. } => todo!(), - Cmd::Export { .. } => todo!(), - Cmd::Create { .. } => todo!(), - Cmd::State { .. } => todo!(), - Cmd::Execute { .. } => todo!(), - Cmd::Consign { .. } => todo!(), - Cmd::Accept { .. } => todo!(), - } - Ok(()) - } -} - -impl Barrow { - pub fn issue(&self, schema: &Path, form: &Path, output: Option<&Path>) -> anyhow::Result<()> { - let schema = Schema::load(schema)?; - let file = File::open(form)?; - let params = serde_yaml::from_reader::<_, IssueParams>(file)?; - - let path = output.unwrap_or(form); - let output = path.with_file_name(&format!("{}.articles", params.name)); - - let articles = schema.issue::(params); - articles.save(output)?; - - Ok(()) - } -} - -fn process(articles: &Path, stock: Option<&Path>) -> anyhow::Result<()> { - let path = stock.unwrap_or(articles); - - let articles = Articles::::load(articles)?; - Stock::new(articles, path); - - Ok(()) -} - -fn state(path: &Path) { - let stock = Stock::::load(path); - let val = serde_yaml::to_string(&stock.state().main).expect("unable to generate YAML"); - println!("{val}"); -} - -fn call(stock: &Path, form: &Path) -> anyhow::Result<()> { - let mut stock = Stock::::load(stock); - let file = File::open(form)?; - let call = serde_yaml::from_reader::<_, CallParams>(file)?; - let opid = stock.call(call); - println!("Operation ID: {opid}"); - Ok(()) -} - -fn export<'a>( - stock: &Path, - terminals: impl IntoIterator, - output: &Path, -) -> anyhow::Result<()> { - let mut stock = Stock::::load(stock); - let file = File::create_new(output)?; - let writer = StrictWriter::with(StreamWriter::new::<{ usize::MAX }>(file)); - stock.export(terminals, writer)?; - Ok(()) -} - -fn accept(stock: &Path, input: &Path) -> anyhow::Result<()> { - let mut stock = Stock::::load(stock); - let file = File::open(input)?; - let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); - - let articles = Articles::::strict_decode(&mut reader)?; - if articles.contract_id() != stock.contract_id() { - return Err("Contract ID mismatch".into()); - } - - stock.consume() -} diff --git a/cli/src/main.rs b/cli/src/main.rs deleted file mode 100644 index 31609d9c..00000000 --- a/cli/src/main.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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. - -#[macro_use] -extern crate clap; - -mod cmd; - -use clap::Parser; -use cmd::Cmd; - -fn main() -> anyhow::Result<()> { Cmd::parse().exec() } diff --git a/examples/token.rs b/examples/token.rs deleted file mode 100644 index c8ecde75..00000000 --- a/examples/token.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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. - -#[macro_use] -extern crate amplify; -#[macro_use] -extern crate strict_types; - -use hypersonic::Schema; -use rgbstd::Stockpile; - -fn main() { - let mut alice = Wallet::load(""); - - let seal1 = alice.next_seal_pub(); - - let schema = Schema::load("").expect("unable to load schema"); - // Contract is articles object - let articles = schema - .start_issue("firstIssue") - .append("ticker", svnum!(0u64), Some(ston!(ticker "TICK", name "Token"))) - .assign("tokenOwners", seal1, svnum!(100_0000), None) - .finish::("TokenContract", 1732529307); - - let mut stockpile = Stockpile::new(articles, "examples/token/data"); - - let bob = Wallet::load(""); - let seal2 = bob.next_seal_pub(); - let seal_change = alice.next_seal_priv(); - // The seal can be also vout-based, use `next_seal_vout` for that purpose - - // Instead of keeping the whole contract ops in the memory, this can be actually done - // using state combined with APIs! - let op = stockpile - .start_deed("transfer") - .using(seal1, ston!()) - .append("tokenOwners", seal2, svnum!(10_0000), None) - .append("tokenOwners", seal_change, svnum!(90_0000), None) - .commit(); - - // PSBT constructor analyses both inputs and outputs of the operation, detecting and checking - // relevant seals (for instance, vout-based). - let psbt = alice.construct_psbt(op); - //let alice_balances = stockpile.select_unspent(alice.utxos(), svnum!(10_0000)); - - for contract_id in alice.affected(psbt) { - // TODO: We need to do blank transitions as well - } - - let anchor = psbt.extract_anchor(stockpile.contract_id()); - // TODO: We need to extract an anchor per each contract - // This adds information about UTXOs to the wallet - let tx = alice.finalize_psbt(); - - // Ensuring Alice's contract is updated - stockpile.append_witness(tx, anchor); - - stockpile.consign_to_file([seal2], "examples/token/transfer.rgb"); - tx.broadcast(); - alice.save(""); - - // Bob's site: - // let diff = Deeds::diff("", transfer); - // let transitions = state.accept(diff); // This also does the verification - // Trace::extend("", transitions); - // Deeds::extend("", diff); - - // Locker, token (stash) and trace are append-only logs - // Only state, wallet (alice) must persist in memory -} diff --git a/src/lib.rs b/src/lib.rs index 6cff9d5b..8942e143 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,18 +24,7 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] -extern crate core; -#[macro_use] -extern crate amplify; -#[macro_use] -extern crate strict_encoding; -#[macro_use] -extern crate commit_verify; -#[macro_use] extern crate rgbcore as rgb; -#[cfg(feature = "serde")] -#[macro_use] -extern crate serde; mod pile; mod stockpile; From c688b844a5c41fa1af6f6fd0ecaa565bd492e9c7 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 8 Dec 2024 14:12:05 +0100 Subject: [PATCH 20/70] move bitcoin-specific functionality behind a feature gate --- .github/workflows/build.yml | 2 +- Cargo.lock | 4 ++-- Cargo.toml | 11 +++++++---- src/lib.rs | 6 ++++++ src/mound.rs | 2 +- src/stockpile.rs | 2 +- src/wallet.rs | 2 +- 7 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0662fcb8..724f9685 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ jobs: strategy: fail-fast: false matrix: - feature: [ fs, serde ] + feature: [ bp, fs, serde ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable diff --git a/Cargo.lock b/Cargo.lock index f18075cf..df6984ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#90d37d566a13510e2634adb19e25d6eba017c166" +source = "git+https://github.com/AluVM/sonic#9f6e96678920f5364e370d761c6ef5d81eb5001a" dependencies = [ "aluvm", "amplify", @@ -739,7 +739,7 @@ checksum = "fa1f0140117847f5470c5ab2e68f7645bfe6fe27933b9160de63832ecaf0f3d2" [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#90d37d566a13510e2634adb19e25d6eba017c166" +source = "git+https://github.com/AluVM/sonic#9f6e96678920f5364e370d761c6ef5d81eb5001a" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index c4856c31..752be41a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,13 +23,16 @@ strict_types = "2.8.1" commit_verify = "0.12.0-beta.1" single_use_seals = "0.12.0-beta.1" hypersonic = "0.12.0-beta.1" -bp-core = "0.12.0-beta.2" +bp-core = { version = "0.12.0-beta.2", optional = true } rgb-core = "0.12.0-beta.3" [features] -default = [] -all = ["fs", "serde"] +default = ["std", "bp"] +all = ["std", "bp", "fs", "serde"] +std = [] +bp = ["bp-core"] serde = [ + "std", "amplify/serde", "strict_encoding/serde", "strict_types/serde", @@ -37,10 +40,10 @@ serde = [ "bp-core/serde", "rgb-core/serde", ] +fs = ["std", "hypersonic/persist-file"] stl = [ "bp-core/stl", "commit_verify/stl" ] -fs = ["hypersonic/persist-file"] [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" diff --git a/src/lib.rs b/src/lib.rs index 8942e143..daec2853 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,15 +23,19 @@ // the License. #![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; extern crate rgbcore as rgb; mod pile; mod stockpile; mod mound; +#[cfg(feature = "bp")] mod wallet; //pub mod stl; +#[cfg(feature = "bp")] pub use bp::{Outpoint, Txid}; pub use mound::Mound; #[cfg(feature = "fs")] @@ -39,4 +43,6 @@ pub use pile::fs::FilePile; pub use pile::Pile; pub use rgb::*; pub use stockpile::Stockpile; +#[cfg(feature = "bp")] +pub use wallet::{Wallet, WalletDescriptor, WalletPersistence}; //pub use stl::{LIB_NAME_RGB_STD, LIB_NAME_RGB_STORAGE}; diff --git a/src/mound.rs b/src/mound.rs index 60f194df..4de8f492 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -22,7 +22,7 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. -use std::collections::BTreeMap; +use alloc::collections::BTreeMap; use hypersonic::{CellAddr, ContractId, Supply}; diff --git a/src/stockpile.rs b/src/stockpile.rs index c368e40c..205597d3 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -22,7 +22,7 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. -// Used in strict encoding; once solved there, remove here +// TODO: Used in strict encoding; once solved there, remove here use std::io; use hypersonic::{Articles, AuthToken, CellAddr, Stock, Supply}; diff --git a/src/wallet.rs b/src/wallet.rs index 5c8d1381..bd1dbb93 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -22,7 +22,7 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. -use std::collections::{BTreeMap, BTreeSet}; +use alloc::collections::{BTreeMap, BTreeSet}; use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Txid, Vout}; From 4362f3cef18c7a3ed3ddbadc863272b50d84b000 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 8 Dec 2024 17:29:37 +0100 Subject: [PATCH 21/70] issue method --- src/lib.rs | 2 + src/mound.rs | 115 ++++++++++++++++++++++++++++++++++++++++------- src/pile.rs | 4 +- src/stockpile.rs | 21 +++++---- src/wallet.rs | 32 +++++++++++-- 5 files changed, 141 insertions(+), 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index daec2853..aa33ea2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,8 @@ #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; +#[macro_use] +extern crate amplify; extern crate rgbcore as rgb; mod pile; diff --git a/src/mound.rs b/src/mound.rs index 4de8f492..f55342db 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -24,42 +24,92 @@ use alloc::collections::BTreeMap; -use hypersonic::{CellAddr, ContractId, Supply}; +use hypersonic::{CellAddr, CodexId, ContractId, IssueParams, Schema, Supply}; use crate::{Pile, Stockpile}; -pub struct Mound, P: Pile, const CAPS: u32>( - BTreeMap>, -); +pub struct Mound, P: Pile, X, const CAPS: u32> { + schemata: BTreeMap, + contracts: BTreeMap>, + persistence: X, +} + +impl, P: Pile, X: Default, const CAPS: u32> Default for Mound { + fn default() -> Self { + Self { + schemata: BTreeMap::new(), + contracts: BTreeMap::new(), + persistence: default!(), + } + } +} + +impl, P: Pile, const CAPS: u32> Mound { + pub fn new() -> Self { + Self { + schemata: BTreeMap::new(), + contracts: BTreeMap::new(), + persistence: (), + } + } +} + +impl, P: Pile, X, const CAPS: u32> Mound { + pub fn with(persistence: X) -> Self { + Self { + schemata: BTreeMap::new(), + contracts: BTreeMap::new(), + persistence, + } + } + + pub fn open(mut loader: impl Excavate) -> Self { + Self { + schemata: loader.schemata().collect(), + contracts: loader.contracts().collect(), + persistence: loader.persistence(), + } + } + + pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { + let stockpile = Stockpile::issue(schema, params, supply, pile); + let id = stockpile.contract_id(); + self.contracts.insert(id, stockpile); + id + } + + pub fn codex_ids(&self) -> impl Iterator + use<'_, S, P, X, CAPS> { + self.schemata.keys().copied() + } -impl, P: Pile, const CAPS: u32> Mound { - pub fn new() -> Self { Self(BTreeMap::new()) } - pub fn excavate(mut loader: impl Excavate) -> Self { - Self(loader.excavate().collect()) + pub fn schemata(&self) -> impl Iterator { + self.schemata.iter().map(|(id, schema)| (*id, schema)) } - pub fn contract_ids(&self) -> impl Iterator + use<'_, S, P, CAPS> { - self.0.keys().copied() + pub fn schema(&self, codex_id: CodexId) -> Option<&Schema> { self.schemata.get(&codex_id) } + + pub fn contract_ids(&self) -> impl Iterator + use<'_, S, P, X, CAPS> { + self.contracts.keys().copied() } pub fn contracts(&self) -> impl Iterator)> { - self.0.iter().map(|(id, stock)| (*id, stock)) + self.contracts.iter().map(|(id, stock)| (*id, stock)) } pub fn contracts_mut( &mut self, ) -> impl Iterator)> { - self.0.iter_mut().map(|(id, stock)| (*id, stock)) + self.contracts.iter_mut().map(|(id, stock)| (*id, stock)) } pub fn contract(&self, id: ContractId) -> &Stockpile { - self.0 + self.contracts .get(&id) .unwrap_or_else(|| panic!("unknown contract {id}")) } pub fn contract_mut(&mut self, id: ContractId) -> &mut Stockpile { - self.0 + self.contracts .get_mut(&id) .unwrap_or_else(|| panic!("unknown contract {id}")) } @@ -67,13 +117,44 @@ impl, P: Pile, const CAPS: u32> Mound { pub fn select<'seal>( &self, seal: &'seal P::Seal, - ) -> impl Iterator + use<'_, 'seal, S, P, CAPS> { - self.0 + ) -> impl Iterator + use<'_, 'seal, S, P, X, CAPS> { + self.contracts .iter() .filter_map(|(id, stockpile)| stockpile.seal(seal).map(|addr| (*id, addr))) } } pub trait Excavate, P: Pile, const CAPS: u32> { - fn excavate(&mut self) -> impl Iterator)>; + type Persistence; + fn persistence(&self) -> Self::Persistence; + fn schemata(&mut self) -> impl Iterator; + fn contracts(&mut self) -> impl Iterator)>; +} + +pub mod file { + use std::path::{Path, PathBuf}; + + use hypersonic::FileSupply; + use strict_encoding::{StrictDecode, StrictEncode}; + + use super::*; + use crate::pile::Protocol; + use crate::FilePile; + + pub type FileMound = + Mound, PathBuf, CAPS>; + + impl FileMound + where + Seal::CliWitness: StrictEncode + StrictDecode, + Seal::PubWitness: StrictEncode + StrictDecode, + { + pub fn path(&self) -> &Path { &self.persistence } + + pub fn issue_file(&mut self, schema: Schema, params: IssueParams) -> ContractId { + let pile = FilePile::::new(params.name.as_str(), &self.persistence); + let supply = FileSupply::new(params.name.as_str(), &self.persistence); + self.issue(schema, params, supply, pile) + } + } } diff --git a/src/pile.rs b/src/pile.rs index dc61193d..9f35bbea 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -33,8 +33,8 @@ pub trait Protocol: SingleUseSeal { pub trait Pile { type Seal: Protocol; - type Hoard: Aora; - type Cache: Aora; + type Hoard: Aora::CliWitness>; + type Cache: Aora::PubWitness>; fn hoard(&self) -> &Self::Hoard; fn cache(&self) -> &Self::Cache; diff --git a/src/stockpile.rs b/src/stockpile.rs index 205597d3..0ec42087 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -25,7 +25,7 @@ // TODO: Used in strict encoding; once solved there, remove here use std::io; -use hypersonic::{Articles, AuthToken, CellAddr, Stock, Supply}; +use hypersonic::{Articles, AuthToken, CellAddr, ContractId, IssueParams, Schema, Stock, Supply}; use single_use_seals::SingleUseSeal; use strict_encoding::{StrictWriter, WriteRaw}; @@ -38,7 +38,8 @@ pub struct Stockpile, P: Pile, const CAPS: u32> { } impl, P: Pile, const CAPS: u32> Stockpile { - pub fn create(articles: Articles, supply: S, pile: P) -> Self { + pub fn issue(schema: Schema, params: IssueParams, supply: S, pile: P) -> Self { + let articles = schema.issue::(params); let stock = Stock::create(articles, supply); Self { stock, pile } } @@ -48,6 +49,8 @@ impl, P: Pile, const CAPS: u32> Stockpile { Self { stock, pile } } + pub fn contract_id(&self) -> ContractId { self.stock.contract_id() } + pub fn seal(&self, seal: &P::Seal) -> Option { let auth = seal.auth_token(); self.stock.state().raw.auth.get(&auth).copied() @@ -74,7 +77,7 @@ impl, P: Pile, const CAPS: u32> Stockpile { mod fs { use std::path::Path; - use hypersonic::{ContractName, FileSupply}; + use hypersonic::FileSupply; use strict_encoding::{StrictDecode, StrictEncode}; use super::*; @@ -85,15 +88,11 @@ mod fs { Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, { - pub fn new(articles: Articles, path: impl AsRef) -> Self { + pub fn issue_file(schema: Schema, params: IssueParams, path: impl AsRef) -> Self { let path = path.as_ref(); - let name = match &articles.contract.meta.name { - ContractName::Unnamed => articles.contract_id().to_string(), - ContractName::Named(name) => name.to_string(), - }; - let pile = FilePile::new(&name, path); - let supply = FileSupply::new(&name, path); - Self::create(articles, supply, pile) + let pile = FilePile::new(params.name.as_str(), path); + let supply = FileSupply::new(params.name.as_str(), path); + Self::issue(schema, params, supply, pile) } pub fn load(path: impl AsRef) -> Self { diff --git a/src/wallet.rs b/src/wallet.rs index bd1dbb93..f466a10d 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -26,7 +26,7 @@ use alloc::collections::{BTreeMap, BTreeSet}; use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Txid, Vout}; -use hypersonic::{AuthToken, CellAddr, ContractId, Operation, Supply}; +use hypersonic::{AuthToken, CellAddr, ContractId, IssueParams, Operation, Schema, Supply}; use crate::pile::Protocol; use crate::{Mound, Pile}; @@ -47,11 +47,12 @@ pub struct Wallet< D: dbc::Proof, S: Supply, P: Pile>, + X, const CAPS: u32, > { pub descriptor: W, pub unspent: BTreeMap)>>, - pub mound: Mound, + pub mound: Mound, } impl< @@ -59,9 +60,14 @@ impl< D: dbc::Proof, S: Supply, P: Pile>, + X, const CAPS: u32, - > Wallet + > Wallet { + pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { + self.mound.issue(schema, params, supply, pile) + } + pub fn assignments( &self, outpoint: Outpoint, @@ -83,3 +89,23 @@ impl< } pub trait WalletPersistence {} + +pub mod file { + use std::path::{Path, PathBuf}; + + use hypersonic::{CodexId, FileSupply, IssueParams, Schema}; + + use super::*; + use crate::FilePile; + + pub type FileWallet = + Wallet>, PathBuf, CAPS>; + + impl FileWallet { + pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + let schema = self.mound.schema(codex_id).expect("unknown codex id"); + // TODO: check that if the issue belongs to the wallet add it to the unspents + self.mound.issue_file(schema.clone(), params) + } + } +} From 34a307cbc2a11ec12b65b509ad76f9d02638e0ad Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 8 Dec 2024 23:51:37 +0100 Subject: [PATCH 22/70] operation prefabs and packs --- Cargo.lock | 11 +-- Cargo.toml | 8 ++- src/bitcoin.rs | 192 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 18 +++-- src/pile.rs | 8 +-- src/stl.rs | 123 ------------------------------- src/wallet.rs | 111 ---------------------------- 7 files changed, 218 insertions(+), 253 deletions(-) create mode 100644 src/bitcoin.rs delete mode 100644 src/stl.rs delete mode 100644 src/wallet.rs diff --git a/Cargo.lock b/Cargo.lock index df6984ab..5ef49e17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,7 +170,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" dependencies = [ "amplify", "chrono", @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" dependencies = [ "amplify", "bp-consensus", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" dependencies = [ "amplify", "base85", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#14892a219e945a62ed6392a97a86044b7d255340" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" dependencies = [ "amplify", "baid64", @@ -591,6 +591,7 @@ dependencies = [ "hypersonic", "rand", "rgb-core", + "serde", "single_use_seals", "strict_encoding", "strict_types", @@ -894,7 +895,7 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ultrasonic" version = "0.12.0-beta.2" -source = "git+https://github.com/AluVM/ultrasonic#69ccba97ed9347db5a7b8ff680e3e1179dcd13e0" +source = "git+https://github.com/AluVM/ultrasonic#239bc019e3f868b07857d2c5bff5df6c8ca0044f" dependencies = [ "amplify", "baid64", diff --git a/Cargo.toml b/Cargo.toml index 752be41a..97a00926 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,14 +25,16 @@ single_use_seals = "0.12.0-beta.1" hypersonic = "0.12.0-beta.1" bp-core = { version = "0.12.0-beta.2", optional = true } rgb-core = "0.12.0-beta.3" +serde = { version = "1.0.215", optional = true } [features] -default = ["std", "bp"] -all = ["std", "bp", "fs", "serde"] +default = ["std", "bitcoin"] +all = ["std", "bitcoin", "fs", "serde"] std = [] -bp = ["bp-core"] +bitcoin = ["bp-core"] serde = [ "std", + "dep:serde", "amplify/serde", "strict_encoding/serde", "strict_types/serde", diff --git a/src/bitcoin.rs b/src/bitcoin.rs new file mode 100644 index 00000000..7328829d --- /dev/null +++ b/src/bitcoin.rs @@ -0,0 +1,192 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 alloc::collections::{BTreeMap, BTreeSet}; + +use amplify::confinement::SmallOrdSet; +use bp::dbc::opret::OpretProof; +use bp::dbc::tapret::TapretProof; +use bp::seals::TxoSeal; +use bp::{dbc, Outpoint, Txid, Vout}; +use hypersonic::{ + AuthToken, CellAddr, ContractId, IssueParams, MethodName, NamedState, Operation, Schema, + StateAtom, Supply, +}; +use strict_encoding::{StrictDeserialize, StrictSerialize}; +use strict_types::StrictVal; + +use crate::pile::Protocol; +use crate::{Mound, Pile}; + +pub trait WalletDescriptor {} + +pub const BTC_OPRET_CAPS: u32 = 0x0001_0001_u32; +pub const BTC_TAPRET_CAPS: u32 = 0x0001_0002_u32; + +pub type OpretSeal = TxoSeal; +pub type TapretSeal = TxoSeal; + +/// Parameters used by BP-based wallet for constructing operations. +/// +/// Differs from [`hypersonic::CallParams`] in the fact that it uses [`TxoSeal`]s instead of +/// AuthTokens for output definitions. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ConstructParams { + pub method: MethodName, + pub global: Vec>, + pub owned: BTreeMap, NamedState>, + pub using: Vec<(AuthToken, StrictVal)>, + pub reading: Vec, +} + +/// Prefabricated operation, which includes information on the contract id and closed seals +/// (previous outputs). +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = "RGB")] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Prefab { + pub contract_id: ContractId, + pub closes: SmallOrdSet, + pub operation: Operation, +} + +/// A pack of prefabricated operations related to the same witness transaction. +/// +/// The pack should cover all contracts assigning state to the witness transaction previous outputs. +/// It is used to add seal closing commitment to the witness transaction PSBT. +#[derive(Clone, Eq, PartialEq, Debug, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = "RGB")] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct PrefabPack(SmallOrdSet); + +impl StrictSerialize for Prefab {} +impl StrictDeserialize for Prefab {} + +impl Protocol for TxoSeal { + type Id = Txid; + + fn auth_token(&self) -> AuthToken { todo!() } +} + +/// Barrow contains a bunch of RGB contract stockpiles, which are held by a single owner; such that +/// when a new operation under any of the contracts happen it may affect other contracts sharing the +/// same UTXOs. +pub struct Barrow< + W: WalletDescriptor, + D: dbc::Proof, + S: Supply, + P: Pile>, + X, + const CAPS: u32, +> { + pub wallet: W, + pub unspent: BTreeMap)>>, + pub mound: Mound, +} + +impl< + W: WalletDescriptor, + D: dbc::Proof, + S: Supply, + P: Pile>, + X, + const CAPS: u32, + > Barrow +{ + pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { + self.mound.issue(schema, params, supply, pile) + } + + pub fn assignments( + &self, + outpoint: Outpoint, + ) -> impl Iterator)> { + self.unspent + .get(&outpoint) + .expect("unknown outpoint") + .iter() + .map(|(id, seal)| (*id, seal)) + } + + pub fn new_vout(&mut self, vout: Vout) -> TxoSeal { todo!() } + + pub fn new_seal(&mut self) -> TxoSeal { todo!() } + + pub fn resolve_seal(&self, opout: CellAddr) -> TxoSeal { todo!() } + + /// Creates a single operation basing on the provided construction parameters. + pub fn prefab(&self, contract_id: ContractId, params: ConstructParams) -> Prefab { + // convert ExecParams into CallParams + todo!() + } + + /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. + pub fn complete(&self, ops: impl IntoIterator) -> PrefabPack { + // add blank operations + todo!() + } +} + +pub mod file { + use std::path::PathBuf; + + use hypersonic::{CodexId, FileSupply, IssueParams}; + + use super::*; + use crate::FilePile; + + pub type FileWallet = + Barrow>, PathBuf, CAPS>; + + impl FileWallet { + pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + let schema = self.mound.schema(codex_id).expect("unknown codex id"); + // TODO: check that if the issue belongs to the wallet add it to the unspents + self.mound.issue_file(schema.clone(), params) + } + } + + pub type BtcMound = + Mound>, PathBuf, CAPS>; + pub type OpretMound = BtcMound; + pub type TapretMound = BtcMound; + + pub enum OmniMound { + Opret(OpretMound), + Tapret(TapretMound), + } + + pub type BpBarrow = + Barrow>, PathBuf, CAPS>; + pub type OpretBarrow = BpBarrow; + pub type TapretBarrow = BpBarrow; + + pub enum OmniBarrow { + Opret(OpretBarrow), + Tapret(TapretBarrow), + } +} diff --git a/src/lib.rs b/src/lib.rs index aa33ea2c..b56acd5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,18 +26,25 @@ #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; + #[macro_use] extern crate amplify; extern crate rgbcore as rgb; +#[cfg(feature = "bitcoin")] +#[macro_use] +extern crate strict_encoding; +#[cfg(all(feature = "serde", feature = "bitcoin"))] +#[macro_use] +extern crate serde; + mod pile; mod stockpile; mod mound; -#[cfg(feature = "bp")] -mod wallet; -//pub mod stl; +#[cfg(feature = "bitcoin")] +pub mod bitcoin; -#[cfg(feature = "bp")] +#[cfg(feature = "bitcoin")] pub use bp::{Outpoint, Txid}; pub use mound::Mound; #[cfg(feature = "fs")] @@ -45,6 +52,3 @@ pub use pile::fs::FilePile; pub use pile::Pile; pub use rgb::*; pub use stockpile::Stockpile; -#[cfg(feature = "bp")] -pub use wallet::{Wallet, WalletDescriptor, WalletPersistence}; -//pub use stl::{LIB_NAME_RGB_STD, LIB_NAME_RGB_STORAGE}; diff --git a/src/pile.rs b/src/pile.rs index 9f35bbea..494c74c3 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -86,12 +86,12 @@ pub mod fs { type Hoard = FileAora; type Cache = FileAora; - fn hoard(&self) -> &Self::Hoard { todo!() } + fn hoard(&self) -> &Self::Hoard { &self.hoard } - fn cache(&self) -> &Self::Cache { todo!() } + fn cache(&self) -> &Self::Cache { &self.cache } - fn hoard_mut(&mut self) -> &mut Self::Hoard { todo!() } + fn hoard_mut(&mut self) -> &mut Self::Hoard { &mut self.hoard } - fn cache_mut(&mut self) -> &mut Self::Cache { todo!() } + fn cache_mut(&mut self) -> &mut Self::Cache { &mut self.cache } } } diff --git a/src/stl.rs b/src/stl.rs deleted file mode 100644 index 67d819d5..00000000 --- a/src/stl.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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 amplify::IoError; -use baid64::Baid64ParseError; -pub use bp::bc::stl::bp_tx_stl; -pub use bp::stl::bp_core_stl; -pub use commit_verify::stl::{commit_verify_stl, LIB_ID_COMMIT_VERIFY}; -pub use rgb::stl::{aluvm_stl, rgb_commit_stl, rgb_logic_stl, LIB_ID_RGB_COMMIT, LIB_ID_RGB_LOGIC}; -use strict_types::stl::{std_stl, strict_types_stl}; -use strict_types::{typesys, CompileError, LibBuilder, TypeLib}; - -use crate::containers::{Contract, Kit, Transfer}; -use crate::persistence::{MemIndex, MemStash, MemState}; - -pub const LIB_NAME_RGB_STD: &str = "RGBStd"; -pub const LIB_NAME_RGB_STORAGE: &str = "RGBStorage"; - -/// Strict types id for the library providing standard data types which may be -/// used in RGB smart contracts. -pub const LIB_ID_RGB_STORAGE: &str = - "stl:dYzM3Ct9-SJ8PljY-C!6hB6y-VlWvDE7-DAtNg3y-zanf6hE#media-fresh-cadet"; - -/// Strict types id for the library representing of RGB StdLib data types. -pub const LIB_ID_RGB_STD: &str = - "stl:3QsSNDHr-YPIKTR9-5O!fLuv-xhcxKT2-0LWrO9b-pG15Nvw#mango-inside-shelf"; - -#[allow(dead_code)] -#[derive(Debug, From)] -pub enum Error { - #[from(std::io::Error)] - Io(IoError), - #[from] - Baid64(Baid64ParseError), - #[from] - Compile(CompileError), - #[from] - Link1(typesys::Error), - #[from] - Link2(Vec), -} - -fn _rgb_std_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_STD), tiny_bset! { - std_stl().to_dependency(), - strict_types_stl().to_dependency(), - commit_verify_stl().to_dependency(), - bp_tx_stl().to_dependency(), - bp_core_stl().to_dependency(), - aluvm_stl().to_dependency(), - rgb_commit_stl().to_dependency(), - rgb_logic_stl().to_dependency(), - }) - .transpile::() - .transpile::() - .transpile::() - .compile() -} - -fn _rgb_storage_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_STORAGE), tiny_bset! { - std_stl().to_dependency(), - strict_types_stl().to_dependency(), - commit_verify_stl().to_dependency(), - bp_tx_stl().to_dependency(), - bp_core_stl().to_dependency(), - aluvm_stl().to_dependency(), - rgb_commit_stl().to_dependency(), - rgb_logic_stl().to_dependency(), - rgb_std_stl().to_dependency() - }) - .transpile::() - .transpile::() - .transpile::() - .compile() -} - -/// Generates strict type library representation of RGB StdLib data types. -pub fn rgb_std_stl() -> TypeLib { _rgb_std_stl().expect("invalid strict type RGBStd library") } - -/// Generates strict type library providing standard storage for state, contract -/// state and index. -pub fn rgb_storage_stl() -> TypeLib { - _rgb_storage_stl().expect("invalid strict type RGBStorage library") -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn std_lib_id() { - let lib = rgb_std_stl(); - assert_eq!(lib.id().to_string(), LIB_ID_RGB_STD); - } - - #[test] - fn storage_lib_id() { - let lib = rgb_storage_stl(); - assert_eq!(lib.id().to_string(), LIB_ID_RGB_STORAGE); - } -} diff --git a/src/wallet.rs b/src/wallet.rs deleted file mode 100644 index f466a10d..00000000 --- a/src/wallet.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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 alloc::collections::{BTreeMap, BTreeSet}; - -use bp::seals::TxoSeal; -use bp::{dbc, Outpoint, Txid, Vout}; -use hypersonic::{AuthToken, CellAddr, ContractId, IssueParams, Operation, Schema, Supply}; - -use crate::pile::Protocol; -use crate::{Mound, Pile}; - -pub trait WalletDescriptor {} - -impl Protocol for TxoSeal { - type Id = Txid; - - fn auth_token(&self) -> AuthToken { todo!() } -} - -/// Wallet contains a bunch of RGB contract stockpiles, which are held by a single owner; such that -/// when a new operation under any of the contracts happen it may affect other contracts sharing the -/// same UTXOs. -pub struct Wallet< - W: WalletDescriptor, - D: dbc::Proof, - S: Supply, - P: Pile>, - X, - const CAPS: u32, -> { - pub descriptor: W, - pub unspent: BTreeMap)>>, - pub mound: Mound, -} - -impl< - W: WalletDescriptor, - D: dbc::Proof, - S: Supply, - P: Pile>, - X, - const CAPS: u32, - > Wallet -{ - pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { - self.mound.issue(schema, params, supply, pile) - } - - pub fn assignments( - &self, - outpoint: Outpoint, - ) -> impl Iterator)> { - self.unspent - .get(&outpoint) - .expect("unknown outpoint") - .iter() - .map(|(id, seal)| (*id, seal)) - } - - pub fn new_vout(&mut self, vout: Vout) -> TxoSeal { todo!() } - - pub fn new_seal(&mut self) -> TxoSeal { todo!() } - - pub fn resolve_seal(&self, opout: CellAddr) -> TxoSeal { todo!() } - - pub fn assemble_psbt(&self, op: Operation) { todo!() } -} - -pub trait WalletPersistence {} - -pub mod file { - use std::path::{Path, PathBuf}; - - use hypersonic::{CodexId, FileSupply, IssueParams, Schema}; - - use super::*; - use crate::FilePile; - - pub type FileWallet = - Wallet>, PathBuf, CAPS>; - - impl FileWallet { - pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { - let schema = self.mound.schema(codex_id).expect("unknown codex id"); - // TODO: check that if the issue belongs to the wallet add it to the unspents - self.mound.issue_file(schema.clone(), params) - } - } -} From 0f3c2f38847a3df722309e36cb4d38b215738ac1 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 9 Dec 2024 09:46:19 +0100 Subject: [PATCH 23/70] seal types enum and dir excavator helper --- Cargo.toml | 2 +- scripts/typelib.sh | 3 -- src/bitcoin.rs | 43 ++++++++++++------ src/lib.rs | 2 +- src/mound.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++- src/stockpile.rs | 14 +++--- 6 files changed, 147 insertions(+), 27 deletions(-) delete mode 100755 scripts/typelib.sh diff --git a/Cargo.toml b/Cargo.toml index 97a00926..78bbb4de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "Apache-2.0" readme = "README.md" [lib] -name = "rgbstd" +name = "rgb" crate-type = ["cdylib", "rlib"] # We need this for WASM [dependencies] diff --git a/scripts/typelib.sh b/scripts/typelib.sh deleted file mode 100755 index d34459b1..00000000 --- a/scripts/typelib.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -cargo run -p rgb-stl --bin rgb-stl diff --git a/src/bitcoin.rs b/src/bitcoin.rs index 7328829d..b61f20cc 100644 --- a/src/bitcoin.rs +++ b/src/bitcoin.rs @@ -41,8 +41,8 @@ use crate::{Mound, Pile}; pub trait WalletDescriptor {} -pub const BTC_OPRET_CAPS: u32 = 0x0001_0001_u32; -pub const BTC_TAPRET_CAPS: u32 = 0x0001_0002_u32; +pub const BITCOIN_OPRET: u32 = 0x0001_0001_u32; +pub const BITCOIN_TAPRET: u32 = 0x0001_0002_u32; pub type OpretSeal = TxoSeal; pub type TapretSeal = TxoSeal; @@ -104,7 +104,7 @@ pub struct Barrow< const CAPS: u32, > { pub wallet: W, - pub unspent: BTreeMap)>>, + //pub unspent: BTreeMap)>>, pub mound: Mound, } @@ -117,10 +117,15 @@ impl< const CAPS: u32, > Barrow { + pub fn with(wallet: W, mound: Mound) -> Self { Self { wallet, mound } } + + pub fn unbind(self) -> (W, Mound) { (self.wallet, self.mound) } + pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { self.mound.issue(schema, params, supply, pile) } + /* pub fn assignments( &self, outpoint: Outpoint, @@ -131,6 +136,7 @@ impl< .iter() .map(|(id, seal)| (*id, seal)) } + */ pub fn new_vout(&mut self, vout: Vout) -> TxoSeal { todo!() } @@ -170,23 +176,32 @@ pub mod file { } } - pub type BtcMound = + pub type DirBtcMound = Mound>, PathBuf, CAPS>; - pub type OpretMound = BtcMound; - pub type TapretMound = BtcMound; + pub type DirOpretMound = DirBtcMound; + pub type DirTapretMound = DirBtcMound; - pub enum OmniMound { - Opret(OpretMound), - Tapret(TapretMound), + pub struct DirMound { + opret: DirOpretMound, + tapret: DirTapretMound, } pub type BpBarrow = Barrow>, PathBuf, CAPS>; - pub type OpretBarrow = BpBarrow; - pub type TapretBarrow = BpBarrow; + pub type DirOpretBarrow = BpBarrow; + pub type DirTapretBarrow = BpBarrow; + + pub enum DirBarrow { + Opret(DirOpretBarrow), + Tapret(DirTapretBarrow), + } - pub enum OmniBarrow { - Opret(OpretBarrow), - Tapret(TapretBarrow), + impl DirBarrow { + pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + match self { + DirBarrow::Opret(barrow) => barrow.issue_file(codex_id, params), + DirBarrow::Tapret(barrow) => barrow.issue_file(codex_id, params), + } + } } } diff --git a/src/lib.rs b/src/lib.rs index b56acd5d..610d63a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ pub mod bitcoin; #[cfg(feature = "bitcoin")] pub use bp::{Outpoint, Txid}; -pub use mound::Mound; +pub use mound::{Excavate, Mound, SealType}; #[cfg(feature = "fs")] pub use pile::fs::FilePile; pub use pile::Pile; diff --git a/src/mound.rs b/src/mound.rs index f55342db..d3e26e63 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -28,6 +28,42 @@ use hypersonic::{CellAddr, CodexId, ContractId, IssueParams, Schema, Supply}; use crate::{Pile, Stockpile}; +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[repr(u32)] +pub enum SealType { + #[cfg(feature = "bitcoin")] + #[display("bitcoin.opret")] + BitcoinOpret = crate::bitcoin::BITCOIN_OPRET, + + #[cfg(feature = "bitcoin")] + #[display("bitcoin.tapret")] + BitcoinTapret = crate::bitcoin::BITCOIN_TAPRET, + + #[cfg(feature = "liquid")] + #[display("liquid.tapret")] + LiquidTapret = crate::liquid::LIQUID_TAPRET, + + #[cfg(feature = "prime")] + #[display("prime")] + Prime = crate::prime::PRIME, +} + +impl From for SealType { + fn from(caps: u32) -> Self { + match caps { + #[cfg(feature = "bitcoin")] + crate::bitcoin::BITCOIN_OPRET => Self::BitcoinOpret, + #[cfg(feature = "bitcoin")] + crate::bitcoin::BITCOIN_TAPRET => Self::BitcoinTapret, + #[cfg(feature = "liquid")] + crate::liquid::LIQUID_TAPRET => Self::LiquidTapret, + #[cfg(feature = "prime")] + crate::prime::PRIME => Self::Prime, + unknown => panic!("unknown seal type {unknown:#10x}"), + } + } +} + pub struct Mound, P: Pile, X, const CAPS: u32> { schemata: BTreeMap, contracts: BTreeMap>, @@ -132,6 +168,9 @@ pub trait Excavate, P: Pile, const CAPS: u32> { } pub mod file { + use std::fs; + use std::fs::FileType; + use std::marker::PhantomData; use std::path::{Path, PathBuf}; use hypersonic::FileSupply; @@ -141,6 +180,69 @@ pub mod file { use crate::pile::Protocol; use crate::FilePile; + struct DirExcavator { + dir: PathBuf, + _phantom: PhantomData, + } + + impl DirExcavator { + pub fn new(dir: PathBuf) -> Self { + Self { + dir, + _phantom: PhantomData, + } + } + + fn contents(&mut self) -> impl Iterator { + let seal = SealType::from(CAPS); + let root = self.dir.join(seal.to_string()); + fs::read_dir(root) + .expect("unable to read directory") + .map(|entry| { + let entry = entry.expect("unable to read directory"); + let ty = entry.file_type().expect("unable to read file type"); + (ty, entry.path()) + }) + } + } + + impl Excavate, CAPS> + for DirExcavator + where + Seal::CliWitness: StrictEncode + StrictDecode, + Seal::PubWitness: StrictEncode + StrictDecode, + { + type Persistence = PathBuf; + + fn persistence(&self) -> Self::Persistence { self.dir.clone() } + + fn schemata(&mut self) -> impl Iterator { + self.contents().filter_map(|(ty, path)| { + if ty.is_file() && path.ends_with(".schema") { + Schema::load(path) + .ok() + .map(|schema| (schema.codex.codex_id(), schema)) + } else { + None + } + }) + } + + fn contracts( + &mut self, + ) -> impl Iterator, CAPS>)> + { + self.contents().filter_map(|(ty, path)| { + if ty.is_file() && path.ends_with(".contract") { + let contract = Stockpile::load(path); + Some((contract.contract_id(), contract)) + } else { + None + } + }) + } + } + pub type FileMound = Mound, PathBuf, CAPS>; @@ -149,12 +251,18 @@ pub mod file { Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, { - pub fn path(&self) -> &Path { &self.persistence } + pub fn load(path: impl AsRef) -> Self { + let path = path.as_ref(); + let excavator = DirExcavator::new(path.to_owned()); + Self::open(excavator) + } pub fn issue_file(&mut self, schema: Schema, params: IssueParams) -> ContractId { let pile = FilePile::::new(params.name.as_str(), &self.persistence); let supply = FileSupply::new(params.name.as_str(), &self.persistence); self.issue(schema, params, supply, pile) } + + pub fn path(&self) -> &Path { &self.persistence } } } diff --git a/src/stockpile.rs b/src/stockpile.rs index 0ec42087..b3c2d6bc 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -88,18 +88,18 @@ mod fs { Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, { - pub fn issue_file(schema: Schema, params: IssueParams, path: impl AsRef) -> Self { - let path = path.as_ref(); - let pile = FilePile::new(params.name.as_str(), path); - let supply = FileSupply::new(params.name.as_str(), path); - Self::issue(schema, params, supply, pile) - } - pub fn load(path: impl AsRef) -> Self { let path = path.as_ref(); let pile = FilePile::open(path); let supply = FileSupply::open(path); Self::open(supply.load_articles(), supply, pile) } + + pub fn issue_file(schema: Schema, params: IssueParams, path: impl AsRef) -> Self { + let path = path.as_ref(); + let pile = FilePile::new(params.name.as_str(), path); + let supply = FileSupply::new(params.name.as_str(), path); + Self::issue(schema, params, supply, pile) + } } } From 8fc84e0ba51ced74e9eb2076aa4932d68ee56795 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 10 Dec 2024 10:50:00 +0100 Subject: [PATCH 24/70] bitcoin and liquid support and integration --- Cargo.toml | 9 +- src/bitcoin.rs | 207 ------------------------- src/lib.rs | 7 +- src/mound.rs | 90 ++++------- src/popls/bp.rs | 375 +++++++++++++++++++++++++++++++++++++++++++++ src/popls/mod.rs | 94 ++++++++++++ src/popls/prime.rs | 25 +++ src/stockpile.rs | 1 + 8 files changed, 534 insertions(+), 274 deletions(-) delete mode 100644 src/bitcoin.rs create mode 100644 src/popls/bp.rs create mode 100644 src/popls/mod.rs create mode 100644 src/popls/prime.rs diff --git a/Cargo.toml b/Cargo.toml index 78bbb4de..92294f01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,14 @@ serde = { version = "1.0.215", optional = true } [features] default = ["std", "bitcoin"] -all = ["std", "bitcoin", "fs", "serde"] +all = ["std", "bitcoin", "liquid", "prime", "fs", "serde"] std = [] + bitcoin = ["bp-core"] +liquid = [] +prime = [] + +fs = ["std", "hypersonic/persist-file"] serde = [ "std", "dep:serde", @@ -42,7 +47,7 @@ serde = [ "bp-core/serde", "rgb-core/serde", ] -fs = ["std", "hypersonic/persist-file"] + stl = [ "bp-core/stl", "commit_verify/stl" ] diff --git a/src/bitcoin.rs b/src/bitcoin.rs deleted file mode 100644 index b61f20cc..00000000 --- a/src/bitcoin.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Standard Library for RGB smart contracts -// -// SPDX-License-Identifier: Apache-2.0 -// -// Designed in 2019-2025 by Dr Maxim Orlovsky -// Written in 2024-2025 by Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. -// Copyright (C) 2024-2025 LNP/BP Laboratories, -// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. -// Copyright (C) 2025 RGB Consortium, Switzerland. -// Copyright (C) 2019-2025 Dr Maxim Orlovsky. -// All rights under the above copyrights are 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 alloc::collections::{BTreeMap, BTreeSet}; - -use amplify::confinement::SmallOrdSet; -use bp::dbc::opret::OpretProof; -use bp::dbc::tapret::TapretProof; -use bp::seals::TxoSeal; -use bp::{dbc, Outpoint, Txid, Vout}; -use hypersonic::{ - AuthToken, CellAddr, ContractId, IssueParams, MethodName, NamedState, Operation, Schema, - StateAtom, Supply, -}; -use strict_encoding::{StrictDeserialize, StrictSerialize}; -use strict_types::StrictVal; - -use crate::pile::Protocol; -use crate::{Mound, Pile}; - -pub trait WalletDescriptor {} - -pub const BITCOIN_OPRET: u32 = 0x0001_0001_u32; -pub const BITCOIN_TAPRET: u32 = 0x0001_0002_u32; - -pub type OpretSeal = TxoSeal; -pub type TapretSeal = TxoSeal; - -/// Parameters used by BP-based wallet for constructing operations. -/// -/// Differs from [`hypersonic::CallParams`] in the fact that it uses [`TxoSeal`]s instead of -/// AuthTokens for output definitions. -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct ConstructParams { - pub method: MethodName, - pub global: Vec>, - pub owned: BTreeMap, NamedState>, - pub using: Vec<(AuthToken, StrictVal)>, - pub reading: Vec, -} - -/// Prefabricated operation, which includes information on the contract id and closed seals -/// (previous outputs). -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = "RGB")] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Prefab { - pub contract_id: ContractId, - pub closes: SmallOrdSet, - pub operation: Operation, -} - -/// A pack of prefabricated operations related to the same witness transaction. -/// -/// The pack should cover all contracts assigning state to the witness transaction previous outputs. -/// It is used to add seal closing commitment to the witness transaction PSBT. -#[derive(Clone, Eq, PartialEq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = "RGB")] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct PrefabPack(SmallOrdSet); - -impl StrictSerialize for Prefab {} -impl StrictDeserialize for Prefab {} - -impl Protocol for TxoSeal { - type Id = Txid; - - fn auth_token(&self) -> AuthToken { todo!() } -} - -/// Barrow contains a bunch of RGB contract stockpiles, which are held by a single owner; such that -/// when a new operation under any of the contracts happen it may affect other contracts sharing the -/// same UTXOs. -pub struct Barrow< - W: WalletDescriptor, - D: dbc::Proof, - S: Supply, - P: Pile>, - X, - const CAPS: u32, -> { - pub wallet: W, - //pub unspent: BTreeMap)>>, - pub mound: Mound, -} - -impl< - W: WalletDescriptor, - D: dbc::Proof, - S: Supply, - P: Pile>, - X, - const CAPS: u32, - > Barrow -{ - pub fn with(wallet: W, mound: Mound) -> Self { Self { wallet, mound } } - - pub fn unbind(self) -> (W, Mound) { (self.wallet, self.mound) } - - pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { - self.mound.issue(schema, params, supply, pile) - } - - /* - pub fn assignments( - &self, - outpoint: Outpoint, - ) -> impl Iterator)> { - self.unspent - .get(&outpoint) - .expect("unknown outpoint") - .iter() - .map(|(id, seal)| (*id, seal)) - } - */ - - pub fn new_vout(&mut self, vout: Vout) -> TxoSeal { todo!() } - - pub fn new_seal(&mut self) -> TxoSeal { todo!() } - - pub fn resolve_seal(&self, opout: CellAddr) -> TxoSeal { todo!() } - - /// Creates a single operation basing on the provided construction parameters. - pub fn prefab(&self, contract_id: ContractId, params: ConstructParams) -> Prefab { - // convert ExecParams into CallParams - todo!() - } - - /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. - pub fn complete(&self, ops: impl IntoIterator) -> PrefabPack { - // add blank operations - todo!() - } -} - -pub mod file { - use std::path::PathBuf; - - use hypersonic::{CodexId, FileSupply, IssueParams}; - - use super::*; - use crate::FilePile; - - pub type FileWallet = - Barrow>, PathBuf, CAPS>; - - impl FileWallet { - pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { - let schema = self.mound.schema(codex_id).expect("unknown codex id"); - // TODO: check that if the issue belongs to the wallet add it to the unspents - self.mound.issue_file(schema.clone(), params) - } - } - - pub type DirBtcMound = - Mound>, PathBuf, CAPS>; - pub type DirOpretMound = DirBtcMound; - pub type DirTapretMound = DirBtcMound; - - pub struct DirMound { - opret: DirOpretMound, - tapret: DirTapretMound, - } - - pub type BpBarrow = - Barrow>, PathBuf, CAPS>; - pub type DirOpretBarrow = BpBarrow; - pub type DirTapretBarrow = BpBarrow; - - pub enum DirBarrow { - Opret(DirOpretBarrow), - Tapret(DirTapretBarrow), - } - - impl DirBarrow { - pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { - match self { - DirBarrow::Opret(barrow) => barrow.issue_file(codex_id, params), - DirBarrow::Tapret(barrow) => barrow.issue_file(codex_id, params), - } - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 610d63a0..6cc19657 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,18 +37,19 @@ extern crate strict_encoding; #[cfg(all(feature = "serde", feature = "bitcoin"))] #[macro_use] extern crate serde; +extern crate core; mod pile; mod stockpile; mod mound; -#[cfg(feature = "bitcoin")] -pub mod bitcoin; +pub mod popls; #[cfg(feature = "bitcoin")] pub use bp::{Outpoint, Txid}; -pub use mound::{Excavate, Mound, SealType}; +pub use mound::{Excavate, Mound}; #[cfg(feature = "fs")] pub use pile::fs::FilePile; pub use pile::Pile; +pub use popls::SealType; pub use rgb::*; pub use stockpile::Stockpile; diff --git a/src/mound.rs b/src/mound.rs index d3e26e63..49ac0ad4 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -28,49 +28,20 @@ use hypersonic::{CellAddr, CodexId, ContractId, IssueParams, Schema, Supply}; use crate::{Pile, Stockpile}; -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[repr(u32)] -pub enum SealType { - #[cfg(feature = "bitcoin")] - #[display("bitcoin.opret")] - BitcoinOpret = crate::bitcoin::BITCOIN_OPRET, - - #[cfg(feature = "bitcoin")] - #[display("bitcoin.tapret")] - BitcoinTapret = crate::bitcoin::BITCOIN_TAPRET, - - #[cfg(feature = "liquid")] - #[display("liquid.tapret")] - LiquidTapret = crate::liquid::LIQUID_TAPRET, - - #[cfg(feature = "prime")] - #[display("prime")] - Prime = crate::prime::PRIME, -} - -impl From for SealType { - fn from(caps: u32) -> Self { - match caps { - #[cfg(feature = "bitcoin")] - crate::bitcoin::BITCOIN_OPRET => Self::BitcoinOpret, - #[cfg(feature = "bitcoin")] - crate::bitcoin::BITCOIN_TAPRET => Self::BitcoinTapret, - #[cfg(feature = "liquid")] - crate::liquid::LIQUID_TAPRET => Self::LiquidTapret, - #[cfg(feature = "prime")] - crate::prime::PRIME => Self::Prime, - unknown => panic!("unknown seal type {unknown:#10x}"), - } - } +pub trait Excavate, P: Pile, const CAPS: u32> { + fn schemata(&mut self) -> impl Iterator; + fn contracts(&mut self) -> impl Iterator)>; } -pub struct Mound, P: Pile, X, const CAPS: u32> { +pub struct Mound, P: Pile, X: Excavate, const CAPS: u32> { schemata: BTreeMap, contracts: BTreeMap>, persistence: X, } -impl, P: Pile, X: Default, const CAPS: u32> Default for Mound { +impl, P: Pile, X: Excavate + Default, const CAPS: u32> Default + for Mound +{ fn default() -> Self { Self { schemata: BTreeMap::new(), @@ -80,17 +51,19 @@ impl, P: Pile, X: Default, const CAPS: u32> Default for Mound, P: Pile, const CAPS: u32> Mound { +impl, P: Pile, X: Excavate + Default, const CAPS: u32> + Mound +{ pub fn new() -> Self { Self { schemata: BTreeMap::new(), contracts: BTreeMap::new(), - persistence: (), + persistence: default!(), } } } -impl, P: Pile, X, const CAPS: u32> Mound { +impl, P: Pile, X: Excavate, const CAPS: u32> Mound { pub fn with(persistence: X) -> Self { Self { schemata: BTreeMap::new(), @@ -99,11 +72,11 @@ impl, P: Pile, X, const CAPS: u32> Mound { } } - pub fn open(mut loader: impl Excavate) -> Self { + pub fn open(mut persistance: X) -> Self { Self { - schemata: loader.schemata().collect(), - contracts: loader.contracts().collect(), - persistence: loader.persistence(), + schemata: persistance.schemata().collect(), + contracts: persistance.contracts().collect(), + persistence: persistance, } } @@ -160,13 +133,6 @@ impl, P: Pile, X, const CAPS: u32> Mound { } } -pub trait Excavate, P: Pile, const CAPS: u32> { - type Persistence; - fn persistence(&self) -> Self::Persistence; - fn schemata(&mut self) -> impl Iterator; - fn contracts(&mut self) -> impl Iterator)>; -} - pub mod file { use std::fs; use std::fs::FileType; @@ -178,9 +144,9 @@ pub mod file { use super::*; use crate::pile::Protocol; - use crate::FilePile; + use crate::{FilePile, SealType}; - struct DirExcavator { + pub struct DirExcavator { dir: PathBuf, _phantom: PhantomData, } @@ -212,16 +178,16 @@ pub mod file { Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, { - type Persistence = PathBuf; - - fn persistence(&self) -> Self::Persistence { self.dir.clone() } - fn schemata(&mut self) -> impl Iterator { self.contents().filter_map(|(ty, path)| { if ty.is_file() && path.ends_with(".schema") { Schema::load(path) .ok() .map(|schema| (schema.codex.codex_id(), schema)) + } else if ty.is_dir() && path.ends_with(".contract") { + let contract = Stockpile::, CAPS>::load(path); + let schema = contract.stock().articles().schema.clone(); + Some((schema.codex.codex_id(), schema)) } else { None } @@ -233,7 +199,7 @@ pub mod file { ) -> impl Iterator, CAPS>)> { self.contents().filter_map(|(ty, path)| { - if ty.is_file() && path.ends_with(".contract") { + if ty.is_dir() && path.ends_with(".contract") { let contract = Stockpile::load(path); Some((contract.contract_id(), contract)) } else { @@ -243,8 +209,8 @@ pub mod file { } } - pub type FileMound = - Mound, PathBuf, CAPS>; + pub type FileMound = + Mound, DirExcavator, CAPS>; impl FileMound where @@ -258,11 +224,11 @@ pub mod file { } pub fn issue_file(&mut self, schema: Schema, params: IssueParams) -> ContractId { - let pile = FilePile::::new(params.name.as_str(), &self.persistence); - let supply = FileSupply::new(params.name.as_str(), &self.persistence); + let pile = FilePile::::new(params.name.as_str(), &self.persistence.dir); + let supply = FileSupply::new(params.name.as_str(), &self.persistence.dir); self.issue(schema, params, supply, pile) } - pub fn path(&self) -> &Path { &self.persistence } + pub fn path(&self) -> &Path { &self.persistence.dir } } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs new file mode 100644 index 00000000..18eb7bcf --- /dev/null +++ b/src/popls/bp.rs @@ -0,0 +1,375 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +//! Implementation of RGB standard library types for Bitcoin protocol, covering Bitcoin and Liquid +//! proof of publication layer 1. + +use alloc::collections::BTreeMap; + +use amplify::confinement::SmallOrdSet; +use bp::dbc::opret::OpretProof; +use bp::dbc::tapret::TapretProof; +use bp::seals::TxoSeal; +use bp::{dbc, Outpoint, Txid, Vout}; +use hypersonic::{ + AuthToken, CellAddr, ContractId, IssueParams, MethodName, NamedState, Operation, Schema, + StateAtom, Supply, +}; +use strict_encoding::{StrictDeserialize, StrictSerialize}; +use strict_types::StrictVal; + +use crate::pile::Protocol; +use crate::{Excavate, Mound, Pile}; + +pub trait WalletProvider {} +pub trait OpretProvider: WalletProvider {} +pub trait TapretProvider: WalletProvider {} + +#[cfg(feature = "bitcoin")] +pub const BITCOIN_OPRET: u32 = 0x0001_0001_u32; +#[cfg(feature = "bitcoin")] +pub const BITCOIN_TAPRET: u32 = 0x0001_0002_u32; +#[cfg(feature = "liquid")] +pub const LIQUID_OPRET: u32 = 0x0002_0001_u32; +#[cfg(feature = "liquid")] +pub const LIQUID_TAPRET: u32 = 0x0002_0002_u32; + +pub type OpretSeal = TxoSeal; +pub type TapretSeal = TxoSeal; + +/// Parameters used by BP-based wallet for constructing operations. +/// +/// Differs from [`hypersonic::CallParams`] in the fact that it uses [`TxoSeal`]s instead of +/// AuthTokens for output definitions. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ConstructParams { + pub method: MethodName, + pub global: Vec>, + pub owned: BTreeMap, NamedState>, + pub using: Vec<(AuthToken, StrictVal)>, + pub reading: Vec, +} + +/// Prefabricated operation, which includes information on the contract id and closed seals +/// (previous outputs). +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = "RGB")] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Prefab { + pub contract_id: ContractId, + pub closes: SmallOrdSet, + pub operation: Operation, +} + +/// A pack of prefabricated operations related to the same witness transaction. +/// +/// The pack should cover all contracts assigning state to the witness transaction previous outputs. +/// It is used to add seal closing commitment to the witness transaction PSBT. +#[derive(Clone, Eq, PartialEq, Debug, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = "RGB")] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct PrefabPack(SmallOrdSet); + +impl StrictSerialize for Prefab {} +impl StrictDeserialize for Prefab {} + +impl Protocol for TxoSeal { + type Id = Txid; + + fn auth_token(&self) -> AuthToken { todo!() } +} + +/// Barrow contains a bunch of RGB contract stockpiles, which are held by a single owner; such that +/// when a new operation under any of the contracts happen it may affect other contracts sharing the +/// same UTXOs. +pub struct Barrow< + W: WalletProvider, + D: dbc::Proof, + S: Supply, + P: Pile>, + X: Excavate, + const CAPS: u32, +> { + pub wallet: W, + //pub unspent: BTreeMap)>>, + pub mound: Mound, +} + +impl< + W: WalletProvider, + D: dbc::Proof, + S: Supply, + P: Pile>, + X: Excavate, + const CAPS: u32, + > Barrow +{ + pub fn with(wallet: W, mound: Mound) -> Self { Self { wallet, mound } } + + pub fn unbind(self) -> (W, Mound) { (self.wallet, self.mound) } + + pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { + self.mound.issue(schema, params, supply, pile) + } + + /* + pub fn assignments( + &self, + outpoint: Outpoint, + ) -> impl Iterator)> { + self.unspent + .get(&outpoint) + .expect("unknown outpoint") + .iter() + .map(|(id, seal)| (*id, seal)) + } + */ + + pub fn new_vout(&mut self, vout: Vout) -> TxoSeal { todo!() } + + pub fn new_seal(&mut self) -> TxoSeal { todo!() } + + pub fn resolve_seal(&self, opout: CellAddr) -> TxoSeal { todo!() } + + /// Creates a single operation basing on the provided construction parameters. + pub fn prefab(&self, contract_id: ContractId, params: ConstructParams) -> Prefab { + // convert ExecParams into CallParams + todo!() + } + + /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. + pub fn complete(&self, ops: impl IntoIterator) -> PrefabPack { + // add blank operations + todo!() + } +} + +pub mod file { + use std::iter; + use std::path::Path; + + use hypersonic::{CodexId, FileSupply, IssueParams}; + + use super::*; + use crate::mound::file::DirExcavator; + use crate::{FilePile, SealType}; + + pub type FileWallet = + Barrow>, DirExcavator, CAPS>, CAPS>; + + impl FileWallet { + pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + let schema = self.mound.schema(codex_id).expect("unknown codex id"); + // TODO: check that if the issue belongs to the wallet add it to the unspents + self.mound.issue_file(schema.clone(), params) + } + } + + pub type DirBtcMound = + Mound>, DirExcavator, CAPS>, CAPS>; + + #[cfg(feature = "bitcoin")] + pub type DirBcOpretMound = DirBtcMound; + #[cfg(feature = "bitcoin")] + pub type DirBcTapretMound = DirBtcMound; + #[cfg(feature = "liquid")] + pub type DirLqOpretMound = DirBtcMound; + #[cfg(feature = "liquid")] + pub type DirLqTapretMound = DirBtcMound; + + pub struct DirMound { + #[cfg(feature = "bitcoin")] + bc_opret: DirBcOpretMound, + #[cfg(feature = "bitcoin")] + bc_tapret: DirBcTapretMound, + #[cfg(feature = "liquid")] + lq_opret: DirLqOpretMound, + #[cfg(feature = "liquid")] + lq_tapret: DirLqTapretMound, + } + + impl DirMound { + pub fn load(root: impl AsRef) -> Self { + #[cfg(feature = "bitcoin")] + let bc_opret = { + let path = root.as_ref().join(SealType::BitcoinOpret.to_string()); + DirBcOpretMound::load(path) + }; + + #[cfg(feature = "bitcoin")] + let bc_tapret = { + let path = root.as_ref().join(SealType::BitcoinTapret.to_string()); + DirBcTapretMound::load(path) + }; + + #[cfg(feature = "liquid")] + let lq_opret = { + let path = root.as_ref().join(SealType::LiquidOpret.to_string()); + DirLqOpretMound::load(path) + }; + + #[cfg(feature = "liquid")] + let lq_tapret = { + let path = root.as_ref().join(SealType::LiquidTapret.to_string()); + DirLqTapretMound::load(path) + }; + + Self { + #[cfg(feature = "bitcoin")] + bc_opret, + #[cfg(feature = "bitcoin")] + bc_tapret, + #[cfg(feature = "liquid")] + lq_opret, + #[cfg(feature = "liquid")] + lq_tapret, + } + } + + pub fn codex_ids(&self) -> impl Iterator + use<'_> { + let iter = iter::empty(); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_opret.codex_ids()); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_tapret.codex_ids()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_opret.codex_ids()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_tapret.codex_ids()); + iter + } + + pub fn schemata(&self) -> impl Iterator { + let iter = iter::empty(); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_opret.schemata()); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_tapret.schemata()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_opret.schemata()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_tapret.schemata()); + iter + } + + pub fn schema(&self, codex_id: CodexId) -> Option<&Schema> { + let res = None; + #[cfg(feature = "bitcoin")] + let res = res.or_else(|| self.bc_opret.schema(codex_id)); + #[cfg(feature = "bitcoin")] + let res = res.or_else(|| self.bc_tapret.schema(codex_id)); + #[cfg(feature = "liquid")] + let res = res.or_else(|| self.lq_opret.schema(codex_id)); + #[cfg(feature = "liquid")] + let res = res.or_else(|| self.lq_tapret.schema(codex_id)); + res + } + + pub fn contract_ids(&self) -> impl Iterator + use<'_> { + let iter = iter::empty(); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_opret.contract_ids()); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_tapret.contract_ids()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_opret.contract_ids()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_tapret.contract_ids()); + iter + } + } + + pub type BpBarrow = + Barrow>, DirExcavator, CAPS>, CAPS>; + + #[cfg(feature = "bitcoin")] + pub type DirBcOpretBarrow = BpBarrow; + #[cfg(feature = "bitcoin")] + pub type DirBcTapretBarrow = BpBarrow; + #[cfg(feature = "liquid")] + pub type DirLqOpretBarrow = BpBarrow; + #[cfg(feature = "liquid")] + pub type DirLqTapretBarrow = BpBarrow; + + pub enum DirBarrow { + #[cfg(feature = "bitcoin")] + BcOpret(DirBcOpretBarrow), + #[cfg(feature = "bitcoin")] + BcTapret(DirBcTapretBarrow), + #[cfg(feature = "liquid")] + LqOpret(DirLqOpretBarrow), + #[cfg(feature = "liquid")] + LqTapret(DirLqTapretBarrow), + } + + impl DirBarrow { + pub fn load_opret(ty: SealType, root: impl AsRef, wallet: O) -> Self { + let mound = DirMound::load(root); + Self::with_opret(ty, mound, wallet) + } + + pub fn load_tapret(ty: SealType, root: impl AsRef, wallet: T) -> Self { + let mound = DirMound::load(root); + Self::with_tapret(ty, mound, wallet) + } + + pub fn with_opret(ty: SealType, mound: DirMound, wallet: O) -> Self { + match ty { + #[cfg(feature = "bitcoin")] + SealType::BitcoinOpret => Self::BcOpret(BpBarrow::with(wallet, mound.bc_opret)), + #[cfg(feature = "liquid")] + SealType::LiquidOpret => Self::LqOpret(BpBarrow::with(wallet, mound.lq_opret)), + _ => panic!("unsupported seal type"), + } + } + + pub fn with_tapret(ty: SealType, mound: DirMound, wallet: T) -> Self { + match ty { + #[cfg(feature = "bitcoin")] + SealType::BitcoinTapret => Self::BcTapret(BpBarrow::with(wallet, mound.bc_tapret)), + #[cfg(feature = "liquid")] + SealType::LiquidTapret => Self::LqTapret(BpBarrow::with(wallet, mound.lq_tapret)), + _ => panic!("unsupported seal type"), + } + } + } + + impl DirBarrow { + pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + match self { + #[cfg(feature = "bitcoin")] + Self::BcOpret(barrow) => barrow.issue_file(codex_id, params), + #[cfg(feature = "bitcoin")] + Self::BcTapret(barrow) => barrow.issue_file(codex_id, params), + #[cfg(feature = "liquid")] + Self::LqOpret(barrow) => barrow.issue_file(codex_id, params), + #[cfg(feature = "liquid")] + Self::LqTapret(barrow) => barrow.issue_file(codex_id, params), + } + } + } +} diff --git a/src/popls/mod.rs b/src/popls/mod.rs new file mode 100644 index 00000000..f63b6550 --- /dev/null +++ b/src/popls/mod.rs @@ -0,0 +1,94 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +//! Proof of publication layers supported by RGB. + +use core::str::FromStr; + +#[cfg(any(feature = "bitcoin", feature = "liquid"))] +pub mod bp; +#[cfg(feature = "prime")] +pub mod prime; + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[repr(u32)] +pub enum SealType { + #[cfg(feature = "bitcoin")] + #[display("bcor")] + BitcoinOpret = self::bp::BITCOIN_OPRET, + + #[cfg(feature = "bitcoin")] + #[display("bctr")] + BitcoinTapret = self::bp::BITCOIN_TAPRET, + + #[cfg(feature = "liquid")] + #[display("lqor")] + LiquidOpret = self::bp::LIQUID_OPRET, + + #[cfg(feature = "liquid")] + #[display("lqtr")] + LiquidTapret = self::bp::LIQUID_TAPRET, + + #[cfg(feature = "prime")] + #[display("prime")] + Prime = self::prime::PRIME, +} + +#[derive(Clone, Eq, PartialEq, Debug, Display, Error)] +#[display("unknown seal type `{0}`")] +pub struct UnknownType(String); + +impl FromStr for SealType { + type Err = UnknownType; + + fn from_str(s: &str) -> Result { + match s { + #[cfg(feature = "bitcoin")] + "bcor" => Ok(SealType::BitcoinOpret), + #[cfg(feature = "bitcoin")] + "bctr" => Ok(SealType::BitcoinTapret), + #[cfg(feature = "liquid")] + "lqtr" => Ok(SealType::LiquidTapret), + #[cfg(feature = "prime")] + "prime" => Ok(SealType::Prime), + _ => Err(UnknownType(s.to_string())), + } + } +} + +impl From for SealType { + fn from(caps: u32) -> Self { + match caps { + #[cfg(feature = "bitcoin")] + self::bp::BITCOIN_OPRET => Self::BitcoinOpret, + #[cfg(feature = "bitcoin")] + self::bp::BITCOIN_TAPRET => Self::BitcoinTapret, + #[cfg(feature = "liquid")] + self::bp::LIQUID_TAPRET => Self::LiquidTapret, + #[cfg(feature = "prime")] + self::prime::PRIME => Self::Prime, + unknown => panic!("unknown seal type {unknown:#10x}"), + } + } +} diff --git a/src/popls/prime.rs b/src/popls/prime.rs new file mode 100644 index 00000000..63c45069 --- /dev/null +++ b/src/popls/prime.rs @@ -0,0 +1,25 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +pub const PRIME: u32 = 0x0010_0001_u32; diff --git a/src/stockpile.rs b/src/stockpile.rs index b3c2d6bc..411a52ea 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -32,6 +32,7 @@ use strict_encoding::{StrictWriter, WriteRaw}; use crate::pile::Protocol; use crate::Pile; +#[derive(Getters)] pub struct Stockpile, P: Pile, const CAPS: u32> { stock: Stock, pile: P, From 8015cf9bc51917ade68cee1f8ea6c537dbe75509 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 10 Dec 2024 15:15:36 +0100 Subject: [PATCH 25/70] implement issue at barrow level --- src/mound.rs | 15 ++++++++++---- src/popls/bp.rs | 55 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/mound.rs b/src/mound.rs index 49ac0ad4..dfffb5b3 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -80,8 +80,15 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound ContractId { - let stockpile = Stockpile::issue(schema, params, supply, pile); + pub fn issue( + &mut self, + codex_id: CodexId, + params: IssueParams, + supply: S, + pile: P, + ) -> ContractId { + let schema = self.schema(codex_id).expect("unknown schema"); + let stockpile = Stockpile::issue(schema.clone(), params, supply, pile); let id = stockpile.contract_id(); self.contracts.insert(id, stockpile); id @@ -223,10 +230,10 @@ pub mod file { Self::open(excavator) } - pub fn issue_file(&mut self, schema: Schema, params: IssueParams) -> ContractId { + pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { let pile = FilePile::::new(params.name.as_str(), &self.persistence.dir); let supply = FileSupply::new(params.name.as_str(), &self.persistence.dir); - self.issue(schema, params, supply, pile) + self.issue(codex_id, params, supply, pile) } pub fn path(&self) -> &Path { &self.persistence.dir } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 18eb7bcf..64fa5302 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -33,8 +33,8 @@ use bp::dbc::tapret::TapretProof; use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Txid, Vout}; use hypersonic::{ - AuthToken, CellAddr, ContractId, IssueParams, MethodName, NamedState, Operation, Schema, - StateAtom, Supply, + AdaptedState, AuthToken, CellAddr, CodexId, ContractId, IssueParams, MethodName, NamedState, + Operation, Schema, StateAtom, Supply, }; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; @@ -132,8 +132,25 @@ impl< pub fn unbind(self) -> (W, Mound) { (self.wallet, self.mound) } - pub fn issue(&mut self, schema: Schema, params: IssueParams, supply: S, pile: P) -> ContractId { - self.mound.issue(schema, params, supply, pile) + pub fn issue( + &mut self, + codex_id: CodexId, + params: IssueParams, + supply: S, + pile: P, + ) -> ContractId { + self.mound.issue(codex_id, params, supply, pile) + } + + pub fn state( + &self, + all: bool, + contract_id: Option, + ) -> impl Iterator { + self.mound + .contracts() + .filter(move |(id, _)| contract_id.is_none() || Some(*id) == contract_id) + .map(|(id, stockpile)| (id, &stockpile.stock().state().main)) } /* @@ -183,9 +200,8 @@ pub mod file { impl FileWallet { pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { - let schema = self.mound.schema(codex_id).expect("unknown codex id"); // TODO: check that if the issue belongs to the wallet add it to the unspents - self.mound.issue_file(schema.clone(), params) + self.mound.issue_file(codex_id, params) } } @@ -203,13 +219,13 @@ pub mod file { pub struct DirMound { #[cfg(feature = "bitcoin")] - bc_opret: DirBcOpretMound, + pub bc_opret: DirBcOpretMound, #[cfg(feature = "bitcoin")] - bc_tapret: DirBcTapretMound, + pub bc_tapret: DirBcTapretMound, #[cfg(feature = "liquid")] - lq_opret: DirLqOpretMound, + pub lq_opret: DirLqOpretMound, #[cfg(feature = "liquid")] - lq_tapret: DirLqTapretMound, + pub lq_tapret: DirLqTapretMound, } impl DirMound { @@ -356,9 +372,7 @@ pub mod file { _ => panic!("unsupported seal type"), } } - } - impl DirBarrow { pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { match self { #[cfg(feature = "bitcoin")] @@ -371,5 +385,22 @@ pub mod file { Self::LqTapret(barrow) => barrow.issue_file(codex_id, params), } } + + pub fn state( + &self, + all: bool, + contract_id: Option, + ) -> Box + '_> { + match self { + #[cfg(feature = "bitcoin")] + Self::BcOpret(barrow) => Box::new(barrow.state(all, contract_id)), + #[cfg(feature = "bitcoin")] + Self::BcTapret(barrow) => Box::new(barrow.state(all, contract_id)), + #[cfg(feature = "liquid")] + Self::LqOpret(barrow) => Box::new(barrow.state(all, contract_id)), + #[cfg(feature = "liquid")] + Self::LqTapret(barrow) => Box::new(barrow.state(all, contract_id)), + } + } } } From d01c882aca5bef2d9f9e71ed8afc482bfc0662ff Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 10 Dec 2024 22:13:12 +0100 Subject: [PATCH 26/70] bp: construction prefabs --- src/popls/bp.rs | 95 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 64fa5302..0e80156c 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -27,6 +27,7 @@ use alloc::collections::BTreeMap; +use amplify::confinement; use amplify::confinement::SmallOrdSet; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; @@ -58,16 +59,38 @@ pub const LIQUID_TAPRET: u32 = 0x0002_0002_u32; pub type OpretSeal = TxoSeal; pub type TapretSeal = TxoSeal; +impl Protocol for TxoSeal { + type Id = Txid; + + fn auth_token(&self) -> AuthToken { todo!() } +} + +// TODO: Support failback seals +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase", untagged) +)] +pub enum BuilderSeal { + #[display("~:{0}")] + Oneself(Vout), + + #[display("{0}")] + Extern(Outpoint), +} + /// Parameters used by BP-based wallet for constructing operations. /// /// Differs from [`hypersonic::CallParams`] in the fact that it uses [`TxoSeal`]s instead of /// AuthTokens for output definitions. #[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct ConstructParams { +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] +pub struct ConstructParams { + pub contract_id: ContractId, pub method: MethodName, pub global: Vec>, - pub owned: BTreeMap, NamedState>, + pub owned: BTreeMap>, pub using: Vec<(AuthToken, StrictVal)>, pub reading: Vec, } @@ -77,30 +100,42 @@ pub struct ConstructParams { #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = "RGB")] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] pub struct Prefab { pub contract_id: ContractId, pub closes: SmallOrdSet, + pub defines: SmallOrdSet, pub operation: Operation, } -/// A pack of prefabricated operations related to the same witness transaction. +/// A bundle of prefabricated operations related to the same witness transaction. /// /// The pack should cover all contracts assigning state to the witness transaction previous outputs. /// It is used to add seal closing commitment to the witness transaction PSBT. -#[derive(Clone, Eq, PartialEq, Debug, Default)] +#[derive(Wrapper, WrapperMut, Clone, Eq, PartialEq, Debug, Default, From)] +#[wrapper(Deref)] +#[wrapper_mut(DerefMut)] #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = "RGB")] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct PrefabPack(SmallOrdSet); +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +pub struct PrefabBundle(SmallOrdSet); -impl StrictSerialize for Prefab {} -impl StrictDeserialize for Prefab {} +impl StrictSerialize for PrefabBundle {} +impl StrictDeserialize for PrefabBundle {} -impl Protocol for TxoSeal { - type Id = Txid; +impl PrefabBundle { + pub fn new(items: impl IntoIterator) -> Result { + let items = SmallOrdSet::try_from_iter(items.into_iter())?; + Ok(Self(items)) + } - fn auth_token(&self) -> AuthToken { todo!() } + pub fn closes(&self) -> impl Iterator + use<'_> { + self.0.iter().flat_map(|item| item.closes.iter().copied()) + } + + pub fn defines(&self) -> impl Iterator + use<'_> { + self.0.iter().flat_map(|item| item.defines.iter().copied()) + } } /// Barrow contains a bunch of RGB contract stockpiles, which are held by a single owner; such that @@ -142,9 +177,9 @@ impl< self.mound.issue(codex_id, params, supply, pile) } + // TODO: Use bitcoin-specific state type aware of outpoints pub fn state( &self, - all: bool, contract_id: Option, ) -> impl Iterator { self.mound @@ -173,13 +208,13 @@ impl< pub fn resolve_seal(&self, opout: CellAddr) -> TxoSeal { todo!() } /// Creates a single operation basing on the provided construction parameters. - pub fn prefab(&self, contract_id: ContractId, params: ConstructParams) -> Prefab { + pub fn prefab(&self, params: ConstructParams) -> Prefab { // convert ExecParams into CallParams todo!() } /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. - pub fn complete(&self, ops: impl IntoIterator) -> PrefabPack { + pub fn bundle(&self, ops: impl IntoIterator) -> PrefabBundle { // add blank operations todo!() } @@ -388,19 +423,37 @@ pub mod file { pub fn state( &self, - all: bool, contract_id: Option, ) -> Box + '_> { match self { #[cfg(feature = "bitcoin")] - Self::BcOpret(barrow) => Box::new(barrow.state(all, contract_id)), + Self::BcOpret(barrow) => Box::new(barrow.state(contract_id)), #[cfg(feature = "bitcoin")] - Self::BcTapret(barrow) => Box::new(barrow.state(all, contract_id)), + Self::BcTapret(barrow) => Box::new(barrow.state(contract_id)), #[cfg(feature = "liquid")] - Self::LqOpret(barrow) => Box::new(barrow.state(all, contract_id)), + Self::LqOpret(barrow) => Box::new(barrow.state(contract_id)), #[cfg(feature = "liquid")] - Self::LqTapret(barrow) => Box::new(barrow.state(all, contract_id)), + Self::LqTapret(barrow) => Box::new(barrow.state(contract_id)), } } + + pub fn prefab(&self, params: ConstructParams) -> Prefab { + match self { + #[cfg(feature = "bitcoin")] + Self::BcOpret(barrow) => barrow.prefab(params), + #[cfg(feature = "bitcoin")] + Self::BcTapret(barrow) => barrow.prefab(params), + #[cfg(feature = "liquid")] + Self::LqOpret(barrow) => barrow.prefab(params), + #[cfg(feature = "liquid")] + Self::LqTapret(barrow) => barrow.prefab(params), + } + } + + pub fn bundle(&self, items: impl IntoIterator) -> PrefabBundle { + let iter = items.into_iter().map(|params| self.prefab(params)); + let items = SmallOrdSet::try_from_iter(iter).expect("too large script"); + PrefabBundle(items) + } } } From b096db7c3f3e5791a7fe8d897259c4890f5c55c4 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 11 Dec 2024 03:00:40 +0100 Subject: [PATCH 27/70] add index to pile --- Cargo.lock | 12 +++---- src/mound.rs | 3 ++ src/pile.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++--- src/stockpile.rs | 31 ++++++++++++------ 4 files changed, 110 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ef49e17..3095f8f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -258,9 +258,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#9f6e96678920f5364e370d761c6ef5d81eb5001a" +source = "git+https://github.com/AluVM/sonic#1867a24ea654d91de1a83347d0854ae1c81625cc" dependencies = [ "aluvm", "amplify", @@ -457,9 +457,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "log" @@ -740,7 +740,7 @@ checksum = "fa1f0140117847f5470c5ab2e68f7645bfe6fe27933b9160de63832ecaf0f3d2" [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#9f6e96678920f5364e370d761c6ef5d81eb5001a" +source = "git+https://github.com/AluVM/sonic#1867a24ea654d91de1a83347d0854ae1c81625cc" dependencies = [ "aluvm", "amplify", diff --git a/src/mound.rs b/src/mound.rs index dfffb5b3..346b9530 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -147,6 +147,7 @@ pub mod file { use std::path::{Path, PathBuf}; use hypersonic::FileSupply; + use single_use_seals::{PublishedWitness, SingleUseSeal}; use strict_encoding::{StrictDecode, StrictEncode}; use super::*; @@ -184,6 +185,7 @@ pub mod file { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, + <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]>, { fn schemata(&mut self) -> impl Iterator { self.contents().filter_map(|(ty, path)| { @@ -223,6 +225,7 @@ pub mod file { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, + <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]>, { pub fn load(path: impl AsRef) -> Self { let path = path.as_ref(); diff --git a/src/pile.rs b/src/pile.rs index 494c74c3..aea79509 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -23,28 +23,42 @@ // the License. use hypersonic::aora::Aora; -use hypersonic::AuthToken; -use single_use_seals::SingleUseSeal; +use hypersonic::{AuthToken, Opid}; +use single_use_seals::{PublishedWitness, SingleUseSeal}; pub trait Protocol: SingleUseSeal { type Id: Ord + From<[u8; 32]> + Into<[u8; 32]>; fn auth_token(&self) -> AuthToken; } +pub trait Index { + fn get(&self, key: K) -> impl ExactSizeIterator; + fn add(&mut self, key: K, val: V); +} + pub trait Pile { type Seal: Protocol; type Hoard: Aora::CliWitness>; type Cache: Aora::PubWitness>; + type Index: Index< + Opid, + <::PubWitness as PublishedWitness>::PubId, + >; fn hoard(&self) -> &Self::Hoard; fn cache(&self) -> &Self::Cache; + fn index(&self) -> &Self::Index; fn hoard_mut(&mut self) -> &mut Self::Hoard; fn cache_mut(&mut self) -> &mut Self::Cache; + fn index_mut(&mut self) -> &mut Self::Index; } #[cfg(feature = "fs")] pub mod fs { + use std::collections::BTreeMap; + use std::fs::File; + use std::io::Read; use std::path::{Path, PathBuf}; use hypersonic::aora::file::FileAora; @@ -52,10 +66,29 @@ pub mod fs { use super::*; + #[derive(Clone, Debug, From)] + pub struct MemIndex(BTreeMap>); + impl Default for MemIndex { + fn default() -> Self { Self(none!()) } + } + + impl Index for MemIndex { + fn get(&self, key: Opid) -> impl ExactSizeIterator { + self.0 + .get(&key) + .expect("unknown operation ID requested from the index") + .iter() + .copied() + } + + fn add(&mut self, key: Opid, val: V) { self.0.entry(key).or_default().push(val) } + } + pub struct FilePile { path: PathBuf, hoard: FileAora, cache: FileAora, + index: MemIndex<<::PubWitness as PublishedWitness>::PubId>, } impl FilePile { @@ -66,14 +99,51 @@ pub mod fs { let hoard = FileAora::new(&path, "hoard"); let cache = FileAora::new(&path, "cache"); - Self { path, hoard, cache } + Self { + path, + hoard, + cache, + index: empty!(), + } } + } + impl FilePile + where <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]> + { pub fn open(path: impl AsRef) -> Self { let path = path.as_ref().to_path_buf(); let hoard = FileAora::open(&path, "hoard"); let cache = FileAora::open(&path, "cache"); - Self { path, hoard, cache } + + let mut index = BTreeMap::new(); + let mut index_file = + File::open(path.join("index.dat")).expect("cannot open index file"); + let mut buf = [0u8; 32]; + while index_file.read_exact(&mut buf).is_ok() { + let opid = Opid::from(buf); + let mut ids = Vec::new(); + let mut len = [0u8; 4]; + index_file + .read_exact(&mut len) + .expect("cannot read index file"); + let mut len = u32::from_le_bytes(len); + while len > 0 { + index_file + .read_exact(&mut buf) + .expect("cannot read index file"); + ids.push(buf.into()); + len -= 1; + } + index.insert(opid, ids); + } + + Self { + path, + hoard, + cache, + index: index.into(), + } } } @@ -85,13 +155,19 @@ pub mod fs { type Seal = Seal; type Hoard = FileAora; type Cache = FileAora; + type Index = + MemIndex<<::PubWitness as PublishedWitness>::PubId>; fn hoard(&self) -> &Self::Hoard { &self.hoard } fn cache(&self) -> &Self::Cache { &self.cache } + fn index(&self) -> &Self::Index { &self.index } + fn hoard_mut(&mut self) -> &mut Self::Hoard { &mut self.hoard } fn cache_mut(&mut self) -> &mut Self::Cache { &mut self.cache } + + fn index_mut(&mut self) -> &mut Self::Index { &mut self.index } } } diff --git a/src/stockpile.rs b/src/stockpile.rs index 411a52ea..a85c0ac3 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -25,11 +25,12 @@ // TODO: Used in strict encoding; once solved there, remove here use std::io; +use hypersonic::aora::Aora; use hypersonic::{Articles, AuthToken, CellAddr, ContractId, IssueParams, Schema, Stock, Supply}; -use single_use_seals::SingleUseSeal; -use strict_encoding::{StrictWriter, WriteRaw}; +use single_use_seals::{PublishedWitness, SingleUseSeal}; +use strict_encoding::{StrictEncode, StrictWriter, WriteRaw}; -use crate::pile::Protocol; +use crate::pile::{Index, Protocol}; use crate::Pile; #[derive(Getters)] @@ -59,18 +60,27 @@ impl, P: Pile, const CAPS: u32> Stockpile { pub fn append_witness( &mut self, - published: ::PubWitness, - client: ::CliWitness, - ) { - todo!() + published: &::PubWitness, + client: &::CliWitness, + ) where + <::PubWitness as PublishedWitness>::PubId: + Into<[u8; 32]>, + { + let id = published.pub_id(); + self.pile.hoard_mut().append(id.into().into(), client); + self.pile.cache_mut().append(id.into().into(), published); } pub fn consign<'a>( &mut self, terminals: impl IntoIterator, - mut writer: StrictWriter, - ) -> io::Result<()> { - todo!() + writer: StrictWriter, + ) -> io::Result<()> + where + <::PubWitness as PublishedWitness>::PubId: StrictEncode, + { + self.stock + .export_aux(terminals, writer, |opid| self.pile.index().get(opid)) } } @@ -88,6 +98,7 @@ mod fs { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, + <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]>, { pub fn load(path: impl AsRef) -> Self { let path = path.as_ref(); From 1ad416abc4602de660fb08c3bbd07bbabbeb1600 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 11 Dec 2024 03:05:29 +0100 Subject: [PATCH 28/70] implement TXO seal conversion into a SONIC auth token --- src/popls/bp.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 0e80156c..a5d2dce0 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -33,6 +33,7 @@ use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Txid, Vout}; +use commit_verify::CommitId; use hypersonic::{ AdaptedState, AuthToken, CellAddr, CodexId, ContractId, IssueParams, MethodName, NamedState, Operation, Schema, StateAtom, Supply, @@ -62,7 +63,15 @@ pub type TapretSeal = TxoSeal; impl Protocol for TxoSeal { type Id = Txid; - fn auth_token(&self) -> AuthToken { todo!() } + // SECURITY: Here we cut SHA256 tagged hash of a single-use seal definition to 30 bytes in order + // to fit it into a field element with no overflows. This must be a secure operation since we + // still have a sufficient 120-bit collision resistance. + fn auth_token(&self) -> AuthToken { + let id = self.commit_id().to_byte_array(); + let mut shortened_id = [0u8; 30]; + shortened_id.copy_from_slice(&id[0..30]); + AuthToken::from_byte_array(shortened_id) + } } // TODO: Support failback seals @@ -201,12 +210,6 @@ impl< } */ - pub fn new_vout(&mut self, vout: Vout) -> TxoSeal { todo!() } - - pub fn new_seal(&mut self) -> TxoSeal { todo!() } - - pub fn resolve_seal(&self, opout: CellAddr) -> TxoSeal { todo!() } - /// Creates a single operation basing on the provided construction parameters. pub fn prefab(&self, params: ConstructParams) -> Prefab { // convert ExecParams into CallParams From f81347c1e4966723baf4b90ffdb2714d40181cd3 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 11 Dec 2024 09:42:21 +0100 Subject: [PATCH 29/70] implement operation prefabrication --- Cargo.lock | 20 +++++------ src/popls/bp.rs | 94 +++++++++++++++++++++++++++++++++++++++++------- src/stockpile.rs | 2 ++ 3 files changed, 93 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3095f8f3..ffd8e5d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,7 +170,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" dependencies = [ "amplify", "chrono", @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" dependencies = [ "amplify", "bp-consensus", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" dependencies = [ "amplify", "base85", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#5d8db23ffa73417937230238d807310eb6052579" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" dependencies = [ "amplify", "baid64", @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#1867a24ea654d91de1a83347d0854ae1c81625cc" +source = "git+https://github.com/AluVM/sonic#f0895034c3795ad6bb637f630a79fa4f5ddd4221" dependencies = [ "aluvm", "amplify", @@ -652,18 +652,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -740,7 +740,7 @@ checksum = "fa1f0140117847f5470c5ab2e68f7645bfe6fe27933b9160de63832ecaf0f3d2" [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#1867a24ea654d91de1a83347d0854ae1c81625cc" +source = "git+https://github.com/AluVM/sonic#f0895034c3795ad6bb637f630a79fa4f5ddd4221" dependencies = [ "aluvm", "amplify", diff --git a/src/popls/bp.rs b/src/popls/bp.rs index a5d2dce0..945e638d 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -33,10 +33,10 @@ use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Txid, Vout}; -use commit_verify::CommitId; +use commit_verify::{CommitId, Digest, DigestExt, Sha256}; use hypersonic::{ - AdaptedState, AuthToken, CellAddr, CodexId, ContractId, IssueParams, MethodName, NamedState, - Operation, Schema, StateAtom, Supply, + AdaptedState, AuthToken, CallParams, CellAddr, CodexId, ContractId, CoreParams, DataCell, + IssueParams, MethodName, NamedState, Operation, Schema, StateAtom, Supply, }; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; @@ -100,7 +100,7 @@ pub struct ConstructParams { pub method: MethodName, pub global: Vec>, pub owned: BTreeMap>, - pub using: Vec<(AuthToken, StrictVal)>, + pub using: Vec<(AuthToken, Outpoint, StrictVal)>, pub reading: Vec, } @@ -211,9 +211,69 @@ impl< */ /// Creates a single operation basing on the provided construction parameters. - pub fn prefab(&self, params: ConstructParams) -> Prefab { + pub fn prefab(&mut self, params: ConstructParams, noise_seed: impl AsRef<[u8]>) -> Prefab { // convert ExecParams into CallParams - todo!() + + let closes = + SmallOrdSet::from_iter_checked(params.using.iter().map(|(_, outpoint, _)| *outpoint)); + let using = params + .using + .into_iter() + .map(|(auth, _, val)| (auth, val)) + .collect(); + let mut defines = SmallOrdSet::new(); + + debug_assert_eq!(noise_seed.as_ref().len(), 32); + let mut noise_endigne = Sha256::new(); + noise_endigne.input_raw(params.contract_id.as_slice()); + noise_endigne.input_raw(noise_seed.as_ref()); + let owned = params + .owned + .into_iter() + .map(|(seal, val)| { + let seal = match seal { + BuilderSeal::Oneself(vout) => { + defines.push(vout).expect("too many seals"); + // NB: We use opret type here, but this doesn't matter since we create seal + // only to produce the auth token, and seals do not commit to their type. + TxoSeal::::vout_no_fallback(vout, noise_endigne.clone()) + } + BuilderSeal::Extern(outpoint) => { + TxoSeal::no_fallback(outpoint, noise_endigne.clone()) + } + }; + let state = DataCell { + data: val.state, + auth: seal.auth_token(), + lock: None, + }; + NamedState { + name: val.name, + state, + } + }) + .collect(); + + let call = CallParams { + core: CoreParams { + method: params.method, + global: params.global, + owned, + }, + using, + reading: params.reading, + }; + + let stockpile = self.mound.contract_mut(params.contract_id); + let opid = stockpile.stock_mut().call(call); + let operation = stockpile.stock_mut().operation(opid); + + Prefab { + contract_id: params.contract_id, + closes, + defines, + operation, + } } /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. @@ -440,21 +500,29 @@ pub mod file { } } - pub fn prefab(&self, params: ConstructParams) -> Prefab { + pub fn prefab(&mut self, params: ConstructParams, noise_seed: impl AsRef<[u8]>) -> Prefab { + // TODO: Mix into a noise seed contract id and other data match self { #[cfg(feature = "bitcoin")] - Self::BcOpret(barrow) => barrow.prefab(params), + Self::BcOpret(barrow) => barrow.prefab(params, noise_seed), #[cfg(feature = "bitcoin")] - Self::BcTapret(barrow) => barrow.prefab(params), + Self::BcTapret(barrow) => barrow.prefab(params, noise_seed), #[cfg(feature = "liquid")] - Self::LqOpret(barrow) => barrow.prefab(params), + Self::LqOpret(barrow) => barrow.prefab(params, noise_seed), #[cfg(feature = "liquid")] - Self::LqTapret(barrow) => barrow.prefab(params), + Self::LqTapret(barrow) => barrow.prefab(params, noise_seed), } } - pub fn bundle(&self, items: impl IntoIterator) -> PrefabBundle { - let iter = items.into_iter().map(|params| self.prefab(params)); + pub fn bundle( + &mut self, + items: impl IntoIterator, + noise_seed: impl AsRef<[u8]>, + ) -> PrefabBundle { + let noise_seed = noise_seed.as_ref(); + let iter = items + .into_iter() + .map(|params| self.prefab(params, noise_seed)); let items = SmallOrdSet::try_from_iter(iter).expect("too large script"); PrefabBundle(items) } diff --git a/src/stockpile.rs b/src/stockpile.rs index a85c0ac3..4d56d7dd 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -35,7 +35,9 @@ use crate::Pile; #[derive(Getters)] pub struct Stockpile, P: Pile, const CAPS: u32> { + #[getter(as_mut)] stock: Stock, + #[getter(as_mut)] pile: P, } From 6f6645d488949b6d0b724fa197ab475a337d3142 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 11 Dec 2024 18:58:42 +0100 Subject: [PATCH 30/70] construct blank operations --- Cargo.lock | 8 ++-- src/popls/bp.rs | 123 ++++++++++++++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffd8e5d3..c2bb4bfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,7 +170,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" dependencies = [ "amplify", "chrono", @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" dependencies = [ "amplify", "bp-consensus", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" dependencies = [ "amplify", "base85", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b2b347ff9d1f1f214844b48db1ce6cb3075bc669" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" dependencies = [ "amplify", "baid64", diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 945e638d..f2f3eec1 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -26,9 +26,10 @@ //! proof of publication layer 1. use alloc::collections::BTreeMap; +use std::collections::BTreeSet; -use amplify::confinement; use amplify::confinement::SmallOrdSet; +use amplify::{confinement, Bytes32}; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; use bp::seals::TxoSeal; @@ -44,7 +45,9 @@ use strict_types::StrictVal; use crate::pile::Protocol; use crate::{Excavate, Mound, Pile}; -pub trait WalletProvider {} +pub trait WalletProvider { + fn noise_seed(&self) -> Bytes32; +} pub trait OpretProvider: WalletProvider {} pub trait TapretProvider: WalletProvider {} @@ -57,6 +60,8 @@ pub const LIQUID_OPRET: u32 = 0x0002_0001_u32; #[cfg(feature = "liquid")] pub const LIQUID_TAPRET: u32 = 0x0002_0002_u32; +pub const BP_BLANK_METHOD: &str = "_"; + pub type OpretSeal = TxoSeal; pub type TapretSeal = TxoSeal; @@ -159,7 +164,6 @@ pub struct Barrow< const CAPS: u32, > { pub wallet: W, - //pub unspent: BTreeMap)>>, pub mound: Mound, } @@ -197,36 +201,22 @@ impl< .map(|(id, stockpile)| (id, &stockpile.stock().state().main)) } - /* - pub fn assignments( - &self, - outpoint: Outpoint, - ) -> impl Iterator)> { - self.unspent - .get(&outpoint) - .expect("unknown outpoint") - .iter() - .map(|(id, seal)| (*id, seal)) - } - */ - /// Creates a single operation basing on the provided construction parameters. - pub fn prefab(&mut self, params: ConstructParams, noise_seed: impl AsRef<[u8]>) -> Prefab { + pub fn prefab(&mut self, params: ConstructParams) -> Prefab { // convert ExecParams into CallParams - let closes = - SmallOrdSet::from_iter_checked(params.using.iter().map(|(_, outpoint, _)| *outpoint)); - let using = params + let (closes, using) = params .using .into_iter() - .map(|(auth, _, val)| (auth, val)) - .collect(); + .map(|(auth, outpoint, val)| (outpoint, (auth, val))) + .unzip(); + let closes = SmallOrdSet::try_from(closes).expect("too many inputs"); let mut defines = SmallOrdSet::new(); - debug_assert_eq!(noise_seed.as_ref().len(), 32); - let mut noise_endigne = Sha256::new(); - noise_endigne.input_raw(params.contract_id.as_slice()); - noise_endigne.input_raw(noise_seed.as_ref()); + let noise_seed = self.wallet.noise_seed(); + let mut noise_engine = Sha256::new(); + noise_engine.input_raw(params.contract_id.as_slice()); + noise_engine.input_raw(noise_seed.as_ref()); let owned = params .owned .into_iter() @@ -236,10 +226,10 @@ impl< defines.push(vout).expect("too many seals"); // NB: We use opret type here, but this doesn't matter since we create seal // only to produce the auth token, and seals do not commit to their type. - TxoSeal::::vout_no_fallback(vout, noise_endigne.clone()) + TxoSeal::::vout_no_fallback(vout, noise_engine.clone()) } BuilderSeal::Extern(outpoint) => { - TxoSeal::no_fallback(outpoint, noise_endigne.clone()) + TxoSeal::no_fallback(outpoint, noise_engine.clone()) } }; let state = DataCell { @@ -277,9 +267,59 @@ impl< } /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. - pub fn bundle(&self, ops: impl IntoIterator) -> PrefabBundle { - // add blank operations - todo!() + pub fn bundle(&mut self, ops: impl IntoIterator) -> PrefabBundle { + let mut outpoints = BTreeSet::::new(); + let mut contracts = BTreeSet::new(); + let mut prefabs = BTreeSet::new(); + for prefab in ops { + contracts.insert(prefab.contract_id); + outpoints.extend(&prefab.closes); + prefabs.insert(prefab); + } + + for (contract_id, stockpile) in self.mound.contracts_mut() { + let noise_seed = self.wallet.noise_seed(); + let mut noise_engine = Sha256::new(); + noise_engine.input_raw(contract_id.as_slice()); + noise_engine.input_raw(noise_seed.as_ref()); + + let using = stockpile + .stock() + .state() + .main + .owned + .values() + .flat_map(BTreeMap::keys) + .filter_map(|addr| { + let auth = stockpile.stock_mut().operation(addr.opid).destructible + [addr.pos as usize] + .auth; + outpoints + .iter() + .copied() + .find(|outpoint| { + TxoSeal::no_fallback(*outpoint, noise_engine.clone()).auth_token() + == auth + }) + .map(|outpoint| (auth, outpoint, StrictVal::Unit)) + }) + .collect(); + + // TODO: Construct new state + let params = ConstructParams { + contract_id, + method: MethodName::from(BP_BLANK_METHOD), + global: none!(), + owned, + using, + reading: none!(), + }; + let blank = self.prefab(params); + let res = prefabs.insert(blank); + debug_assert!(res); + } + + PrefabBundle(SmallOrdSet::try_from(prefabs).expect("too many operations")) } } @@ -500,29 +540,22 @@ pub mod file { } } - pub fn prefab(&mut self, params: ConstructParams, noise_seed: impl AsRef<[u8]>) -> Prefab { + pub fn prefab(&mut self, params: ConstructParams) -> Prefab { // TODO: Mix into a noise seed contract id and other data match self { #[cfg(feature = "bitcoin")] - Self::BcOpret(barrow) => barrow.prefab(params, noise_seed), + Self::BcOpret(barrow) => barrow.prefab(params), #[cfg(feature = "bitcoin")] - Self::BcTapret(barrow) => barrow.prefab(params, noise_seed), + Self::BcTapret(barrow) => barrow.prefab(params), #[cfg(feature = "liquid")] - Self::LqOpret(barrow) => barrow.prefab(params, noise_seed), + Self::LqOpret(barrow) => barrow.prefab(params), #[cfg(feature = "liquid")] - Self::LqTapret(barrow) => barrow.prefab(params, noise_seed), + Self::LqTapret(barrow) => barrow.prefab(params), } } - pub fn bundle( - &mut self, - items: impl IntoIterator, - noise_seed: impl AsRef<[u8]>, - ) -> PrefabBundle { - let noise_seed = noise_seed.as_ref(); - let iter = items - .into_iter() - .map(|params| self.prefab(params, noise_seed)); + pub fn bundle(&mut self, items: impl IntoIterator) -> PrefabBundle { + let iter = items.into_iter().map(|params| self.prefab(params)); let items = SmallOrdSet::try_from_iter(iter).expect("too large script"); PrefabBundle(items) } From b588e2a708a9acf6ed184dd9137a6f612d7c57b3 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 14 Dec 2024 09:38:36 +0100 Subject: [PATCH 31/70] bundle blank operations --- Cargo.lock | 10 +++---- src/popls/bp.rs | 71 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2bb4bfe..7eb875d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -243,9 +243,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "shlex", ] @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#f0895034c3795ad6bb637f630a79fa4f5ddd4221" +source = "git+https://github.com/AluVM/sonic#f2855dfaad3d38b46f61d7c712e22fb7592a26c5" dependencies = [ "aluvm", "amplify", @@ -740,7 +740,7 @@ checksum = "fa1f0140117847f5470c5ab2e68f7645bfe6fe27933b9160de63832ecaf0f3d2" [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#f0895034c3795ad6bb637f630a79fa4f5ddd4221" +source = "git+https://github.com/AluVM/sonic#f2855dfaad3d38b46f61d7c712e22fb7592a26c5" dependencies = [ "aluvm", "amplify", @@ -895,7 +895,7 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ultrasonic" version = "0.12.0-beta.2" -source = "git+https://github.com/AluVM/ultrasonic#239bc019e3f868b07857d2c5bff5df6c8ca0044f" +source = "git+https://github.com/AluVM/ultrasonic#68df7d94f61b73ac3e543ff35008c9ab76d9c131" dependencies = [ "amplify", "baid64", diff --git a/src/popls/bp.rs b/src/popls/bp.rs index f2f3eec1..6b4329dd 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -37,7 +37,8 @@ use bp::{dbc, Outpoint, Txid, Vout}; use commit_verify::{CommitId, Digest, DigestExt, Sha256}; use hypersonic::{ AdaptedState, AuthToken, CallParams, CellAddr, CodexId, ContractId, CoreParams, DataCell, - IssueParams, MethodName, NamedState, Operation, Schema, StateAtom, Supply, + IssueParams, MethodName, NamedState, Operation, Schema, StateAtom, StateCalc, StateName, + Supply, }; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; @@ -104,9 +105,9 @@ pub struct ConstructParams { pub contract_id: ContractId, pub method: MethodName, pub global: Vec>, - pub owned: BTreeMap>, - pub using: Vec<(AuthToken, Outpoint, StrictVal)>, pub reading: Vec, + pub using: Vec<(CellAddr, Outpoint, StrictVal)>, + pub owned: Vec<(BuilderSeal, NamedState)>, } /// Prefabricated operation, which includes information on the contract id and closed seals @@ -267,7 +268,11 @@ impl< } /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. - pub fn bundle(&mut self, ops: impl IntoIterator) -> PrefabBundle { + pub fn bundle( + &mut self, + ops: impl IntoIterator, + seal: BuilderSeal, + ) -> PrefabBundle { let mut outpoints = BTreeSet::::new(); let mut contracts = BTreeSet::new(); let mut prefabs = BTreeSet::new(); @@ -277,20 +282,20 @@ impl< prefabs.insert(prefab); } + let mut prefab_params = Vec::new(); for (contract_id, stockpile) in self.mound.contracts_mut() { let noise_seed = self.wallet.noise_seed(); let mut noise_engine = Sha256::new(); noise_engine.input_raw(contract_id.as_slice()); noise_engine.input_raw(noise_seed.as_ref()); - let using = stockpile - .stock() - .state() - .main - .owned - .values() - .flat_map(BTreeMap::keys) - .filter_map(|addr| { + // TODO: Simplify the expression + // We need to clone here not to conflict with mutable call below + let owned = stockpile.stock().state().main.owned.clone(); + let (using, prev): (_, Vec<_>) = owned + .iter() + .flat_map(|(name, map)| map.iter().map(move |(addr, val)| (name, *addr, val))) + .filter_map(|(name, addr, val)| { let auth = stockpile.stock_mut().operation(addr.opid).destructible [addr.pos as usize] .auth; @@ -298,27 +303,51 @@ impl< .iter() .copied() .find(|outpoint| { - TxoSeal::no_fallback(*outpoint, noise_engine.clone()).auth_token() + TxoSeal::::no_fallback(*outpoint, noise_engine.clone()) + .auth_token() == auth }) - .map(|outpoint| (auth, outpoint, StrictVal::Unit)) + .map(|outpoint| ((addr, outpoint, StrictVal::Unit), (name.clone(), val))) }) - .collect(); + .unzip(); + + let api = &stockpile.stock().articles().schema.default_api; + let mut calcs = BTreeMap::>::new(); + for (name, val) in prev { + let calc = calcs + .entry(name.clone()) + .or_insert_with(|| api.calculate(name)); + calc.accumulate(val.clone()).expect("non-computable state"); + } + + let noise_seed = self.wallet.noise_seed(); + let mut noise_engine = Sha256::new(); + noise_engine.input_raw(contract_id.as_slice()); + noise_engine.input_raw(noise_seed.as_ref()); + let mut owned = Vec::new(); + for (name, calc) in calcs { + for state in calc.diff().expect("non-computable state") { + let state = NamedState { + name: name.clone(), + state, + }; + owned.push((seal, state)); + } + } - // TODO: Construct new state let params = ConstructParams { contract_id, method: MethodName::from(BP_BLANK_METHOD), global: none!(), - owned, - using, reading: none!(), + using, + owned, }; - let blank = self.prefab(params); - let res = prefabs.insert(blank); - debug_assert!(res); + prefab_params.push(params); } + prefabs.extend(prefab_params.into_iter().map(|params| self.prefab(params))); + PrefabBundle(SmallOrdSet::try_from(prefabs).expect("too many operations")) } } From aca04fc724173455bc02f0245cfa42f45b703a75 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 15 Dec 2024 13:05:11 +0100 Subject: [PATCH 32/70] implement consign and accept procedures --- Cargo.lock | 4 +-- src/lib.rs | 1 - src/mound.rs | 6 ++-- src/pile.rs | 65 ++++++++++++++++++++++++++++++++++------- src/popls/bp.rs | 4 +-- src/stockpile.rs | 76 +++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 127 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7eb875d2..a40b2ce9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#f2855dfaad3d38b46f61d7c712e22fb7592a26c5" +source = "git+https://github.com/AluVM/sonic#da9ff1d43e4694ff4188f8125e08495681285e1e" dependencies = [ "aluvm", "amplify", @@ -740,7 +740,7 @@ checksum = "fa1f0140117847f5470c5ab2e68f7645bfe6fe27933b9160de63832ecaf0f3d2" [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#f2855dfaad3d38b46f61d7c712e22fb7592a26c5" +source = "git+https://github.com/AluVM/sonic#da9ff1d43e4694ff4188f8125e08495681285e1e" dependencies = [ "aluvm", "amplify", diff --git a/src/lib.rs b/src/lib.rs index 6cc19657..62948159 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,6 @@ extern crate strict_encoding; #[cfg(all(feature = "serde", feature = "bitcoin"))] #[macro_use] extern crate serde; -extern crate core; mod pile; mod stockpile; diff --git a/src/mound.rs b/src/mound.rs index 346b9530..1e45a9b8 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -147,7 +147,7 @@ pub mod file { use std::path::{Path, PathBuf}; use hypersonic::FileSupply; - use single_use_seals::{PublishedWitness, SingleUseSeal}; + use single_use_seals::PublishedWitness; use strict_encoding::{StrictDecode, StrictEncode}; use super::*; @@ -185,7 +185,7 @@ pub mod file { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, - <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]>, + >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]>, { fn schemata(&mut self) -> impl Iterator { self.contents().filter_map(|(ty, path)| { @@ -225,7 +225,7 @@ pub mod file { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, - <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]>, + >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]>, { pub fn load(path: impl AsRef) -> Self { let path = path.as_ref(); diff --git a/src/pile.rs b/src/pile.rs index aea79509..93e8fb43 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -27,7 +27,6 @@ use hypersonic::{AuthToken, Opid}; use single_use_seals::{PublishedWitness, SingleUseSeal}; pub trait Protocol: SingleUseSeal { - type Id: Ord + From<[u8; 32]> + Into<[u8; 32]>; fn auth_token(&self) -> AuthToken; } @@ -38,8 +37,14 @@ pub trait Index { pub trait Pile { type Seal: Protocol; - type Hoard: Aora::CliWitness>; - type Cache: Aora::PubWitness>; + type Hoard: Aora< + Id = <::PubWitness as PublishedWitness>::PubId, + Item = ::CliWitness, + >; + type Cache: Aora< + Id = <::PubWitness as PublishedWitness>::PubId, + Item = ::PubWitness, + >; type Index: Index< Opid, <::PubWitness as PublishedWitness>::PubId, @@ -52,6 +57,28 @@ pub trait Pile { fn hoard_mut(&mut self) -> &mut Self::Hoard; fn cache_mut(&mut self) -> &mut Self::Cache; fn index_mut(&mut self) -> &mut Self::Index; + + fn retrieve( + &mut self, + opid: Opid, + ) -> impl ExactSizeIterator< + Item = ( + ::CliWitness, + ::PubWitness, + ), + >; + + fn append( + &mut self, + opid: Opid, + client: ::CliWitness, + published: ::PubWitness, + ) { + let pubid = published.pub_id(); + self.index_mut().add(opid, pubid); + self.hoard_mut().append(pubid, &client); + self.cache_mut().append(pubid, &published); + } } #[cfg(feature = "fs")] @@ -84,14 +111,18 @@ pub mod fs { fn add(&mut self, key: Opid, val: V) { self.0.entry(key).or_default().push(val) } } - pub struct FilePile { + pub struct FilePile + where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> + { path: PathBuf, - hoard: FileAora, - cache: FileAora, + hoard: FileAora<>::PubId, Seal::CliWitness>, + cache: FileAora<>::PubId, Seal::PubWitness>, index: MemIndex<<::PubWitness as PublishedWitness>::PubId>, } - impl FilePile { + impl FilePile + where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> + { pub fn new(name: &str, path: impl AsRef) -> Self { let mut path = path.as_ref().to_path_buf(); path.push(name); @@ -109,7 +140,7 @@ pub mod fs { } impl FilePile - where <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]> + where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> { pub fn open(path: impl AsRef) -> Self { let path = path.as_ref().to_path_buf(); @@ -151,10 +182,13 @@ pub mod fs { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, + >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]>, { type Seal = Seal; - type Hoard = FileAora; - type Cache = FileAora; + type Hoard = + FileAora<>::PubId, Seal::CliWitness>; + type Cache = + FileAora<>::PubId, Seal::PubWitness>; type Index = MemIndex<<::PubWitness as PublishedWitness>::PubId>; @@ -169,5 +203,16 @@ pub mod fs { fn cache_mut(&mut self) -> &mut Self::Cache { &mut self.cache } fn index_mut(&mut self) -> &mut Self::Index { &mut self.index } + + fn retrieve( + &mut self, + opid: Opid, + ) -> impl ExactSizeIterator { + self.index.get(opid).map(|pubid| { + let client = self.hoard.read(pubid); + let published = self.cache.read(pubid); + (client, published) + }) + } } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 6b4329dd..e1300153 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -33,7 +33,7 @@ use amplify::{confinement, Bytes32}; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; use bp::seals::TxoSeal; -use bp::{dbc, Outpoint, Txid, Vout}; +use bp::{dbc, Outpoint, Vout}; use commit_verify::{CommitId, Digest, DigestExt, Sha256}; use hypersonic::{ AdaptedState, AuthToken, CallParams, CellAddr, CodexId, ContractId, CoreParams, DataCell, @@ -67,8 +67,6 @@ pub type OpretSeal = TxoSeal; pub type TapretSeal = TxoSeal; impl Protocol for TxoSeal { - type Id = Txid; - // SECURITY: Here we cut SHA256 tagged hash of a single-use seal definition to 30 bytes in order // to fit it into a field element with no overflows. This must be a secure operation since we // still have a sufficient 120-bit collision resistance. diff --git a/src/stockpile.rs b/src/stockpile.rs index 4d56d7dd..a5f4b577 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -22,15 +22,18 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. +use core::borrow::Borrow; // TODO: Used in strict encoding; once solved there, remove here use std::io; use hypersonic::aora::Aora; -use hypersonic::{Articles, AuthToken, CellAddr, ContractId, IssueParams, Schema, Stock, Supply}; +use hypersonic::{ + AcceptError, Articles, AuthToken, CellAddr, ContractId, IssueParams, Schema, Stock, Supply, +}; use single_use_seals::{PublishedWitness, SingleUseSeal}; -use strict_encoding::{StrictEncode, StrictWriter, WriteRaw}; +use strict_encoding::{ReadRaw, StrictDecode, StrictEncode, StrictReader, StrictWriter, WriteRaw}; -use crate::pile::{Index, Protocol}; +use crate::pile::Protocol; use crate::Pile; #[derive(Getters)] @@ -69,29 +72,58 @@ impl, P: Pile, const CAPS: u32> Stockpile { Into<[u8; 32]>, { let id = published.pub_id(); - self.pile.hoard_mut().append(id.into().into(), client); - self.pile.cache_mut().append(id.into().into(), published); + self.pile.hoard_mut().append(id, client); + self.pile.cache_mut().append(id, published); } - pub fn consign<'a>( + pub fn consign( &mut self, - terminals: impl IntoIterator, + terminals: impl IntoIterator>, writer: StrictWriter, ) -> io::Result<()> where + ::CliWitness: StrictEncode, + ::PubWitness: StrictEncode, <::PubWitness as PublishedWitness>::PubId: StrictEncode, { self.stock - .export_aux(terminals, writer, |opid| self.pile.index().get(opid)) + .export_aux(terminals, writer, |opid, mut writer| { + let iter = self.pile.retrieve(opid); + let len = iter.len(); + writer = (len as u64).strict_encode(writer)?; + for (client, published) in iter { + writer = client.strict_encode(writer)?; + writer = published.strict_encode(writer)?; + } + Ok(writer) + }) + } + + pub fn accept(&mut self, reader: &mut StrictReader) -> Result<(), AcceptError> + where + ::CliWitness: StrictDecode, + ::PubWitness: StrictDecode, + <::PubWitness as PublishedWitness>::PubId: StrictDecode, + { + self.stock.accept_aux(reader, |opid, reader| { + let len = u64::strict_decode(reader)?; + for _ in 0..len { + let client = ::CliWitness::strict_decode(reader)?; + let published = ::PubWitness::strict_decode(reader)?; + self.pile.append(opid, client, published); + } + Ok(()) + }) } } #[cfg(feature = "fs")] mod fs { + use std::fs::File; use std::path::Path; use hypersonic::FileSupply; - use strict_encoding::{StrictDecode, StrictEncode}; + use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictEncode}; use super::*; use crate::FilePile; @@ -100,7 +132,7 @@ mod fs { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, - <::PubWitness as PublishedWitness>::PubId: From<[u8; 32]>, + >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]>, { pub fn load(path: impl AsRef) -> Self { let path = path.as_ref(); @@ -115,5 +147,29 @@ mod fs { let supply = FileSupply::new(params.name.as_str(), path); Self::issue(schema, params, supply, pile) } + + pub fn consign_to_file( + &mut self, + terminals: impl IntoIterator>, + path: impl AsRef, + ) -> io::Result<()> + where + (Seal::CliWitness, Seal::PubWitness): StrictEncode, + >::PubId: StrictEncode, + { + let file = File::create_new(path)?; + let writer = StrictWriter::with(StreamWriter::new::<{ usize::MAX }>(file)); + self.consign(terminals, writer) + } + + pub fn accept_from_file(&mut self, path: impl AsRef) -> Result<(), AcceptError> + where + (Seal::CliWitness, Seal::PubWitness): StrictDecode, + >::PubId: StrictDecode, + { + let file = File::open(path)?; + let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); + self.accept(&mut reader) + } } } From 626f22c0c47e8eda71c503fc8361a7430edab5c6 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 15 Dec 2024 13:17:44 +0100 Subject: [PATCH 33/70] amend consign and accept methods --- src/mound.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++-- src/stockpile.rs | 16 +++++++---- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/mound.rs b/src/mound.rs index 1e45a9b8..cebeb574 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -23,8 +23,16 @@ // the License. use alloc::collections::BTreeMap; +use core::borrow::Borrow; +use std::io; -use hypersonic::{CellAddr, CodexId, ContractId, IssueParams, Schema, Supply}; +use hypersonic::{ + AcceptError, AuthToken, CellAddr, CodexId, ContractId, IssueParams, Schema, Supply, +}; +use single_use_seals::{PublishedWitness, SingleUseSeal}; +use strict_encoding::{ + ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, +}; use crate::{Pile, Stockpile}; @@ -118,6 +126,8 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound bool { self.contracts.contains_key(&id) } + pub fn contract(&self, id: ContractId) -> &Stockpile { self.contracts .get(&id) @@ -138,17 +148,47 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound>, + mut writer: StrictWriter, + ) -> io::Result<()> + where + ::CliWitness: StrictDumb + StrictEncode, + ::PubWitness: StrictDumb + StrictEncode, + <::PubWitness as PublishedWitness>::PubId: StrictEncode, + { + writer = contract_id.strict_encode(writer)?; + self.contract_mut(contract_id).consign(terminals, writer) + } + + pub fn accept(&mut self, reader: &mut StrictReader) -> Result<(), AcceptError> + where + ::CliWitness: StrictDecode, + ::PubWitness: StrictDecode, + <::PubWitness as PublishedWitness>::PubId: StrictDecode, + { + let contract_id = ContractId::strict_decode(reader)?; + if self.has_contract(contract_id) { + self.contract_mut(contract_id).accept(reader) + } else { + // TODO: Create new contract + todo!() + } + } } pub mod file { use std::fs; - use std::fs::FileType; + use std::fs::{File, FileType}; use std::marker::PhantomData; use std::path::{Path, PathBuf}; use hypersonic::FileSupply; use single_use_seals::PublishedWitness; - use strict_encoding::{StrictDecode, StrictEncode}; + use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictEncode}; use super::*; use crate::pile::Protocol; @@ -240,5 +280,32 @@ pub mod file { } pub fn path(&self) -> &Path { &self.persistence.dir } + + pub fn consign_to_file( + &mut self, + contract_id: ContractId, + terminals: impl IntoIterator>, + path: impl AsRef, + ) -> io::Result<()> + where + Seal::CliWitness: StrictDumb, + Seal::PubWitness: StrictDumb, + >::PubId: StrictEncode, + { + let file = File::create_new(path)?; + let writer = StrictWriter::with(StreamWriter::new::<{ usize::MAX }>(file)); + self.consign(contract_id, terminals, writer) + } + + pub fn accept_from_file(&mut self, path: impl AsRef) -> Result<(), AcceptError> + where + Seal::CliWitness: StrictDumb, + Seal::PubWitness: StrictDumb, + >::PubId: StrictDecode, + { + let file = File::open(path)?; + let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); + self.accept(&mut reader) + } } } diff --git a/src/stockpile.rs b/src/stockpile.rs index a5f4b577..4ed38cee 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -31,7 +31,9 @@ use hypersonic::{ AcceptError, Articles, AuthToken, CellAddr, ContractId, IssueParams, Schema, Stock, Supply, }; use single_use_seals::{PublishedWitness, SingleUseSeal}; -use strict_encoding::{ReadRaw, StrictDecode, StrictEncode, StrictReader, StrictWriter, WriteRaw}; +use strict_encoding::{ + ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, +}; use crate::pile::Protocol; use crate::Pile; @@ -82,8 +84,8 @@ impl, P: Pile, const CAPS: u32> Stockpile { writer: StrictWriter, ) -> io::Result<()> where - ::CliWitness: StrictEncode, - ::PubWitness: StrictEncode, + ::CliWitness: StrictDumb + StrictEncode, + ::PubWitness: StrictDumb + StrictEncode, <::PubWitness as PublishedWitness>::PubId: StrictEncode, { self.stock @@ -123,7 +125,7 @@ mod fs { use std::path::Path; use hypersonic::FileSupply; - use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictEncode}; + use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictDumb, StrictEncode}; use super::*; use crate::FilePile; @@ -154,7 +156,8 @@ mod fs { path: impl AsRef, ) -> io::Result<()> where - (Seal::CliWitness, Seal::PubWitness): StrictEncode, + Seal::CliWitness: StrictDumb, + Seal::PubWitness: StrictDumb, >::PubId: StrictEncode, { let file = File::create_new(path)?; @@ -164,7 +167,8 @@ mod fs { pub fn accept_from_file(&mut self, path: impl AsRef) -> Result<(), AcceptError> where - (Seal::CliWitness, Seal::PubWitness): StrictDecode, + Seal::CliWitness: StrictDumb, + Seal::PubWitness: StrictDumb, >::PubId: StrictDecode, { let file = File::open(path)?; From 95ce0ade203de3a1db1959bdf58662061bf9fcea Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 16 Dec 2024 00:08:38 +0100 Subject: [PATCH 34/70] refactor accept into consume: use RGB Core verification --- Cargo.lock | 13 +++++---- Cargo.toml | 2 +- src/mound.rs | 28 ++++++++++++------- src/pile.rs | 18 +++++-------- src/stockpile.rs | 70 +++++++++++++++++++++++++++++++++++++----------- 5 files changed, 90 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a40b2ce9..d4adc541 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#da9ff1d43e4694ff4188f8125e08495681285e1e" +source = "git+https://github.com/AluVM/sonic#bea04376a11ee1f5df79895323f8805ae94f95f0" dependencies = [ "aluvm", "amplify", @@ -570,12 +570,13 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#059dc252372f4f01b6ab7a7dfed939095fdd886e" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#6c4752b1ca1ceeed10073c8e5420b1011f20ddbc" dependencies = [ "amplify", "commit_verify", "getrandom", "single_use_seals", + "strict_encoding", "ultrasonic", "wasm-bindgen", ] @@ -734,13 +735,15 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" version = "0.12.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1f0140117847f5470c5ab2e68f7645bfe6fe27933b9160de63832ecaf0f3d2" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#b5ea9abeec487436ceb8d2e572a8e34305fd5d70" +dependencies = [ + "strict_encoding", +] [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#da9ff1d43e4694ff4188f8125e08495681285e1e" +source = "git+https://github.com/AluVM/sonic#bea04376a11ee1f5df79895323f8805ae94f95f0" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index 92294f01..d264aeec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,6 @@ serde = [ "strict_types/serde", "commit_verify/serde", "bp-core/serde", - "rgb-core/serde", ] stl = [ @@ -66,5 +65,6 @@ features = ["all"] [patch.crates-io] ultrasonic = { git = "https://github.com/AluVM/ultrasonic" } hypersonic = { git = "https://github.com/AluVM/sonic" } +single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.12" } bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.12" } diff --git a/src/mound.rs b/src/mound.rs index cebeb574..89c38b4f 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -29,9 +29,11 @@ use std::io; use hypersonic::{ AcceptError, AuthToken, CellAddr, CodexId, ContractId, IssueParams, Schema, Supply, }; +use rgb::VerificationError; use single_use_seals::{PublishedWitness, SingleUseSeal}; use strict_encoding::{ - ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, + DecodeError, ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, + WriteRaw, }; use crate::{Pile, Stockpile}; @@ -164,19 +166,24 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound) -> Result<(), AcceptError> + pub fn consume( + &mut self, + reader: &mut StrictReader, + ) -> Result<(), VerificationError> where ::CliWitness: StrictDecode, ::PubWitness: StrictDecode, <::PubWitness as PublishedWitness>::PubId: StrictDecode, { - let contract_id = ContractId::strict_decode(reader)?; - if self.has_contract(contract_id) { - self.contract_mut(contract_id).accept(reader) + let contract_id = + ContractId::strict_decode(reader).map_err(|e| VerificationError::Retrieve(e.into()))?; + let contract = if self.has_contract(contract_id) { + self.contract_mut(contract_id) } else { // TODO: Create new contract todo!() - } + }; + contract.consume(reader) } } @@ -297,15 +304,18 @@ pub mod file { self.consign(contract_id, terminals, writer) } - pub fn accept_from_file(&mut self, path: impl AsRef) -> Result<(), AcceptError> + pub fn consume_from_file( + &mut self, + path: impl AsRef, + ) -> Result<(), VerificationError> where Seal::CliWitness: StrictDumb, Seal::PubWitness: StrictDumb, >::PubId: StrictDecode, { - let file = File::open(path)?; + let file = File::open(path).map_err(|e| VerificationError::Retrieve(e.into()))?; let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); - self.accept(&mut reader) + self.consume(&mut reader) } } } diff --git a/src/pile.rs b/src/pile.rs index 93e8fb43..4744970f 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -22,11 +22,12 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. +use amplify::Bytes32; use hypersonic::aora::Aora; use hypersonic::{AuthToken, Opid}; -use single_use_seals::{PublishedWitness, SingleUseSeal}; +use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; -pub trait Protocol: SingleUseSeal { +pub trait Protocol: SingleUseSeal { fn auth_token(&self) -> AuthToken; } @@ -68,16 +69,11 @@ pub trait Pile { ), >; - fn append( - &mut self, - opid: Opid, - client: ::CliWitness, - published: ::PubWitness, - ) { - let pubid = published.pub_id(); + fn append(&mut self, opid: Opid, witness: &SealWitness) { + let pubid = witness.published.pub_id(); self.index_mut().add(opid, pubid); - self.hoard_mut().append(pubid, &client); - self.cache_mut().append(pubid, &published); + self.hoard_mut().append(pubid, &witness.client); + self.cache_mut().append(pubid, &witness.published); } } diff --git a/src/stockpile.rs b/src/stockpile.rs index 4ed38cee..01013c99 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -25,14 +25,18 @@ use core::borrow::Borrow; // TODO: Used in strict encoding; once solved there, remove here use std::io; +use std::io::ErrorKind; use hypersonic::aora::Aora; use hypersonic::{ - AcceptError, Articles, AuthToken, CellAddr, ContractId, IssueParams, Schema, Stock, Supply, + AcceptError, Articles, AuthToken, CellAddr, ContractId, IssueParams, Memory, Opid, Schema, + Stock, Supply, }; +use rgb::{ContractApi, ContractVerify, Transaction, VerificationError}; use single_use_seals::{PublishedWitness, SingleUseSeal}; use strict_encoding::{ - ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, + DecodeError, ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, + WriteRaw, }; use crate::pile::Protocol; @@ -101,21 +105,54 @@ impl, P: Pile, const CAPS: u32> Stockpile { }) } - pub fn accept(&mut self, reader: &mut StrictReader) -> Result<(), AcceptError> + pub fn consume( + &mut self, + reader: &mut StrictReader, + ) -> Result<(), VerificationError> where ::CliWitness: StrictDecode, ::PubWitness: StrictDecode, <::PubWitness as PublishedWitness>::PubId: StrictDecode, { - self.stock.accept_aux(reader, |opid, reader| { - let len = u64::strict_decode(reader)?; - for _ in 0..len { - let client = ::CliWitness::strict_decode(reader)?; - let published = ::PubWitness::strict_decode(reader)?; - self.pile.append(opid, client, published); - } - Ok(()) - }) + let articles = + Articles::::strict_decode(reader).map_err(VerificationError::Retrieve)?; + self.stock + .merge_articles(articles) + .map_err(|e| VerificationError::Apply(Opid::strict_dumb(), AcceptError::Articles(e)))?; + + let schema = self.stock.articles().schema.clone(); + self.evaluate( + self.contract_id(), + &schema.codex, + &schema, + move || -> Option> { + match Transaction::strict_decode(reader) { + Ok(transaction) => Some(Ok(transaction)), + Err(DecodeError::Io(e)) if e.kind() == ErrorKind::UnexpectedEof => None, + Err(e) => Some(Err(e.into())), + } + }, + )?; + + self.stock.complete_update(); + Ok(()) + } +} + +impl, P: Pile, const CAPS: u32> ContractApi for Stockpile { + type Error = AcceptError; + + fn memory(&self) -> &impl Memory { &self.stock.state().raw } + + fn apply(&mut self, transaction: Transaction) -> Result<(), Self::Error> { + let opid = transaction.operation.opid(); + + for witness in &transaction.witness { + self.pile.append(opid, witness); + } + + self.stock.apply(transaction.operation)?; + Ok(()) } } @@ -165,15 +202,18 @@ mod fs { self.consign(terminals, writer) } - pub fn accept_from_file(&mut self, path: impl AsRef) -> Result<(), AcceptError> + pub fn consume_from_file( + &mut self, + path: impl AsRef, + ) -> Result<(), VerificationError> where Seal::CliWitness: StrictDumb, Seal::PubWitness: StrictDumb, >::PubId: StrictDecode, { - let file = File::open(path)?; + let file = File::open(path).map_err(|e| VerificationError::Retrieve(e.into()))?; let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); - self.accept(&mut reader) + self.consume(&mut reader) } } } From e2c92a9ea5c438d063d83a33f1104b90c5f4ba1e Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 16 Dec 2024 10:38:35 +0100 Subject: [PATCH 35/70] refactor verification and consignment consumption with state machines --- Cargo.lock | 7 ++- Cargo.toml | 6 +- src/lib.rs | 2 +- src/mound.rs | 29 ++++----- src/pile.rs | 49 ++++++++------- src/popls/bp.rs | 37 +++-------- src/popls/mod.rs | 18 +++--- src/popls/prime.rs | 2 - src/stockpile.rs | 150 ++++++++++++++++++++++++++++++++------------- 9 files changed, 169 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4adc541..a8f8dd21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#bea04376a11ee1f5df79895323f8805ae94f95f0" +source = "git+https://github.com/AluVM/sonic#b380ab911ddad447f890cfa3288bbdfa4251e25b" dependencies = [ "aluvm", "amplify", @@ -570,9 +570,10 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#6c4752b1ca1ceeed10073c8e5420b1011f20ddbc" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#e51a59b0bdf2d2bc39e867d996bf8233f2fd5357" dependencies = [ "amplify", + "bp-core", "commit_verify", "getrandom", "single_use_seals", @@ -743,7 +744,7 @@ dependencies = [ [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#bea04376a11ee1f5df79895323f8805ae94f95f0" +source = "git+https://github.com/AluVM/sonic#b380ab911ddad447f890cfa3288bbdfa4251e25b" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index d264aeec..2e975aff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,9 +32,9 @@ default = ["std", "bitcoin"] all = ["std", "bitcoin", "liquid", "prime", "fs", "serde"] std = [] -bitcoin = ["bp-core"] -liquid = [] -prime = [] +bitcoin = ["bp-core", "rgb-core/bitcoin"] +liquid = ["rgb-core/liquid"] +prime = ["rgb-core/prime"] fs = ["std", "hypersonic/persist-file"] serde = [ diff --git a/src/lib.rs b/src/lib.rs index 62948159..988dd38e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,4 +51,4 @@ pub use pile::fs::FilePile; pub use pile::Pile; pub use popls::SealType; pub use rgb::*; -pub use stockpile::Stockpile; +pub use stockpile::{ConsumeError, Stockpile}; diff --git a/src/mound.rs b/src/mound.rs index 89c38b4f..68b357e9 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -26,17 +26,13 @@ use alloc::collections::BTreeMap; use core::borrow::Borrow; use std::io; -use hypersonic::{ - AcceptError, AuthToken, CellAddr, CodexId, ContractId, IssueParams, Schema, Supply, -}; -use rgb::VerificationError; +use hypersonic::{AuthToken, CellAddr, CodexId, ContractId, IssueParams, Schema, Supply}; use single_use_seals::{PublishedWitness, SingleUseSeal}; use strict_encoding::{ - DecodeError, ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, - WriteRaw, + ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, }; -use crate::{Pile, Stockpile}; +use crate::{ConsumeError, Pile, Stockpile}; pub trait Excavate, P: Pile, const CAPS: u32> { fn schemata(&mut self) -> impl Iterator; @@ -169,14 +165,13 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound, - ) -> Result<(), VerificationError> + ) -> Result<(), ConsumeError> where ::CliWitness: StrictDecode, ::PubWitness: StrictDecode, <::PubWitness as PublishedWitness>::PubId: StrictDecode, { - let contract_id = - ContractId::strict_decode(reader).map_err(|e| VerificationError::Retrieve(e.into()))?; + let contract_id = ContractId::strict_decode(reader)?; let contract = if self.has_contract(contract_id) { self.contract_mut(contract_id) } else { @@ -194,19 +189,19 @@ pub mod file { use std::path::{Path, PathBuf}; use hypersonic::FileSupply; + use rgb::SonicSeal; use single_use_seals::PublishedWitness; use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictEncode}; use super::*; - use crate::pile::Protocol; use crate::{FilePile, SealType}; - pub struct DirExcavator { + pub struct DirExcavator { dir: PathBuf, _phantom: PhantomData, } - impl DirExcavator { + impl DirExcavator { pub fn new(dir: PathBuf) -> Self { Self { dir, @@ -227,7 +222,7 @@ pub mod file { } } - impl Excavate, CAPS> + impl Excavate, CAPS> for DirExcavator where Seal::CliWitness: StrictEncode + StrictDecode, @@ -268,7 +263,7 @@ pub mod file { pub type FileMound = Mound, DirExcavator, CAPS>; - impl FileMound + impl FileMound where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, @@ -307,13 +302,13 @@ pub mod file { pub fn consume_from_file( &mut self, path: impl AsRef, - ) -> Result<(), VerificationError> + ) -> Result<(), ConsumeError> where Seal::CliWitness: StrictDumb, Seal::PubWitness: StrictDumb, >::PubId: StrictDecode, { - let file = File::open(path).map_err(|e| VerificationError::Retrieve(e.into()))?; + let file = File::open(path)?; let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); self.consume(&mut reader) } diff --git a/src/pile.rs b/src/pile.rs index 4744970f..1c2865bd 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -22,22 +22,19 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. -use amplify::Bytes32; +use amplify::confinement::SmallVec; use hypersonic::aora::Aora; -use hypersonic::{AuthToken, Opid}; +use hypersonic::Opid; +use rgb::SonicSeal; use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; -pub trait Protocol: SingleUseSeal { - fn auth_token(&self) -> AuthToken; -} - pub trait Index { fn get(&self, key: K) -> impl ExactSizeIterator; fn add(&mut self, key: K, val: V); } pub trait Pile { - type Seal: Protocol; + type Seal: SonicSeal; type Hoard: Aora< Id = <::PubWitness as PublishedWitness>::PubId, Item = ::CliWitness, @@ -46,6 +43,7 @@ pub trait Pile { Id = <::PubWitness as PublishedWitness>::PubId, Item = ::PubWitness, >; + type Keep: Aora>; type Index: Index< Opid, <::PubWitness as PublishedWitness>::PubId, @@ -53,21 +51,15 @@ pub trait Pile { fn hoard(&self) -> &Self::Hoard; fn cache(&self) -> &Self::Cache; + fn keep(&self) -> &Self::Keep; fn index(&self) -> &Self::Index; fn hoard_mut(&mut self) -> &mut Self::Hoard; fn cache_mut(&mut self) -> &mut Self::Cache; + fn keep_mut(&mut self) -> &mut Self::Keep; fn index_mut(&mut self) -> &mut Self::Index; - fn retrieve( - &mut self, - opid: Opid, - ) -> impl ExactSizeIterator< - Item = ( - ::CliWitness, - ::PubWitness, - ), - >; + fn retrieve(&mut self, opid: Opid) -> impl ExactSizeIterator>; fn append(&mut self, opid: Opid, witness: &SealWitness) { let pubid = witness.published.pub_id(); @@ -107,16 +99,17 @@ pub mod fs { fn add(&mut self, key: Opid, val: V) { self.0.entry(key).or_default().push(val) } } - pub struct FilePile + pub struct FilePile where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> { path: PathBuf, hoard: FileAora<>::PubId, Seal::CliWitness>, cache: FileAora<>::PubId, Seal::PubWitness>, + keep: FileAora>, index: MemIndex<<::PubWitness as PublishedWitness>::PubId>, } - impl FilePile + impl FilePile where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> { pub fn new(name: &str, path: impl AsRef) -> Self { @@ -125,23 +118,26 @@ pub mod fs { let hoard = FileAora::new(&path, "hoard"); let cache = FileAora::new(&path, "cache"); + let keep = FileAora::new(&path, "keep"); Self { path, hoard, cache, + keep, index: empty!(), } } } - impl FilePile + impl FilePile where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> { pub fn open(path: impl AsRef) -> Self { let path = path.as_ref().to_path_buf(); let hoard = FileAora::open(&path, "hoard"); let cache = FileAora::open(&path, "cache"); + let keep = FileAora::open(&path, "keep"); let mut index = BTreeMap::new(); let mut index_file = @@ -169,12 +165,13 @@ pub mod fs { path, hoard, cache, + keep, index: index.into(), } } } - impl Pile for FilePile + impl Pile for FilePile where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, @@ -185,6 +182,7 @@ pub mod fs { FileAora<>::PubId, Seal::CliWitness>; type Cache = FileAora<>::PubId, Seal::PubWitness>; + type Keep = FileAora>; type Index = MemIndex<<::PubWitness as PublishedWitness>::PubId>; @@ -192,22 +190,23 @@ pub mod fs { fn cache(&self) -> &Self::Cache { &self.cache } + fn keep(&self) -> &Self::Keep { &self.keep } + fn index(&self) -> &Self::Index { &self.index } fn hoard_mut(&mut self) -> &mut Self::Hoard { &mut self.hoard } fn cache_mut(&mut self) -> &mut Self::Cache { &mut self.cache } + fn keep_mut(&mut self) -> &mut Self::Keep { &mut self.keep } + fn index_mut(&mut self) -> &mut Self::Index { &mut self.index } - fn retrieve( - &mut self, - opid: Opid, - ) -> impl ExactSizeIterator { + fn retrieve(&mut self, opid: Opid) -> impl ExactSizeIterator> { self.index.get(opid).map(|pubid| { let client = self.hoard.read(pubid); let published = self.cache.read(pubid); - (client, published) + SealWitness::new(published, client) }) } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index e1300153..761ac13b 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -34,16 +34,15 @@ use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Vout}; -use commit_verify::{CommitId, Digest, DigestExt, Sha256}; +use commit_verify::{Digest, DigestExt, Sha256}; use hypersonic::{ - AdaptedState, AuthToken, CallParams, CellAddr, CodexId, ContractId, CoreParams, DataCell, - IssueParams, MethodName, NamedState, Operation, Schema, StateAtom, StateCalc, StateName, - Supply, + AdaptedState, CallParams, CellAddr, CodexId, ContractId, CoreParams, DataCell, IssueParams, + MethodName, NamedState, Operation, Schema, StateAtom, StateCalc, StateName, Supply, }; +use rgb::SonicSeal; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; -use crate::pile::Protocol; use crate::{Excavate, Mound, Pile}; pub trait WalletProvider { @@ -52,32 +51,8 @@ pub trait WalletProvider { pub trait OpretProvider: WalletProvider {} pub trait TapretProvider: WalletProvider {} -#[cfg(feature = "bitcoin")] -pub const BITCOIN_OPRET: u32 = 0x0001_0001_u32; -#[cfg(feature = "bitcoin")] -pub const BITCOIN_TAPRET: u32 = 0x0001_0002_u32; -#[cfg(feature = "liquid")] -pub const LIQUID_OPRET: u32 = 0x0002_0001_u32; -#[cfg(feature = "liquid")] -pub const LIQUID_TAPRET: u32 = 0x0002_0002_u32; - pub const BP_BLANK_METHOD: &str = "_"; -pub type OpretSeal = TxoSeal; -pub type TapretSeal = TxoSeal; - -impl Protocol for TxoSeal { - // SECURITY: Here we cut SHA256 tagged hash of a single-use seal definition to 30 bytes in order - // to fit it into a field element with no overflows. This must be a secure operation since we - // still have a sufficient 120-bit collision resistance. - fn auth_token(&self) -> AuthToken { - let id = self.commit_id().to_byte_array(); - let mut shortened_id = [0u8; 30]; - shortened_id.copy_from_slice(&id[0..30]); - AuthToken::from_byte_array(shortened_id) - } -} - // TODO: Support failback seals #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] #[cfg_attr( @@ -355,6 +330,10 @@ pub mod file { use std::path::Path; use hypersonic::{CodexId, FileSupply, IssueParams}; + #[cfg(feature = "bitcoin")] + use rgb::{BITCOIN_OPRET, BITCOIN_TAPRET}; + #[cfg(feature = "liquid")] + use rgb::{LIQUID_OPRET, LIQUID_TAPRET}; use super::*; use crate::mound::file::DirExcavator; diff --git a/src/popls/mod.rs b/src/popls/mod.rs index f63b6550..e27dd88a 100644 --- a/src/popls/mod.rs +++ b/src/popls/mod.rs @@ -36,23 +36,23 @@ pub mod prime; pub enum SealType { #[cfg(feature = "bitcoin")] #[display("bcor")] - BitcoinOpret = self::bp::BITCOIN_OPRET, + BitcoinOpret = rgb::BITCOIN_OPRET, #[cfg(feature = "bitcoin")] #[display("bctr")] - BitcoinTapret = self::bp::BITCOIN_TAPRET, + BitcoinTapret = rgb::BITCOIN_TAPRET, #[cfg(feature = "liquid")] #[display("lqor")] - LiquidOpret = self::bp::LIQUID_OPRET, + LiquidOpret = rgb::LIQUID_OPRET, #[cfg(feature = "liquid")] #[display("lqtr")] - LiquidTapret = self::bp::LIQUID_TAPRET, + LiquidTapret = rgb::LIQUID_TAPRET, #[cfg(feature = "prime")] #[display("prime")] - Prime = self::prime::PRIME, + Prime = rgb::PRIME_SEALS, } #[derive(Clone, Eq, PartialEq, Debug, Display, Error)] @@ -81,13 +81,13 @@ impl From for SealType { fn from(caps: u32) -> Self { match caps { #[cfg(feature = "bitcoin")] - self::bp::BITCOIN_OPRET => Self::BitcoinOpret, + rgb::BITCOIN_OPRET => Self::BitcoinOpret, #[cfg(feature = "bitcoin")] - self::bp::BITCOIN_TAPRET => Self::BitcoinTapret, + rgb::BITCOIN_TAPRET => Self::BitcoinTapret, #[cfg(feature = "liquid")] - self::bp::LIQUID_TAPRET => Self::LiquidTapret, + rgb::LIQUID_TAPRET => Self::LiquidTapret, #[cfg(feature = "prime")] - self::prime::PRIME => Self::Prime, + rgb::PRIME_SEALS => Self::Prime, unknown => panic!("unknown seal type {unknown:#10x}"), } } diff --git a/src/popls/prime.rs b/src/popls/prime.rs index 63c45069..9445dc21 100644 --- a/src/popls/prime.rs +++ b/src/popls/prime.rs @@ -21,5 +21,3 @@ // 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. - -pub const PRIME: u32 = 0x0010_0001_u32; diff --git a/src/stockpile.rs b/src/stockpile.rs index 01013c99..a428d6c2 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -23,23 +23,27 @@ // the License. use core::borrow::Borrow; +use core::marker::PhantomData; // TODO: Used in strict encoding; once solved there, remove here use std::io; -use std::io::ErrorKind; +use amplify::confinement::SmallVec; +use amplify::IoError; use hypersonic::aora::Aora; use hypersonic::{ - AcceptError, Articles, AuthToken, CellAddr, ContractId, IssueParams, Memory, Opid, Schema, - Stock, Supply, + Articles, AuthToken, CellAddr, Codex, ContractId, IssueParams, LibRepo, Memory, MergeError, + Operation, Opid, Schema, Stock, Supply, }; -use rgb::{ContractApi, ContractVerify, Transaction, VerificationError}; -use single_use_seals::{PublishedWitness, SingleUseSeal}; +use rgb::{ + ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SonicSeal, Step, + VerificationError, +}; +use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; use strict_encoding::{ DecodeError, ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, }; -use crate::pile::Protocol; use crate::Pile; #[derive(Getters)] @@ -94,68 +98,130 @@ impl, P: Pile, const CAPS: u32> Stockpile { { self.stock .export_aux(terminals, writer, |opid, mut writer| { + // Write seal definitions + let seals = self.pile.keep_mut().read(opid); + writer = seals.strict_encode(writer)?; + + // Write witnesses let iter = self.pile.retrieve(opid); let len = iter.len(); writer = (len as u64).strict_encode(writer)?; - for (client, published) in iter { - writer = client.strict_encode(writer)?; - writer = published.strict_encode(writer)?; + for witness in iter { + writer = witness.strict_encode(writer)?; } + Ok(writer) }) } pub fn consume( &mut self, - reader: &mut StrictReader, - ) -> Result<(), VerificationError> + stream: &mut StrictReader, + ) -> Result<(), ConsumeError> where ::CliWitness: StrictDecode, ::PubWitness: StrictDecode, <::PubWitness as PublishedWitness>::PubId: StrictDecode, { - let articles = - Articles::::strict_decode(reader).map_err(VerificationError::Retrieve)?; - self.stock - .merge_articles(articles) - .map_err(|e| VerificationError::Apply(Opid::strict_dumb(), AcceptError::Articles(e)))?; - - let schema = self.stock.articles().schema.clone(); - self.evaluate( - self.contract_id(), - &schema.codex, - &schema, - move || -> Option> { - match Transaction::strict_decode(reader) { - Ok(transaction) => Some(Ok(transaction)), - Err(DecodeError::Io(e)) if e.kind() == ErrorKind::UnexpectedEof => None, - Err(e) => Some(Err(e.into())), - } - }, - )?; + let articles = Articles::::strict_decode(stream)?; + self.stock.merge_articles(articles)?; + + // We need to clone due to a borrow checker. + let reader = OpReader { + stream, + _phantom: PhantomData, + }; + self.evaluate(reader)?; self.stock.complete_update(); Ok(()) } } -impl, P: Pile, const CAPS: u32> ContractApi for Stockpile { - type Error = AcceptError; +pub struct OpReader<'r, Seal: SonicSeal, R: ReadRaw> { + stream: &'r mut StrictReader, + _phantom: PhantomData, +} - fn memory(&self) -> &impl Memory { &self.stock.state().raw } +impl<'r, Seal: SonicSeal, R: ReadRaw> ReadOperation for OpReader<'r, Seal, R> { + type Seal = Seal; + type WitnessReader = WitnessReader<'r, Seal, R>; + + fn read_operation(self) -> Option<(OperationSeals, Self::WitnessReader)> { + match Operation::strict_decode(self.stream) { + Ok(operation) => { + let defined_seals = SmallVec::strict_decode(self.stream) + .expect("Failed to read consignment stream"); + let op_seals = OperationSeals { + operation, + defined_seals, + }; + Some((op_seals, WitnessReader { parent: self })) + } + Err(DecodeError::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => None, + Err(e) => { + // TODO: Report error via a side-channel + panic!("Failed to read consignment stream: {}", e); + } + } + } +} + +pub struct WitnessReader<'r, Seal: SonicSeal, R: ReadRaw> { + parent: OpReader<'r, Seal, R>, +} - fn apply(&mut self, transaction: Transaction) -> Result<(), Self::Error> { - let opid = transaction.operation.opid(); +impl<'r, Seal: SonicSeal, R: ReadRaw> ReadWitness for WitnessReader<'r, Seal, R> { + type Seal = Seal; + type OpReader = OpReader<'r, Seal, R>; - for witness in &transaction.witness { - self.pile.append(opid, witness); + fn read_witness(self) -> Step<(SealWitness, Self), Self::OpReader> { + match SealWitness::strict_decode(self.parent.stream) { + Ok(witness) => Step::Next((witness, self)), + Err(DecodeError::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => { + Step::Complete(self.parent) + } + Err(e) => { + // TODO: Report error via a side-channel + panic!("Failed to read consignment stream: {}", e); + } } + } +} - self.stock.apply(transaction.operation)?; - Ok(()) +impl, P: Pile, const CAPS: u32> ContractApi for Stockpile { + fn contract_id(&self) -> ContractId { self.stock.contract_id() } + + fn codex(&self) -> &Codex { &self.stock.articles().schema.codex } + + fn repo(&self) -> &impl LibRepo { &self.stock.articles().schema } + + fn memory(&self) -> &impl Memory { &self.stock.state().raw } + + fn apply_operation(&mut self, op: OperationSeals) { self.stock.apply(op.operation); } + + fn apply_witness(&mut self, opid: Opid, witness: SealWitness) { + self.pile.append(opid, &witness); } } +#[derive(Display, From)] +#[display(doc_comments)] +pub enum ConsumeError { + #[from] + #[from(io::Error)] + Io(IoError), + + #[from] + Decode(DecodeError), + + #[from] + Merge(MergeError), + + #[from] + Verify(VerificationError), +} + #[cfg(feature = "fs")] mod fs { use std::fs::File; @@ -167,7 +233,7 @@ mod fs { use super::*; use crate::FilePile; - impl Stockpile, CAPS> + impl Stockpile, CAPS> where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, @@ -205,13 +271,13 @@ mod fs { pub fn consume_from_file( &mut self, path: impl AsRef, - ) -> Result<(), VerificationError> + ) -> Result<(), ConsumeError> where Seal::CliWitness: StrictDumb, Seal::PubWitness: StrictDumb, >::PubId: StrictDecode, { - let file = File::open(path).map_err(|e| VerificationError::Retrieve(e.into()))?; + let file = File::open(path)?; let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); self.consume(&mut reader) } From f77cd44833f6d1d356a406c91c9f7e631090921c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 16 Dec 2024 13:12:38 +0100 Subject: [PATCH 36/70] add support for global schemata --- src/popls/bp.rs | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 761ac13b..173e01a6 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -326,8 +326,8 @@ impl< } pub mod file { - use std::iter; use std::path::Path; + use std::{fs, iter}; use hypersonic::{CodexId, FileSupply, IssueParams}; #[cfg(feature = "bitcoin")] @@ -362,6 +362,7 @@ pub mod file { pub type DirLqTapretMound = DirBtcMound; pub struct DirMound { + pub schemata: BTreeMap, #[cfg(feature = "bitcoin")] pub bc_opret: DirBcOpretMound, #[cfg(feature = "bitcoin")] @@ -374,31 +375,35 @@ pub mod file { impl DirMound { pub fn load(root: impl AsRef) -> Self { + let schemata = fs::read_dir(root.as_ref()) + .expect("unable to read directory") + .filter_map(|entry| { + let entry = entry.expect("unable to read directory"); + let ty = entry.file_type().expect("unable to read file type"); + if ty.is_file() && entry.path().ends_with(".schema") { + Schema::load(entry.path()) + .ok() + .map(|schema| (schema.codex.codex_id(), schema)) + } else { + None + } + }) + .collect(); + #[cfg(feature = "bitcoin")] - let bc_opret = { - let path = root.as_ref().join(SealType::BitcoinOpret.to_string()); - DirBcOpretMound::load(path) - }; + let bc_opret = { DirBcOpretMound::load(root.as_ref()) }; #[cfg(feature = "bitcoin")] - let bc_tapret = { - let path = root.as_ref().join(SealType::BitcoinTapret.to_string()); - DirBcTapretMound::load(path) - }; + let bc_tapret = { DirBcTapretMound::load(root.as_ref()) }; #[cfg(feature = "liquid")] - let lq_opret = { - let path = root.as_ref().join(SealType::LiquidOpret.to_string()); - DirLqOpretMound::load(path) - }; + let lq_opret = { DirLqOpretMound::load(root.as_ref()) }; #[cfg(feature = "liquid")] - let lq_tapret = { - let path = root.as_ref().join(SealType::LiquidTapret.to_string()); - DirLqTapretMound::load(path) - }; + let lq_tapret = { DirLqTapretMound::load(root.as_ref()) }; Self { + schemata, #[cfg(feature = "bitcoin")] bc_opret, #[cfg(feature = "bitcoin")] @@ -411,7 +416,7 @@ pub mod file { } pub fn codex_ids(&self) -> impl Iterator + use<'_> { - let iter = iter::empty(); + let iter = self.schemata.keys().copied(); #[cfg(feature = "bitcoin")] let iter = iter.chain(self.bc_opret.codex_ids()); #[cfg(feature = "bitcoin")] @@ -424,7 +429,7 @@ pub mod file { } pub fn schemata(&self) -> impl Iterator { - let iter = iter::empty(); + let iter = self.schemata.iter().map(|(k, v)| (*k, v)); #[cfg(feature = "bitcoin")] let iter = iter.chain(self.bc_opret.schemata()); #[cfg(feature = "bitcoin")] @@ -437,7 +442,7 @@ pub mod file { } pub fn schema(&self, codex_id: CodexId) -> Option<&Schema> { - let res = None; + let res = self.schemata.get(&codex_id); #[cfg(feature = "bitcoin")] let res = res.or_else(|| self.bc_opret.schema(codex_id)); #[cfg(feature = "bitcoin")] From f5ef7e486fc7208b9ea7e94dfbb56e165fff894d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 16 Dec 2024 15:14:49 +0100 Subject: [PATCH 37/70] fix reading schemata --- src/mound.rs | 3 ++- src/popls/bp.rs | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mound.rs b/src/mound.rs index 68b357e9..00fa43b3 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -183,6 +183,7 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound impl Iterator { self.contents().filter_map(|(ty, path)| { - if ty.is_file() && path.ends_with(".schema") { + if ty.is_file() && path.extension().and_then(OsStr::to_str) == Some("schema") { Schema::load(path) .ok() .map(|schema| (schema.codex.codex_id(), schema)) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 173e01a6..117ba074 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -326,6 +326,7 @@ impl< } pub mod file { + use std::ffi::OsStr; use std::path::Path; use std::{fs, iter}; @@ -380,7 +381,9 @@ pub mod file { .filter_map(|entry| { let entry = entry.expect("unable to read directory"); let ty = entry.file_type().expect("unable to read file type"); - if ty.is_file() && entry.path().ends_with(".schema") { + if ty.is_file() + && entry.path().extension().and_then(OsStr::to_str) == Some("schema") + { Schema::load(entry.path()) .ok() .map(|schema| (schema.codex.codex_id(), schema)) From f1e77ec1e5980b571e1658e68654d31e79aceee6 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 16 Dec 2024 17:18:33 +0100 Subject: [PATCH 38/70] use costom issue params with seals and outpoints --- Cargo.lock | 9 ++-- Cargo.toml | 2 + src/lib.rs | 2 +- src/mound.rs | 18 +++---- src/popls/bp.rs | 120 +++++++++++++++++++++++++++++++---------------- src/stockpile.rs | 69 +++++++++++++++++++++++++-- 6 files changed, 157 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8f8dd21..ede7df6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,7 +170,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" dependencies = [ "amplify", "chrono", @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" dependencies = [ "amplify", "bp-consensus", @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" dependencies = [ "amplify", "base85", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#eadb08cf45fc3d50afe5d0243d779d54e4ab5468" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" dependencies = [ "amplify", "baid64", @@ -588,6 +588,7 @@ version = "0.12.0-alpha.1" dependencies = [ "amplify", "bp-core", + "chrono", "commit_verify", "getrandom", "hypersonic", diff --git a/Cargo.toml b/Cargo.toml index 2e975aff..60fad502 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ single_use_seals = "0.12.0-beta.1" hypersonic = "0.12.0-beta.1" bp-core = { version = "0.12.0-beta.2", optional = true } rgb-core = "0.12.0-beta.3" +chrono = "0.4.39" serde = { version = "1.0.215", optional = true } [features] @@ -45,6 +46,7 @@ serde = [ "strict_types/serde", "commit_verify/serde", "bp-core/serde", + "chrono/serde" ] stl = [ diff --git a/src/lib.rs b/src/lib.rs index 988dd38e..6020bb33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,4 +51,4 @@ pub use pile::fs::FilePile; pub use pile::Pile; pub use popls::SealType; pub use rgb::*; -pub use stockpile::{ConsumeError, Stockpile}; +pub use stockpile::{ConsumeError, CreateParams, Stockpile}; diff --git a/src/mound.rs b/src/mound.rs index 00fa43b3..d5c0d08f 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -26,13 +26,13 @@ use alloc::collections::BTreeMap; use core::borrow::Borrow; use std::io; -use hypersonic::{AuthToken, CellAddr, CodexId, ContractId, IssueParams, Schema, Supply}; +use hypersonic::{AuthToken, CellAddr, CodexId, ContractId, Schema, Supply}; use single_use_seals::{PublishedWitness, SingleUseSeal}; use strict_encoding::{ ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, }; -use crate::{ConsumeError, Pile, Stockpile}; +use crate::{ConsumeError, CreateParams, Pile, Stockpile}; pub trait Excavate, P: Pile, const CAPS: u32> { fn schemata(&mut self) -> impl Iterator; @@ -86,14 +86,8 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound ContractId { - let schema = self.schema(codex_id).expect("unknown schema"); + pub fn issue(&mut self, params: CreateParams, supply: S, pile: P) -> ContractId { + let schema = self.schema(params.codex_id).expect("unknown schema"); let stockpile = Stockpile::issue(schema.clone(), params, supply, pile); let id = stockpile.contract_id(); self.contracts.insert(id, stockpile); @@ -276,10 +270,10 @@ pub mod file { Self::open(excavator) } - pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + pub fn issue_to_file(&mut self, params: CreateParams) -> ContractId { let pile = FilePile::::new(params.name.as_str(), &self.persistence.dir); let supply = FileSupply::new(params.name.as_str(), &self.persistence.dir); - self.issue(codex_id, params, supply, pile) + self.issue(params, supply, pile) } pub fn path(&self) -> &Path { &self.persistence.dir } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 117ba074..acee68c3 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -36,14 +36,14 @@ use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Vout}; use commit_verify::{Digest, DigestExt, Sha256}; use hypersonic::{ - AdaptedState, CallParams, CellAddr, CodexId, ContractId, CoreParams, DataCell, IssueParams, - MethodName, NamedState, Operation, Schema, StateAtom, StateCalc, StateName, Supply, + AdaptedState, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, NamedState, + Operation, Schema, StateAtom, StateCalc, StateName, Supply, }; use rgb::SonicSeal; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; -use crate::{Excavate, Mound, Pile}; +use crate::{CreateParams, Excavate, Mound, Pile}; pub trait WalletProvider { fn noise_seed(&self) -> Bytes32; @@ -68,18 +68,42 @@ pub enum BuilderSeal { Extern(Outpoint), } +impl CreateParams { + pub fn transform(self, mut noise_engine: Sha256) -> CreateParams> { + noise_engine.input_raw(self.codex_id.as_slice()); + noise_engine.input_raw(self.method.as_bytes()); + noise_engine.input_raw(self.name.as_bytes()); + noise_engine.input_raw(&self.timestamp.unwrap_or_default().timestamp().to_be_bytes()); + CreateParams { + codex_id: self.codex_id, + method: self.method, + name: self.name, + timestamp: self.timestamp, + global: self.global, + owned: self + .owned + .into_iter() + .enumerate() + .map(|(nonce, (outpoint, state))| { + (TxoSeal::no_fallback(outpoint, noise_engine.clone(), nonce as u64), state) + }) + .collect(), + } + } +} + /// Parameters used by BP-based wallet for constructing operations. /// -/// Differs from [`hypersonic::CallParams`] in the fact that it uses [`TxoSeal`]s instead of -/// AuthTokens for output definitions. +/// Differs from [`CallParams`] in the fact that it uses [`BuilderSeal`]s instead of +/// [`hypersonic::AuthTokens`] for output definitions. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] pub struct ConstructParams { pub contract_id: ContractId, pub method: MethodName, - pub global: Vec>, pub reading: Vec, pub using: Vec<(CellAddr, Outpoint, StrictVal)>, + pub global: Vec>, pub owned: Vec<(BuilderSeal, NamedState)>, } @@ -154,14 +178,9 @@ impl< pub fn unbind(self) -> (W, Mound) { (self.wallet, self.mound) } - pub fn issue( - &mut self, - codex_id: CodexId, - params: IssueParams, - supply: S, - pile: P, - ) -> ContractId { - self.mound.issue(codex_id, params, supply, pile) + pub fn issue(&mut self, params: CreateParams, supply: S, pile: P) -> ContractId { + self.mound + .issue(params.transform(self.noise_engine()), supply, pile) } // TODO: Use bitcoin-specific state type aware of outpoints @@ -175,10 +194,16 @@ impl< .map(|(id, stockpile)| (id, &stockpile.stock().state().main)) } + fn noise_engine(&self) -> Sha256 { + let noise_seed = self.wallet.noise_seed(); + let mut noise_engine = Sha256::new(); + noise_engine.input_raw(noise_seed.as_ref()); + noise_engine + } + /// Creates a single operation basing on the provided construction parameters. pub fn prefab(&mut self, params: ConstructParams) -> Prefab { - // convert ExecParams into CallParams - + // convert ConstructParams into CallParams let (closes, using) = params .using .into_iter() @@ -187,23 +212,26 @@ impl< let closes = SmallOrdSet::try_from(closes).expect("too many inputs"); let mut defines = SmallOrdSet::new(); - let noise_seed = self.wallet.noise_seed(); - let mut noise_engine = Sha256::new(); + let mut noise_engine = self.noise_engine(); noise_engine.input_raw(params.contract_id.as_slice()); - noise_engine.input_raw(noise_seed.as_ref()); let owned = params .owned .into_iter() - .map(|(seal, val)| { + .enumerate() + .map(|(nonce, (seal, val))| { let seal = match seal { BuilderSeal::Oneself(vout) => { defines.push(vout).expect("too many seals"); // NB: We use opret type here, but this doesn't matter since we create seal // only to produce the auth token, and seals do not commit to their type. - TxoSeal::::vout_no_fallback(vout, noise_engine.clone()) + TxoSeal::::vout_no_fallback( + vout, + noise_engine.clone(), + nonce as u64, + ) } BuilderSeal::Extern(outpoint) => { - TxoSeal::no_fallback(outpoint, noise_engine.clone()) + TxoSeal::no_fallback(outpoint, noise_engine.clone(), nonce as u64) } }; let state = DataCell { @@ -256,11 +284,10 @@ impl< } let mut prefab_params = Vec::new(); + let root_noise_engine = self.noise_engine(); for (contract_id, stockpile) in self.mound.contracts_mut() { - let noise_seed = self.wallet.noise_seed(); - let mut noise_engine = Sha256::new(); + let mut noise_engine = root_noise_engine.clone(); noise_engine.input_raw(contract_id.as_slice()); - noise_engine.input_raw(noise_seed.as_ref()); // TODO: Simplify the expression // We need to clone here not to conflict with mutable call below @@ -275,12 +302,19 @@ impl< outpoints .iter() .copied() - .find(|outpoint| { - TxoSeal::::no_fallback(*outpoint, noise_engine.clone()) - .auth_token() + .enumerate() + .find(|(nonce, outpoint)| { + TxoSeal::::no_fallback( + *outpoint, + noise_engine.clone(), + *nonce as u64, + ) + .auth_token() == auth }) - .map(|outpoint| ((addr, outpoint, StrictVal::Unit), (name.clone(), val))) + .map(|(_, outpoint)| { + ((addr, outpoint, StrictVal::Unit), (name.clone(), val)) + }) }) .unzip(); @@ -293,10 +327,6 @@ impl< calc.accumulate(val.clone()).expect("non-computable state"); } - let noise_seed = self.wallet.noise_seed(); - let mut noise_engine = Sha256::new(); - noise_engine.input_raw(contract_id.as_slice()); - noise_engine.input_raw(noise_seed.as_ref()); let mut owned = Vec::new(); for (name, calc) in calcs { for state in calc.diff().expect("non-computable state") { @@ -330,7 +360,7 @@ pub mod file { use std::path::Path; use std::{fs, iter}; - use hypersonic::{CodexId, FileSupply, IssueParams}; + use hypersonic::{CodexId, FileSupply}; #[cfg(feature = "bitcoin")] use rgb::{BITCOIN_OPRET, BITCOIN_TAPRET}; #[cfg(feature = "liquid")] @@ -344,9 +374,9 @@ pub mod file { Barrow>, DirExcavator, CAPS>, CAPS>; impl FileWallet { - pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + pub fn issue_to_file(&mut self, params: CreateParams>) -> ContractId { // TODO: check that if the issue belongs to the wallet add it to the unspents - self.mound.issue_file(codex_id, params) + self.mound.issue_to_file(params) } } @@ -525,16 +555,24 @@ pub mod file { } } - pub fn issue_file(&mut self, codex_id: CodexId, params: IssueParams) -> ContractId { + pub fn issue_to_file(&mut self, params: CreateParams) -> ContractId { match self { #[cfg(feature = "bitcoin")] - Self::BcOpret(barrow) => barrow.issue_file(codex_id, params), + Self::BcOpret(barrow) => { + barrow.issue_to_file(params.transform(barrow.noise_engine())) + } #[cfg(feature = "bitcoin")] - Self::BcTapret(barrow) => barrow.issue_file(codex_id, params), + Self::BcTapret(barrow) => { + barrow.issue_to_file(params.transform(barrow.noise_engine())) + } #[cfg(feature = "liquid")] - Self::LqOpret(barrow) => barrow.issue_file(codex_id, params), + Self::LqOpret(barrow) => { + barrow.issue_to_file(params.transform(barrow.noise_engine())) + } #[cfg(feature = "liquid")] - Self::LqTapret(barrow) => barrow.issue_file(codex_id, params), + Self::LqTapret(barrow) => { + barrow.issue_to_file(params.transform(barrow.noise_engine())) + } } } diff --git a/src/stockpile.rs b/src/stockpile.rs index a428d6c2..9a8ff590 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -29,10 +29,12 @@ use std::io; use amplify::confinement::SmallVec; use amplify::IoError; +use chrono::{DateTime, Utc}; use hypersonic::aora::Aora; use hypersonic::{ - Articles, AuthToken, CellAddr, Codex, ContractId, IssueParams, LibRepo, Memory, MergeError, - Operation, Opid, Schema, Stock, Supply, + Articles, AuthToken, CellAddr, Codex, CodexId, ContractId, CoreParams, DataCell, IssueParams, + LibRepo, Memory, MergeError, MethodName, NamedState, Operation, Opid, Schema, StateAtom, Stock, + Supply, }; use rgb::{ ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SonicSeal, Step, @@ -41,11 +43,34 @@ use rgb::{ use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; use strict_encoding::{ DecodeError, ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, - WriteRaw, + TypeName, WriteRaw, }; +use strict_types::StrictVal; use crate::Pile; +/// Parameters used by RGB for contract creation operations. +/// +/// Differs from [`IssueParams`] in the fact that it uses full seal data instead of +/// [`hypersonic::AuthTokens`] for output definitions. +#[derive(Clone)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde( + rename_all = "camelCase", + bound = "Seal: serde::Serialize + for<'d> serde::Deserialize<'d>" + ) +)] +pub struct CreateParams { + pub codex_id: CodexId, + pub method: MethodName, + pub name: TypeName, + pub timestamp: Option>, + pub global: Vec>, + pub owned: Vec<(Seal, NamedState)>, +} + #[derive(Getters)] pub struct Stockpile, P: Pile, const CAPS: u32> { #[getter(as_mut)] @@ -55,9 +80,39 @@ pub struct Stockpile, P: Pile, const CAPS: u32> { } impl, P: Pile, const CAPS: u32> Stockpile { - pub fn issue(schema: Schema, params: IssueParams, supply: S, pile: P) -> Self { + pub fn issue(schema: Schema, params: CreateParams, supply: S, mut pile: P) -> Self { + assert_eq!(params.codex_id, schema.codex.codex_id()); + + let seals = SmallVec::try_from_iter(params.owned.iter().map(|(seal, _)| seal.clone())) + .expect("too many outputs"); + let params = IssueParams { + name: params.name, + timestamp: params.timestamp, + core: CoreParams { + method: params.method, + global: params.global, + owned: params + .owned + .into_iter() + .map(|(seal, state)| NamedState { + name: state.name, + state: DataCell { + auth: seal.auth_token(), + data: state.state, + lock: None, + }, + }) + .collect(), + }, + }; + let articles = schema.issue::(params); let stock = Stock::create(articles, supply); + + // Init seals + pile.keep_mut() + .append(stock.articles().contract.genesis_opid(), &seals); + Self { stock, pile } } @@ -246,7 +301,11 @@ mod fs { Self::open(supply.load_articles(), supply, pile) } - pub fn issue_file(schema: Schema, params: IssueParams, path: impl AsRef) -> Self { + pub fn issue_to_file( + schema: Schema, + params: CreateParams, + path: impl AsRef, + ) -> Self { let path = path.as_ref(); let pile = FilePile::new(params.name.as_str(), path); let supply = FileSupply::new(params.name.as_str(), path); From 8fe8c798746d2bf4b58cd604a1ddc2fdcc7bb99d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 16 Dec 2024 17:30:42 +0100 Subject: [PATCH 39/70] add seal type to the issue parameters --- Cargo.lock | 4 ++- Cargo.toml | 1 + src/lib.rs | 1 - src/mound.rs | 2 +- src/popls/bp.rs | 4 ++- src/popls/mod.rs | 64 ------------------------------------------------ src/stockpile.rs | 6 +++-- 7 files changed, 12 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ede7df6a..99948df0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,12 +570,13 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#e51a59b0bdf2d2bc39e867d996bf8233f2fd5357" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#f95a75c43ea335082f0c9671ae26c8f765da582e" dependencies = [ "amplify", "bp-core", "commit_verify", "getrandom", + "serde", "single_use_seals", "strict_encoding", "ultrasonic", @@ -739,6 +740,7 @@ name = "single_use_seals" version = "0.12.0-beta.1" source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#b5ea9abeec487436ceb8d2e572a8e34305fd5d70" dependencies = [ + "serde", "strict_encoding", ] diff --git a/Cargo.toml b/Cargo.toml index 60fad502..a0b01f12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ serde = [ "strict_types/serde", "commit_verify/serde", "bp-core/serde", + "rgb-core/serde", "chrono/serde" ] diff --git a/src/lib.rs b/src/lib.rs index 6020bb33..7196d5b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,6 +49,5 @@ pub use mound::{Excavate, Mound}; #[cfg(feature = "fs")] pub use pile::fs::FilePile; pub use pile::Pile; -pub use popls::SealType; pub use rgb::*; pub use stockpile::{ConsumeError, CreateParams, Stockpile}; diff --git a/src/mound.rs b/src/mound.rs index d5c0d08f..b3948fb4 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -205,7 +205,7 @@ pub mod file { } fn contents(&mut self) -> impl Iterator { - let seal = SealType::from(CAPS); + let seal = SealType::try_from(CAPS).expect("unknown seal type"); let root = self.dir.join(seal.to_string()); fs::read_dir(root) .expect("unable to read directory") diff --git a/src/popls/bp.rs b/src/popls/bp.rs index acee68c3..ba858a20 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -71,11 +71,13 @@ pub enum BuilderSeal { impl CreateParams { pub fn transform(self, mut noise_engine: Sha256) -> CreateParams> { noise_engine.input_raw(self.codex_id.as_slice()); + noise_engine.input_raw(&(self.seal_type as u32).to_le_bytes()); noise_engine.input_raw(self.method.as_bytes()); noise_engine.input_raw(self.name.as_bytes()); - noise_engine.input_raw(&self.timestamp.unwrap_or_default().timestamp().to_be_bytes()); + noise_engine.input_raw(&self.timestamp.unwrap_or_default().timestamp().to_le_bytes()); CreateParams { codex_id: self.codex_id, + seal_type: self.seal_type, method: self.method, name: self.name, timestamp: self.timestamp, diff --git a/src/popls/mod.rs b/src/popls/mod.rs index e27dd88a..061c57cc 100644 --- a/src/popls/mod.rs +++ b/src/popls/mod.rs @@ -24,71 +24,7 @@ //! Proof of publication layers supported by RGB. -use core::str::FromStr; - #[cfg(any(feature = "bitcoin", feature = "liquid"))] pub mod bp; #[cfg(feature = "prime")] pub mod prime; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[repr(u32)] -pub enum SealType { - #[cfg(feature = "bitcoin")] - #[display("bcor")] - BitcoinOpret = rgb::BITCOIN_OPRET, - - #[cfg(feature = "bitcoin")] - #[display("bctr")] - BitcoinTapret = rgb::BITCOIN_TAPRET, - - #[cfg(feature = "liquid")] - #[display("lqor")] - LiquidOpret = rgb::LIQUID_OPRET, - - #[cfg(feature = "liquid")] - #[display("lqtr")] - LiquidTapret = rgb::LIQUID_TAPRET, - - #[cfg(feature = "prime")] - #[display("prime")] - Prime = rgb::PRIME_SEALS, -} - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error)] -#[display("unknown seal type `{0}`")] -pub struct UnknownType(String); - -impl FromStr for SealType { - type Err = UnknownType; - - fn from_str(s: &str) -> Result { - match s { - #[cfg(feature = "bitcoin")] - "bcor" => Ok(SealType::BitcoinOpret), - #[cfg(feature = "bitcoin")] - "bctr" => Ok(SealType::BitcoinTapret), - #[cfg(feature = "liquid")] - "lqtr" => Ok(SealType::LiquidTapret), - #[cfg(feature = "prime")] - "prime" => Ok(SealType::Prime), - _ => Err(UnknownType(s.to_string())), - } - } -} - -impl From for SealType { - fn from(caps: u32) -> Self { - match caps { - #[cfg(feature = "bitcoin")] - rgb::BITCOIN_OPRET => Self::BitcoinOpret, - #[cfg(feature = "bitcoin")] - rgb::BITCOIN_TAPRET => Self::BitcoinTapret, - #[cfg(feature = "liquid")] - rgb::LIQUID_TAPRET => Self::LiquidTapret, - #[cfg(feature = "prime")] - rgb::PRIME_SEALS => Self::Prime, - unknown => panic!("unknown seal type {unknown:#10x}"), - } - } -} diff --git a/src/stockpile.rs b/src/stockpile.rs index 9a8ff590..2ba93664 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -37,8 +37,8 @@ use hypersonic::{ Supply, }; use rgb::{ - ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SonicSeal, Step, - VerificationError, + ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SealType, SonicSeal, + Step, VerificationError, }; use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; use strict_encoding::{ @@ -64,6 +64,7 @@ use crate::Pile; )] pub struct CreateParams { pub codex_id: CodexId, + pub seal_type: SealType, pub method: MethodName, pub name: TypeName, pub timestamp: Option>, @@ -82,6 +83,7 @@ pub struct Stockpile, P: Pile, const CAPS: u32> { impl, P: Pile, const CAPS: u32> Stockpile { pub fn issue(schema: Schema, params: CreateParams, supply: S, mut pile: P) -> Self { assert_eq!(params.codex_id, schema.codex.codex_id()); + assert_eq!(params.seal_type as u32, CAPS, "invalid seal type for the issue"); let seals = SmallVec::try_from_iter(params.owned.iter().map(|(seal, _)| seal.clone())) .expect("too many outputs"); From cbec3f51e8e85692d3dd5793c8f0af5b9a3fb3d7 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 16 Dec 2024 20:38:06 +0100 Subject: [PATCH 40/70] debug contract issue --- Cargo.lock | 4 ++-- src/lib.rs | 2 +- src/mound.rs | 22 +++++++++++++--------- src/pile.rs | 9 +++++++-- src/popls/bp.rs | 32 ++++++++++++++++++++++---------- src/stockpile.rs | 33 ++++++++++++++++++++++++++------- 6 files changed, 71 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99948df0..aa6f7ff2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,7 +389,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#b380ab911ddad447f890cfa3288bbdfa4251e25b" +source = "git+https://github.com/AluVM/sonic#e8506c8ea31d08ff180a56d6bd3413033494e5a8" dependencies = [ "aluvm", "amplify", @@ -747,7 +747,7 @@ dependencies = [ [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#b380ab911ddad447f890cfa3288bbdfa4251e25b" +source = "git+https://github.com/AluVM/sonic#e8506c8ea31d08ff180a56d6bd3413033494e5a8" dependencies = [ "aluvm", "amplify", diff --git a/src/lib.rs b/src/lib.rs index 7196d5b1..9b5f8459 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,4 +50,4 @@ pub use mound::{Excavate, Mound}; pub use pile::fs::FilePile; pub use pile::Pile; pub use rgb::*; -pub use stockpile::{ConsumeError, CreateParams, Stockpile}; +pub use stockpile::{Assignment, ConsumeError, CreateParams, Stockpile}; diff --git a/src/mound.rs b/src/mound.rs index b3948fb4..ac91c86a 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -26,6 +26,7 @@ use alloc::collections::BTreeMap; use core::borrow::Borrow; use std::io; +use hypersonic::expect::Expect; use hypersonic::{AuthToken, CellAddr, CodexId, ContractId, Schema, Supply}; use single_use_seals::{PublishedWitness, SingleUseSeal}; use strict_encoding::{ @@ -87,7 +88,9 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound, supply: S, pile: P) -> ContractId { - let schema = self.schema(params.codex_id).expect("unknown schema"); + let schema = self + .schema(params.codex_id) + .expect_or_else(|| format!("Unknown codex `{}`", params.codex_id)); let stockpile = Stockpile::issue(schema.clone(), params, supply, pile); let id = stockpile.contract_id(); self.contracts.insert(id, stockpile); @@ -183,6 +186,7 @@ pub mod file { use std::marker::PhantomData; use std::path::{Path, PathBuf}; + use hypersonic::expect::Expect; use hypersonic::FileSupply; use rgb::SonicSeal; use single_use_seals::PublishedWitness; @@ -205,10 +209,8 @@ pub mod file { } fn contents(&mut self) -> impl Iterator { - let seal = SealType::try_from(CAPS).expect("unknown seal type"); - let root = self.dir.join(seal.to_string()); - fs::read_dir(root) - .expect("unable to read directory") + fs::read_dir(&self.dir) + .expect_or_else(|| format!("unable to read directory `{}`", self.dir.display())) .map(|entry| { let entry = entry.expect("unable to read directory"); let ty = entry.file_type().expect("unable to read file type"); @@ -226,11 +228,13 @@ pub mod file { { fn schemata(&mut self) -> impl Iterator { self.contents().filter_map(|(ty, path)| { - if ty.is_file() && path.extension().and_then(OsStr::to_str) == Some("schema") { + if ty.is_file() && path.extension().and_then(OsStr::to_str) == Some("issuer") { Schema::load(path) .ok() .map(|schema| (schema.codex.codex_id(), schema)) - } else if ty.is_dir() && path.ends_with(".contract") { + } else if ty.is_dir() + && path.extension().and_then(OsStr::to_str) == Some("contract") + { let contract = Stockpile::, CAPS>::load(path); let schema = contract.stock().articles().schema.clone(); Some((schema.codex.codex_id(), schema)) @@ -245,7 +249,7 @@ pub mod file { ) -> impl Iterator, CAPS>)> { self.contents().filter_map(|(ty, path)| { - if ty.is_dir() && path.ends_with(".contract") { + if ty.is_dir() && path.extension().and_then(OsStr::to_str) == Some("contract") { let contract = Stockpile::load(path); Some((contract.contract_id(), contract)) } else { @@ -271,8 +275,8 @@ pub mod file { } pub fn issue_to_file(&mut self, params: CreateParams) -> ContractId { - let pile = FilePile::::new(params.name.as_str(), &self.persistence.dir); let supply = FileSupply::new(params.name.as_str(), &self.persistence.dir); + let pile = FilePile::::new(params.name.as_str(), &self.persistence.dir); self.issue(params, supply, pile) } diff --git a/src/pile.rs b/src/pile.rs index 1c2865bd..2614324e 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -77,6 +77,7 @@ pub mod fs { use std::path::{Path, PathBuf}; use hypersonic::aora::file::FileAora; + use hypersonic::expect::Expect; use strict_encoding::{StrictDecode, StrictEncode}; use super::*; @@ -115,10 +116,13 @@ pub mod fs { pub fn new(name: &str, path: impl AsRef) -> Self { let mut path = path.as_ref().to_path_buf(); path.push(name); + path.set_extension("contract"); let hoard = FileAora::new(&path, "hoard"); let cache = FileAora::new(&path, "cache"); let keep = FileAora::new(&path, "keep"); + File::create_new(path.join("index.dat")) + .expect_or_else(|| format!("unable to create index file `{}`", path.display())); Self { path, @@ -140,8 +144,9 @@ pub mod fs { let keep = FileAora::open(&path, "keep"); let mut index = BTreeMap::new(); - let mut index_file = - File::open(path.join("index.dat")).expect("cannot open index file"); + let index_name = path.join("index.dat"); + let mut index_file = File::open(&index_name) + .expect_or_else(|| format!("unable to open index file `{}`", index_name.display())); let mut buf = [0u8; 32]; while index_file.read_exact(&mut buf).is_ok() { let opid = Opid::from(buf); diff --git a/src/popls/bp.rs b/src/popls/bp.rs index ba858a20..a465b824 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -43,7 +43,7 @@ use rgb::SonicSeal; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; -use crate::{CreateParams, Excavate, Mound, Pile}; +use crate::{Assignment, CreateParams, Excavate, Mound, Pile}; pub trait WalletProvider { fn noise_seed(&self) -> Bytes32; @@ -86,8 +86,16 @@ impl CreateParams { .owned .into_iter() .enumerate() - .map(|(nonce, (outpoint, state))| { - (TxoSeal::no_fallback(outpoint, noise_engine.clone(), nonce as u64), state) + .map(|(nonce, assignment)| NamedState { + name: assignment.name, + state: Assignment { + seal: TxoSeal::no_fallback( + assignment.state.seal, + noise_engine.clone(), + nonce as u64, + ), + data: assignment.state.data, + }, }) .collect(), } @@ -408,15 +416,17 @@ pub mod file { impl DirMound { pub fn load(root: impl AsRef) -> Self { - let schemata = fs::read_dir(root.as_ref()) + let root = root.as_ref(); + let schemata = fs::read_dir(root) .expect("unable to read directory") .filter_map(|entry| { let entry = entry.expect("unable to read directory"); let ty = entry.file_type().expect("unable to read file type"); if ty.is_file() - && entry.path().extension().and_then(OsStr::to_str) == Some("schema") + && entry.path().extension().and_then(OsStr::to_str) == Some("issuer") { Schema::load(entry.path()) + .inspect_err(|err| eprintln!("Unable to load schema: {}", err)) .ok() .map(|schema| (schema.codex.codex_id(), schema)) } else { @@ -426,16 +436,18 @@ pub mod file { .collect(); #[cfg(feature = "bitcoin")] - let bc_opret = { DirBcOpretMound::load(root.as_ref()) }; + let bc_opret = { DirBcOpretMound::load(root.join(SealType::BitcoinOpret.to_string())) }; #[cfg(feature = "bitcoin")] - let bc_tapret = { DirBcTapretMound::load(root.as_ref()) }; + let bc_tapret = + { DirBcTapretMound::load(root.join(SealType::BitcoinTapret.to_string())) }; #[cfg(feature = "liquid")] - let lq_opret = { DirLqOpretMound::load(root.as_ref()) }; + let lq_opret = { DirLqOpretMound::load(root.join(SealType::LiquidOpret.to_string())) }; #[cfg(feature = "liquid")] - let lq_tapret = { DirLqTapretMound::load(root.as_ref()) }; + let lq_tapret = + { DirLqTapretMound::load(root.join(SealType::LiquidTapret.to_string())) }; Self { schemata, @@ -528,7 +540,7 @@ pub mod file { impl DirBarrow { pub fn load_opret(ty: SealType, root: impl AsRef, wallet: O) -> Self { - let mound = DirMound::load(root); + let mound = DirMound::load(root.as_ref()); Self::with_opret(ty, mound, wallet) } diff --git a/src/stockpile.rs b/src/stockpile.rs index 2ba93664..81c75c0b 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -49,6 +49,20 @@ use strict_types::StrictVal; use crate::Pile; +#[derive(Clone)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde( + rename_all = "camelCase", + bound = "Seal: serde::Serialize + for<'d> serde::Deserialize<'d>" + ) +)] +pub struct Assignment { + pub seal: Seal, + pub data: StrictVal, +} + /// Parameters used by RGB for contract creation operations. /// /// Differs from [`IssueParams`] in the fact that it uses full seal data instead of @@ -69,7 +83,7 @@ pub struct CreateParams { pub name: TypeName, pub timestamp: Option>, pub global: Vec>, - pub owned: Vec<(Seal, NamedState)>, + pub owned: Vec>>, } #[derive(Getters)] @@ -85,8 +99,13 @@ impl, P: Pile, const CAPS: u32> Stockpile { assert_eq!(params.codex_id, schema.codex.codex_id()); assert_eq!(params.seal_type as u32, CAPS, "invalid seal type for the issue"); - let seals = SmallVec::try_from_iter(params.owned.iter().map(|(seal, _)| seal.clone())) - .expect("too many outputs"); + let seals = SmallVec::try_from_iter( + params + .owned + .iter() + .map(|assignment| assignment.state.seal.clone()), + ) + .expect("too many outputs"); let params = IssueParams { name: params.name, timestamp: params.timestamp, @@ -96,11 +115,11 @@ impl, P: Pile, const CAPS: u32> Stockpile { owned: params .owned .into_iter() - .map(|(seal, state)| NamedState { - name: state.name, + .map(|assignment| NamedState { + name: assignment.name, state: DataCell { - auth: seal.auth_token(), - data: state.state, + auth: assignment.state.seal.auth_token(), + data: assignment.state.data, lock: None, }, }) From 455bf09e54fe3cebc25b5d009ce97fb309f1aa99 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 17 Dec 2024 02:46:21 +0100 Subject: [PATCH 41/70] contract and codex info objects --- src/info.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ src/mound.rs | 10 +++++-- src/pile.rs | 5 +--- src/popls/bp.rs | 15 +++++++++- 5 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/info.rs diff --git a/src/info.rs b/src/info.rs new file mode 100644 index 00000000..dfbc865f --- /dev/null +++ b/src/info.rs @@ -0,0 +1,73 @@ +// Standard Library for RGB smart contracts +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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 amplify::confinement::TinyString; +use chrono::{DateTime, Utc}; +use hypersonic::{Articles, Codex, CodexId, ContractId, ContractName, Identity}; +use rgb::SealType; + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] +pub struct ContractInfo { + pub id: ContractId, + pub name: ContractName, + pub issuer: Identity, + pub timestamp: DateTime, + pub codex: CodexInfo, + pub ty: SealType, +} + +impl ContractInfo { + pub fn new(id: ContractId, articles: &Articles) -> Self { + Self { + id, + name: articles.contract.meta.name.clone(), + issuer: articles.contract.meta.issuer.clone(), + timestamp: DateTime::from_timestamp(articles.contract.meta.timestamp, 0) + .expect("Invalid timestamp"), + codex: CodexInfo::new(&articles.schema.codex), + ty: SealType::try_from(CAPS).unwrap(), + } + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] +pub struct CodexInfo { + pub id: CodexId, + pub name: TinyString, + pub developer: Identity, + pub timestamp: DateTime, +} + +impl CodexInfo { + pub fn new(codex: &Codex) -> Self { + Self { + id: codex.codex_id(), + name: codex.name.clone(), + developer: codex.developer.clone(), + timestamp: DateTime::from_timestamp(codex.timestamp, 0).expect("Invalid timestamp"), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 9b5f8459..4741594d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,10 +41,12 @@ extern crate serde; mod pile; mod stockpile; mod mound; +mod info; pub mod popls; #[cfg(feature = "bitcoin")] pub use bp::{Outpoint, Txid}; +pub use info::ContractInfo; pub use mound::{Excavate, Mound}; #[cfg(feature = "fs")] pub use pile::fs::FilePile; diff --git a/src/mound.rs b/src/mound.rs index ac91c86a..7fc417ee 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -33,7 +33,7 @@ use strict_encoding::{ ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, }; -use crate::{ConsumeError, CreateParams, Pile, Stockpile}; +use crate::{ConsumeError, ContractInfo, CreateParams, Pile, Stockpile}; pub trait Excavate, P: Pile, const CAPS: u32> { fn schemata(&mut self) -> impl Iterator; @@ -115,6 +115,12 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound impl Iterator + use<'_, S, P, X, CAPS> { + self.contracts + .iter() + .map(|(id, stockpile)| ContractInfo::new(*id, stockpile.stock().articles())) + } + pub fn contracts_mut( &mut self, ) -> impl Iterator)> { @@ -193,7 +199,7 @@ pub mod file { use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictEncode}; use super::*; - use crate::{FilePile, SealType}; + use crate::FilePile; pub struct DirExcavator { dir: PathBuf, diff --git a/src/pile.rs b/src/pile.rs index 2614324e..75ee44fa 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -74,7 +74,7 @@ pub mod fs { use std::collections::BTreeMap; use std::fs::File; use std::io::Read; - use std::path::{Path, PathBuf}; + use std::path::Path; use hypersonic::aora::file::FileAora; use hypersonic::expect::Expect; @@ -103,7 +103,6 @@ pub mod fs { pub struct FilePile where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> { - path: PathBuf, hoard: FileAora<>::PubId, Seal::CliWitness>, cache: FileAora<>::PubId, Seal::PubWitness>, keep: FileAora>, @@ -125,7 +124,6 @@ pub mod fs { .expect_or_else(|| format!("unable to create index file `{}`", path.display())); Self { - path, hoard, cache, keep, @@ -167,7 +165,6 @@ pub mod fs { } Self { - path, hoard, cache, keep, diff --git a/src/popls/bp.rs b/src/popls/bp.rs index a465b824..443c7f6b 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -378,7 +378,7 @@ pub mod file { use super::*; use crate::mound::file::DirExcavator; - use crate::{FilePile, SealType}; + use crate::{ContractInfo, FilePile, SealType}; pub type FileWallet = Barrow>, DirExcavator, CAPS>, CAPS>; @@ -513,6 +513,19 @@ pub mod file { let iter = iter.chain(self.lq_tapret.contract_ids()); iter } + + pub fn contracts_info(&self) -> impl Iterator + use<'_> { + let iter = iter::empty(); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_opret.contracts_info()); + #[cfg(feature = "bitcoin")] + let iter = iter.chain(self.bc_tapret.contracts_info()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_opret.contracts_info()); + #[cfg(feature = "liquid")] + let iter = iter.chain(self.lq_tapret.contracts_info()); + iter + } } pub type BpBarrow = From 15a8a5505ec6823248e962824e340f5c52eab4ac Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 17 Dec 2024 15:38:41 +0100 Subject: [PATCH 42/70] wallet methods --- src/popls/bp.rs | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 443c7f6b..e9bcc001 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -36,8 +36,8 @@ use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Vout}; use commit_verify::{Digest, DigestExt, Sha256}; use hypersonic::{ - AdaptedState, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, NamedState, - Operation, Schema, StateAtom, StateCalc, StateName, Supply, + AdaptedState, AuthToken, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, + NamedState, Operation, Schema, StateAtom, StateCalc, StateName, Supply, }; use rgb::SonicSeal; use strict_encoding::{StrictDeserialize, StrictSerialize}; @@ -47,6 +47,7 @@ use crate::{Assignment, CreateParams, Excavate, Mound, Pile}; pub trait WalletProvider { fn noise_seed(&self) -> Bytes32; + fn utxos(&self) -> impl Iterator; } pub trait OpretProvider: WalletProvider {} pub trait TapretProvider: WalletProvider {} @@ -193,6 +194,12 @@ impl< .issue(params.transform(self.noise_engine()), supply, pile) } + pub fn auth_token(&mut self, nonce: u64) -> Option { + let outpoint = self.wallet.utxos().next()?; + let seal = TxoSeal::::no_fallback(outpoint, self.noise_engine(), nonce); + Some(seal.auth_token()) + } + // TODO: Use bitcoin-specific state type aware of outpoints pub fn state( &self, @@ -603,6 +610,19 @@ pub mod file { } } + pub fn auth_token(&mut self, nonce: u64) -> Option { + match self { + #[cfg(feature = "bitcoin")] + Self::BcOpret(barrow) => barrow.auth_token(nonce), + #[cfg(feature = "bitcoin")] + Self::BcTapret(barrow) => barrow.auth_token(nonce), + #[cfg(feature = "liquid")] + Self::LqOpret(barrow) => barrow.auth_token(nonce), + #[cfg(feature = "liquid")] + Self::LqTapret(barrow) => barrow.auth_token(nonce), + } + } + pub fn state( &self, contract_id: Option, @@ -620,7 +640,6 @@ pub mod file { } pub fn prefab(&mut self, params: ConstructParams) -> Prefab { - // TODO: Mix into a noise seed contract id and other data match self { #[cfg(feature = "bitcoin")] Self::BcOpret(barrow) => barrow.prefab(params), @@ -638,5 +657,25 @@ pub mod file { let items = SmallOrdSet::try_from_iter(iter).expect("too large script"); PrefabBundle(items) } + + pub fn wallet_tapret(&mut self) -> &mut T { + match self { + #[cfg(feature = "bitcoin")] + Self::BcTapret(barrow) => &mut barrow.wallet, + #[cfg(feature = "liquid")] + Self::LqTapret(barrow) => &mut barrow.wallet, + _ => panic!("Invalid wallet type"), + } + } + + pub fn wallet_opret(&mut self) -> &mut O { + match self { + #[cfg(feature = "bitcoin")] + Self::BcOpret(barrow) => &mut barrow.wallet, + #[cfg(feature = "liquid")] + Self::LqOpret(barrow) => &mut barrow.wallet, + _ => panic!("Invalid wallet type"), + } + } } } From b758e4bddf02028f70891dd9cacdc876a828280a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 17 Dec 2024 19:03:21 +0100 Subject: [PATCH 43/70] add EitherSeal type --- src/popls/bp.rs | 25 ++++++++++++++++++++----- src/stockpile.rs | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index e9bcc001..832f38ba 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -43,6 +43,7 @@ use rgb::SonicSeal; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; +use crate::stockpile::EitherSeal; use crate::{Assignment, CreateParams, Excavate, Mound, Pile}; pub trait WalletProvider { @@ -69,6 +70,21 @@ pub enum BuilderSeal { Extern(Outpoint), } +impl EitherSeal { + pub fn transform( + self, + noise_engine: Sha256, + nonce: u64, + ) -> EitherSeal> { + match self { + EitherSeal::Known(seal) => { + EitherSeal::Known(TxoSeal::no_fallback(seal, noise_engine, nonce)) + } + EitherSeal::External(auth) => EitherSeal::External(auth), + } + } +} + impl CreateParams { pub fn transform(self, mut noise_engine: Sha256) -> CreateParams> { noise_engine.input_raw(self.codex_id.as_slice()); @@ -90,11 +106,10 @@ impl CreateParams { .map(|(nonce, assignment)| NamedState { name: assignment.name, state: Assignment { - seal: TxoSeal::no_fallback( - assignment.state.seal, - noise_engine.clone(), - nonce as u64, - ), + seal: assignment + .state + .seal + .transform(noise_engine.clone(), nonce as u64), data: assignment.state.data, }, }) diff --git a/src/stockpile.rs b/src/stockpile.rs index 81c75c0b..6cbfee7d 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -49,7 +49,37 @@ use strict_types::StrictVal; use crate::Pile; -#[derive(Clone)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, From)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(untagged, bound = "Seal: serde::Serialize + for<'d> serde::Deserialize<'d>") +)] +pub enum EitherSeal { + Known(Seal), + #[from] + External(AuthToken), +} + +impl EitherSeal { + pub fn auth_token(&self) -> AuthToken + where Seal: SonicSeal { + match self { + EitherSeal::Known(seal) => seal.auth_token(), + EitherSeal::External(auth) => *auth, + } + } + + pub fn to_explicit(&self) -> Option + where Seal: Clone { + match self { + EitherSeal::Known(seal) => Some(seal.clone()), + EitherSeal::External(_) => None, + } + } +} + +#[derive(Clone, Debug)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -58,8 +88,8 @@ use crate::Pile; bound = "Seal: serde::Serialize + for<'d> serde::Deserialize<'d>" ) )] -pub struct Assignment { - pub seal: Seal, +pub struct Assignment { + pub seal: EitherSeal, pub data: StrictVal, } @@ -67,7 +97,7 @@ pub struct Assignment { /// /// Differs from [`IssueParams`] in the fact that it uses full seal data instead of /// [`hypersonic::AuthTokens`] for output definitions. -#[derive(Clone)] +#[derive(Clone, Debug, From)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -103,7 +133,7 @@ impl, P: Pile, const CAPS: u32> Stockpile { params .owned .iter() - .map(|assignment| assignment.state.seal.clone()), + .filter_map(|assignment| assignment.state.seal.to_explicit()), ) .expect("too many outputs"); let params = IssueParams { From 7164f7aade580f518c0f6ee68f6347f83e28c856 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 18 Dec 2024 10:41:52 +0100 Subject: [PATCH 44/70] fix PrefabParams with using assignment --- src/mound.rs | 2 ++ src/popls/bp.rs | 57 +++++++++++++++++++++++++++++------------------- src/stockpile.rs | 4 ++-- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/mound.rs b/src/mound.rs index 7fc417ee..0ced4978 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -40,9 +40,11 @@ pub trait Excavate, P: Pile, const CAPS: u32> { fn contracts(&mut self) -> impl Iterator)>; } +/// Mound is a collection of smart contracts which have homogenous capabilities. pub struct Mound, P: Pile, X: Excavate, const CAPS: u32> { schemata: BTreeMap, contracts: BTreeMap>, + /// Persistence does loading of a stockpiles and their storage when a new contract is added. persistence: X, } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 832f38ba..09a17523 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -46,6 +46,7 @@ use strict_types::StrictVal; use crate::stockpile::EitherSeal; use crate::{Assignment, CreateParams, Excavate, Mound, Pile}; +/// Trait abstracting specific implementation of a bitcoin wallet. pub trait WalletProvider { fn noise_seed(&self) -> Bytes32; fn utxos(&self) -> impl Iterator; @@ -56,7 +57,7 @@ pub trait TapretProvider: WalletProvider {} pub const BP_BLANK_METHOD: &str = "_"; // TODO: Support failback seals -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -67,7 +68,7 @@ pub enum BuilderSeal { Oneself(Vout), #[display("{0}")] - Extern(Outpoint), + Extern(AuthToken), } impl EitherSeal { @@ -118,19 +119,27 @@ impl CreateParams { } } +#[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] +pub struct UsedState { + pub addr: CellAddr, + pub outpoint: Outpoint, + pub val: StrictVal, +} + /// Parameters used by BP-based wallet for constructing operations. /// /// Differs from [`CallParams`] in the fact that it uses [`BuilderSeal`]s instead of /// [`hypersonic::AuthTokens`] for output definitions. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] -pub struct ConstructParams { +pub struct PrefabParams { pub contract_id: ContractId, pub method: MethodName, pub reading: Vec, - pub using: Vec<(CellAddr, Outpoint, StrictVal)>, + pub using: Vec, pub global: Vec>, - pub owned: Vec<(BuilderSeal, NamedState)>, + pub owned: Vec>>, } /// Prefabricated operation, which includes information on the contract id and closed seals @@ -234,12 +243,12 @@ impl< } /// Creates a single operation basing on the provided construction parameters. - pub fn prefab(&mut self, params: ConstructParams) -> Prefab { + pub fn prefab(&mut self, params: PrefabParams) -> Prefab { // convert ConstructParams into CallParams let (closes, using) = params .using .into_iter() - .map(|(auth, outpoint, val)| (outpoint, (auth, val))) + .map(|used| (used.outpoint, (used.addr, used.val))) .unzip(); let closes = SmallOrdSet::try_from(closes).expect("too many inputs"); let mut defines = SmallOrdSet::new(); @@ -250,8 +259,8 @@ impl< .owned .into_iter() .enumerate() - .map(|(nonce, (seal, val))| { - let seal = match seal { + .map(|(nonce, assignment)| { + let auth = match assignment.state.seal { BuilderSeal::Oneself(vout) => { defines.push(vout).expect("too many seals"); // NB: We use opret type here, but this doesn't matter since we create seal @@ -261,18 +270,17 @@ impl< noise_engine.clone(), nonce as u64, ) + .auth_token() } - BuilderSeal::Extern(outpoint) => { - TxoSeal::no_fallback(outpoint, noise_engine.clone(), nonce as u64) - } + BuilderSeal::Extern(auth) => auth, }; let state = DataCell { - data: val.state, - auth: seal.auth_token(), + data: assignment.state.data, + auth, lock: None, }; NamedState { - name: val.name, + name: assignment.name, state, } }) @@ -345,7 +353,12 @@ impl< == auth }) .map(|(_, outpoint)| { - ((addr, outpoint, StrictVal::Unit), (name.clone(), val)) + let prevout = UsedState { + addr, + outpoint, + val: StrictVal::Unit, + }; + (prevout, (name.clone(), val)) }) }) .unzip(); @@ -361,16 +374,16 @@ impl< let mut owned = Vec::new(); for (name, calc) in calcs { - for state in calc.diff().expect("non-computable state") { + for data in calc.diff().expect("non-computable state") { let state = NamedState { name: name.clone(), - state, + state: Assignment { seal, data }, }; - owned.push((seal, state)); + owned.push(state); } } - let params = ConstructParams { + let params = PrefabParams { contract_id, method: MethodName::from(BP_BLANK_METHOD), global: none!(), @@ -654,7 +667,7 @@ pub mod file { } } - pub fn prefab(&mut self, params: ConstructParams) -> Prefab { + pub fn prefab(&mut self, params: PrefabParams) -> Prefab { match self { #[cfg(feature = "bitcoin")] Self::BcOpret(barrow) => barrow.prefab(params), @@ -667,7 +680,7 @@ pub mod file { } } - pub fn bundle(&mut self, items: impl IntoIterator) -> PrefabBundle { + pub fn bundle(&mut self, items: impl IntoIterator) -> PrefabBundle { let iter = items.into_iter().map(|params| self.prefab(params)); let items = SmallOrdSet::try_from_iter(iter).expect("too large script"); PrefabBundle(items) diff --git a/src/stockpile.rs b/src/stockpile.rs index 6cbfee7d..4ec409ca 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -89,7 +89,7 @@ impl EitherSeal { ) )] pub struct Assignment { - pub seal: EitherSeal, + pub seal: Seal, pub data: StrictVal, } @@ -113,7 +113,7 @@ pub struct CreateParams { pub name: TypeName, pub timestamp: Option>, pub global: Vec>, - pub owned: Vec>>, + pub owned: Vec>>>, } #[derive(Getters)] From 27a3897d4de08c1f973fb601d414e8844a575fb8 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 20 Dec 2024 13:13:14 +0100 Subject: [PATCH 45/70] chore: update fmt rules --- .rustfmt.toml | 2 ++ src/mound.rs | 7 +------ src/pile.rs | 14 ++------------ src/popls/bp.rs | 35 ++++++----------------------------- src/stockpile.rs | 10 ++-------- 5 files changed, 13 insertions(+), 55 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index 6d14899a..29c789ac 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -5,8 +5,10 @@ max_width = 100 array_width = 100 attr_fn_like_width = 100 comment_width = 100 +chain_width = 60 fn_call_width = 100 single_line_if_else_max_width = 100 +struct_lit_width = 60 fn_single_line = true format_code_in_doc_comments = true diff --git a/src/mound.rs b/src/mound.rs index 0ced4978..2353ed29 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -209,12 +209,7 @@ pub mod file { } impl DirExcavator { - pub fn new(dir: PathBuf) -> Self { - Self { - dir, - _phantom: PhantomData, - } - } + pub fn new(dir: PathBuf) -> Self { Self { dir, _phantom: PhantomData } } fn contents(&mut self) -> impl Iterator { fs::read_dir(&self.dir) diff --git a/src/pile.rs b/src/pile.rs index 75ee44fa..534152fe 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -123,12 +123,7 @@ pub mod fs { File::create_new(path.join("index.dat")) .expect_or_else(|| format!("unable to create index file `{}`", path.display())); - Self { - hoard, - cache, - keep, - index: empty!(), - } + Self { hoard, cache, keep, index: empty!() } } } @@ -164,12 +159,7 @@ pub mod fs { index.insert(opid, ids); } - Self { - hoard, - cache, - keep, - index: index.into(), - } + Self { hoard, cache, keep, index: index.into() } } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 09a17523..53220ad5 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -274,24 +274,13 @@ impl< } BuilderSeal::Extern(auth) => auth, }; - let state = DataCell { - data: assignment.state.data, - auth, - lock: None, - }; - NamedState { - name: assignment.name, - state, - } + let state = DataCell { data: assignment.state.data, auth, lock: None }; + NamedState { name: assignment.name, state } }) .collect(); let call = CallParams { - core: CoreParams { - method: params.method, - global: params.global, - owned, - }, + core: CoreParams { method: params.method, global: params.global, owned }, using, reading: params.reading, }; @@ -300,12 +289,7 @@ impl< let opid = stockpile.stock_mut().call(call); let operation = stockpile.stock_mut().operation(opid); - Prefab { - contract_id: params.contract_id, - closes, - defines, - operation, - } + Prefab { contract_id: params.contract_id, closes, defines, operation } } /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. @@ -353,11 +337,7 @@ impl< == auth }) .map(|(_, outpoint)| { - let prevout = UsedState { - addr, - outpoint, - val: StrictVal::Unit, - }; + let prevout = UsedState { addr, outpoint, val: StrictVal::Unit }; (prevout, (name.clone(), val)) }) }) @@ -375,10 +355,7 @@ impl< let mut owned = Vec::new(); for (name, calc) in calcs { for data in calc.diff().expect("non-computable state") { - let state = NamedState { - name: name.clone(), - state: Assignment { seal, data }, - }; + let state = NamedState { name: name.clone(), state: Assignment { seal, data } }; owned.push(state); } } diff --git a/src/stockpile.rs b/src/stockpile.rs index 4ec409ca..b8a4d88f 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -233,10 +233,7 @@ impl, P: Pile, const CAPS: u32> Stockpile { self.stock.merge_articles(articles)?; // We need to clone due to a borrow checker. - let reader = OpReader { - stream, - _phantom: PhantomData, - }; + let reader = OpReader { stream, _phantom: PhantomData }; self.evaluate(reader)?; self.stock.complete_update(); @@ -258,10 +255,7 @@ impl<'r, Seal: SonicSeal, R: ReadRaw> ReadOperation for OpReader<'r, Seal, R> { Ok(operation) => { let defined_seals = SmallVec::strict_decode(self.stream) .expect("Failed to read consignment stream"); - let op_seals = OperationSeals { - operation, - defined_seals, - }; + let op_seals = OperationSeals { operation, defined_seals }; Some((op_seals, WitnessReader { parent: self })) } Err(DecodeError::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => None, From 02823ad1bf60cad81052e9a9300fcd8db2ad7836 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 20 Dec 2024 21:35:05 +0100 Subject: [PATCH 46/70] add outpoint information into contract state --- src/popls/bp.rs | 19 +++++++------- src/stockpile.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 53220ad5..d2e3d1cd 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -36,14 +36,14 @@ use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Vout}; use commit_verify::{Digest, DigestExt, Sha256}; use hypersonic::{ - AdaptedState, AuthToken, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, - NamedState, Operation, Schema, StateAtom, StateCalc, StateName, Supply, + AuthToken, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, NamedState, + Operation, Schema, StateAtom, StateCalc, StateName, Supply, }; use rgb::SonicSeal; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::StrictVal; -use crate::stockpile::EitherSeal; +use crate::stockpile::{ContractState, EitherSeal}; use crate::{Assignment, CreateParams, Excavate, Mound, Pile}; /// Trait abstracting specific implementation of a bitcoin wallet. @@ -226,13 +226,14 @@ impl< // TODO: Use bitcoin-specific state type aware of outpoints pub fn state( - &self, + &mut self, contract_id: Option, - ) -> impl Iterator { + ) -> impl Iterator)> + use<'_, W, D, S, P, X, CAPS> + { self.mound - .contracts() + .contracts_mut() .filter(move |(id, _)| contract_id.is_none() || Some(*id) == contract_id) - .map(|(id, stockpile)| (id, &stockpile.stock().state().main)) + .map(|(id, stockpile)| (id, stockpile.state().transform(|seal| seal.primary))) } fn noise_engine(&self) -> Sha256 { @@ -629,9 +630,9 @@ pub mod file { } pub fn state( - &self, + &mut self, contract_id: Option, - ) -> Box + '_> { + ) -> Box)> + '_> { match self { #[cfg(feature = "bitcoin")] Self::BcOpret(barrow) => Box::new(barrow.state(contract_id)), diff --git a/src/stockpile.rs b/src/stockpile.rs index b8a4d88f..0da195ff 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -22,6 +22,7 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. +use alloc::collections::BTreeMap; use core::borrow::Borrow; use core::marker::PhantomData; // TODO: Used in strict encoding; once solved there, remove here @@ -33,8 +34,8 @@ use chrono::{DateTime, Utc}; use hypersonic::aora::Aora; use hypersonic::{ Articles, AuthToken, CellAddr, Codex, CodexId, ContractId, CoreParams, DataCell, IssueParams, - LibRepo, Memory, MergeError, MethodName, NamedState, Operation, Opid, Schema, StateAtom, Stock, - Supply, + LibRepo, Memory, MergeError, MethodName, NamedState, Operation, Opid, Schema, StateAtom, + StateName, Stock, Supply, }; use rgb::{ ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SealType, SonicSeal, @@ -79,7 +80,7 @@ impl EitherSeal { } } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -93,6 +94,43 @@ pub struct Assignment { pub data: StrictVal, } +#[derive(Clone, Eq, PartialEq, Debug, Default)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde( + rename_all = "camelCase", + bound = "Seal: serde::Serialize + for<'d> serde::Deserialize<'d>" + ) +)] +pub struct ContractState { + pub immutable: BTreeMap>, + pub owned: BTreeMap>>, + pub computed: BTreeMap, +} + +impl ContractState { + pub fn transform(self, f: impl Fn(Seal) -> To) -> ContractState { + ContractState { + immutable: self.immutable, + owned: self + .owned + .into_iter() + .map(|(name, map)| { + let map = map + .into_iter() + .map(|(addr, data)| { + (addr, Assignment { seal: f(data.seal), data: data.data }) + }) + .collect(); + (name, map) + }) + .collect(), + computed: self.computed, + } + } +} + /// Parameters used by RGB for contract creation operations. /// /// Differs from [`IssueParams`] in the fact that it uses full seal data instead of @@ -179,6 +217,30 @@ impl, P: Pile, const CAPS: u32> Stockpile { self.stock.state().raw.auth.get(&auth).copied() } + pub fn state(&mut self) -> ContractState { + let state = self.stock().state().main.clone(); + ContractState { + immutable: state.immutable, + owned: state + .owned + .into_iter() + .map(|(name, map)| { + let map = map + .into_iter() + .map(|(addr, data)| { + let seal = self.pile_mut().keep_mut().read(addr.opid) + [addr.pos as usize] + .clone(); + (addr, Assignment { seal, data }) + }) + .collect(); + (name, map) + }) + .collect(), + computed: state.computed, + } + } + pub fn append_witness( &mut self, published: &::PubWitness, From 67d3dd40b141981f669827eb9fb1e15f04ba8fe7 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 21 Dec 2024 13:24:56 +0100 Subject: [PATCH 47/70] rgbx: command-line toolbox utility --- Cargo.lock | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 58 +++++++++++++++------ cli/Cargo.toml | 22 ++++++++ cli/src/cmd.rs | 44 ++++++++++++++++ cli/src/exec.rs | 56 ++++++++++++++++++++ cli/src/main.rs | 37 ++++++++++++++ 6 files changed, 334 insertions(+), 15 deletions(-) create mode 100644 cli/Cargo.toml create mode 100644 cli/src/cmd.rs create mode 100644 cli/src/exec.rs create mode 100644 cli/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index aa6f7ff2..d0d578dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,61 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" + [[package]] name = "arrayvec" version = "0.7.6" @@ -271,6 +326,52 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "commit_encoding_derive" version = "0.12.0-beta.1" @@ -439,6 +540,12 @@ dependencies = [ "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.14" @@ -603,6 +710,19 @@ dependencies = [ "wasm-bindgen-test", ] +[[package]] +name = "rgbx" +version = "0.12.0-alpha.1" +dependencies = [ + "amplify", + "anyhow", + "clap", + "rgb-std", + "serde", + "serde_yaml", + "strict_encoding", +] + [[package]] name = "ripemd" version = "0.1.3" @@ -817,6 +937,12 @@ dependencies = [ "serde_str_helpers", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -926,6 +1052,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index a0b01f12..d04faac2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,32 +1,60 @@ -[package] -name = "rgb-std" +[workspace] +members = [".", "cli"] +default-members = ["."] + +[workspace.package] version = "0.12.0-alpha.1" -description = "Standard Library for RGB smart contracts" -authors = ["Dr Maxim Orlovsky "] -homepage = "https://github.com/RGB-WG" -repository = "https://github.com/RGB-WG/rgb-std" keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] categories = ["cryptography::cryptocurrencies"] -rust-version = "1.77.0" # Due to use of `rustfix` +authors = ["Dr Maxim Orlovsky "] +homepage = "https://rgb.tech" +repository = "https://github.com/RGB-WG/rgb-std" +rust-version = "1.77.0" edition = "2021" license = "Apache-2.0" -readme = "README.md" - -[lib] -name = "rgb" -crate-type = ["cdylib", "rlib"] # We need this for WASM -[dependencies] +[workspace.dependencies] amplify = "4.8.0" strict_encoding = "2.8.1" strict_types = "2.8.1" commit_verify = "0.12.0-beta.1" single_use_seals = "0.12.0-beta.1" hypersonic = "0.12.0-beta.1" -bp-core = { version = "0.12.0-beta.2", optional = true } +bp-core = "0.12.0-beta.2" rgb-core = "0.12.0-beta.3" +rgb-std = { version = "0.12.0-alpha.1", path = "." } chrono = "0.4.39" -serde = { version = "1.0.215", optional = true } +serde = "1.0.215" + +[package] +name = "rgb-std" +description = "Standard Library for RGB smart contracts" +version.workspace = true +keywords.workspace = true +categories.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +rust-version.workspace = true +edition.workspace = true +license.workspace = true +readme = "README.md" + +[lib] +name = "rgb" +crate-type = ["cdylib", "rlib"] # We need this for WASM + +[dependencies] +amplify.workspace = true +strict_encoding.workspace = true +strict_types.workspace = true +commit_verify.workspace = true +single_use_seals.workspace = true +hypersonic.workspace = true +bp-core = { workspace = true, optional = true } +rgb-core.workspace = true +chrono.workspace = true +serde = { workspace = true, optional = true } [features] default = ["std", "bitcoin"] diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 00000000..373f0e9d --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rgbx" +description = "RGB command-line toolbox utility" +version.workspace = true +keywords.workspace = true +categories.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +rust-version.workspace = true +edition.workspace = true +license.workspace = true +readme = "../README.md" + +[dependencies] +amplify.workspace = true +strict_encoding.workspace = true +rgb-std = { workspace = true, features = ["fs", "serde"] } +serde.workspace = true +serde_yaml = "0.9.34" +anyhow = "1.0.93" +clap = { version = "4.5.21", features = ["derive", "env"] } diff --git a/cli/src/cmd.rs b/cli/src/cmd.rs new file mode 100644 index 00000000..f1e16bc6 --- /dev/null +++ b/cli/src/cmd.rs @@ -0,0 +1,44 @@ +// RGB command-line toolbox utility +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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::path::PathBuf; + +use clap::ValueHint; + +#[derive(Parser)] +pub struct Args { + /// Command to execute + #[clap(subcommand)] + pub command: Cmd, +} + +#[derive(Parser)] +pub enum Cmd { + /// Inspect the provided binary file + Inspect { + /// File to inspect + #[clap(value_hint = ValueHint::FilePath)] + file: PathBuf, + }, +} diff --git a/cli/src/exec.rs b/cli/src/exec.rs new file mode 100644 index 00000000..aec51f0c --- /dev/null +++ b/cli/src/exec.rs @@ -0,0 +1,56 @@ +// RGB command-line toolbox utility +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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::io::stdout; + +use rgb::popls::bp::PrefabBundle; +use strict_encoding::StrictDeserialize; + +use crate::cmd::{Args, Cmd}; + +impl Args { + pub fn exec(&self) -> anyhow::Result<()> { + match &self.command { + Cmd::Inspect { file } => match file.extension() { + Some(ext) if ext == "pfab" => { + let pfab = PrefabBundle::strict_deserialize_from_file::<{ usize::MAX }>(file)?; + serde_yaml::to_writer(stdout(), &pfab)?; + } + Some(_) => { + return Err(anyhow!( + "Unknown file type for '{}': the extension is not recognized", + file.display() + )) + } + None => { + return Err(anyhow!( + "The file '{}' has no extension; unable to detect the file type", + file.display() + )) + } + }, + } + Ok(()) + } +} diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 00000000..fd46cf9f --- /dev/null +++ b/cli/src/main.rs @@ -0,0 +1,37 @@ +// RGB command-line toolbox utility +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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. + +#[macro_use] +extern crate clap; +#[macro_use] +extern crate anyhow; + +pub mod cmd; +mod exec; + +use clap::Parser; + +use crate::cmd::Args; + +fn main() -> anyhow::Result<()> { Args::parse().exec() } From c867468f6008072656f4a6361c5092a70be3d62a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 21 Dec 2024 16:09:28 +0100 Subject: [PATCH 48/70] rgbx: command for dumping consignments --- Cargo.lock | 26 +++++---- cli/Cargo.toml | 10 ++++ cli/src/cmd.rs | 23 ++++++++ cli/src/dump.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++++ cli/src/exec.rs | 29 ++++++++++ cli/src/main.rs | 1 + src/stockpile.rs | 14 +++-- 7 files changed, 230 insertions(+), 17 deletions(-) create mode 100644 cli/src/dump.rs diff --git a/Cargo.lock b/Cargo.lock index d0d578dd..28ef9b80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" dependencies = [ "amplify", "chrono", @@ -239,7 +239,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" dependencies = [ "amplify", "bp-consensus", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" dependencies = [ "amplify", "base85", @@ -271,7 +271,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#961885bd7f0d30f32a759089ee077a32b1325dbf" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" dependencies = [ "amplify", "baid64", @@ -298,9 +298,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ "shlex", ] @@ -490,7 +490,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#e8506c8ea31d08ff180a56d6bd3413033494e5a8" +source = "git+https://github.com/AluVM/sonic#8d2d1127602d3639e014c6a022d52554402564f7" dependencies = [ "aluvm", "amplify", @@ -564,9 +564,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "log" @@ -677,7 +677,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#f95a75c43ea335082f0c9671ae26c8f765da582e" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#e422aa37d51099f0015575c507b4da133a26df6b" dependencies = [ "amplify", "bp-core", @@ -717,10 +717,12 @@ dependencies = [ "amplify", "anyhow", "clap", + "hypersonic", "rgb-std", "serde", "serde_yaml", "strict_encoding", + "toml", ] [[package]] @@ -867,7 +869,7 @@ dependencies = [ [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#e8506c8ea31d08ff180a56d6bd3413033494e5a8" +source = "git+https://github.com/AluVM/sonic#8d2d1127602d3639e014c6a022d52554402564f7" dependencies = [ "aluvm", "amplify", @@ -1028,7 +1030,7 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ultrasonic" version = "0.12.0-beta.2" -source = "git+https://github.com/AluVM/ultrasonic#68df7d94f61b73ac3e543ff35008c9ab76d9c131" +source = "git+https://github.com/AluVM/ultrasonic#178a7b83a4ba6e5657210e7261b1075de79576b7" dependencies = [ "amplify", "baid64", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 373f0e9d..cfe7523a 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,8 +15,18 @@ readme = "../README.md" [dependencies] amplify.workspace = true strict_encoding.workspace = true +hypersonic.workspace = true rgb-std = { workspace = true, features = ["fs", "serde"] } serde.workspace = true serde_yaml = "0.9.34" +toml = "0.8.19" anyhow = "1.0.93" clap = { version = "4.5.21", features = ["derive", "env"] } + +[features] +defaul = ["bitcoin"] +all = ["bitcoin", "liquid", "prime"] + +bitcoin = ["rgb-std/bitcoin"] +liquid = ["rgb-std/liquid"] +prime = ["rgb-std/prime"] diff --git a/cli/src/cmd.rs b/cli/src/cmd.rs index f1e16bc6..3c6e2427 100644 --- a/cli/src/cmd.rs +++ b/cli/src/cmd.rs @@ -25,6 +25,7 @@ use std::path::PathBuf; use clap::ValueHint; +use rgb::SealType; #[derive(Parser)] pub struct Args { @@ -41,4 +42,26 @@ pub enum Cmd { #[clap(value_hint = ValueHint::FilePath)] file: PathBuf, }, + + /// Dump complex data into multiple debug files + /// + /// Works for contract consignments and stockpiles + Dump { + /// Remove the destination directory if it already exists + #[clap(short, long, global = true)] + force: bool, + + /// The seal type used by the contract + seal: SealType, + + /// Source data to process + #[clap(value_hint = ValueHint::FilePath)] + src: PathBuf, + + /// Destination directory to put dump files + /// + /// If skipped, adds `dump` subdirectory to the `src` path. + #[clap(value_hint = ValueHint::FilePath)] + dst: Option, + }, } diff --git a/cli/src/dump.rs b/cli/src/dump.rs new file mode 100644 index 00000000..420d9dd0 --- /dev/null +++ b/cli/src/dump.rs @@ -0,0 +1,144 @@ +// RGB command-line toolbox utility +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are 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::fs::File; +use std::io::Write; +use std::path::Path; +use std::{fs, io}; + +use amplify::confinement::SmallVec; +use hypersonic::{Articles, ContractId, Operation}; +use rgb::bitcoin::{OpretSeal, TapretSeal}; +use rgb::{ + SealType, SealWitness, BITCOIN_OPRET, BITCOIN_TAPRET, LIQUID_OPRET, LIQUID_TAPRET, PRIME_SEALS, +}; +use strict_encoding::{DecodeError, StreamReader, StrictDecode, StrictReader}; + +pub fn dumb_consignment(seal: SealType, src: &Path, dst: impl AsRef) -> anyhow::Result<()> { + let dst = dst.as_ref(); + fs::create_dir_all(dst)?; + + let file = File::open(src)?; + let mut stream = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); + + let cointract_id = ContractId::strict_decode(&mut stream)?; + println!("Dumping consignment for {} into '{}'", cointract_id, dst.display()); + + print!("Processing contract articles ... "); + let out = File::create_new(dst.join("0-articles.yaml"))?; + match seal { + #[cfg(feature = "bitcoin")] + SealType::BitcoinOpret => { + let articles = Articles::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &articles)?; + } + #[cfg(feature = "bitcoin")] + SealType::BitcoinTapret => { + let articles = Articles::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &articles)?; + } + #[cfg(feature = "liquid")] + SealType::LiquidOpret => { + let articles = Articles::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &articles)?; + } + #[cfg(feature = "liquid")] + SealType::LiquidTapret => { + let articles = Articles::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &articles)?; + } + #[cfg(feature = "prime")] + SealType::Prime => { + let articles = Articles::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &articles)?; + } + } + println!("success"); + + let mut op_count = 1; + let mut seal_count = 0; + let mut witness_count = 0; + loop { + match Operation::strict_decode(&mut stream) { + Ok(operation) => { + let opid = operation.opid(); + + let out = File::create_new(dst.join(format!("{op_count:04}-op.{opid}.yaml")))?; + serde_yaml::to_writer(&out, &operation)?; + + let mut out = File::create_new(dst.join(format!("{op_count:04}-seals.toml")))?; + // Seal definition is not distinct between tapret and opret, so we save on match + // here + let defined_seals = SmallVec::::strict_decode(&mut stream) + .expect("Failed to read consignment stream"); + out.write_all(toml::to_string(&defined_seals)?.as_bytes())?; + seal_count += defined_seals.len(); + + let len = u64::strict_decode(&mut stream)?; + for no in 0..len { + let out = File::create_new( + dst.join(format!("{op_count:04}-witness-{:02}.toml", no + 1)), + )?; + match seal { + #[cfg(feature = "bitcoin")] + SealType::BitcoinOpret => { + let witness = SealWitness::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &witness)?; + } + #[cfg(feature = "bitcoin")] + SealType::BitcoinTapret => { + let witness = SealWitness::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &witness)?; + } + #[cfg(feature = "liquid")] + SealType::LiquidOpret => { + let witness = SealWitness::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &witness)?; + } + #[cfg(feature = "liquid")] + SealType::LiquidTapret => { + let witness = SealWitness::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &witness)?; + } + #[cfg(feature = "prime")] + SealType::Prime => { + todo!() + } + } + } + + witness_count += len as usize; + op_count += 1; + } + Err(DecodeError::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => break, + Err(e) => return Err(anyhow!("Failed to read consignment stream: {}", e)), + } + print!( + "Processing: {op_count} operations, {seal_count} seals, {witness_count} witnesses ... \ + \r" + ); + } + println!("complete"); + Ok(()) +} diff --git a/cli/src/exec.rs b/cli/src/exec.rs index aec51f0c..80178ebc 100644 --- a/cli/src/exec.rs +++ b/cli/src/exec.rs @@ -22,12 +22,14 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. +use std::fs; use std::io::stdout; use rgb::popls::bp::PrefabBundle; use strict_encoding::StrictDeserialize; use crate::cmd::{Args, Cmd}; +use crate::dump::dumb_consignment; impl Args { pub fn exec(&self) -> anyhow::Result<()> { @@ -50,6 +52,33 @@ impl Args { )) } }, + Cmd::Dump { force, seal, src, dst } => { + let dst = dst + .as_ref() + .map(|p| p.to_owned()) + .or_else(|| src.parent().map(|path| path.join("dump"))) + .ok_or(anyhow!("Can't detect destination path for '{}'", src.display()))?; + match src.extension() { + Some(ext) if ext == "rgb" => { + if *force { + fs::remove_dir_all(&dst)?; + } + dumb_consignment(*seal, src, dst)?; + } + Some(_) => { + return Err(anyhow!( + "Can't detect type for '{}': the extension is not recognized", + src.display() + )) + } + None => { + return Err(anyhow!( + "The path '{}' can't be recognized as a known data", + src.display() + )) + } + } + } } Ok(()) } diff --git a/cli/src/main.rs b/cli/src/main.rs index fd46cf9f..6a714e70 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -29,6 +29,7 @@ extern crate anyhow; pub mod cmd; mod exec; +mod dump; use clap::Parser; diff --git a/src/stockpile.rs b/src/stockpile.rs index 0da195ff..86eb33fb 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -318,7 +318,9 @@ impl<'r, Seal: SonicSeal, R: ReadRaw> ReadOperation for OpReader<'r, Seal, R> { let defined_seals = SmallVec::strict_decode(self.stream) .expect("Failed to read consignment stream"); let op_seals = OperationSeals { operation, defined_seals }; - Some((op_seals, WitnessReader { parent: self })) + let count = + u64::strict_decode(self.stream).expect("Failed to read consignment stream"); + Some((op_seals, WitnessReader { parent: self, left: count })) } Err(DecodeError::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => None, Err(e) => { @@ -330,6 +332,7 @@ impl<'r, Seal: SonicSeal, R: ReadRaw> ReadOperation for OpReader<'r, Seal, R> { } pub struct WitnessReader<'r, Seal: SonicSeal, R: ReadRaw> { + left: u64, parent: OpReader<'r, Seal, R>, } @@ -337,12 +340,13 @@ impl<'r, Seal: SonicSeal, R: ReadRaw> ReadWitness for WitnessReader<'r, Seal, R> type Seal = Seal; type OpReader = OpReader<'r, Seal, R>; - fn read_witness(self) -> Step<(SealWitness, Self), Self::OpReader> { + fn read_witness(mut self) -> Step<(SealWitness, Self), Self::OpReader> { + self.left -= 1; + if self.left == 0 { + return Step::Complete(self.parent); + } match SealWitness::strict_decode(self.parent.stream) { Ok(witness) => Step::Next((witness, self)), - Err(DecodeError::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => { - Step::Complete(self.parent) - } Err(e) => { // TODO: Report error via a side-channel panic!("Failed to read consignment stream: {}", e); From 28f9eadb33dc474f1bcc35bab5b134553d7769de Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 21 Dec 2024 16:32:53 +0100 Subject: [PATCH 49/70] bp: store newly defined seals to keep --- src/popls/bp.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index d2e3d1cd..4778b21e 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -28,13 +28,14 @@ use alloc::collections::BTreeMap; use std::collections::BTreeSet; -use amplify::confinement::SmallOrdSet; +use amplify::confinement::{SmallOrdSet, SmallVec}; use amplify::{confinement, Bytes32}; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; use bp::seals::TxoSeal; use bp::{dbc, Outpoint, Vout}; use commit_verify::{Digest, DigestExt, Sha256}; +use hypersonic::aora::Aora; use hypersonic::{ AuthToken, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, NamedState, Operation, Schema, StateAtom, StateCalc, StateName, Supply, @@ -254,6 +255,7 @@ impl< let closes = SmallOrdSet::try_from(closes).expect("too many inputs"); let mut defines = SmallOrdSet::new(); + let mut seals = SmallVec::new(); let mut noise_engine = self.noise_engine(); noise_engine.input_raw(params.contract_id.as_slice()); let owned = params @@ -264,14 +266,13 @@ impl< let auth = match assignment.state.seal { BuilderSeal::Oneself(vout) => { defines.push(vout).expect("too many seals"); - // NB: We use opret type here, but this doesn't matter since we create seal - // only to produce the auth token, and seals do not commit to their type. - TxoSeal::::vout_no_fallback( + let seal = TxoSeal::::vout_no_fallback( vout, noise_engine.clone(), nonce as u64, - ) - .auth_token() + ); + seals.push(seal).expect("too many seals"); + seal.auth_token() } BuilderSeal::Extern(auth) => auth, }; @@ -289,6 +290,7 @@ impl< let stockpile = self.mound.contract_mut(params.contract_id); let opid = stockpile.stock_mut().call(call); let operation = stockpile.stock_mut().operation(opid); + stockpile.pile_mut().keep_mut().append(opid, &seals); Prefab { contract_id: params.contract_id, closes, defines, operation } } From 37907921d86da11f7c2e035a6f6e1c8eb8cb255f Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 21 Dec 2024 16:40:38 +0100 Subject: [PATCH 50/70] distinguish `state_all` from `state` method --- src/popls/bp.rs | 40 ++++++++++++++++++++++++++++++++++++++-- src/stockpile.rs | 22 +++++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/popls/bp.rs b/src/popls/bp.rs index 4778b21e..d2ae71bf 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -50,6 +50,7 @@ use crate::{Assignment, CreateParams, Excavate, Mound, Pile}; /// Trait abstracting specific implementation of a bitcoin wallet. pub trait WalletProvider { fn noise_seed(&self) -> Bytes32; + fn has_utxo(&self, outpoint: Outpoint) -> bool; fn utxos(&self) -> impl Iterator; } pub trait OpretProvider: WalletProvider {} @@ -225,7 +226,6 @@ impl< Some(seal.auth_token()) } - // TODO: Use bitcoin-specific state type aware of outpoints pub fn state( &mut self, contract_id: Option, @@ -234,7 +234,27 @@ impl< self.mound .contracts_mut() .filter(move |(id, _)| contract_id.is_none() || Some(*id) == contract_id) - .map(|(id, stockpile)| (id, stockpile.state().transform(|seal| seal.primary))) + .map(|(id, stockpile)| { + let state = stockpile.state().filter_map(|seal| { + if self.wallet.has_utxo(seal.primary) { + Some(seal.primary) + } else { + None + } + }); + (id, state) + }) + } + + pub fn state_all( + &mut self, + contract_id: Option, + ) -> impl Iterator)> + use<'_, W, D, S, P, X, CAPS> + { + self.mound + .contracts_mut() + .filter(move |(id, _)| contract_id.is_none() || Some(*id) == contract_id) + .map(|(id, stockpile)| (id, stockpile.state().map(|seal| seal.primary))) } fn noise_engine(&self) -> Sha256 { @@ -647,6 +667,22 @@ pub mod file { } } + pub fn state_all( + &mut self, + contract_id: Option, + ) -> Box)> + '_> { + match self { + #[cfg(feature = "bitcoin")] + Self::BcOpret(barrow) => Box::new(barrow.state_all(contract_id)), + #[cfg(feature = "bitcoin")] + Self::BcTapret(barrow) => Box::new(barrow.state_all(contract_id)), + #[cfg(feature = "liquid")] + Self::LqOpret(barrow) => Box::new(barrow.state_all(contract_id)), + #[cfg(feature = "liquid")] + Self::LqTapret(barrow) => Box::new(barrow.state_all(contract_id)), + } + } + pub fn prefab(&mut self, params: PrefabParams) -> Prefab { match self { #[cfg(feature = "bitcoin")] diff --git a/src/stockpile.rs b/src/stockpile.rs index 86eb33fb..4f2f2227 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -110,7 +110,7 @@ pub struct ContractState { } impl ContractState { - pub fn transform(self, f: impl Fn(Seal) -> To) -> ContractState { + pub fn map(self, f: impl Fn(Seal) -> To) -> ContractState { ContractState { immutable: self.immutable, owned: self @@ -129,6 +129,26 @@ impl ContractState { computed: self.computed, } } + + pub fn filter_map(self, f: impl Fn(Seal) -> Option) -> ContractState { + ContractState { + immutable: self.immutable, + owned: self + .owned + .into_iter() + .map(|(name, map)| { + let map = map + .into_iter() + .filter_map(|(addr, data)| { + Some((addr, Assignment { seal: f(data.seal)?, data: data.data })) + }) + .collect(); + (name, map) + }) + .collect(), + computed: self.computed, + } + } } /// Parameters used by RGB for contract creation operations. From 0c288e09d8e8efe20933c7d6e2392426830da16b Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 21 Dec 2024 18:13:35 +0100 Subject: [PATCH 51/70] rgbx: dump stockpile --- Cargo.lock | 4 +- cli/src/dump.rs | 174 +++++++++++++++++++++++++++++------------------- cli/src/exec.rs | 114 ++++++++++++++++++++++++------- src/lib.rs | 2 +- src/pile.rs | 3 + 5 files changed, 202 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28ef9b80..14caa3c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,7 +490,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#8d2d1127602d3639e014c6a022d52554402564f7" +source = "git+https://github.com/AluVM/sonic#f5278ec3da97a129ea7f3681d707463ea1bddf5d" dependencies = [ "aluvm", "amplify", @@ -869,7 +869,7 @@ dependencies = [ [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#8d2d1127602d3639e014c6a022d52554402564f7" +source = "git+https://github.com/AluVM/sonic#f5278ec3da97a129ea7f3681d707463ea1bddf5d" dependencies = [ "aluvm", "amplify", diff --git a/cli/src/dump.rs b/cli/src/dump.rs index 420d9dd0..033436db 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -22,20 +22,110 @@ // or implied. See the License for the specific language governing permissions and limitations under // the License. +use std::collections::BTreeMap; use std::fs::File; use std::io::Write; use std::path::Path; use std::{fs, io}; use amplify::confinement::SmallVec; -use hypersonic::{Articles, ContractId, Operation}; -use rgb::bitcoin::{OpretSeal, TapretSeal}; -use rgb::{ - SealType, SealWitness, BITCOIN_OPRET, BITCOIN_TAPRET, LIQUID_OPRET, LIQUID_TAPRET, PRIME_SEALS, -}; -use strict_encoding::{DecodeError, StreamReader, StrictDecode, StrictReader}; - -pub fn dumb_consignment(seal: SealType, src: &Path, dst: impl AsRef) -> anyhow::Result<()> { +use hypersonic::aora::Aora; +use hypersonic::{Articles, ContractId, FileSupply, Operation}; +use rgb::{FilePile, Index, Pile, PublishedWitness, SealWitness, SonicSeal, Stockpile}; +use serde::{Deserialize, Serialize}; +use strict_encoding::{DecodeError, StreamReader, StrictDecode, StrictEncode, StrictReader}; + +// TODO: Auto-compute seal type out of the articles data +pub fn dump_stockpile( + src: &Path, + dst: impl AsRef, +) -> anyhow::Result<()> +where + Seal: Serialize, + Seal::CliWitness: Serialize + StrictEncode + StrictDecode, + Seal::PubWitness: Serialize + StrictEncode + StrictDecode, + >::PubId: + Ord + From<[u8; 32]> + Into<[u8; 32]> + Serialize, +{ + let dst = dst.as_ref(); + fs::create_dir_all(dst)?; + + print!("Reading contract stockpile from '{}' ... ", src.display()); + let mut stockpile = Stockpile::, CAPS>::load(src); + println!("success reading {}", stockpile.contract_id()); + + print!("Processing contract articles ... "); + let out = File::create_new(dst.join("articles.yaml"))?; + serde_yaml::to_writer(&out, stockpile.stock().articles())?; + println!("success"); + + print!("Processing operations ... none found"); + for (no, (opid, op)) in stockpile.stock_mut().operations().enumerate() { + let out = File::create_new(dst.join(format!("{:04}-{opid}.op.yaml", no + 1)))?; + serde_yaml::to_writer(&out, &op)?; + print!("\rProcessing operations ... {} processed", no + 1); + } + println!(); + + print!("Processing trace ... none state transitions found"); + for (no, (opid, st)) in stockpile.stock_mut().trace().enumerate() { + let out = File::create_new(dst.join(format!("{:04}-{opid}.st.yaml", no + 1)))?; + serde_yaml::to_writer(&out, &st)?; + print!("\rProcessing trace ... {} state transition processed", no + 1); + } + println!(); + + print!("Processing anchors ... none found"); + for (no, (txid, anchor)) in stockpile.pile_mut().hoard_mut().iter().enumerate() { + let out = File::create_new(dst.join(format!("{txid}.anchor.yaml")))?; + serde_yaml::to_writer(&out, &anchor)?; + print!("\rProcessing anchors ... {} processed", no + 1); + } + println!(); + + print!("Processing witness transactions ... none found"); + for (no, (txid, tx)) in stockpile.pile_mut().cache_mut().iter().enumerate() { + let out = File::create_new(dst.join(format!("{txid}.yaml")))?; + serde_yaml::to_writer(&out, &tx)?; + print!("\rProcessing witness transactions ... {} processed", no + 1); + } + println!(); + + print!("Processing seal definitions ... none found"); + let mut seal_count = 0; + for (no, (opid, seals)) in stockpile.pile_mut().keep_mut().iter().enumerate() { + let out = File::create_new(dst.join(format!("{no:04}-{opid}.seals.yaml")))?; + serde_yaml::to_writer(&out, &seals)?; + seal_count += seals.len(); + print!("\rProcessing seal definitions ... {seal_count} processed"); + } + println!(); + + print!("Processing index ... "); + let index = stockpile.pile().index(); + let index = index + .keys() + .map(|opid| (opid, index.get(opid).collect::>())) + .collect::>(); + let mut out = File::create_new(dst.join("index.toml"))?; + out.write_all(toml::to_string(&index)?.as_bytes())?; + println!("success"); + + Ok(()) +} + +// TODO: Auto-compute seal type out of the articles data +pub fn dump_consignment( + src: &Path, + dst: impl AsRef, +) -> anyhow::Result<()> +where + Seal: Serialize, + Seal::CliWitness: Serialize + for<'de> Deserialize<'de> + StrictEncode + StrictDecode, + Seal::PubWitness: Serialize + for<'de> Deserialize<'de> + StrictEncode + StrictDecode, + >::PubId: + Ord + From<[u8; 32]> + Into<[u8; 32]> + Serialize, +{ let dst = dst.as_ref(); fs::create_dir_all(dst)?; @@ -47,38 +137,14 @@ pub fn dumb_consignment(seal: SealType, src: &Path, dst: impl AsRef) -> an print!("Processing contract articles ... "); let out = File::create_new(dst.join("0-articles.yaml"))?; - match seal { - #[cfg(feature = "bitcoin")] - SealType::BitcoinOpret => { - let articles = Articles::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &articles)?; - } - #[cfg(feature = "bitcoin")] - SealType::BitcoinTapret => { - let articles = Articles::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &articles)?; - } - #[cfg(feature = "liquid")] - SealType::LiquidOpret => { - let articles = Articles::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &articles)?; - } - #[cfg(feature = "liquid")] - SealType::LiquidTapret => { - let articles = Articles::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &articles)?; - } - #[cfg(feature = "prime")] - SealType::Prime => { - let articles = Articles::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &articles)?; - } - } + let articles = Articles::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &articles)?; println!("success"); let mut op_count = 1; let mut seal_count = 0; let mut witness_count = 0; + println!(); loop { match Operation::strict_decode(&mut stream) { Ok(operation) => { @@ -88,9 +154,7 @@ pub fn dumb_consignment(seal: SealType, src: &Path, dst: impl AsRef) -> an serde_yaml::to_writer(&out, &operation)?; let mut out = File::create_new(dst.join(format!("{op_count:04}-seals.toml")))?; - // Seal definition is not distinct between tapret and opret, so we save on match - // here - let defined_seals = SmallVec::::strict_decode(&mut stream) + let defined_seals = SmallVec::::strict_decode(&mut stream) .expect("Failed to read consignment stream"); out.write_all(toml::to_string(&defined_seals)?.as_bytes())?; seal_count += defined_seals.len(); @@ -100,32 +164,8 @@ pub fn dumb_consignment(seal: SealType, src: &Path, dst: impl AsRef) -> an let out = File::create_new( dst.join(format!("{op_count:04}-witness-{:02}.toml", no + 1)), )?; - match seal { - #[cfg(feature = "bitcoin")] - SealType::BitcoinOpret => { - let witness = SealWitness::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &witness)?; - } - #[cfg(feature = "bitcoin")] - SealType::BitcoinTapret => { - let witness = SealWitness::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &witness)?; - } - #[cfg(feature = "liquid")] - SealType::LiquidOpret => { - let witness = SealWitness::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &witness)?; - } - #[cfg(feature = "liquid")] - SealType::LiquidTapret => { - let witness = SealWitness::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &witness)?; - } - #[cfg(feature = "prime")] - SealType::Prime => { - todo!() - } - } + let witness = SealWitness::::strict_decode(&mut stream)?; + serde_yaml::to_writer(&out, &witness)?; } witness_count += len as usize; @@ -135,10 +175,10 @@ pub fn dumb_consignment(seal: SealType, src: &Path, dst: impl AsRef) -> an Err(e) => return Err(anyhow!("Failed to read consignment stream: {}", e)), } print!( - "Processing: {op_count} operations, {seal_count} seals, {witness_count} witnesses ... \ - \r" + "\rParsing stream ... {op_count} operations, {seal_count} seals, {witness_count} \ + witnesses processed", ); } - println!("complete"); + println!(); Ok(()) } diff --git a/cli/src/exec.rs b/cli/src/exec.rs index 80178ebc..366ae1a4 100644 --- a/cli/src/exec.rs +++ b/cli/src/exec.rs @@ -25,11 +25,13 @@ use std::fs; use std::io::stdout; +use rgb::bitcoin::{OpretSeal, TapretSeal}; use rgb::popls::bp::PrefabBundle; +use rgb::{SealType, BITCOIN_OPRET, BITCOIN_TAPRET, LIQUID_OPRET, LIQUID_TAPRET}; use strict_encoding::StrictDeserialize; use crate::cmd::{Args, Cmd}; -use crate::dump::dumb_consignment; +use crate::dump::{dump_consignment, dump_stockpile}; impl Args { pub fn exec(&self) -> anyhow::Result<()> { @@ -52,33 +54,95 @@ impl Args { )) } }, - Cmd::Dump { force, seal, src, dst } => { - let dst = dst - .as_ref() - .map(|p| p.to_owned()) - .or_else(|| src.parent().map(|path| path.join("dump"))) - .ok_or(anyhow!("Can't detect destination path for '{}'", src.display()))?; - match src.extension() { - Some(ext) if ext == "rgb" => { - if *force { - fs::remove_dir_all(&dst)?; - } - dumb_consignment(*seal, src, dst)?; - } - Some(_) => { - return Err(anyhow!( - "Can't detect type for '{}': the extension is not recognized", - src.display() - )) + Cmd::Dump { force, seal, src, dst } => match src.extension() { + Some(ext) if ext == "rgb" => { + let dst = dst + .as_ref() + .map(|p| p.to_owned()) + .or_else(|| src.parent().map(|path| path.join("dump"))) + .ok_or(anyhow!("Can't detect destination path for '{}'", src.display()))?; + if *force { + fs::remove_dir_all(&dst).or_else(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + Ok(()) + } else { + Err(e) + } + })?; } - None => { - return Err(anyhow!( - "The path '{}' can't be recognized as a known data", - src.display() - )) + match seal { + #[cfg(feature = "bitcoin")] + SealType::BitcoinOpret => { + dump_consignment::(src, dst) + } + #[cfg(feature = "bitcoin")] + SealType::BitcoinTapret => { + dump_consignment::(src, dst) + } + #[cfg(feature = "liquid")] + SealType::LiquidOpret => { + dump_consignment::(src, dst) + } + #[cfg(feature = "liquid")] + SealType::LiquidTapret => { + dump_consignment::(src, dst) + } + #[cfg(feature = "prime")] + SealType::Prime => { + todo!() + } + }?; + } + Some(ext) if ext == "contract" => { + let dst = dst + .as_ref() + .map(|p| p.to_owned()) + .unwrap_or_else(|| src.join("dump")); + if *force { + fs::remove_dir_all(&dst).or_else(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + Ok(()) + } else { + Err(e) + } + })?; } + match seal { + #[cfg(feature = "bitcoin")] + SealType::BitcoinOpret => { + dump_stockpile::(src, dst) + } + #[cfg(feature = "bitcoin")] + SealType::BitcoinTapret => { + dump_stockpile::(src, dst) + } + #[cfg(feature = "liquid")] + SealType::LiquidOpret => { + dump_stockpile::(src, dst) + } + #[cfg(feature = "liquid")] + SealType::LiquidTapret => { + dump_stockpile::(src, dst) + } + #[cfg(feature = "prime")] + SealType::Prime => { + todo!() + } + }?; + } + Some(_) => { + return Err(anyhow!( + "Can't detect type for '{}': the extension is not recognized", + src.display() + )) } - } + None => { + return Err(anyhow!( + "The path '{}' can't be recognized as a known data", + src.display() + )) + } + }, } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 4741594d..2172d634 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,6 @@ pub use info::ContractInfo; pub use mound::{Excavate, Mound}; #[cfg(feature = "fs")] pub use pile::fs::FilePile; -pub use pile::Pile; +pub use pile::{Index, Pile}; pub use rgb::*; pub use stockpile::{Assignment, ConsumeError, CreateParams, Stockpile}; diff --git a/src/pile.rs b/src/pile.rs index 534152fe..1691bab1 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -29,6 +29,7 @@ use rgb::SonicSeal; use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; pub trait Index { + fn keys(&self) -> impl Iterator; fn get(&self, key: K) -> impl ExactSizeIterator; fn add(&mut self, key: K, val: V); } @@ -89,6 +90,8 @@ pub mod fs { } impl Index for MemIndex { + fn keys(&self) -> impl Iterator { self.0.keys().copied() } + fn get(&self, key: Opid) -> impl ExactSizeIterator { self.0 .get(&key) From 81b0e03c0998f6ed558b6248aa4e2b31842deee6 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 21 Dec 2024 21:23:26 +0100 Subject: [PATCH 52/70] attest operation --- Cargo.lock | 12 +++++----- src/mound.rs | 13 ++++++++++- src/pile.rs | 13 +++++++---- src/popls/bp.rs | 58 +++++++++++++++++++++++++++++++++++++++--------- src/stockpile.rs | 16 +++++-------- 5 files changed, 81 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14caa3c2..bd8f2ae5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" dependencies = [ "amplify", "chrono", @@ -239,7 +239,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" dependencies = [ "amplify", "bp-consensus", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" dependencies = [ "amplify", "base85", @@ -271,7 +271,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#51866fdc629a2af3db1b2e53f1326d7c9a636db2" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" dependencies = [ "amplify", "baid64", @@ -798,9 +798,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", diff --git a/src/mound.rs b/src/mound.rs index 2353ed29..2c1122ba 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -27,7 +27,7 @@ use core::borrow::Borrow; use std::io; use hypersonic::expect::Expect; -use hypersonic::{AuthToken, CellAddr, CodexId, ContractId, Schema, Supply}; +use hypersonic::{AuthToken, CellAddr, CodexId, ContractId, Opid, Schema, Supply}; use single_use_seals::{PublishedWitness, SingleUseSeal}; use strict_encoding::{ ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, @@ -152,6 +152,17 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound::PubWitness, + anchors: impl IntoIterator::CliWitness)>, + ) { + for (contract_id, opid, anchor) in anchors { + self.contract_mut(contract_id) + .attest(opid, &anchor, pub_witness); + } + } + pub fn consign( &mut self, contract_id: ContractId, diff --git a/src/pile.rs b/src/pile.rs index 1691bab1..2302151d 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -62,11 +62,16 @@ pub trait Pile { fn retrieve(&mut self, opid: Opid) -> impl ExactSizeIterator>; - fn append(&mut self, opid: Opid, witness: &SealWitness) { - let pubid = witness.published.pub_id(); + fn append( + &mut self, + opid: Opid, + anchor: &::CliWitness, + published: &::PubWitness, + ) { + let pubid = published.pub_id(); self.index_mut().add(opid, pubid); - self.hoard_mut().append(pubid, &witness.client); - self.cache_mut().append(pubid, &witness.published); + self.hoard_mut().append(pubid, &anchor); + self.cache_mut().append(pubid, &published); } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index d2ae71bf..a7319cdb 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -25,16 +25,16 @@ //! Implementation of RGB standard library types for Bitcoin protocol, covering Bitcoin and Liquid //! proof of publication layer 1. -use alloc::collections::BTreeMap; -use std::collections::BTreeSet; +use alloc::collections::{btree_set, BTreeMap, BTreeSet}; -use amplify::confinement::{SmallOrdSet, SmallVec}; -use amplify::{confinement, Bytes32}; +use amplify::confinement::{SmallOrdMap, SmallOrdSet, SmallVec}; +use amplify::{confinement, Bytes32, Wrapper}; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; -use bp::seals::TxoSeal; -use bp::{dbc, Outpoint, Vout}; -use commit_verify::{Digest, DigestExt, Sha256}; +use bp::seals::{mmb, Anchor, TxoSeal}; +use bp::{dbc, Outpoint, Tx, Vout}; +use commit_verify::mpc::ProtocolId; +use commit_verify::{mpc, Digest, DigestExt, Sha256}; use hypersonic::aora::Aora; use hypersonic::{ AuthToken, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, NamedState, @@ -151,7 +151,6 @@ pub struct PrefabParams { #[strict_type(lib = "RGB")] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))] pub struct Prefab { - pub contract_id: ContractId, pub closes: SmallOrdSet, pub defines: SmallOrdSet, pub operation: Operation, @@ -172,6 +171,13 @@ pub struct PrefabBundle(SmallOrdSet); impl StrictSerialize for PrefabBundle {} impl StrictDeserialize for PrefabBundle {} +impl<'a> IntoIterator for &'a PrefabBundle { + type Item = &'a Prefab; + type IntoIter = btree_set::Iter<'a, Prefab>; + + fn into_iter(self) -> Self::IntoIter { self.0.iter() } +} + impl PrefabBundle { pub fn new(items: impl IntoIterator) -> Result { let items = SmallOrdSet::try_from_iter(items.into_iter())?; @@ -311,8 +317,9 @@ impl< let opid = stockpile.stock_mut().call(call); let operation = stockpile.stock_mut().operation(opid); stockpile.pile_mut().keep_mut().append(opid, &seals); + debug_assert_eq!(operation.contract_id, params.contract_id); - Prefab { contract_id: params.contract_id, closes, defines, operation } + Prefab { closes, defines, operation } } /// Completes creation of a prefabricated operation pack, adding blank operations if necessary. @@ -325,7 +332,7 @@ impl< let mut contracts = BTreeSet::new(); let mut prefabs = BTreeSet::new(); for prefab in ops { - contracts.insert(prefab.contract_id); + contracts.insert(prefab.operation.contract_id); outpoints.extend(&prefab.closes); prefabs.insert(prefab); } @@ -398,6 +405,37 @@ impl< PrefabBundle(SmallOrdSet::try_from(prefabs).expect("too many operations")) } + + pub fn attest( + &mut self, + bundle: &PrefabBundle, + witness: &Tx, + mpc: mpc::MerkleBlock, + dbc: D, + prevouts: &[Outpoint], + ) { + let iter = bundle.iter().map(|prefab| { + let protocol_id = ProtocolId::from(prefab.operation.contract_id.to_byte_array()); + let opid = prefab.operation.opid(); + let anchor = Anchor { + mmb_proof: mmb::BundleProof { + map: SmallOrdMap::from_iter_checked(prefab.closes.iter().map(|prevout| { + let pos = prevouts + .iter() + .position(|p| p == prevout) + .expect("PSBT misses one of operation inputs"); + (pos as u32, opid.into_inner()) + })), + }, + mpc_protocol: protocol_id, + mpc_proof: mpc.to_merkle_proof(protocol_id).expect("Invalid MPC proof"), + dbc_proof: dbc.clone(), + fallback_proof: default!(), + }; + (prefab.operation.contract_id, opid, anchor) + }); + self.mound.attest(witness, iter); + } } pub mod file { diff --git a/src/stockpile.rs b/src/stockpile.rs index 4f2f2227..ae2f0327 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -261,17 +261,13 @@ impl, P: Pile, const CAPS: u32> Stockpile { } } - pub fn append_witness( + pub fn attest( &mut self, + opid: Opid, + anchor: &::CliWitness, published: &::PubWitness, - client: &::CliWitness, - ) where - <::PubWitness as PublishedWitness>::PubId: - Into<[u8; 32]>, - { - let id = published.pub_id(); - self.pile.hoard_mut().append(id, client); - self.pile.cache_mut().append(id, published); + ) { + self.pile.append(opid, anchor, published); } pub fn consign( @@ -387,7 +383,7 @@ impl, P: Pile, const CAPS: u32> ContractApi for Stockpi fn apply_operation(&mut self, op: OperationSeals) { self.stock.apply(op.operation); } fn apply_witness(&mut self, opid: Opid, witness: SealWitness) { - self.pile.append(opid, &witness); + self.pile.append(opid, &witness.client, &witness.published); } } From 300b453448e7f31494a659974c0e66f90b644318 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 20:10:29 +0100 Subject: [PATCH 53/70] support anchor merging --- Cargo.lock | 40 +++++++++++++++++++--------------------- Cargo.toml | 1 + src/mound.rs | 2 +- src/pile.rs | 14 +++++++++++--- src/popls/bp.rs | 11 +++++++++-- src/stockpile.rs | 4 ++-- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd8f2ae5..6580f2e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arrayvec" @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" dependencies = [ "amplify", "chrono", @@ -239,7 +239,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" dependencies = [ "amplify", "bp-consensus", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" dependencies = [ "amplify", "base85", @@ -271,7 +271,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#8e6d2d3d3a144359897f3324039ee459efee89db" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" dependencies = [ "amplify", "baid64", @@ -357,7 +357,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -375,8 +375,7 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "commit_encoding_derive" version = "0.12.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "137f212bdbb4abf7bb648ba73feed1d981a4f4681821b15d79a37bfdbc206070" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#293358fda9b848a5ec2a7cfd0b49bf8c5f49a017" dependencies = [ "amplify", "amplify_syn", @@ -388,8 +387,7 @@ dependencies = [ [[package]] name = "commit_verify" version = "0.12.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef304002218b4136632abe4145a168d8b8f95e4d5443d377240ab2b1868a52a" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#293358fda9b848a5ec2a7cfd0b49bf8c5f49a017" dependencies = [ "amplify", "commit_encoding_derive", @@ -677,7 +675,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#e422aa37d51099f0015575c507b4da133a26df6b" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#8e59e169503598adea8ecf8109c632da366a4831" dependencies = [ "amplify", "bp-core", @@ -793,7 +791,7 @@ checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -860,7 +858,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" version = "0.12.0-beta.1" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#b5ea9abeec487436ceb8d2e572a8e34305fd5d70" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#293358fda9b848a5ec2a7cfd0b49bf8c5f49a017" dependencies = [ "serde", "strict_encoding", @@ -958,9 +956,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" dependencies = [ "proc-macro2", "quote", @@ -984,7 +982,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1113,7 +1111,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "wasm-bindgen-shared", ] @@ -1148,7 +1146,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1181,7 +1179,7 @@ checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1312,7 +1310,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d04faac2..dad50d21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ features = ["all"] [patch.crates-io] ultrasonic = { git = "https://github.com/AluVM/ultrasonic" } hypersonic = { git = "https://github.com/AluVM/sonic" } +commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.12" } single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.12" } bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.12" } diff --git a/src/mound.rs b/src/mound.rs index 2c1122ba..8e588749 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -159,7 +159,7 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound { @@ -65,12 +65,20 @@ pub trait Pile { fn append( &mut self, opid: Opid, - anchor: &::CliWitness, + anchor: ::CliWitness, published: &::PubWitness, ) { let pubid = published.pub_id(); self.index_mut().add(opid, pubid); - self.hoard_mut().append(pubid, &anchor); + if self.hoard_mut().has(pubid) { + let mut prev_anchor = self.hoard_mut().read(pubid); + if prev_anchor != anchor { + prev_anchor.merge(anchor).expect("Invalid anchor"); + self.hoard_mut().append(pubid, &prev_anchor); + } + } else { + self.hoard_mut().append(pubid, &anchor); + } self.cache_mut().append(pubid, &published); } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index a7319cdb..d30af86e 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -28,7 +28,7 @@ use alloc::collections::{btree_set, BTreeMap, BTreeSet}; use amplify::confinement::{SmallOrdMap, SmallOrdSet, SmallVec}; -use amplify::{confinement, Bytes32, Wrapper}; +use amplify::{confinement, ByteArray, Bytes32, Wrapper}; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; use bp::seals::{mmb, Anchor, TxoSeal}; @@ -171,6 +171,13 @@ pub struct PrefabBundle(SmallOrdSet); impl StrictSerialize for PrefabBundle {} impl StrictDeserialize for PrefabBundle {} +impl IntoIterator for PrefabBundle { + type Item = Prefab; + type IntoIter = btree_set::IntoIter; + + fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } +} + impl<'a> IntoIterator for &'a PrefabBundle { type Item = &'a Prefab; type IntoIter = btree_set::Iter<'a, Prefab>; @@ -424,7 +431,7 @@ impl< .iter() .position(|p| p == prevout) .expect("PSBT misses one of operation inputs"); - (pos as u32, opid.into_inner()) + (pos as u32, mmb::Message::from_byte_array(opid.to_byte_array())) })), }, mpc_protocol: protocol_id, diff --git a/src/stockpile.rs b/src/stockpile.rs index ae2f0327..40971ad1 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -264,7 +264,7 @@ impl, P: Pile, const CAPS: u32> Stockpile { pub fn attest( &mut self, opid: Opid, - anchor: &::CliWitness, + anchor: ::CliWitness, published: &::PubWitness, ) { self.pile.append(opid, anchor, published); @@ -383,7 +383,7 @@ impl, P: Pile, const CAPS: u32> ContractApi for Stockpi fn apply_operation(&mut self, op: OperationSeals) { self.stock.apply(op.operation); } fn apply_witness(&mut self, opid: Opid, witness: SealWitness) { - self.pile.append(opid, &witness.client, &witness.published); + self.pile.append(opid, witness.client, &witness.published); } } From a85ca8e09dfc59c57e7d83b8853a40b20fcf1671 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 20:29:31 +0100 Subject: [PATCH 54/70] chore: re-export data types from sonic --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 2172d634..baa65e9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,7 @@ pub mod popls; #[cfg(feature = "bitcoin")] pub use bp::{Outpoint, Txid}; +pub use hypersonic::*; pub use info::ContractInfo; pub use mound::{Excavate, Mound}; #[cfg(feature = "fs")] From c91f90ad3807728154a8892939abb15f8331ded8 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 21:18:22 +0100 Subject: [PATCH 55/70] make index persistent --- src/pile.rs | 121 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 41 deletions(-) diff --git a/src/pile.rs b/src/pile.rs index 1a978d8d..3856115c 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -87,8 +87,9 @@ pub trait Pile { pub mod fs { use std::collections::BTreeMap; use std::fs::File; - use std::io::Read; - use std::path::Path; + use std::io; + use std::io::{Read, Write}; + use std::path::{Path, PathBuf}; use hypersonic::aora::file::FileAora; use hypersonic::expect::Expect; @@ -97,36 +98,91 @@ pub mod fs { use super::*; #[derive(Clone, Debug, From)] - pub struct MemIndex(BTreeMap>); - impl Default for MemIndex { - fn default() -> Self { Self(none!()) } + pub struct FileIndex + where Id: Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> + { + path: PathBuf, + cache: BTreeMap>, } - impl Index for MemIndex { - fn keys(&self) -> impl Iterator { self.0.keys().copied() } + impl FileIndex + where Id: Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> + { + pub fn create(path: PathBuf) -> io::Result { + File::create_new(&path)?; + Ok(Self { cache: none!(), path }) + } + + pub fn new(path: PathBuf) -> io::Result { + let mut cache = BTreeMap::new(); + let mut index_file = File::open(&path)?; + let mut buf = [0u8; 32]; + while index_file.read_exact(&mut buf).is_ok() { + let opid = Opid::from(buf); + let mut ids = Vec::new(); + let mut len = [0u8; 4]; + index_file + .read_exact(&mut len) + .expect("cannot read index file"); + let mut len = u32::from_le_bytes(len); + while len > 0 { + index_file + .read_exact(&mut buf) + .expect("cannot read index file"); + ids.push(buf.into()); + len -= 1; + } + cache.insert(opid, ids); + } + Ok(Self { path, cache }) + } - fn get(&self, key: Opid) -> impl ExactSizeIterator { - self.0 + pub fn save(&self) -> io::Result<()> { + let mut index_file = File::create(&self.path)?; + for (opid, ids) in &self.cache { + index_file.write_all(opid.as_slice())?; + let len = ids.len() as u32; + index_file.write_all(&len.to_le_bytes())?; + for id in ids { + index_file.write_all(&(*id).into())?; + } + } + Ok(()) + } + } + + impl Index for FileIndex + where Id: Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> + { + fn keys(&self) -> impl Iterator { self.cache.keys().copied() } + + fn get(&self, key: Opid) -> impl ExactSizeIterator { + self.cache .get(&key) .expect("unknown operation ID requested from the index") .iter() .copied() } - fn add(&mut self, key: Opid, val: V) { self.0.entry(key).or_default().push(val) } + fn add(&mut self, key: Opid, val: Id) { + self.cache.entry(key).or_default().push(val); + self.save().expect("Cannot save index file"); + } } pub struct FilePile - where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> + where >::PubId: + Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> { hoard: FileAora<>::PubId, Seal::CliWitness>, cache: FileAora<>::PubId, Seal::PubWitness>, keep: FileAora>, - index: MemIndex<<::PubWitness as PublishedWitness>::PubId>, + index: FileIndex<<::PubWitness as PublishedWitness>::PubId>, } impl FilePile - where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> + where >::PubId: + Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> { pub fn new(name: &str, path: impl AsRef) -> Self { let mut path = path.as_ref().to_path_buf(); @@ -136,15 +192,16 @@ pub mod fs { let hoard = FileAora::new(&path, "hoard"); let cache = FileAora::new(&path, "cache"); let keep = FileAora::new(&path, "keep"); - File::create_new(path.join("index.dat")) - .expect_or_else(|| format!("unable to create index file `{}`", path.display())); + let index = FileIndex::create(path.join("index.dat")) + .expect_or(format!("unable to create index file `{}`", path.display())); - Self { hoard, cache, keep, index: empty!() } + Self { hoard, cache, keep, index } } } impl FilePile - where >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]> + where >::PubId: + Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> { pub fn open(path: impl AsRef) -> Self { let path = path.as_ref().to_path_buf(); @@ -152,30 +209,11 @@ pub mod fs { let cache = FileAora::open(&path, "cache"); let keep = FileAora::open(&path, "keep"); - let mut index = BTreeMap::new(); let index_name = path.join("index.dat"); - let mut index_file = File::open(&index_name) - .expect_or_else(|| format!("unable to open index file `{}`", index_name.display())); - let mut buf = [0u8; 32]; - while index_file.read_exact(&mut buf).is_ok() { - let opid = Opid::from(buf); - let mut ids = Vec::new(); - let mut len = [0u8; 4]; - index_file - .read_exact(&mut len) - .expect("cannot read index file"); - let mut len = u32::from_le_bytes(len); - while len > 0 { - index_file - .read_exact(&mut buf) - .expect("cannot read index file"); - ids.push(buf.into()); - len -= 1; - } - index.insert(opid, ids); - } + let index = FileIndex::new(index_name.clone()) + .expect_or(format!("unable to open index file `{}`", index_name.display())); - Self { hoard, cache, keep, index: index.into() } + Self { hoard, cache, keep, index } } } @@ -183,7 +221,8 @@ pub mod fs { where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, - >::PubId: Ord + From<[u8; 32]> + Into<[u8; 32]>, + >::PubId: + Copy + Ord + From<[u8; 32]> + Into<[u8; 32]>, { type Seal = Seal; type Hoard = @@ -192,7 +231,7 @@ pub mod fs { FileAora<>::PubId, Seal::PubWitness>; type Keep = FileAora>; type Index = - MemIndex<<::PubWitness as PublishedWitness>::PubId>; + FileIndex<<::PubWitness as PublishedWitness>::PubId>; fn hoard(&self) -> &Self::Hoard { &self.hoard } From 52497ef2b8c7460e5a5fbc3c6fa9b6b3d98edbb3 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 21:23:11 +0100 Subject: [PATCH 56/70] rgbx: fix dump implementation --- cli/src/dump.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/src/dump.rs b/cli/src/dump.rs index 033436db..c93abbd5 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -153,16 +153,16 @@ where let out = File::create_new(dst.join(format!("{op_count:04}-op.{opid}.yaml")))?; serde_yaml::to_writer(&out, &operation)?; - let mut out = File::create_new(dst.join(format!("{op_count:04}-seals.toml")))?; + let out = File::create_new(dst.join(format!("{op_count:04}-seals.yml")))?; let defined_seals = SmallVec::::strict_decode(&mut stream) .expect("Failed to read consignment stream"); - out.write_all(toml::to_string(&defined_seals)?.as_bytes())?; + serde_yaml::to_writer(&out, &defined_seals)?; seal_count += defined_seals.len(); let len = u64::strict_decode(&mut stream)?; for no in 0..len { let out = File::create_new( - dst.join(format!("{op_count:04}-witness-{:02}.toml", no + 1)), + dst.join(format!("{op_count:04}-witness-{:02}.yaml", no + 1)), )?; let witness = SealWitness::::strict_decode(&mut stream)?; serde_yaml::to_writer(&out, &witness)?; From 80919076322cc12dcd2181e9efa63e11bb81efec Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 21:56:17 +0100 Subject: [PATCH 57/70] fix ConsumeError display derive --- src/stockpile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stockpile.rs b/src/stockpile.rs index 40971ad1..fe3e4fd5 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -388,7 +388,7 @@ impl, P: Pile, const CAPS: u32> ContractApi for Stockpi } #[derive(Display, From)] -#[display(doc_comments)] +#[display(inner)] pub enum ConsumeError { #[from] #[from(io::Error)] From 4ff4bfdcee5d5a4724220ca3f3a1f00a3e8229e1 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 23:39:23 +0100 Subject: [PATCH 58/70] do not panic on empty witness list for an operation genesis and extensions have no witnesses --- src/pile.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pile.rs b/src/pile.rs index 3856115c..9308828a 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -157,11 +157,10 @@ pub mod fs { fn keys(&self) -> impl Iterator { self.cache.keys().copied() } fn get(&self, key: Opid) -> impl ExactSizeIterator { - self.cache - .get(&key) - .expect("unknown operation ID requested from the index") - .iter() - .copied() + match self.cache.get(&key) { + Some(ids) => ids.clone().into_iter(), + None => vec![].into_iter(), + } } fn add(&mut self, key: Opid, val: Id) { From 6b2bafca2be2eb67f99c690f377dc236c4ef0a35 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 23:56:27 +0100 Subject: [PATCH 59/70] read genesis seals from a consignment --- src/stockpile.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/stockpile.rs b/src/stockpile.rs index fe3e4fd5..a86ff03a 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -308,11 +308,21 @@ impl, P: Pile, const CAPS: u32> Stockpile { <::PubWitness as PublishedWitness>::PubId: StrictDecode, { let articles = Articles::::strict_decode(stream)?; + let genesis_opid = articles.contract.genesis_opid(); self.stock.merge_articles(articles)?; + let defined_seals = SmallVec::strict_decode(stream)?; + self.pile.keep_mut().append(genesis_opid, &defined_seals); + let count = u64::strict_decode(stream)?; + // Genesis must have no witness + if count != 0 { + return Err(ConsumeError::Decode(DecodeError::DataIntegrityError(s!( + "contract genesis must have no witnesses" + )))); + } // We need to clone due to a borrow checker. - let reader = OpReader { stream, _phantom: PhantomData }; - self.evaluate(reader)?; + let op_reader = OpReader { stream, _phantom: PhantomData }; + self.evaluate(op_reader)?; self.stock.complete_update(); Ok(()) From 55ad6b29284edbf07c024e3f5dd69159ffba85b8 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 22 Dec 2024 23:56:44 +0100 Subject: [PATCH 60/70] rgbx: support genesis seals in consignment dump --- Cargo.lock | 6 +++--- cli/src/dump.rs | 32 +++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6580f2e8..b9193972 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,7 +488,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#f5278ec3da97a129ea7f3681d707463ea1bddf5d" +source = "git+https://github.com/AluVM/sonic#ad79a795fa4e5e4b651d2655d2dd88ae7781b8ee" dependencies = [ "aluvm", "amplify", @@ -675,7 +675,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#8e59e169503598adea8ecf8109c632da366a4831" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#86cfd57c9f7fa1d10b05ad2d9a41e9acf064ce77" dependencies = [ "amplify", "bp-core", @@ -867,7 +867,7 @@ dependencies = [ [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#f5278ec3da97a129ea7f3681d707463ea1bddf5d" +source = "git+https://github.com/AluVM/sonic#ad79a795fa4e5e4b651d2655d2dd88ae7781b8ee" dependencies = [ "aluvm", "amplify", diff --git a/cli/src/dump.rs b/cli/src/dump.rs index c93abbd5..a53613f6 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -135,15 +135,37 @@ where let cointract_id = ContractId::strict_decode(&mut stream)?; println!("Dumping consignment for {} into '{}'", cointract_id, dst.display()); + let mut op_count = 1; + let mut seal_count = 0; + let mut witness_count = 0; + print!("Processing contract articles ... "); - let out = File::create_new(dst.join("0-articles.yaml"))?; let articles = Articles::::strict_decode(&mut stream)?; - serde_yaml::to_writer(&out, &articles)?; + let out = File::create_new( + dst.join(format!("0000-genesis.{}.yaml", articles.contract.genesis_opid())), + )?; + serde_yaml::to_writer(&out, &articles.contract.genesis)?; + let out = + File::create_new(dst.join(format!("codex.{}.yaml", articles.schema.codex.codex_id())))?; + serde_yaml::to_writer(&out, &articles.schema.codex)?; + let out = File::create_new(dst.join("schema.yaml"))?; + serde_yaml::to_writer(&out, &articles.schema)?; + + let out = File::create_new(dst.join("0000-seals.yml"))?; + let defined_seals = + SmallVec::::strict_decode(&mut stream).expect("Failed to read consignment stream"); + serde_yaml::to_writer(&out, &defined_seals)?; + seal_count += defined_seals.len(); + + let count = u64::strict_decode(&mut stream)?; + if count != 0 { + println!("error"); + return Err(anyhow!( + "consignment stream has {count} witnesses, but 0 witnesses are expected", + )); + } println!("success"); - let mut op_count = 1; - let mut seal_count = 0; - let mut witness_count = 0; println!(); loop { match Operation::strict_decode(&mut stream) { From 761b58034876ffed2cb6b931f530a1481188c6b7 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 01:50:39 +0100 Subject: [PATCH 61/70] debug consignment consume --- Cargo.lock | 6 +++--- src/stockpile.rs | 39 ++++++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b9193972..8e964bba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,7 +488,7 @@ dependencies = [ [[package]] name = "hypersonic" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#ad79a795fa4e5e4b651d2655d2dd88ae7781b8ee" +source = "git+https://github.com/AluVM/sonic#2d6bb980ff2cbd242b888c01199b0d9850092253" dependencies = [ "aluvm", "amplify", @@ -867,7 +867,7 @@ dependencies = [ [[package]] name = "sonic-api" version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#ad79a795fa4e5e4b651d2655d2dd88ae7781b8ee" +source = "git+https://github.com/AluVM/sonic#2d6bb980ff2cbd242b888c01199b0d9850092253" dependencies = [ "aluvm", "amplify", @@ -1028,7 +1028,7 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ultrasonic" version = "0.12.0-beta.2" -source = "git+https://github.com/AluVM/ultrasonic#178a7b83a4ba6e5657210e7261b1075de79576b7" +source = "git+https://github.com/AluVM/ultrasonic#1b20385acdfa8558143223c202fc42f0884c2739" dependencies = [ "amplify", "baid64", diff --git a/src/stockpile.rs b/src/stockpile.rs index a86ff03a..ed5a494f 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -31,11 +31,13 @@ use std::io; use amplify::confinement::SmallVec; use amplify::IoError; use chrono::{DateTime, Utc}; +use commit_verify::ReservedBytes; use hypersonic::aora::Aora; +use hypersonic::sigs::ContentSigs; use hypersonic::{ - Articles, AuthToken, CellAddr, Codex, CodexId, ContractId, CoreParams, DataCell, IssueParams, - LibRepo, Memory, MergeError, MethodName, NamedState, Operation, Opid, Schema, StateAtom, - StateName, Stock, Supply, + Articles, AuthToken, CellAddr, Codex, CodexId, Contract, ContractId, CoreParams, DataCell, + IssueParams, LibRepo, Memory, MergeError, MethodName, NamedState, Operation, Opid, Schema, + StateAtom, StateName, Stock, Supply, }; use rgb::{ ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SealType, SonicSeal, @@ -48,7 +50,7 @@ use strict_encoding::{ }; use strict_types::StrictVal; -use crate::Pile; +use crate::{ContractMeta, Pile}; #[derive(Copy, Clone, PartialEq, Eq, Debug, From)] #[cfg_attr( @@ -307,23 +309,26 @@ impl, P: Pile, const CAPS: u32> Stockpile { ::PubWitness: StrictDecode, <::PubWitness as PublishedWitness>::PubId: StrictDecode, { - let articles = Articles::::strict_decode(stream)?; - let genesis_opid = articles.contract.genesis_opid(); - self.stock.merge_articles(articles)?; - let defined_seals = SmallVec::strict_decode(stream)?; - self.pile.keep_mut().append(genesis_opid, &defined_seals); - let count = u64::strict_decode(stream)?; - // Genesis must have no witness - if count != 0 { - return Err(ConsumeError::Decode(DecodeError::DataIntegrityError(s!( - "contract genesis must have no witnesses" - )))); - } + // TODO: Add version + + // We need to read articles field by field since we have to evaluate genesis separately + let schema = Schema::strict_decode(stream)?; + let contract_sigs = ContentSigs::strict_decode(stream)?; + let codex_version = ReservedBytes::<2>::strict_decode(stream)?; + let meta = ContractMeta::::strict_decode(stream)?; + let codex = Codex::strict_decode(stream)?; // We need to clone due to a borrow checker. let op_reader = OpReader { stream, _phantom: PhantomData }; self.evaluate(op_reader)?; + let genesis = self.stock.articles().contract.genesis.clone(); + let articles = Articles:: { + contract: Contract { version: codex_version, meta, codex, genesis }, + contract_sigs, + schema, + }; + self.stock.merge_articles(articles)?; self.stock.complete_update(); Ok(()) } @@ -367,10 +372,10 @@ impl<'r, Seal: SonicSeal, R: ReadRaw> ReadWitness for WitnessReader<'r, Seal, R> type OpReader = OpReader<'r, Seal, R>; fn read_witness(mut self) -> Step<(SealWitness, Self), Self::OpReader> { - self.left -= 1; if self.left == 0 { return Step::Complete(self.parent); } + self.left -= 1; match SealWitness::strict_decode(self.parent.stream) { Ok(witness) => Step::Next((witness, self)), Err(e) => { From 73c30de2f8eedb906a592e01e9be9fe4416b43c1 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 02:24:18 +0100 Subject: [PATCH 62/70] add register_seal method to a Wallet interface --- Cargo.lock | 10 +++++----- src/popls/bp.rs | 7 +++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e964bba..712c7095 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" dependencies = [ "amplify", "chrono", @@ -239,7 +239,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" dependencies = [ "amplify", "bp-consensus", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" dependencies = [ "amplify", "base85", @@ -271,7 +271,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#749ad5a83a60c60055b8925871655e81cb3d24d0" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" dependencies = [ "amplify", "baid64", @@ -675,7 +675,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#86cfd57c9f7fa1d10b05ad2d9a41e9acf064ce77" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#4224b8c3dfd08eec949c81f31c374caed0c2c1b8" dependencies = [ "amplify", "bp-core", diff --git a/src/popls/bp.rs b/src/popls/bp.rs index d30af86e..bcc93485 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -31,7 +31,7 @@ use amplify::confinement::{SmallOrdMap, SmallOrdSet, SmallVec}; use amplify::{confinement, ByteArray, Bytes32, Wrapper}; use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; -use bp::seals::{mmb, Anchor, TxoSeal}; +use bp::seals::{mmb, Anchor, TxoSeal, TxoSealDef}; use bp::{dbc, Outpoint, Tx, Vout}; use commit_verify::mpc::ProtocolId; use commit_verify::{mpc, Digest, DigestExt, Sha256}; @@ -52,6 +52,7 @@ pub trait WalletProvider { fn noise_seed(&self) -> Bytes32; fn has_utxo(&self, outpoint: Outpoint) -> bool; fn utxos(&self) -> impl Iterator; + fn register_seal(&mut self, seal: TxoSealDef); } pub trait OpretProvider: WalletProvider {} pub trait TapretProvider: WalletProvider {} @@ -236,7 +237,9 @@ impl< pub fn auth_token(&mut self, nonce: u64) -> Option { let outpoint = self.wallet.utxos().next()?; let seal = TxoSeal::::no_fallback(outpoint, self.noise_engine(), nonce); - Some(seal.auth_token()) + let auth = seal.auth_token(); + self.wallet.register_seal(seal.to_definition()); + Some(auth) } pub fn state( From 40a845fe3ad61fb310297bca4fd8db2852ec943b Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 03:10:00 +0100 Subject: [PATCH 63/70] resolve seals on consignment consume --- Cargo.lock | 10 +++++----- src/mound.rs | 21 ++++---------------- src/popls/bp.rs | 50 +++++++++++++++++++++++++++++++++++++++++++---- src/stockpile.rs | 51 ++++++++++++++++++++++-------------------------- 4 files changed, 78 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 712c7095..115c8e3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" dependencies = [ "amplify", "chrono", @@ -239,7 +239,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" dependencies = [ "amplify", "bp-consensus", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" dependencies = [ "amplify", "base85", @@ -271,7 +271,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#a1ba5cb2e514841002f7a756cdb283d4a869e6ff" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" dependencies = [ "amplify", "baid64", @@ -675,7 +675,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#4224b8c3dfd08eec949c81f31c374caed0c2c1b8" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#7ac0fd908a100b299f6d015034a63fa60a4c47f8" dependencies = [ "amplify", "bp-core", diff --git a/src/mound.rs b/src/mound.rs index 8e588749..f6192133 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -33,7 +33,7 @@ use strict_encoding::{ ReadRaw, StrictDecode, StrictDumb, StrictEncode, StrictReader, StrictWriter, WriteRaw, }; -use crate::{ConsumeError, ContractInfo, CreateParams, Pile, Stockpile}; +use crate::{ConsumeError, ContractInfo, CreateParams, Pile, StateCell, Stockpile}; pub trait Excavate, P: Pile, const CAPS: u32> { fn schemata(&mut self) -> impl Iterator; @@ -181,6 +181,7 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound, + seal_resolver: impl FnMut(&[StateCell]) -> Vec, ) -> Result<(), ConsumeError> where ::CliWitness: StrictDecode, @@ -194,7 +195,7 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound(file)); self.consign(contract_id, terminals, writer) } - - pub fn consume_from_file( - &mut self, - path: impl AsRef, - ) -> Result<(), ConsumeError> - where - Seal::CliWitness: StrictDumb, - Seal::PubWitness: StrictDumb, - >::PubId: StrictDecode, - { - let file = File::open(path)?; - let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); - self.consume(&mut reader) - } } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index bcc93485..9d31f1e4 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -40,12 +40,12 @@ use hypersonic::{ AuthToken, CallParams, CellAddr, ContractId, CoreParams, DataCell, MethodName, NamedState, Operation, Schema, StateAtom, StateCalc, StateName, Supply, }; -use rgb::SonicSeal; -use strict_encoding::{StrictDeserialize, StrictSerialize}; +use rgb::SealAuthToken; +use strict_encoding::{ReadRaw, StrictDecode, StrictDeserialize, StrictReader, StrictSerialize}; use strict_types::StrictVal; use crate::stockpile::{ContractState, EitherSeal}; -use crate::{Assignment, CreateParams, Excavate, Mound, Pile}; +use crate::{Assignment, ConsumeError, CreateParams, Excavate, Mound, Pile}; /// Trait abstracting specific implementation of a bitcoin wallet. pub trait WalletProvider { @@ -53,6 +53,10 @@ pub trait WalletProvider { fn has_utxo(&self, outpoint: Outpoint) -> bool; fn utxos(&self) -> impl Iterator; fn register_seal(&mut self, seal: TxoSealDef); + fn resolve_seals( + &self, + seals: impl Iterator, + ) -> impl Iterator; } pub trait OpretProvider: WalletProvider {} pub trait TapretProvider: WalletProvider {} @@ -446,18 +450,32 @@ impl< }); self.mound.attest(witness, iter); } + + pub fn consume( + &mut self, + reader: &mut StrictReader, + ) -> Result<(), ConsumeError>> { + self.mound.consume(reader, |cells| { + self.wallet + .resolve_seals(cells.iter().map(|cell| cell.auth)) + .map(TxoSeal::::from_definition) + .collect() + }) + } } pub mod file { use std::ffi::OsStr; + use std::fs::File; use std::path::Path; - use std::{fs, iter}; + use std::{fs, io, iter}; use hypersonic::{CodexId, FileSupply}; #[cfg(feature = "bitcoin")] use rgb::{BITCOIN_OPRET, BITCOIN_TAPRET}; #[cfg(feature = "liquid")] use rgb::{LIQUID_OPRET, LIQUID_TAPRET}; + use strict_encoding::{StreamReader, StrictReader}; use super::*; use crate::mound::file::DirExcavator; @@ -750,6 +768,30 @@ pub mod file { PrefabBundle(items) } + pub fn consume_from_file(&mut self, path: impl AsRef) -> io::Result<()> { + let file = File::open(path)?; + let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); + match self { + #[cfg(feature = "bitcoin")] + Self::BcOpret(barrow) => barrow + .consume(&mut reader) + .unwrap_or_else(|err| panic!("Unable to accept a consignment: {err}")), + #[cfg(feature = "bitcoin")] + Self::BcTapret(barrow) => barrow + .consume(&mut reader) + .unwrap_or_else(|err| panic!("Unable to accept a consignment: {err}")), + #[cfg(feature = "liquid")] + Self::LqOpret(barrow) => barrow + .consume(&mut reader) + .unwrap_or_else(|err| panic!("Unable to accept a consignment: {err}")), + #[cfg(feature = "liquid")] + Self::LqTapret(barrow) => barrow + .consume(&mut reader) + .unwrap_or_else(|err| panic!("Unable to accept a consignment: {err}")), + } + Ok(()) + } + pub fn wallet_tapret(&mut self) -> &mut T { match self { #[cfg(feature = "bitcoin")] diff --git a/src/stockpile.rs b/src/stockpile.rs index ed5a494f..9c78878b 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -40,8 +40,8 @@ use hypersonic::{ StateAtom, StateName, Stock, Supply, }; use rgb::{ - ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SealType, SonicSeal, - Step, VerificationError, + ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SealAuthToken, + SealType, SonicSeal, Step, VerificationError, }; use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; use strict_encoding::{ @@ -50,7 +50,7 @@ use strict_encoding::{ }; use strict_types::StrictVal; -use crate::{ContractMeta, Pile}; +use crate::{ContractMeta, Pile, StateCell}; #[derive(Copy, Clone, PartialEq, Eq, Debug, From)] #[cfg_attr( @@ -303,6 +303,7 @@ impl, P: Pile, const CAPS: u32> Stockpile { pub fn consume( &mut self, stream: &mut StrictReader, + seal_resolver: impl FnMut(&[StateCell]) -> Vec, ) -> Result<(), ConsumeError> where ::CliWitness: StrictDecode, @@ -319,7 +320,7 @@ impl, P: Pile, const CAPS: u32> Stockpile { let codex = Codex::strict_decode(stream)?; // We need to clone due to a borrow checker. - let op_reader = OpReader { stream, _phantom: PhantomData }; + let op_reader = OpReader { stream, seal_resolver, _phantom: PhantomData }; self.evaluate(op_reader)?; let genesis = self.stock.articles().contract.genesis.clone(); @@ -334,20 +335,26 @@ impl, P: Pile, const CAPS: u32> Stockpile { } } -pub struct OpReader<'r, Seal: SonicSeal, R: ReadRaw> { +pub struct OpReader<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> { stream: &'r mut StrictReader, + seal_resolver: F, _phantom: PhantomData, } -impl<'r, Seal: SonicSeal, R: ReadRaw> ReadOperation for OpReader<'r, Seal, R> { +impl<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> ReadOperation + for OpReader<'r, Seal, R, F> +{ type Seal = Seal; - type WitnessReader = WitnessReader<'r, Seal, R>; + type WitnessReader = WitnessReader<'r, Seal, R, F>; - fn read_operation(self) -> Option<(OperationSeals, Self::WitnessReader)> { + fn read_operation(mut self) -> Option<(OperationSeals, Self::WitnessReader)> { match Operation::strict_decode(self.stream) { Ok(operation) => { - let defined_seals = SmallVec::strict_decode(self.stream) + let mut defined_seals = SmallVec::strict_decode(self.stream) .expect("Failed to read consignment stream"); + defined_seals + .extend((self.seal_resolver)(operation.destructible.as_ref())) + .expect("Too many seals defined in the operation"); let op_seals = OperationSeals { operation, defined_seals }; let count = u64::strict_decode(self.stream).expect("Failed to read consignment stream"); @@ -362,14 +369,16 @@ impl<'r, Seal: SonicSeal, R: ReadRaw> ReadOperation for OpReader<'r, Seal, R> { } } -pub struct WitnessReader<'r, Seal: SonicSeal, R: ReadRaw> { +pub struct WitnessReader<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> { left: u64, - parent: OpReader<'r, Seal, R>, + parent: OpReader<'r, Seal, R, F>, } -impl<'r, Seal: SonicSeal, R: ReadRaw> ReadWitness for WitnessReader<'r, Seal, R> { +impl<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> ReadWitness + for WitnessReader<'r, Seal, R, F> +{ type Seal = Seal; - type OpReader = OpReader<'r, Seal, R>; + type OpReader = OpReader<'r, Seal, R, F>; fn read_witness(mut self) -> Step<(SealWitness, Self), Self::OpReader> { if self.left == 0 { @@ -425,7 +434,7 @@ mod fs { use std::path::Path; use hypersonic::FileSupply; - use strict_encoding::{StreamReader, StreamWriter, StrictDecode, StrictDumb, StrictEncode}; + use strict_encoding::{StreamWriter, StrictDecode, StrictDumb, StrictEncode}; use super::*; use crate::FilePile; @@ -468,19 +477,5 @@ mod fs { let writer = StrictWriter::with(StreamWriter::new::<{ usize::MAX }>(file)); self.consign(terminals, writer) } - - pub fn consume_from_file( - &mut self, - path: impl AsRef, - ) -> Result<(), ConsumeError> - where - Seal::CliWitness: StrictDumb, - Seal::PubWitness: StrictDumb, - >::PubId: StrictDecode, - { - let file = File::open(path)?; - let mut reader = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); - self.consume(&mut reader) - } } } From 3c9b93fed928b31b8203ace215d94fc6c7ef0f1f Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 03:16:28 +0100 Subject: [PATCH 64/70] rename SonicSeal into RgbSeal --- Cargo.lock | 10 +++++----- cli/src/dump.rs | 6 +++--- src/mound.rs | 10 +++++----- src/pile.rs | 12 ++++++------ src/stockpile.rs | 18 +++++++++--------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 115c8e3f..6cb9961f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" dependencies = [ "amplify", "chrono", @@ -239,7 +239,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" dependencies = [ "amplify", "bp-consensus", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" dependencies = [ "amplify", "base85", @@ -271,7 +271,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#f42b77490142a28e7da916dfd80257e45a52d524" +source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" dependencies = [ "amplify", "baid64", @@ -675,7 +675,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#7ac0fd908a100b299f6d015034a63fa60a4c47f8" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#a67daed7e8c9c0a64e746211f7635b72c1a19574" dependencies = [ "amplify", "bp-core", diff --git a/cli/src/dump.rs b/cli/src/dump.rs index a53613f6..2e59f4fd 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -31,12 +31,12 @@ use std::{fs, io}; use amplify::confinement::SmallVec; use hypersonic::aora::Aora; use hypersonic::{Articles, ContractId, FileSupply, Operation}; -use rgb::{FilePile, Index, Pile, PublishedWitness, SealWitness, SonicSeal, Stockpile}; +use rgb::{FilePile, Index, Pile, PublishedWitness, RgbSeal, SealWitness, Stockpile}; use serde::{Deserialize, Serialize}; use strict_encoding::{DecodeError, StreamReader, StrictDecode, StrictEncode, StrictReader}; // TODO: Auto-compute seal type out of the articles data -pub fn dump_stockpile( +pub fn dump_stockpile( src: &Path, dst: impl AsRef, ) -> anyhow::Result<()> @@ -115,7 +115,7 @@ where } // TODO: Auto-compute seal type out of the articles data -pub fn dump_consignment( +pub fn dump_consignment( src: &Path, dst: impl AsRef, ) -> anyhow::Result<()> diff --git a/src/mound.rs b/src/mound.rs index f6192133..46c9cd2e 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -208,19 +208,19 @@ pub mod file { use hypersonic::expect::Expect; use hypersonic::FileSupply; - use rgb::SonicSeal; + use rgb::RgbSeal; use single_use_seals::PublishedWitness; use strict_encoding::{StreamWriter, StrictDecode, StrictEncode}; use super::*; use crate::FilePile; - pub struct DirExcavator { + pub struct DirExcavator { dir: PathBuf, _phantom: PhantomData, } - impl DirExcavator { + impl DirExcavator { pub fn new(dir: PathBuf) -> Self { Self { dir, _phantom: PhantomData } } fn contents(&mut self) -> impl Iterator { @@ -234,7 +234,7 @@ pub mod file { } } - impl Excavate, CAPS> + impl Excavate, CAPS> for DirExcavator where Seal::CliWitness: StrictEncode + StrictDecode, @@ -277,7 +277,7 @@ pub mod file { pub type FileMound = Mound, DirExcavator, CAPS>; - impl FileMound + impl FileMound where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, diff --git a/src/pile.rs b/src/pile.rs index 9308828a..39609736 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -25,7 +25,7 @@ use amplify::confinement::SmallVec; use hypersonic::aora::Aora; use hypersonic::Opid; -use rgb::{ClientSideWitness, SonicSeal}; +use rgb::{ClientSideWitness, RgbSeal}; use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; pub trait Index { @@ -35,7 +35,7 @@ pub trait Index { } pub trait Pile { - type Seal: SonicSeal; + type Seal: RgbSeal; type Hoard: Aora< Id = <::PubWitness as PublishedWitness>::PubId, Item = ::CliWitness, @@ -169,7 +169,7 @@ pub mod fs { } } - pub struct FilePile + pub struct FilePile where >::PubId: Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> { @@ -179,7 +179,7 @@ pub mod fs { index: FileIndex<<::PubWitness as PublishedWitness>::PubId>, } - impl FilePile + impl FilePile where >::PubId: Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> { @@ -198,7 +198,7 @@ pub mod fs { } } - impl FilePile + impl FilePile where >::PubId: Copy + Ord + From<[u8; 32]> + Into<[u8; 32]> { @@ -216,7 +216,7 @@ pub mod fs { } } - impl Pile for FilePile + impl Pile for FilePile where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, diff --git a/src/stockpile.rs b/src/stockpile.rs index 9c78878b..386dd371 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -40,8 +40,8 @@ use hypersonic::{ StateAtom, StateName, Stock, Supply, }; use rgb::{ - ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, SealAuthToken, - SealType, SonicSeal, Step, VerificationError, + ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, RgbSeal, + SealAuthToken, SealType, Step, VerificationError, }; use single_use_seals::{PublishedWitness, SealWitness, SingleUseSeal}; use strict_encoding::{ @@ -66,7 +66,7 @@ pub enum EitherSeal { impl EitherSeal { pub fn auth_token(&self) -> AuthToken - where Seal: SonicSeal { + where Seal: RgbSeal { match self { EitherSeal::Known(seal) => seal.auth_token(), EitherSeal::External(auth) => *auth, @@ -335,13 +335,13 @@ impl, P: Pile, const CAPS: u32> Stockpile { } } -pub struct OpReader<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> { +pub struct OpReader<'r, Seal: RgbSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> { stream: &'r mut StrictReader, seal_resolver: F, _phantom: PhantomData, } -impl<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> ReadOperation +impl<'r, Seal: RgbSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> ReadOperation for OpReader<'r, Seal, R, F> { type Seal = Seal; @@ -369,12 +369,12 @@ impl<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> ReadO } } -pub struct WitnessReader<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> { +pub struct WitnessReader<'r, Seal: RgbSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> { left: u64, parent: OpReader<'r, Seal, R, F>, } -impl<'r, Seal: SonicSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> ReadWitness +impl<'r, Seal: RgbSeal, R: ReadRaw, F: FnMut(&[StateCell]) -> Vec> ReadWitness for WitnessReader<'r, Seal, R, F> { type Seal = Seal; @@ -413,7 +413,7 @@ impl, P: Pile, const CAPS: u32> ContractApi for Stockpi #[derive(Display, From)] #[display(inner)] -pub enum ConsumeError { +pub enum ConsumeError { #[from] #[from(io::Error)] Io(IoError), @@ -439,7 +439,7 @@ mod fs { use super::*; use crate::FilePile; - impl Stockpile, CAPS> + impl Stockpile, CAPS> where Seal::CliWitness: StrictEncode + StrictDecode, Seal::PubWitness: StrictEncode + StrictDecode, From 4d9b189cbd5c43d7949351302d73b2efc90b5aa8 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 03:22:27 +0100 Subject: [PATCH 65/70] save resolved seals to pile --- src/stockpile.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/stockpile.rs b/src/stockpile.rs index 386dd371..0611bac2 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -404,7 +404,12 @@ impl, P: Pile, const CAPS: u32> ContractApi for Stockpi fn memory(&self) -> &impl Memory { &self.stock.state().raw } - fn apply_operation(&mut self, op: OperationSeals) { self.stock.apply(op.operation); } + fn apply_operation(&mut self, op: OperationSeals) { + self.pile + .keep_mut() + .append(op.operation.opid(), &op.defined_seals); + self.stock.apply(op.operation); + } fn apply_witness(&mut self, opid: Opid, witness: SealWitness) { self.pile.append(opid, witness.client, &witness.published); From 369f17e3b533aa5e8c6eda4e6de46aca0fd45981 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 03:34:41 +0100 Subject: [PATCH 66/70] use magic bytes and version in consignment stream --- Cargo.lock | 1 + cli/Cargo.toml | 1 + cli/src/dump.rs | 21 ++++++++++++++++++--- src/lib.rs | 2 +- src/mound.rs | 14 ++++++++++++++ src/stockpile.rs | 3 +++ 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6cb9961f..15b7cb06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -715,6 +715,7 @@ dependencies = [ "amplify", "anyhow", "clap", + "commit_verify", "hypersonic", "rgb-std", "serde", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cfe7523a..fcae6bd5 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,6 +15,7 @@ readme = "../README.md" [dependencies] amplify.workspace = true strict_encoding.workspace = true +commit_verify.workspace = true hypersonic.workspace = true rgb-std = { workspace = true, features = ["fs", "serde"] } serde.workspace = true diff --git a/cli/src/dump.rs b/cli/src/dump.rs index 2e59f4fd..1f7b5c8d 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -29,9 +29,15 @@ use std::path::Path; use std::{fs, io}; use amplify::confinement::SmallVec; +use amplify::hex::ToHex; +use amplify::Bytes16; +use commit_verify::ReservedBytes; use hypersonic::aora::Aora; use hypersonic::{Articles, ContractId, FileSupply, Operation}; -use rgb::{FilePile, Index, Pile, PublishedWitness, RgbSeal, SealWitness, Stockpile}; +use rgb::{ + ConsumeError, FilePile, Index, Pile, PublishedWitness, RgbSeal, SealWitness, Stockpile, + MAGIC_BYTES_CONSIGNMENT, +}; use serde::{Deserialize, Serialize}; use strict_encoding::{DecodeError, StreamReader, StrictDecode, StrictEncode, StrictReader}; @@ -132,8 +138,17 @@ where let file = File::open(src)?; let mut stream = StrictReader::with(StreamReader::new::<{ usize::MAX }>(file)); - let cointract_id = ContractId::strict_decode(&mut stream)?; - println!("Dumping consignment for {} into '{}'", cointract_id, dst.display()); + let magic_bytes = Bytes16::strict_decode(&mut stream)?; + if magic_bytes.to_byte_array() != MAGIC_BYTES_CONSIGNMENT { + return Err(anyhow!( + ConsumeError::::UnrecognizedMagic(magic_bytes.to_hex()).to_string() + )); + } + // Version + ReservedBytes::<2>::strict_decode(&mut stream)?; + + let contract_id = ContractId::strict_decode(&mut stream)?; + println!("Dumping consignment for {} into '{}'", contract_id, dst.display()); let mut op_count = 1; let mut seal_count = 0; diff --git a/src/lib.rs b/src/lib.rs index baa65e9f..89dc5411 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ pub mod popls; pub use bp::{Outpoint, Txid}; pub use hypersonic::*; pub use info::ContractInfo; -pub use mound::{Excavate, Mound}; +pub use mound::{Excavate, Mound, MAGIC_BYTES_CONSIGNMENT}; #[cfg(feature = "fs")] pub use pile::fs::FilePile; pub use pile::{Index, Pile}; diff --git a/src/mound.rs b/src/mound.rs index 46c9cd2e..ef7fdbbb 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -26,6 +26,9 @@ use alloc::collections::BTreeMap; use core::borrow::Borrow; use std::io; +use amplify::hex::ToHex; +use amplify::Bytes16; +use commit_verify::ReservedBytes; use hypersonic::expect::Expect; use hypersonic::{AuthToken, CellAddr, CodexId, ContractId, Opid, Schema, Supply}; use single_use_seals::{PublishedWitness, SingleUseSeal}; @@ -35,6 +38,8 @@ use strict_encoding::{ use crate::{ConsumeError, ContractInfo, CreateParams, Pile, StateCell, Stockpile}; +pub const MAGIC_BYTES_CONSIGNMENT: [u8; 16] = *b"RGB CONSIGNMENT\0"; + pub trait Excavate, P: Pile, const CAPS: u32> { fn schemata(&mut self) -> impl Iterator; fn contracts(&mut self) -> impl Iterator)>; @@ -174,6 +179,9 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound::PubWitness: StrictDumb + StrictEncode, <::PubWitness as PublishedWitness>::PubId: StrictEncode, { + writer = MAGIC_BYTES_CONSIGNMENT.strict_encode(writer)?; + // Version + writer = 0x00u16.strict_encode(writer)?; writer = contract_id.strict_encode(writer)?; self.contract_mut(contract_id).consign(terminals, writer) } @@ -188,6 +196,12 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound::PubWitness: StrictDecode, <::PubWitness as PublishedWitness>::PubId: StrictDecode, { + let magic_bytes = Bytes16::strict_decode(reader)?; + if magic_bytes.to_byte_array() != MAGIC_BYTES_CONSIGNMENT { + return Err(ConsumeError::UnrecognizedMagic(magic_bytes.to_hex())); + } + // Version + ReservedBytes::<2>::strict_decode(reader)?; let contract_id = ContractId::strict_decode(reader)?; let contract = if self.has_contract(contract_id) { self.contract_mut(contract_id) diff --git a/src/stockpile.rs b/src/stockpile.rs index 0611bac2..ef32eb71 100644 --- a/src/stockpile.rs +++ b/src/stockpile.rs @@ -419,6 +419,9 @@ impl, P: Pile, const CAPS: u32> ContractApi for Stockpi #[derive(Display, From)] #[display(inner)] pub enum ConsumeError { + #[display("unrecognized magic bytes in consignment stream ({0})")] + UnrecognizedMagic(String), + #[from] #[from(io::Error)] Io(IoError), From 0d535af2cf6973909d00a79278bdfc8dffe9f124 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 20:21:37 +0100 Subject: [PATCH 67/70] chore: update dependencies --- Cargo.lock | 67 +++++++++++++++++++++++++++++++----------------------- Cargo.toml | 22 ++++++------------ 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15b7cb06..c759d1be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aluvm" -version = "0.12.0-beta.3" +version = "0.12.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24cbb8887879db8e58ad1aada824eabe4aaa8a90b0b3fbd992e9e001625673a0" +checksum = "ecadfc638661bf95a89674ab269895ff0ef2e23e265f4e9bacb4b00aeb4ed574" dependencies = [ "amplify", "baid64", @@ -224,8 +224,9 @@ dependencies = [ [[package]] name = "bp-consensus" -version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1303344864858bcdbe31e36ba2285efb4cdd53e1c6b275b8840c88469a3f18f" dependencies = [ "amplify", "chrono", @@ -238,8 +239,9 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469adfa23c07f6c178392f278a32ab43bf7c370ca0d29f4865ecd568b946b5d4" dependencies = [ "amplify", "bp-consensus", @@ -256,8 +258,9 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58353b119115259123518bcc1a2578b326d74dbabddb0b31c682d83509858c9" dependencies = [ "amplify", "base85", @@ -270,8 +273,9 @@ dependencies = [ [[package]] name = "bp-seals" -version = "0.12.0-beta.2" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.12#b5d5cdddab5d97b6350398273215fe1c67e90f9b" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f15dc1cad42e0cc9801509500a6cee6b6f99da473513209d495707d20397b0" dependencies = [ "amplify", "baid64", @@ -374,8 +378,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "commit_encoding_derive" -version = "0.12.0-beta.1" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#293358fda9b848a5ec2a7cfd0b49bf8c5f49a017" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9613582af45e1564c09d813dae82e7c7bca95678b9c42dae955a8499ecc6ae95" dependencies = [ "amplify", "amplify_syn", @@ -386,8 +391,9 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.12.0-beta.1" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#293358fda9b848a5ec2a7cfd0b49bf8c5f49a017" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b822f3253ddad821c2a08b88d6534cc322e57dfe3aa8a5bbe88cce8beecc965" dependencies = [ "amplify", "commit_encoding_derive", @@ -487,8 +493,9 @@ dependencies = [ [[package]] name = "hypersonic" -version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#2d6bb980ff2cbd242b888c01199b0d9850092253" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9503bbd34bf82c772915e2289d6f391747527f1163034a6445507042784782" dependencies = [ "aluvm", "amplify", @@ -674,8 +681,9 @@ dependencies = [ [[package]] name = "rgb-core" -version = "0.12.0-beta.3" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.12#a67daed7e8c9c0a64e746211f7635b72c1a19574" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "205437a4ae2f6b581042d18451502bddb6269b75f86457200309e782fd65d96d" dependencies = [ "amplify", "bp-core", @@ -690,7 +698,7 @@ dependencies = [ [[package]] name = "rgb-std" -version = "0.12.0-alpha.1" +version = "0.12.0-beta.4" dependencies = [ "amplify", "bp-core", @@ -710,7 +718,7 @@ dependencies = [ [[package]] name = "rgbx" -version = "0.12.0-alpha.1" +version = "0.12.0-beta.4" dependencies = [ "amplify", "anyhow", @@ -858,8 +866,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.12.0-beta.1" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.12#293358fda9b848a5ec2a7cfd0b49bf8c5f49a017" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84e1ecf8923d062bff162583e1f71f517e535974196512a13ab47d8816b38998" dependencies = [ "serde", "strict_encoding", @@ -867,8 +876,9 @@ dependencies = [ [[package]] name = "sonic-api" -version = "0.12.0-beta.1" -source = "git+https://github.com/AluVM/sonic#2d6bb980ff2cbd242b888c01199b0d9850092253" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489bc80ac788479701f4d236e722e2624bf1825dfd91be2f8b90c81b543cc6f2" dependencies = [ "aluvm", "amplify", @@ -1028,8 +1038,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ultrasonic" -version = "0.12.0-beta.2" -source = "git+https://github.com/AluVM/ultrasonic#1b20385acdfa8558143223c202fc42f0884c2739" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6881096bf32a9a2beee8171df572de24d549c02c257814fb901089b7c9dc1fc4" dependencies = [ "amplify", "baid64", @@ -1316,9 +1327,9 @@ dependencies = [ [[package]] name = "zk-aluvm" -version = "0.12.0-beta.2" +version = "0.12.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f06b3c7a5e4ddf056024c9028004c34b0a0a1b575b2dc2abe4e31ae9f9073ec" +checksum = "7ccc204be52b2d144d3961a17676d191477cc468a2a82779f4502db83d58a083" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index dad50d21..56b8b19a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [".", "cli"] default-members = ["."] [workspace.package] -version = "0.12.0-alpha.1" +version = "0.12.0-beta.4" keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] categories = ["cryptography::cryptocurrencies"] authors = ["Dr Maxim Orlovsky "] @@ -17,12 +17,12 @@ license = "Apache-2.0" amplify = "4.8.0" strict_encoding = "2.8.1" strict_types = "2.8.1" -commit_verify = "0.12.0-beta.1" -single_use_seals = "0.12.0-beta.1" -hypersonic = "0.12.0-beta.1" -bp-core = "0.12.0-beta.2" -rgb-core = "0.12.0-beta.3" -rgb-std = { version = "0.12.0-alpha.1", path = "." } +commit_verify = "=0.12.0-beta.4" +single_use_seals = "=0.12.0-beta.4" +hypersonic = "=0.12.0-beta.4" +bp-core = "=0.12.0-beta.4" +rgb-core = "=0.12.0-beta.4" +rgb-std = { version = "=0.12.0-beta.4", path = "." } chrono = "0.4.39" serde = "1.0.215" @@ -92,11 +92,3 @@ wasm-bindgen-test = "0.3" [package.metadata.docs.rs] features = ["all"] - -[patch.crates-io] -ultrasonic = { git = "https://github.com/AluVM/ultrasonic" } -hypersonic = { git = "https://github.com/AluVM/sonic" } -commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.12" } -single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.12" } -bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.12" } -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.12" } From 51bf4a25fb6d18811878c0382eec076558739a16 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 20:25:54 +0100 Subject: [PATCH 68/70] chore: bump MSRV to 1.82 --- .github/workflows/build.yml | 6 +++--- .github/workflows/codecov.yml | 4 ++-- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 4 ++-- Cargo.toml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 724f9685..083105ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,12 +5,12 @@ on: branches: - master tags: - - 'v[0-9]+\.*' + - 'v[0-9]+.*' pull_request: branches: - master - develop - - 'v[0-9]+.[0-9]+' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always @@ -57,7 +57,7 @@ jobs: strategy: fail-fast: false matrix: - toolchain: [ nightly, beta, stable, 1.77.0 ] + toolchain: [ nightly, beta, stable, 1.82.0 ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 3711d7ad..9ba863f5 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -5,12 +5,12 @@ on: branches: - master tags: - - 'v[0-9]+\.*' + - 'v[0-9]+.*' pull_request: branches: - master - develop - - 'v[0-9]+.[0-9]+' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ab5249d1..91f36b69 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,7 +5,7 @@ on: branches: - master - develop - - 'v[0-9]+.[0-9]+' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9821d00e..7b009567 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,12 +5,12 @@ on: branches: - master tags: - - 'v[0-9]+\.*' + - 'v[0-9]+.*' pull_request: branches: - master - develop - - 'v[0-9]+.[0-9]+' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always diff --git a/Cargo.toml b/Cargo.toml index 56b8b19a..9d64f387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ categories = ["cryptography::cryptocurrencies"] authors = ["Dr Maxim Orlovsky "] homepage = "https://rgb.tech" repository = "https://github.com/RGB-WG/rgb-std" -rust-version = "1.77.0" +rust-version = "1.82.0" edition = "2021" license = "Apache-2.0" From eba6ac845584aa33fd1060940f54db9d6f2d6c32 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 23 Dec 2024 20:33:06 +0100 Subject: [PATCH 69/70] chore: fix feature gates --- src/mound.rs | 1 + src/popls/bp.rs | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/mound.rs b/src/mound.rs index ef7fdbbb..39b28d5d 100644 --- a/src/mound.rs +++ b/src/mound.rs @@ -213,6 +213,7 @@ impl, P: Pile, X: Excavate, const CAPS: u32> Mound Date: Mon, 23 Dec 2024 20:34:30 +0100 Subject: [PATCH 70/70] chore: fix clippy lints --- cli/src/dump.rs | 8 ++++---- src/pile.rs | 2 +- src/popls/bp.rs | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/src/dump.rs b/cli/src/dump.rs index 1f7b5c8d..08d3e825 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -42,12 +42,12 @@ use serde::{Deserialize, Serialize}; use strict_encoding::{DecodeError, StreamReader, StrictDecode, StrictEncode, StrictReader}; // TODO: Auto-compute seal type out of the articles data -pub fn dump_stockpile( +pub fn dump_stockpile( src: &Path, dst: impl AsRef, ) -> anyhow::Result<()> where - Seal: Serialize, + Seal: RgbSeal + Serialize, Seal::CliWitness: Serialize + StrictEncode + StrictDecode, Seal::PubWitness: Serialize + StrictEncode + StrictDecode, >::PubId: @@ -121,12 +121,12 @@ where } // TODO: Auto-compute seal type out of the articles data -pub fn dump_consignment( +pub fn dump_consignment( src: &Path, dst: impl AsRef, ) -> anyhow::Result<()> where - Seal: Serialize, + Seal: RgbSeal + Serialize, Seal::CliWitness: Serialize + for<'de> Deserialize<'de> + StrictEncode + StrictDecode, Seal::PubWitness: Serialize + for<'de> Deserialize<'de> + StrictEncode + StrictDecode, >::PubId: diff --git a/src/pile.rs b/src/pile.rs index 39609736..de35b72c 100644 --- a/src/pile.rs +++ b/src/pile.rs @@ -79,7 +79,7 @@ pub trait Pile { } else { self.hoard_mut().append(pubid, &anchor); } - self.cache_mut().append(pubid, &published); + self.cache_mut().append(pubid, published); } } diff --git a/src/popls/bp.rs b/src/popls/bp.rs index b1e81a40..a7b990b5 100644 --- a/src/popls/bp.rs +++ b/src/popls/bp.rs @@ -450,6 +450,7 @@ impl< self.mound.attest(witness, iter); } + #[allow(clippy::result_large_err)] pub fn consume( &mut self, reader: &mut StrictReader,