From a9f2a85be8705892bdafb86806609aa869004b0a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 19 Apr 2024 11:11:51 +0200 Subject: [PATCH 01/32] cli: save wallet data when modified Closes #173 --- cli/src/command.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cli/src/command.rs b/cli/src/command.rs index 7a176c2..79d1fd4 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -690,7 +690,8 @@ impl Exec for RgbArgs { .set_amount_raw(*value) .finish(); println!("{invoice}"); - Some(runtime.into_stock()) + runtime.store(); + None } Command::Prepare { v2, @@ -719,7 +720,8 @@ impl Exec for RgbArgs { PsbtVer::V2 => println!("{psbt:#}"), }, } - Some(runtime.into_stock()) + runtime.store(); + None } Command::Consign { invoice, @@ -735,7 +737,8 @@ impl Exec for RgbArgs { let mut psbt_file = File::create(psbt_name)?; psbt.encode(psbt.version, &mut psbt_file)?; transfer.save_file(out_file)?; - Some(runtime.into_stock()) + runtime.store(); + None } Command::Transfer { v2, @@ -767,7 +770,8 @@ impl Exec for RgbArgs { PsbtVer::V2 => println!("{psbt:#}"), }, } - Some(runtime.into_stock()) + runtime.store(); + None } Command::Inspect { file, dir, path } => { #[derive(Clone, Debug)] From ac43eb2709fe06cb102b7083ea6205634573f2df Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 19 Apr 2024 13:56:47 +0200 Subject: [PATCH 02/32] descriptor: fix serde serialization. Remove serde_with --- Cargo.lock | 41 ++++++++++------------------------------- Cargo.toml | 4 +--- src/descriptor.rs | 6 ------ src/lib.rs | 3 --- 4 files changed, 11 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 161973c..8e14db4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,7 +328,7 @@ dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1 0.29.0", + "secp256k1", "serde", "strict_encoding", "strict_types", @@ -361,7 +361,7 @@ dependencies = [ "base85", "bp-consensus", "commit_verify", - "secp256k1 0.29.0", + "secp256k1", "serde", "strict_encoding", ] @@ -369,7 +369,7 @@ dependencies = [ [[package]] name = "bp-derive" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#7dd16a84edc8c308856155d990d9df4311c35bfc" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" dependencies = [ "amplify", "bitcoin_hashes", @@ -418,7 +418,7 @@ dependencies = [ [[package]] name = "bp-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#7dd16a84edc8c308856155d990d9df4311c35bfc" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" dependencies = [ "amplify", "bech32", @@ -446,7 +446,7 @@ dependencies = [ [[package]] name = "bp-std" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#7dd16a84edc8c308856155d990d9df4311c35bfc" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" dependencies = [ "amplify", "bp-consensus", @@ -744,7 +744,7 @@ dependencies = [ [[package]] name = "descriptors" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#7dd16a84edc8c308856155d990d9df4311c35bfc" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" dependencies = [ "amplify", "bp-derive", @@ -1414,7 +1414,7 @@ dependencies = [ [[package]] name = "psbt" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#7dd16a84edc8c308856155d990d9df4311c35bfc" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" dependencies = [ "amplify", "base64", @@ -1625,7 +1625,6 @@ dependencies = [ "rgb-psbt", "rgb-std", "serde", - "serde_with", "serde_yaml", "strict_types", ] @@ -1822,18 +1821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ "rand", - "secp256k1-sys 0.9.2", - "serde", -] - -[[package]] -name = "secp256k1" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" -dependencies = [ - "rand", - "secp256k1-sys 0.10.0", + "secp256k1-sys", "serde", ] @@ -1846,15 +1834,6 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" -dependencies = [ - "cc", -] - [[package]] name = "secp256k1-zkp" version = "0.10.1" @@ -1863,7 +1842,7 @@ checksum = "c4e48ef9c98bfbcb98bd15693ffa19676cb3e29426b75eda8b73c05cdd7959f8" dependencies = [ "bitcoin-private", "rand", - "secp256k1 0.28.2", + "secp256k1", "secp256k1-zkp-sys", "serde", ] @@ -1875,7 +1854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ead52f43074bae2ddbd1e0e66e6b170135e76117f5ea9916f33d7bd0b36e29" dependencies = [ "cc", - "secp256k1-sys 0.9.2", + "secp256k1-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ccf6c2d..691f01f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ rgb-psbt = { version = "0.11.0-beta.5", path = "psbt" } indexmap = "2.0.2" chrono = "0.4.31" serde_crate = { package = "serde", version = "1", features = ["derive"] } -serde_with = "3.4.0" serde_yaml = "0.9.19" log = { version = "0.4", features = ["max_level_trace", "release_max_level_debug"] } @@ -79,7 +78,6 @@ indexmap = { workspace = true } chrono = { workspace = true } serde_crate = { workspace = true, optional = true } serde_yaml = { workspace = true, optional = true } -serde_with = { workspace = true, optional = true } log = { workspace = true, optional = true } [features] @@ -87,7 +85,7 @@ default = ["esplora_blocking"] all = ["esplora_blocking", "electrum", "serde", "log"] esplora_blocking = ["bp-esplora", "bp-wallet/esplora"] electrum = ["bp-electrum", "bp-wallet/electrum"] -serde = ["serde_crate", "serde_with", "serde_yaml", "bp-std/serde", "bp-wallet/serde", "descriptors/serde", "rgb-psbt/serde"] +serde = ["serde_crate", "serde_yaml", "bp-std/serde", "bp-wallet/serde", "descriptors/serde", "rgb-psbt/serde"] [package.metadata.docs.rs] features = ["all"] diff --git a/src/descriptor.rs b/src/descriptor.rs index 2c1c02f..609ad25 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -109,7 +109,6 @@ impl From for Keychain { fn from(keychain: RgbKeychain) -> Self { Keychain::from(keychain as u8) } } -#[cfg_attr(feature = "serde", serde_as)] #[derive(Clone, Eq, PartialEq, Debug)] #[cfg_attr( feature = "serde", @@ -119,11 +118,6 @@ impl From for Keychain { pub struct TapretKey { pub internal_key: K, // TODO: Allow multiple tweaks per index by introducing derivation using new Terminal trait - // TODO: Change serde implementation for both Terminal and TapretCommitment - #[cfg_attr( - feature = "serde", - serde_as(as = "HashMap") - )] pub tweaks: HashMap, } diff --git a/src/lib.rs b/src/lib.rs index 5ff46a6..891c873 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,9 +24,6 @@ extern crate amplify; #[cfg(feature = "serde")] #[macro_use] extern crate serde_crate as serde; -#[cfg(feature = "serde")] -#[macro_use] -extern crate serde_with; mod runtime; mod descriptor; From bd49deddc5399306600fb6db4d70fa66e5fd1ee5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 17 Apr 2024 01:21:34 +0200 Subject: [PATCH 03/32] cli: use new info objects --- cli/src/command.rs | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/cli/src/command.rs b/cli/src/command.rs index 79d1fd4..c60e0b9 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -38,7 +38,7 @@ use rgbstd::contract::{ContractId, GenesisSeal, GraphSeal, StateType}; use rgbstd::interface::{AmountChange, ContractSuppl, FilterExclude, IfaceId}; use rgbstd::invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet}; use rgbstd::persistence::fs::StoreFs; -use rgbstd::persistence::{SchemaIfaces, StashReadProvider}; +use rgbstd::persistence::StashReadProvider; use rgbstd::schema::SchemaId; use rgbstd::validation::Validity; use rgbstd::vm::RgbIsa; @@ -315,20 +315,15 @@ impl Exec for RgbArgs { } Command::Schemata => { let stock = self.rgb_stock()?; - for schema_iface in stock.schemata()? { - print!("{} ", schema_iface.schema.schema_id()); - for iimpl in schema_iface.iimpls.values() { - let iface = stock.iface(iimpl.iface_id)?; - print!("{} ", iface.name); - } - println!(); + for info in stock.schemata()? { + print!("{info}"); } None } Command::Interfaces => { let stock = self.rgb_stock()?; - for (id, name) in stock.ifaces()? { - println!("{} {id}", name); + for info in stock.ifaces()? { + print!("{info}"); } None } @@ -525,10 +520,7 @@ impl Exec for RgbArgs { .expect("contract must specify interface under which it is constructed") .as_str() .expect("interface name must be a string"); - let SchemaIfaces { - ref schema, - ref iimpls, - } = stock.schema(*schema_id)?; + let schema_ifaces = stock.schema(*schema_id)?; let iface_name = tn!(iface_name.to_owned()); let iface = stock .iface(iface_name.clone()) @@ -538,7 +530,7 @@ impl Exec for RgbArgs { })? .clone(); let iface_id = iface.iface_id(); - let iface_impl = iimpls.get(&iface_id).ok_or_else(|| { + let iface_impl = schema_ifaces.get(iface_id).ok_or_else(|| { RuntimeError::Custom(format!( "no known interface implementation for {iface_name}" )) @@ -561,7 +553,8 @@ impl Exec for RgbArgs { .find(|info| info.name.as_str() == name) .unwrap_or_else(|| panic!("unknown type name '{name}'")) .id; - let sem_id = schema + let sem_id = schema_ifaces + .schema .global_types .get(&state_type) .expect("invalid schema implementation") @@ -597,7 +590,8 @@ impl Exec for RgbArgs { .find(|info| info.name.as_str() == name) .expect("unknown type name") .id; - let state_schema = schema + let state_schema = schema_ifaces + .schema .owned_types .get(&state_type) .expect("invalid schema implementation"); @@ -883,19 +877,16 @@ impl Exec for RgbArgs { fs::create_dir_all(format!("{root_dir}/index"))?; // Stash - for schema_ifaces in stock.schemata()? { + for (id, schema_ifaces) in stock.as_stash_provider().debug_schemata() { fs::write( - format!( - "{root_dir}/stash/schemata/{}.yaml", - schema_ifaces.schema.schema_id() - ), + format!("{root_dir}/stash/schemata/{}.yaml", id), serde_yaml::to_string(&schema_ifaces)?, )?; } - for (id, name) in stock.ifaces()? { + for (id, iface) in stock.as_stash_provider().debug_ifaces() { fs::write( - format!("{root_dir}/stash/ifaces/{id}.{name}.yaml"), - serde_yaml::to_string(stock.iface(id)?)?, + format!("{root_dir}/stash/ifaces/{id}.{}.yaml", iface.name), + serde_yaml::to_string(stock.iface(*id)?)?, )?; } for (id, genesis) in stock.as_stash_provider().debug_geneses() { From 1de06b1104e799b025922b65efcb19693ecc6665 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 17 Apr 2024 11:44:18 +0200 Subject: [PATCH 04/32] cli: improve command printouts --- cli/src/args.rs | 16 ++++++++++++---- cli/src/command.rs | 21 ++++++++++++--------- cli/src/main.rs | 6 ++++-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/cli/src/args.rs b/cli/src/args.rs index edc6a83..9f58066 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -74,18 +74,26 @@ impl Default for RgbArgs { impl RgbArgs { pub fn rgb_stock(&self) -> Result { - eprint!("Loading stock ... "); + if self.verbose > 2 { + eprint!("Loading stock ... "); + } let runtime = Runtime::::load_walletless(&self.general.base_dir())?; - eprintln!("success"); + if self.verbose > 2 { + eprintln!("success"); + } Ok(runtime) } pub fn rgb_runtime(&self, config: &Config) -> Result { let bprt = self.inner.bp_runtime::(config)?; - eprint!("Loading stock ... "); + if self.verbose > 2 { + eprint!("Loading stock ... "); + } let runtime = Runtime::::load_attach(self.general.base_dir(), bprt)?; - eprintln!("success"); + if self.verbose > 2 { + eprintln!("success"); + } Ok(runtime) } diff --git a/cli/src/command.rs b/cli/src/command.rs index c60e0b9..f6f4e9e 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -879,19 +879,22 @@ impl Exec for RgbArgs { // Stash for (id, schema_ifaces) in stock.as_stash_provider().debug_schemata() { fs::write( - format!("{root_dir}/stash/schemata/{}.yaml", id), + format!( + "{root_dir}/stash/schemata/{}.{id:-}.yaml", + schema_ifaces.schema.name + ), serde_yaml::to_string(&schema_ifaces)?, )?; } for (id, iface) in stock.as_stash_provider().debug_ifaces() { fs::write( - format!("{root_dir}/stash/ifaces/{id}.{}.yaml", iface.name), + format!("{root_dir}/stash/ifaces/{}.{id:-}.yaml", iface.name), serde_yaml::to_string(stock.iface(*id)?)?, )?; } for (id, genesis) in stock.as_stash_provider().debug_geneses() { fs::write( - format!("{root_dir}/stash/geneses/{id}.yaml"), + format!("{root_dir}/stash/geneses/{id:-}.yaml"), serde_yaml::to_string(genesis)?, )?; } @@ -899,7 +902,7 @@ impl Exec for RgbArgs { for suppl in list { fs::write( format!( - "{root_dir}/stash/geneses/{id}.suppl.{}.yaml", + "{root_dir}/stash/geneses/{id:-}.suppl.{}.yaml", suppl.suppl_id() ), serde_yaml::to_string(suppl)?, @@ -908,24 +911,24 @@ impl Exec for RgbArgs { } for (id, bundle) in stock.as_stash_provider().debug_bundles() { fs::write( - format!("{root_dir}/stash/bundles/{id}.yaml"), + format!("{root_dir}/stash/bundles/{id:-}.yaml"), serde_yaml::to_string(bundle)?, )?; } for (id, witness) in stock.as_stash_provider().debug_witnesses() { fs::write( - format!("{root_dir}/stash/witnesses/{id}.yaml"), + format!("{root_dir}/stash/witnesses/{id:-}.yaml"), serde_yaml::to_string(witness)?, )?; } for (id, extension) in stock.as_stash_provider().debug_extensions() { fs::write( - format!("{root_dir}/stash/extensions/{id}.yaml"), + format!("{root_dir}/stash/extensions/{id:-}.yaml"), serde_yaml::to_string(extension)?, )?; } fs::write( - format!("{root_dir}/seal-secret.yaml"), + format!("{root_dir}/stash/seal-secret.yaml"), serde_yaml::to_string(stock.as_stash_provider().debug_secret_seals())?, )?; // TODO: Add sigs debugging @@ -933,7 +936,7 @@ impl Exec for RgbArgs { // State for (id, history) in stock.as_state_provider().debug_history() { fs::write( - format!("{root_dir}/state/{id}.yaml"), + format!("{root_dir}/state/{id:-}.yaml"), serde_yaml::to_string(history)?, )?; } diff --git a/cli/src/main.rs b/cli/src/main.rs index 47030a2..bebf6c8 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -56,8 +56,10 @@ fn run() -> Result<(), RuntimeError> { LogLevel::from_verbosity_flag_count(args.verbose).apply(); trace!("Command-line arguments: {:#?}", &args); - eprintln!("RGB: command-line wallet for RGB smart contracts"); - eprintln!(" by LNP/BP Standards Association\n"); + if args.verbose > 3 { + eprintln!("RGB: command-line wallet for RGB smart contracts"); + eprintln!(" by LNP/BP Standards Association\n"); + } let conf = Config::load(&args.conf_path("rgb")); debug!("Executing command: {:?}", args.command); From 424cb95ef5bfbe71aefe5a438fd975eb0d83fe87 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 22 Apr 2024 19:18:07 +0200 Subject: [PATCH 05/32] chore: update dependencies --- Cargo.lock | 134 +++++++++++++++++++++++++++------------------ Cargo.toml | 18 +++--- cli/src/command.rs | 5 +- psbt/src/rgb.rs | 6 +- 4 files changed, 99 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e14db4..7fec365 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,10 +29,10 @@ dependencies = [ [[package]] name = "aluvm" version = "0.11.0-beta.5" -source = "git+https://github.com/AluVM/rust-aluvm?branch=v0.11#d18ea84836a8a96f3dfe61c99b94f2eab1417819" +source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#3fc2434ee9af51e935b44e5ea682fef933019bda" dependencies = [ "amplify", - "ascii-armor", + "ascii-armor 0.2.0", "baid58", "blake3", "getrandom", @@ -204,6 +204,19 @@ dependencies = [ "strict_encoding", ] +[[package]] +name = "ascii-armor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44ce552de9efa4fdee1a7920f3587e17689bf4a4ba149a7892f91820673c1e29" +dependencies = [ + "amplify", + "baid58", + "base85", + "sha2", + "strict_encoding", +] + [[package]] name = "autocfg" version = "1.2.0" @@ -323,12 +336,12 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#27a4b711613f88276b5b7da0c2a3b27164b431e8" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1", + "secp256k1 0.29.0", "serde", "strict_encoding", "strict_types", @@ -337,7 +350,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#27a4b711613f88276b5b7da0c2a3b27164b431e8" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" dependencies = [ "amplify", "bp-consensus", @@ -355,13 +368,13 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#27a4b711613f88276b5b7da0c2a3b27164b431e8" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" dependencies = [ "amplify", "base85", "bp-consensus", "commit_verify", - "secp256k1", + "secp256k1 0.29.0", "serde", "strict_encoding", ] @@ -369,7 +382,7 @@ dependencies = [ [[package]] name = "bp-derive" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" dependencies = [ "amplify", "bitcoin_hashes", @@ -391,7 +404,7 @@ dependencies = [ "byteorder", "libc", "log", - "rustls 0.21.10", + "rustls 0.21.11", "serde", "serde_json", "sha2", @@ -418,7 +431,7 @@ dependencies = [ [[package]] name = "bp-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" dependencies = [ "amplify", "bech32", @@ -430,7 +443,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=v0.11#27a4b711613f88276b5b7da0c2a3b27164b431e8" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" dependencies = [ "amplify", "baid58", @@ -446,7 +459,7 @@ dependencies = [ [[package]] name = "bp-std" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" dependencies = [ "amplify", "bp-consensus", @@ -484,7 +497,7 @@ dependencies = [ [[package]] name = "bp-wallet" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-wallet?branch=v0.11#5d07f271605395a0d7e4d10c87283fbcb4203e1b" +source = "git+https://github.com/BP-WG/bp-wallet?branch=v0.11#e05f6c75a1a150851a4b08fcec74f02230de6bb1" dependencies = [ "amplify", "bp-electrum", @@ -520,9 +533,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" [[package]] name = "cfg-if" @@ -605,7 +618,7 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "commit_encoding_derive" version = "0.11.0-beta.5" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#d32e1af11a599643b235706efd51d0097347f082" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#f51e1e0d010b1531acc939d2443af552e8755bb7" dependencies = [ "amplify", "amplify_syn", @@ -617,7 +630,7 @@ dependencies = [ [[package]] name = "commit_verify" version = "0.11.0-beta.5" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#d32e1af11a599643b235706efd51d0097347f082" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#f51e1e0d010b1531acc939d2443af552e8755bb7" dependencies = [ "amplify", "commit_encoding_derive", @@ -744,7 +757,7 @@ dependencies = [ [[package]] name = "descriptors" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" dependencies = [ "amplify", "bp-derive", @@ -1414,7 +1427,7 @@ dependencies = [ [[package]] name = "psbt" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#95ff22306108188729a0646838154efe8b7d715d" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" dependencies = [ "amplify", "base64", @@ -1551,11 +1564,11 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#551d6d6fc3c7bf10119b20145ddae852fba6446d" +source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#648bb45ab4dd4c000e8ba1872a2a7ce47cd2217e" dependencies = [ "aluvm", "amplify", - "ascii-armor", + "ascii-armor 0.2.0", "baid58", "bp-core", "chrono", @@ -1573,7 +1586,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#baf4b823eeed514f08bd9bf89d0c426b5517262b" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#0a392e705e1cfd246508021467f2963552d366d7" dependencies = [ "amplify", "baid58", @@ -1632,11 +1645,11 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#baf4b823eeed514f08bd9bf89d0c426b5517262b" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#0a392e705e1cfd246508021467f2963552d366d7" dependencies = [ "aluvm", "amplify", - "ascii-armor", + "ascii-armor 0.3.0", "baid58", "base85", "bp-core", @@ -1710,9 +1723,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad" dependencies = [ "bitflags 2.5.0", "errno", @@ -1723,9 +1736,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ "log", "ring", @@ -1735,14 +1748,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.3" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki 0.102.2", + "rustls-webpki 0.102.3", "subtle", "zeroize", ] @@ -1774,9 +1787,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.2" +version = "0.102.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" dependencies = [ "ring", "rustls-pki-types", @@ -1821,7 +1834,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ "rand", - "secp256k1-sys", + "secp256k1-sys 0.9.2", + "serde", +] + +[[package]] +name = "secp256k1" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +dependencies = [ + "rand", + "secp256k1-sys 0.10.0", "serde", ] @@ -1834,6 +1858,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +dependencies = [ + "cc", +] + [[package]] name = "secp256k1-zkp" version = "0.10.1" @@ -1842,7 +1875,7 @@ checksum = "c4e48ef9c98bfbcb98bd15693ffa19676cb3e29426b75eda8b73c05cdd7959f8" dependencies = [ "bitcoin-private", "rand", - "secp256k1", + "secp256k1 0.28.2", "secp256k1-zkp-sys", "serde", ] @@ -1854,7 +1887,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ead52f43074bae2ddbd1e0e66e6b170135e76117f5ea9916f33d7bd0b36e29" dependencies = [ "cc", - "secp256k1-sys", + "secp256k1-sys 0.9.2", ] [[package]] @@ -2008,7 +2041,7 @@ dependencies = [ [[package]] name = "single_use_seals" version = "0.11.0-beta.5" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#d32e1af11a599643b235706efd51d0097347f082" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#f51e1e0d010b1531acc939d2443af552e8755bb7" dependencies = [ "amplify_derive", ] @@ -2052,8 +2085,7 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strict_encoding" version = "2.7.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c463f8ea993e323740d78544473e791adb91ac659f5bf2c1a59db64a34f99fc" +source = "git+https://github.com/strict-types/strict-encoding?branch=develop#03d4b8ff346e8582632388c4112585d5cf714a0a" dependencies = [ "amplify", "half", @@ -2064,8 +2096,7 @@ dependencies = [ [[package]] name = "strict_encoding_derive" version = "2.7.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475fa6f1fdde6e0555422b5111ad34bde30a1459af3599f920c3af9829772c0e" +source = "git+https://github.com/strict-types/strict-encoding?branch=develop#03d4b8ff346e8582632388c4112585d5cf714a0a" dependencies = [ "amplify_syn", "heck 0.4.1", @@ -2077,11 +2108,10 @@ dependencies = [ [[package]] name = "strict_types" version = "2.7.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "152bd04284e9093f23a911d0d89b7dd950a461af1ed5e243f6215fbcd45e9445" +source = "git+https://github.com/strict-types/strict-types?branch=develop#acc3a7508c49c34c3344e2dd4359e1ade08fae67" dependencies = [ "amplify", - "ascii-armor", + "ascii-armor 0.3.0", "baid58", "half", "indexmap 2.2.6", @@ -2194,18 +2224,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", @@ -2332,9 +2362,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.9" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ "indexmap 2.2.6", "serde", @@ -2423,9 +2453,9 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.22.3", + "rustls 0.22.4", "rustls-pki-types", - "rustls-webpki 0.102.2", + "rustls-webpki 0.102.3", "serde", "serde_json", "socks", diff --git a/Cargo.toml b/Cargo.toml index 691f01f..d88c7c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,18 +91,20 @@ serde = ["serde_crate", "serde_yaml", "bp-std/serde", "bp-wallet/serde", "descri features = ["all"] [patch.crates-io] +strict_encoding = { git = "https://github.com/strict-types/strict-encoding", branch = "develop" } +strict_types = { git = "https://github.com/strict-types/strict-types", branch = "develop" } commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.11" } single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.11" } -bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } -bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } -bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } -bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "v0.11" } +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 = "v0.11" } bp-std = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "v0.11" } psbt = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } descriptors = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } -aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "v0.11" } -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.11" } -rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "v0.11" } -rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "v0.11" } +aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "develop" } +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "develop" } +rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "develop" } +rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "develop" } diff --git a/cli/src/command.rs b/cli/src/command.rs index f6f4e9e..f060fa1 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -34,7 +34,6 @@ use rgbstd::containers::{ BuilderSeal, ContainerVer, ContentId, ContentSigs, Contract, FileContent, Terminal, Transfer, UniversalFile, }; -use rgbstd::contract::{ContractId, GenesisSeal, GraphSeal, StateType}; use rgbstd::interface::{AmountChange, ContractSuppl, FilterExclude, IfaceId}; use rgbstd::invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet}; use rgbstd::persistence::fs::StoreFs; @@ -42,7 +41,9 @@ use rgbstd::persistence::StashReadProvider; use rgbstd::schema::SchemaId; use rgbstd::validation::Validity; use rgbstd::vm::RgbIsa; -use rgbstd::{BundleId, OutputSeal, XChain, XOutputSeal}; +use rgbstd::{ + BundleId, ContractId, GenesisSeal, GraphSeal, OutputSeal, StateType, XChain, XOutputSeal, +}; use seals::txout::CloseMethod; use serde_crate::{Deserialize, Serialize}; use strict_types::encoding::{FieldName, TypeName}; diff --git a/psbt/src/rgb.rs b/psbt/src/rgb.rs index 49ef4d2..94cb3eb 100644 --- a/psbt/src/rgb.rs +++ b/psbt/src/rgb.rs @@ -27,10 +27,12 @@ use bp::dbc::Method; use bp::seals::txout::CloseMethod; use commit_verify::mpc; use psbt::{KeyAlreadyPresent, KeyMap, MpcPsbtError, PropKey, Psbt}; -use rgbstd::accessors::{MergeReveal, MergeRevealError}; use rgbstd::containers::BundleDichotomy; use rgbstd::interface::VelocityHint; -use rgbstd::{ContractId, InputMap, OpId, Operation, Transition, TransitionBundle, Vin}; +use rgbstd::{ + ContractId, InputMap, MergeReveal, MergeRevealError, OpId, Operation, Transition, + TransitionBundle, Vin, +}; use strict_encoding::{DeserializeError, StrictDeserialize, StrictSerialize}; // TODO: Instead of storing whole RGB contract in PSBT create a shortened From 110d489d1f3ee4cb0ed64d8e24e9f4f40b0fb5ee Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 22 Apr 2024 21:13:19 +0200 Subject: [PATCH 06/32] cli: print contracts by interface standard --- Cargo.lock | 25 +++++++++++++++++++---- Cargo.toml | 2 ++ cli/Cargo.toml | 1 + cli/src/command.rs | 50 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fec365..2db0a11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1583,10 +1583,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "rgb-interfaces" +version = "0.11.0-beta.6" +source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#b8e612752963a366bd890100e3f9633a3100059b" +dependencies = [ + "aluvm", + "amplify", + "bp-core", + "chrono", + "rgb-std", + "serde_json", + "sha2", + "strict_encoding", + "strict_types", +] + [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#0a392e705e1cfd246508021467f2963552d366d7" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#28f9492df5369f7366b325592b1bc7d3171e9a4b" dependencies = [ "amplify", "baid58", @@ -1645,7 +1661,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#0a392e705e1cfd246508021467f2963552d366d7" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#28f9492df5369f7366b325592b1bc7d3171e9a4b" dependencies = [ "aluvm", "amplify", @@ -1681,6 +1697,7 @@ dependencies = [ "env_logger", "log", "psbt", + "rgb-interfaces", "rgb-runtime", "rgb-std", "serde", @@ -1723,9 +1740,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.33" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", diff --git a/Cargo.toml b/Cargo.toml index d88c7c4..4dfc2c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ descriptors = "0.11.0-beta.5" psbt = { version = "0.11.0-beta.5", features = ["client-side-validation"] } rgb-std = { version = "0.11.0-beta.5", features = ["fs"] } rgb-psbt = { version = "0.11.0-beta.5", path = "psbt" } +rgb-interfaces = "0.11.0-beta.5" indexmap = "2.0.2" chrono = "0.4.31" serde_crate = { package = "serde", version = "1", features = ["derive"] } @@ -108,3 +109,4 @@ aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "develop" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "develop" } rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "develop" } rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "develop" } +rgb-interfaces = { git = "https://github.com/RGB-WG/rgb-interfaces", branch = "develop" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 8f8fa82..8ced854 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,6 +27,7 @@ bp-wallet = { workspace = true } bp-util = { workspace = true } psbt = { workspace = true } rgb-std = { workspace = true, features = ["serde"] } +rgb-interfaces = { workspace = true } rgb-runtime = { version = "0.11.0-beta.5", path = "..", features = ["electrum", "esplora_blocking", "log", "serde"] } log = { workspace = true } env_logger = "0.10.1" diff --git a/cli/src/command.rs b/cli/src/command.rs index f060fa1..169eb32 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -28,6 +28,7 @@ use amplify::confinement::{SmallOrdMap, TinyOrdMap, TinyOrdSet, U16 as MAX16}; use baid58::ToBaid58; use bp_util::{BpCommand, Config, Exec}; use bpstd::Sats; +use ifaces::{IfaceStandard, Rgb20, Rgb21, Rgb25}; use psbt::{Psbt, PsbtVer}; use rgb_rt::{DescriptorRgb, RgbKeychain, RuntimeError, TransferParams}; use rgbstd::containers::{ @@ -42,7 +43,8 @@ use rgbstd::schema::SchemaId; use rgbstd::validation::Validity; use rgbstd::vm::RgbIsa; use rgbstd::{ - BundleId, ContractId, GenesisSeal, GraphSeal, OutputSeal, StateType, XChain, XOutputSeal, + BundleId, ContractId, GenesisSeal, GraphSeal, Identity, OutputSeal, StateType, XChain, + XOutputSeal, }; use seals::txout::CloseMethod; use serde_crate::{Deserialize, Serialize}; @@ -67,8 +69,13 @@ pub enum Command { Schemata, /// Prints out list of known RGB interfaces Interfaces, + /// Prints out list of known RGB contracts - Contracts, + #[display("contracts")] + Contracts { + /// Select only contracts using specific interface standard + standard: Option, + }, /// Imports RGB data into the stash: contracts, schema, interfaces, etc #[display("import")] @@ -142,6 +149,9 @@ pub enum Command { /// Schema name to use for the contract schema: SchemaId, //String, + /// Issuer identity string + issuer: Identity, + /// File containing contract genesis description in YAML format contract: PathBuf, }, @@ -328,10 +338,37 @@ impl Exec for RgbArgs { } None } - Command::Contracts => { + Command::Contracts { standard: None } => { + let stock = self.rgb_stock()?; + for info in stock.contracts()? { + println!("{info}"); + } + None + } + Command::Contracts { + standard: Some(IfaceStandard::Rgb20), + } => { + let stock = self.rgb_stock()?; + for info in stock.contracts_by::()? { + println!("{info}"); + } + None + } + Command::Contracts { + standard: Some(IfaceStandard::Rgb21), + } => { + let stock = self.rgb_stock()?; + for info in stock.contracts_by::()? { + println!("{info}"); + } + None + } + Command::Contracts { + standard: Some(IfaceStandard::Rgb25), + } => { let stock = self.rgb_stock()?; - for id in stock.contract_ids()? { - println!("{id}"); + for info in stock.contracts_by::()? { + println!("{info}"); } None } @@ -504,6 +541,7 @@ impl Exec for RgbArgs { } Command::Issue { schema: schema_id, + issuer, contract, } => { let mut stock = self.rgb_stock()?; @@ -537,7 +575,7 @@ impl Exec for RgbArgs { )) })?; - let mut builder = stock.contract_builder(*schema_id, iface_id)?; + let mut builder = stock.contract_builder(issuer.clone(), *schema_id, iface_id)?; let types = builder.type_system().clone(); if let Some(globals) = code.get("globals") { From f79837409cf03875d4d57c43b783bf60f75e602c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 25 Apr 2024 18:16:14 +0200 Subject: [PATCH 07/32] chore: update dependencies to use Baid64 identitfiers --- Cargo.lock | 131 ++++++++++++++++++++------------------------- Cargo.toml | 9 ++-- cli/Cargo.toml | 2 +- cli/src/command.rs | 12 ++--- psbt/Cargo.toml | 4 +- psbt/src/rgb.rs | 3 +- src/runtime.rs | 2 +- 7 files changed, 75 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2db0a11..f57c15e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,11 +29,11 @@ dependencies = [ [[package]] name = "aluvm" version = "0.11.0-beta.5" -source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#3fc2434ee9af51e935b44e5ea682fef933019bda" +source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#d8efe3007a5680a99cf86159b8dcc81cf1ed7278" dependencies = [ "amplify", - "ascii-armor 0.2.0", - "baid58", + "ascii-armor", + "baid64", "blake3", "getrandom", "half", @@ -193,25 +193,11 @@ dependencies = [ [[package]] name = "ascii-armor" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743d90b41a39d6e3920eef64a70f6411097cbb47141606a45b2a96533ec7111c" -dependencies = [ - "amplify", - "baid58", - "base85", - "sha2", - "strict_encoding", -] - -[[package]] -name = "ascii-armor" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44ce552de9efa4fdee1a7920f3587e17689bf4a4ba149a7892f91820673c1e29" +version = "0.4.0" +source = "git+https://github.com/UBIDECO/ascii-armor#38dc9767f36db3957ac3dade280a04d9a72b6be4" dependencies = [ "amplify", - "baid58", + "baid64", "base85", "sha2", "strict_encoding", @@ -239,28 +225,28 @@ dependencies = [ ] [[package]] -name = "baid58" -version = "0.4.4" +name = "baid64" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0585242d87ed976e05db6ae86a0f771f140104a4b6c91b4c3e43b9b2357486" +checksum = "7b8b80494235048845f856b267a4a1d97df59fd14ed7ca92652f834ce93becc6" dependencies = [ - "base58", - "blake3", + "amplify", + "base64 0.22.0", "mnemonic", "sha2", ] [[package]] -name = "base58" -version = "0.2.0" +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.21.7" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" [[package]] name = "base85" @@ -336,7 +322,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" dependencies = [ "amplify", "chrono", @@ -350,7 +336,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" dependencies = [ "amplify", "bp-consensus", @@ -368,7 +354,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" dependencies = [ "amplify", "base85", @@ -443,10 +429,10 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#91e195d45a24c3e5623f0cbe0738ea2fca315bae" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" dependencies = [ "amplify", - "baid58", + "baid64", "bp-consensus", "bp-dbc", "commit_verify", @@ -477,7 +463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecf9b988b0c9536f1b95268b592d5425584527006027c38ed172e85bc71bdd85" dependencies = [ "amplify", - "base64", + "base64 0.21.7", "bp-electrum", "bp-esplora", "bp-std", @@ -618,7 +604,7 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "commit_encoding_derive" version = "0.11.0-beta.5" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#f51e1e0d010b1531acc939d2443af552e8755bb7" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#5e50b251aa5a5c4d83c47dad609a15ef3d50800f" dependencies = [ "amplify", "amplify_syn", @@ -630,7 +616,7 @@ dependencies = [ [[package]] name = "commit_verify" version = "0.11.0-beta.5" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#f51e1e0d010b1531acc939d2443af552e8755bb7" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#5e50b251aa5a5c4d83c47dad609a15ef3d50800f" dependencies = [ "amplify", "commit_encoding_derive", @@ -1430,7 +1416,7 @@ version = "0.11.0-beta.5" source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" dependencies = [ "amplify", - "base64", + "base64 0.21.7", "bp-core", "bp-derive", "chrono", @@ -1526,7 +1512,7 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1564,12 +1550,12 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#648bb45ab4dd4c000e8ba1872a2a7ce47cd2217e" +source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#0d7bbcc45d448b71d6c93beb804a3c7062e6891c" dependencies = [ "aluvm", "amplify", - "ascii-armor 0.2.0", - "baid58", + "ascii-armor", + "baid64", "bp-core", "chrono", "commit_verify", @@ -1586,7 +1572,7 @@ dependencies = [ [[package]] name = "rgb-interfaces" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#b8e612752963a366bd890100e3f9633a3100059b" +source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#33d936693486468d2edffb85b685f3d24c3f2683" dependencies = [ "aluvm", "amplify", @@ -1602,15 +1588,16 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#28f9492df5369f7366b325592b1bc7d3171e9a4b" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#c232cbea40dcd3f2aebaf91e63006108abf64f91" dependencies = [ "amplify", - "baid58", + "baid64", "bp-core", "bp-invoice", "fluent-uri", "indexmap 2.2.6", "percent-encoding", + "rand", "rgb-core", "serde", "strict_encoding", @@ -1622,7 +1609,7 @@ name = "rgb-psbt" version = "0.11.0-beta.5" dependencies = [ "amplify", - "baid58", + "baid64", "bp-core", "bp-std", "commit_verify", @@ -1640,7 +1627,7 @@ name = "rgb-runtime" version = "0.11.0-beta.5" dependencies = [ "amplify", - "baid58", + "baid64", "bp-core", "bp-electrum", "bp-esplora", @@ -1661,12 +1648,12 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#28f9492df5369f7366b325592b1bc7d3171e9a4b" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#c232cbea40dcd3f2aebaf91e63006108abf64f91" dependencies = [ "aluvm", "amplify", - "ascii-armor 0.3.0", - "baid58", + "ascii-armor", + "baid64", "base85", "bp-core", "chrono", @@ -1687,7 +1674,7 @@ name = "rgb-wallet" version = "0.11.0-beta.5" dependencies = [ "amplify", - "baid58", + "baid64", "bp-seals", "bp-std", "bp-util", @@ -1783,14 +1770,14 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] [[package]] name = "rustls-pki-types" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" +checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" [[package]] name = "rustls-webpki" @@ -1994,11 +1981,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" +checksum = "2c85f8e96d1d6857f13768fcbd895fcb06225510022a2774ed8b5150581847b0" dependencies = [ - "base64", + "base64 0.22.0", "chrono", "hex", "indexmap 1.9.3", @@ -2012,9 +1999,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" +checksum = "c8b3a576c4eb2924262d5951a3b737ccaf16c931e39a2810c36f9a7e25575557" dependencies = [ "darling", "proc-macro2", @@ -2058,7 +2045,7 @@ dependencies = [ [[package]] name = "single_use_seals" version = "0.11.0-beta.5" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#f51e1e0d010b1531acc939d2443af552e8755bb7" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#5e50b251aa5a5c4d83c47dad609a15ef3d50800f" dependencies = [ "amplify_derive", ] @@ -2102,7 +2089,7 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strict_encoding" version = "2.7.0-beta.3" -source = "git+https://github.com/strict-types/strict-encoding?branch=develop#03d4b8ff346e8582632388c4112585d5cf714a0a" +source = "git+https://github.com/strict-types/strict-encoding?branch=develop#7fbf31b2bc0f117cba5ae676e46e4ef3656616f5" dependencies = [ "amplify", "half", @@ -2113,7 +2100,7 @@ dependencies = [ [[package]] name = "strict_encoding_derive" version = "2.7.0-beta.3" -source = "git+https://github.com/strict-types/strict-encoding?branch=develop#03d4b8ff346e8582632388c4112585d5cf714a0a" +source = "git+https://github.com/strict-types/strict-encoding?branch=develop#7fbf31b2bc0f117cba5ae676e46e4ef3656616f5" dependencies = [ "amplify_syn", "heck 0.4.1", @@ -2125,11 +2112,11 @@ dependencies = [ [[package]] name = "strict_types" version = "2.7.0-beta.3" -source = "git+https://github.com/strict-types/strict-types?branch=develop#acc3a7508c49c34c3344e2dd4359e1ade08fae67" +source = "git+https://github.com/strict-types/strict-types?branch=develop#a2e860f36f24b477712551a6db349edcf08efb3e" dependencies = [ "amplify", - "ascii-armor 0.3.0", - "baid58", + "ascii-armor", + "baid64", "half", "indexmap 2.2.6", "serde", @@ -2462,11 +2449,11 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.6" +version = "2.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" dependencies = [ - "base64", + "base64 0.22.0", "flate2", "log", "once_cell", @@ -2668,11 +2655,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4dfc2c5..6fb64b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ license = "Apache-2.0" [workspace.dependencies] amplify = "4.6.0" -baid58 = "0.4.4" +baid64 = "0.1.0" commit_verify = "0.11.0-beta.5" strict_encoding = "2.7.0-beta.3" strict_types = "2.7.0-beta.3" @@ -64,7 +64,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] amplify = { workspace = true } -baid58 = { workspace = true } +baid64 = { workspace = true } bp-electrum = { workspace = true, optional = true } commit_verify = { workspace = true } strict_types = { workspace = true } @@ -92,10 +92,11 @@ serde = ["serde_crate", "serde_yaml", "bp-std/serde", "bp-wallet/serde", "descri features = ["all"] [patch.crates-io] +ascii-armor = { git = "https://github.com/UBIDECO/ascii-armor" } strict_encoding = { git = "https://github.com/strict-types/strict-encoding", branch = "develop" } strict_types = { git = "https://github.com/strict-types/strict-types", branch = "develop" } -commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.11" } -single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.11" } +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" } 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" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 8ced854..e85abe0 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -18,7 +18,7 @@ path = "src/main.rs" [dependencies] amplify = { workspace = true } -baid58 = { workspace = true } +baid64 = { workspace = true } strict_types = { workspace = true, features = ["serde"] } commit_verify = { workspace = true } bp-seals = { workspace = true } diff --git a/cli/src/command.rs b/cli/src/command.rs index 169eb32..ef7225e 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -25,17 +25,17 @@ use std::path::PathBuf; use std::str::FromStr; use amplify::confinement::{SmallOrdMap, TinyOrdMap, TinyOrdSet, U16 as MAX16}; -use baid58::ToBaid58; +use baid64::DisplayBaid64; use bp_util::{BpCommand, Config, Exec}; use bpstd::Sats; use ifaces::{IfaceStandard, Rgb20, Rgb21, Rgb25}; use psbt::{Psbt, PsbtVer}; use rgb_rt::{DescriptorRgb, RgbKeychain, RuntimeError, TransferParams}; use rgbstd::containers::{ - BuilderSeal, ContainerVer, ContentId, ContentSigs, Contract, FileContent, Terminal, Transfer, - UniversalFile, + BuilderSeal, ContainerVer, ContentId, ContentSigs, Contract, FileContent, Supplement, Terminal, + Transfer, UniversalFile, }; -use rgbstd::interface::{AmountChange, ContractSuppl, FilterExclude, IfaceId}; +use rgbstd::interface::{AmountChange, FilterExclude, IfaceId}; use rgbstd::invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet}; use rgbstd::persistence::fs::StoreFs; use rgbstd::persistence::StashReadProvider; @@ -814,7 +814,7 @@ impl Exec for RgbArgs { version: ContainerVer, transfer: bool, terminals: SmallOrdMap, - supplements: TinyOrdSet, + supplements: TinyOrdSet, signatures: TinyOrdMap, } @@ -842,7 +842,7 @@ impl Exec for RgbArgs { for lib in consignment.scripts { let mut buf = Vec::new(); lib.print_disassemble::(&mut buf)?; - map.insert(format!("{}.aluasm", lib.id().to_baid58().mnemonic()), unsafe { + map.insert(format!("{}.aluasm", lib.id().to_baid64_mnemonic()), unsafe { String::from_utf8_unchecked(buf) }); } diff --git a/psbt/Cargo.toml b/psbt/Cargo.toml index a2fbf1b..8d81d02 100644 --- a/psbt/Cargo.toml +++ b/psbt/Cargo.toml @@ -18,7 +18,7 @@ crate-type = ["cdylib", "rlib"] # We need this for WASM [dependencies] amplify = { workspace = true } -baid58 = { workspace = true } +baid64 = { workspace = true } commit_verify = { workspace = true } strict_encoding = { workspace = true } bp-core = { workspace = true } @@ -40,4 +40,4 @@ all = ["serde"] serde = ["bp-core/serde", "bp-std/serde", "psbt/serde", "rgb-std/serde"] [package.metadata.docs.rs] -features = [ "all" ] +features = ["all"] diff --git a/psbt/src/rgb.rs b/psbt/src/rgb.rs index 94cb3eb..3029acb 100644 --- a/psbt/src/rgb.rs +++ b/psbt/src/rgb.rs @@ -27,8 +27,7 @@ use bp::dbc::Method; use bp::seals::txout::CloseMethod; use commit_verify::mpc; use psbt::{KeyAlreadyPresent, KeyMap, MpcPsbtError, PropKey, Psbt}; -use rgbstd::containers::BundleDichotomy; -use rgbstd::interface::VelocityHint; +use rgbstd::containers::{BundleDichotomy, VelocityHint}; use rgbstd::{ ContractId, InputMap, MergeReveal, MergeRevealError, OpId, Operation, Transition, TransitionBundle, Vin, diff --git a/src/runtime.rs b/src/runtime.rs index c4b3092..6f32704 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -80,7 +80,7 @@ pub enum RuntimeError { /// invalid identifier. #[from] #[display(doc_comments)] - InvalidId(baid58::Baid58ParseError), + InvalidId(baid64::Baid64ParseError), /// the contract source doesn't fit requirements imposed by the used schema. /// From 0c6f941221f89115eaa4d98fe83bb8271f211db4 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 25 Apr 2024 20:44:36 +0200 Subject: [PATCH 08/32] display debugging --- Cargo.lock | 6 +++--- cli/src/command.rs | 49 +++++++++++++++++++++++++++++----------------- src/runtime.rs | 1 + 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f57c15e..4044d00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1572,7 +1572,7 @@ dependencies = [ [[package]] name = "rgb-interfaces" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#33d936693486468d2edffb85b685f3d24c3f2683" +source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#3068b168163953700661c4afeffebd44088e3d07" dependencies = [ "aluvm", "amplify", @@ -1588,7 +1588,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#c232cbea40dcd3f2aebaf91e63006108abf64f91" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#824a90ef5b897533563bc119d14796ab2bacd5e1" dependencies = [ "amplify", "baid64", @@ -1648,7 +1648,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#c232cbea40dcd3f2aebaf91e63006108abf64f91" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#824a90ef5b897533563bc119d14796ab2bacd5e1" dependencies = [ "aluvm", "amplify", diff --git a/cli/src/command.rs b/cli/src/command.rs index ef7225e..9834266 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -341,7 +341,7 @@ impl Exec for RgbArgs { Command::Contracts { standard: None } => { let stock = self.rgb_stock()?; for info in stock.contracts()? { - println!("{info}"); + print!("{info}"); } None } @@ -350,7 +350,7 @@ impl Exec for RgbArgs { } => { let stock = self.rgb_stock()?; for info in stock.contracts_by::()? { - println!("{info}"); + print!("{info}"); } None } @@ -359,7 +359,7 @@ impl Exec for RgbArgs { } => { let stock = self.rgb_stock()?; for info in stock.contracts_by::()? { - println!("{info}"); + print!("{info}"); } None } @@ -368,7 +368,7 @@ impl Exec for RgbArgs { } => { let stock = self.rgb_stock()?; for info in stock.contracts_by::()? { - println!("{info}"); + print!("{info}"); } None } @@ -419,18 +419,18 @@ impl Exec for RgbArgs { match content { UniversalFile::Kit(kit) => { let id = kit.kit_id(); - eprintln!("Importing kit {id}"); + eprintln!("Importing kit {id}:"); let mut iface_names = map![]; let mut schema_names = map![]; for iface in &kit.ifaces { let iface_id = iface.iface_id(); iface_names.insert(iface_id, &iface.name); - eprintln!("- Interface {} {}", iface.name, iface_id); + eprintln!("- interface {} {:-}", iface.name, iface_id); } for schema in &kit.schemata { let schema_id = schema.schema_id(); schema_names.insert(schema_id, &schema.name); - eprintln!("- Schema {} {}", schema.name, schema_id); + eprintln!("- schema {} {:-}", schema.name, schema_id); } for iimpl in &kit.iimpls { let iface = iface_names @@ -441,24 +441,30 @@ impl Exec for RgbArgs { .get(&iimpl.schema_id) .map(|name| name.to_string()) .unwrap_or_else(|| iimpl.schema_id.to_string()); - eprintln!("- Implementation of {iface} for {schema}",); + eprintln!("- implementation of {iface} for {schema}",); } for lib in &kit.scripts { - eprintln!("- AluVM library {}", lib.id()); + eprintln!("- script library {}", lib.id()); } - eprintln!("- Strict types: {} definitions", kit.types.len()); + eprintln!("- strict types: {} definitions", kit.types.len()); let kit = kit.validate().map_err(|(status, _)| status.to_string())?; stock.import_kit(kit)?; eprintln!("Kit is imported"); } UniversalFile::Contract(contract) => { - let mut resolver = self.resolver()?; let id = contract.consignment_id(); + eprintln!("Importing consignment {id}:"); + let mut resolver = self.resolver()?; + eprint!("- validating the contract {} ... ", contract.contract_id()); let contract = contract .validate(&mut resolver, self.general.network.is_testnet()) - .map_err(|(status, _)| status.to_string())?; + .map_err(|(status, _)| { + eprintln!("failure"); + status.to_string() + })?; + eprintln!("success"); stock.import_contract(contract, &mut resolver)?; - eprintln!("Contract {id} is imported"); + eprintln!("Consignment is imported"); } UniversalFile::Transfer(_) => { return Err(s!("use `validate` and `accept` commands to work with \ @@ -912,6 +918,7 @@ impl Exec for RgbArgs { fs::create_dir_all(format!("{root_dir}/stash/bundles"))?; fs::create_dir_all(format!("{root_dir}/stash/witnesses"))?; fs::create_dir_all(format!("{root_dir}/stash/extensions"))?; + fs::create_dir_all(format!("{root_dir}/stash/supplements"))?; fs::create_dir_all(format!("{root_dir}/state"))?; fs::create_dir_all(format!("{root_dir}/index"))?; @@ -919,7 +926,7 @@ impl Exec for RgbArgs { for (id, schema_ifaces) in stock.as_stash_provider().debug_schemata() { fs::write( format!( - "{root_dir}/stash/schemata/{}.{id:-}.yaml", + "{root_dir}/stash/schemata/{}.{id:-#}.yaml", schema_ifaces.schema.name ), serde_yaml::to_string(&schema_ifaces)?, @@ -927,7 +934,7 @@ impl Exec for RgbArgs { } for (id, iface) in stock.as_stash_provider().debug_ifaces() { fs::write( - format!("{root_dir}/stash/ifaces/{}.{id:-}.yaml", iface.name), + format!("{root_dir}/stash/ifaces/{}.{id:-#}.yaml", iface.name), serde_yaml::to_string(stock.iface(*id)?)?, )?; } @@ -950,22 +957,28 @@ impl Exec for RgbArgs { } for (id, bundle) in stock.as_stash_provider().debug_bundles() { fs::write( - format!("{root_dir}/stash/bundles/{id:-}.yaml"), + format!("{root_dir}/stash/bundles/{id}.yaml"), serde_yaml::to_string(bundle)?, )?; } for (id, witness) in stock.as_stash_provider().debug_witnesses() { fs::write( - format!("{root_dir}/stash/witnesses/{id:-}.yaml"), + format!("{root_dir}/stash/witnesses/{id}.yaml"), serde_yaml::to_string(witness)?, )?; } for (id, extension) in stock.as_stash_provider().debug_extensions() { fs::write( - format!("{root_dir}/stash/extensions/{id:-}.yaml"), + format!("{root_dir}/stash/extensions/{id}.yaml"), serde_yaml::to_string(extension)?, )?; } + for (id, suppl) in stock.as_stash_provider().debug_suppl() { + fs::write( + format!("{root_dir}/stash/supplements/{id:#}.yaml"), + serde_yaml::to_string(suppl)?, + )?; + } fs::write( format!("{root_dir}/stash/seal-secret.yaml"), serde_yaml::to_string(stock.as_stash_provider().debug_secret_seals())?, diff --git a/src/runtime.rs b/src/runtime.rs index 6f32704..cd83441 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -187,6 +187,7 @@ where let stock = Stock::default(); std::fs::create_dir_all(stock_path)?; stock.store(stock_path)?; + eprintln!("success"); return Ok(stock) } eprintln!("stock file is damaged"); From 71f86e1a1729ffc92217054ab8019c4207a1ed47 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 26 Apr 2024 22:45:21 +0200 Subject: [PATCH 09/32] chore: update dependencies --- Cargo.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4044d00..aa9205e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,7 +390,7 @@ dependencies = [ "byteorder", "libc", "log", - "rustls 0.21.11", + "rustls 0.21.12", "serde", "serde_json", "sha2", @@ -834,9 +834,9 @@ checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" dependencies = [ "crc32fast", "miniz_oxide", @@ -1572,7 +1572,7 @@ dependencies = [ [[package]] name = "rgb-interfaces" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#3068b168163953700661c4afeffebd44088e3d07" +source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#69d86f16dc61f48c95bb3977b4f93dc8f1292892" dependencies = [ "aluvm", "amplify", @@ -1588,7 +1588,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#824a90ef5b897533563bc119d14796ab2bacd5e1" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#cef39a08e3586b59973c1eae038e15f898814be4" dependencies = [ "amplify", "baid64", @@ -1648,7 +1648,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#824a90ef5b897533563bc119d14796ab2bacd5e1" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#cef39a08e3586b59973c1eae038e15f898814be4" dependencies = [ "aluvm", "amplify", @@ -1740,9 +1740,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.11" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", @@ -2089,7 +2089,7 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strict_encoding" version = "2.7.0-beta.3" -source = "git+https://github.com/strict-types/strict-encoding?branch=develop#7fbf31b2bc0f117cba5ae676e46e4ef3656616f5" +source = "git+https://github.com/strict-types/strict-encoding?branch=develop#901e26ee8b01b3bcff4d7ac76acff2fcc633634b" dependencies = [ "amplify", "half", @@ -2100,7 +2100,7 @@ dependencies = [ [[package]] name = "strict_encoding_derive" version = "2.7.0-beta.3" -source = "git+https://github.com/strict-types/strict-encoding?branch=develop#7fbf31b2bc0f117cba5ae676e46e4ef3656616f5" +source = "git+https://github.com/strict-types/strict-encoding?branch=develop#901e26ee8b01b3bcff4d7ac76acff2fcc633634b" dependencies = [ "amplify_syn", "heck 0.4.1", @@ -2818,9 +2818,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" dependencies = [ "memchr", ] From de32d18bb5fb47e7aa5bd861eef6a0543dd071ee Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 16:22:40 +0200 Subject: [PATCH 10/32] refactor: decouple BP wallet from runtime via traits --- Cargo.lock | 65 +++++++------------------- Cargo.toml | 26 +++++------ cli/Cargo.toml | 3 +- cli/src/args.rs | 16 +++---- cli/src/command.rs | 4 +- cli/src/main.rs | 8 +++- src/descriptor.rs | 35 +++++++------- src/lib.rs | 2 + src/pay.rs | 14 ++++-- src/runtime.rs | 112 ++++++++++++++++++++++++--------------------- src/wallet.rs | 59 ++++++++++++++++++++++++ 11 files changed, 195 insertions(+), 149 deletions(-) create mode 100644 src/wallet.rs diff --git a/Cargo.lock b/Cargo.lock index aa9205e..6f6204f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,7 +194,8 @@ dependencies = [ [[package]] name = "ascii-armor" version = "0.4.0" -source = "git+https://github.com/UBIDECO/ascii-armor#38dc9767f36db3957ac3dade280a04d9a72b6be4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f438560a7273569cd4ab8fcf227d0490c1ff01f7cba5e004791752ae8f96091" dependencies = [ "amplify", "baid64", @@ -368,7 +369,7 @@ dependencies = [ [[package]] name = "bp-derive" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" dependencies = [ "amplify", "bitcoin_hashes", @@ -417,7 +418,7 @@ dependencies = [ [[package]] name = "bp-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" dependencies = [ "amplify", "bech32", @@ -445,7 +446,7 @@ dependencies = [ [[package]] name = "bp-std" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" dependencies = [ "amplify", "bp-consensus", @@ -457,48 +458,28 @@ dependencies = [ ] [[package]] -name = "bp-util" +name = "bp-wallet" version = "0.11.0-beta.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecf9b988b0c9536f1b95268b592d5425584527006027c38ed172e85bc71bdd85" +source = "git+https://github.com/BP-WG/bp-wallet?branch=develop#db23c6a1a1e5f7060b68f20c6329abb1377195eb" dependencies = [ "amplify", "base64 0.21.7", "bp-electrum", "bp-esplora", "bp-std", - "bp-wallet", "clap", "descriptors", "env_logger", "log", "psbt", "serde", + "serde_json", "serde_yaml", "shellexpand", "strict_encoding", "toml", ] -[[package]] -name = "bp-wallet" -version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-wallet?branch=v0.11#e05f6c75a1a150851a4b08fcec74f02230de6bb1" -dependencies = [ - "amplify", - "bp-electrum", - "bp-esplora", - "bp-std", - "cfg_eval", - "descriptors", - "psbt", - "serde", - "serde_json", - "serde_with", - "serde_yaml", - "toml", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -529,17 +510,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_eval" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "chrono" version = "0.4.38" @@ -743,7 +713,7 @@ dependencies = [ [[package]] name = "descriptors" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" dependencies = [ "amplify", "bp-derive", @@ -828,9 +798,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "flate2" @@ -1413,7 +1383,7 @@ dependencies = [ [[package]] name = "psbt" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#6741b11d42e92557ae884b7d5208013f0314807f" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" dependencies = [ "amplify", "base64 0.21.7", @@ -1572,7 +1542,7 @@ dependencies = [ [[package]] name = "rgb-interfaces" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#69d86f16dc61f48c95bb3977b4f93dc8f1292892" +source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#eb10305796ca3efbf92e0b3c171c6996d7461120" dependencies = [ "aluvm", "amplify", @@ -1677,7 +1647,6 @@ dependencies = [ "baid64", "bp-seals", "bp-std", - "bp-util", "bp-wallet", "clap", "commit_verify", @@ -1919,18 +1888,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.199" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 6fb64b9..accea3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,12 +29,11 @@ strict_types = "2.7.0-beta.3" bp-core = "0.11.0-beta.5" bp-seals = "0.11.0-beta.5" bp-std = "0.11.0-beta.5" -bp-wallet = "0.11.0-beta.5" -bp-util = "0.11.0-beta.5" bp-electrum = "0.11.0-beta.5" bp-esplora = "0.11.0-beta.5" descriptors = "0.11.0-beta.5" psbt = { version = "0.11.0-beta.5", features = ["client-side-validation"] } +bp-wallet = { version = "0.11.0-beta.5" } rgb-std = { version = "0.11.0-beta.5", features = ["fs"] } rgb-psbt = { version = "0.11.0-beta.5", path = "psbt" } rgb-interfaces = "0.11.0-beta.5" @@ -70,9 +69,9 @@ commit_verify = { workspace = true } strict_types = { workspace = true } bp-core = { workspace = true } bp-std = { workspace = true } -bp-wallet = { workspace = true, features = ["fs"] } bp-esplora = { workspace = true, optional = true } descriptors = { workspace = true } +bp-wallet = { workspace = true } rgb-std = { workspace = true } rgb-psbt = { workspace = true } indexmap = { workspace = true } @@ -83,16 +82,16 @@ log = { workspace = true, optional = true } [features] default = ["esplora_blocking"] -all = ["esplora_blocking", "electrum", "serde", "log"] -esplora_blocking = ["bp-esplora", "bp-wallet/esplora"] -electrum = ["bp-electrum", "bp-wallet/electrum"] -serde = ["serde_crate", "serde_yaml", "bp-std/serde", "bp-wallet/serde", "descriptors/serde", "rgb-psbt/serde"] +all = ["esplora_blocking", "electrum", "serde", "log", "fs"] +fs = ["serde", "bp-wallet/fs"] +esplora_blocking = ["bp-esplora"] +electrum = ["bp-electrum"] +serde = ["serde_crate", "serde_yaml", "bp-std/serde", "descriptors/serde", "rgb-psbt/serde"] [package.metadata.docs.rs] features = ["all"] [patch.crates-io] -ascii-armor = { git = "https://github.com/UBIDECO/ascii-armor" } strict_encoding = { git = "https://github.com/strict-types/strict-encoding", branch = "develop" } strict_types = { git = "https://github.com/strict-types/strict-types", branch = "develop" } commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } @@ -101,11 +100,12 @@ 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 = "v0.11" } -bp-std = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } -bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "v0.11" } -psbt = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } -descriptors = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } +bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } +bp-derive = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } +bp-std = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } +bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "develop" } +psbt = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } +descriptors = { git = "https://github.com/BP-WG/bp-std", branch = "develop" } aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "develop" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "develop" } rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "develop" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index e85abe0..92b1718 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -23,8 +23,7 @@ strict_types = { workspace = true, features = ["serde"] } commit_verify = { workspace = true } bp-seals = { workspace = true } bp-std = { workspace = true, features = ["serde"] } -bp-wallet = { workspace = true } -bp-util = { workspace = true } +bp-wallet = { workspace = true, features = ["cli"] } psbt = { workspace = true } rgb-std = { workspace = true, features = ["serde"] } rgb-interfaces = { workspace = true } diff --git a/cli/src/args.rs b/cli/src/args.rs index 9f58066..5e0ba9b 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -21,15 +21,15 @@ #![allow(clippy::needless_update)] // Caused by the From derivation macro -use bp_util::{Config, DescriptorOpts}; use bpstd::{Wpkh, XpubDerivable}; +use bpwallet::cli::{Args as BpArgs, Config, DescriptorOpts}; use rgb_rt::{ electrum, esplora_blocking, AnyResolver, AnyResolverError, RgbDescr, Runtime, RuntimeError, TapretKey, }; use rgbstd::persistence::Stock; -use crate::Command; +use crate::{CliRuntime, Command}; #[derive(Args, Clone, PartialEq, Eq, Debug)] #[group()] @@ -65,7 +65,7 @@ impl DescriptorOpts for DescrRgbOpts { #[command(author, version, about)] pub struct RgbArgs { #[clap(flatten)] - pub inner: bp_util::Args, + pub inner: BpArgs, } impl Default for RgbArgs { @@ -77,7 +77,7 @@ impl RgbArgs { if self.verbose > 2 { eprint!("Loading stock ... "); } - let runtime = Runtime::::load_walletless(&self.general.base_dir())?; + let runtime = CliRuntime::load_walletless(&self.general.base_dir())?; if self.verbose > 2 { eprintln!("success"); } @@ -85,12 +85,12 @@ impl RgbArgs { Ok(runtime) } - pub fn rgb_runtime(&self, config: &Config) -> Result { - let bprt = self.inner.bp_runtime::(config)?; + pub fn rgb_runtime(&self, config: &Config) -> Result { + let wallet = self.inner.bp_runtime::(config)?.detach(); if self.verbose > 2 { eprint!("Loading stock ... "); } - let runtime = Runtime::::load_attach(self.general.base_dir(), bprt)?; + let runtime = Runtime::load_attach(self.general.base_dir(), wallet)?; if self.verbose > 2 { eprintln!("success"); } @@ -100,7 +100,7 @@ impl RgbArgs { #[allow(clippy::result_large_err)] pub fn resolver(&self) -> Result { - if self.resolver.electrum != bp_util::DEFAULT_ELECTRUM { + if self.resolver.electrum != bpwallet::cli::DEFAULT_ELECTRUM { match electrum::Resolver::new(&self.resolver.electrum) { Ok(c) => Ok(AnyResolver::Electrum(Box::new(c))), Err(e) => Err(AnyResolverError::Electrum(e)), diff --git a/cli/src/command.rs b/cli/src/command.rs index 9834266..f743c51 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -26,8 +26,8 @@ use std::str::FromStr; use amplify::confinement::{SmallOrdMap, TinyOrdMap, TinyOrdSet, U16 as MAX16}; use baid64::DisplayBaid64; -use bp_util::{BpCommand, Config, Exec}; use bpstd::Sats; +use bpwallet::cli::{BpCommand, Config, Exec}; use ifaces::{IfaceStandard, Rgb20, Rgb21, Rgb25}; use psbt::{Psbt, PsbtVer}; use rgb_rt::{DescriptorRgb, RgbKeychain, RuntimeError, TransferParams}; @@ -59,7 +59,7 @@ use crate::RgbArgs; pub enum Command { #[clap(flatten)] #[display(inner)] - General(bp_util::Command), + General(bpwallet::cli::Command), #[clap(flatten)] #[display(inner)] diff --git a/cli/src/main.rs b/cli/src/main.rs index bebf6c8..6add484 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -34,13 +34,17 @@ mod args; use std::process::ExitCode; -use bp_util::{Config, Exec, LogLevel}; +use bpstd::XpubDerivable; +use bpwallet::cli::{Config, Exec, LogLevel}; +use bpwallet::Wallet; use clap::Parser; -use rgb_rt::RuntimeError; +use rgb_rt::{RgbDescr, Runtime, RuntimeError}; pub use crate::args::RgbArgs; pub use crate::command::Command; +pub type CliRuntime = Runtime>; + fn main() -> ExitCode { if let Err(err) = run() { eprintln!("Error: {err}"); diff --git a/src/descriptor.rs b/src/descriptor.rs index 609ad25..13ac0b8 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -20,8 +20,8 @@ // limitations under the License. use std::collections::{BTreeSet, HashMap}; +use std::iter; use std::str::FromStr; -use std::{iter, vec}; use amplify::Wrapper; use bp::dbc::tapret::TapretCommitment; @@ -182,15 +182,17 @@ impl From> for TapretKey { } impl Descriptor for TapretKey { - type KeyIter<'k> = iter::Once<&'k K> where Self: 'k, K: 'k; - type VarIter<'v> = iter::Empty<&'v ()> where Self: 'v, (): 'v; - type XpubIter<'x> = iter::Once<&'x XpubSpec> where Self: 'x; - fn class(&self) -> SpkClass { SpkClass::P2tr } - fn keys(&self) -> Self::KeyIter<'_> { iter::once(&self.internal_key) } - fn vars(&self) -> Self::VarIter<'_> { iter::empty() } - fn xpubs(&self) -> Self::XpubIter<'_> { iter::once(self.internal_key.xpub_spec()) } + fn keys<'a>(&'a self) -> impl Iterator + where K: 'a { + iter::once(&self.internal_key) + } + fn vars<'a>(&'a self) -> impl Iterator + where (): 'a { + iter::empty() + } + fn xpubs(&self) -> impl Iterator { iter::once(self.internal_key.xpub_spec()) } fn compr_keyset(&self, _terminal: Terminal) -> IndexMap { IndexMap::new() @@ -273,10 +275,6 @@ impl Derive for RgbDescr { impl + DeriveCompr + DeriveXOnly> Descriptor for RgbDescr where Self: Derive { - type KeyIter<'k> = vec::IntoIter<&'k K> where Self: 'k, K: 'k; - type VarIter<'v> = iter::Empty<&'v ()> where Self: 'v, (): 'v; - type XpubIter<'x> = vec::IntoIter<&'x XpubSpec> where Self: 'x; - fn class(&self) -> SpkClass { match self { RgbDescr::Wpkh(d) => d.class(), @@ -284,7 +282,8 @@ where Self: Derive } } - fn keys(&self) -> Self::KeyIter<'_> { + fn keys<'a>(&'a self) -> impl Iterator + where K: 'a { match self { RgbDescr::Wpkh(d) => d.keys().collect::>(), RgbDescr::TapretKey(d) => d.keys().collect::>(), @@ -292,14 +291,12 @@ where Self: Derive .into_iter() } - fn vars(&self) -> Self::VarIter<'_> { - match self { - RgbDescr::Wpkh(d) => d.vars(), - RgbDescr::TapretKey(d) => d.vars(), - } + fn vars<'a>(&'a self) -> impl Iterator + where (): 'a { + iter::empty() } - fn xpubs(&self) -> Self::XpubIter<'_> { + fn xpubs<'a>(&'a self) -> impl Iterator { match self { RgbDescr::Wpkh(d) => d.xpubs().collect::>(), RgbDescr::TapretKey(d) => d.xpubs().collect::>(), diff --git a/src/lib.rs b/src/lib.rs index 891c873..27f808f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,9 +29,11 @@ mod runtime; mod descriptor; mod pay; mod resolvers; +mod wallet; pub use descriptor::{DescriptorRgb, RgbDescr, RgbKeychain, TapTweakAlreadyAssigned, TapretKey}; pub use pay::{CompletionError, CompositionError, PayError, TransferParams}; #[cfg(any(feature = "electrum", feature = "esplora_blocking"))] pub use resolvers::*; pub use runtime::{ContractOutpointsFilter, Runtime, RuntimeError}; +pub use wallet::{Persisting, WalletProvider}; diff --git a/src/pay.rs b/src/pay.rs index 788eed1..2817ae6 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -25,8 +25,10 @@ use bp::dbc::tapret::TapretProof; use bp::seals::txout::{CloseMethod, ExplicitSeal}; use bp::{Outpoint, Sats, ScriptPubkey, Vout}; use bpstd::Address; -use bpwallet::{Beneficiary as BpBeneficiary, ConstructionError, PsbtMeta, TxParams}; -use psbt::{CommitError, EmbedError, Psbt, RgbPsbt, TapretKeyError}; +use psbt::{ + Beneficiary as BpBeneficiary, CommitError, ConstructionError, EmbedError, Psbt, PsbtMeta, + RgbPsbt, TapretKeyError, TxParams, +}; use rgbstd::containers::Transfer; use rgbstd::interface::ContractError; use rgbstd::invoice::{Amount, Beneficiary, InvoiceState, RgbInvoice}; @@ -38,6 +40,7 @@ use rgbstd::XChain; use crate::{ ContractOutpointsFilter, DescriptorRgb, RgbKeychain, Runtime, TapTweakAlreadyAssigned, + WalletProvider, }; #[derive(Debug, Display, Error, From)] @@ -147,7 +150,9 @@ impl TransferParams { } } -impl Runtime { +impl> Runtime +where W::Descr: DescriptorRgb +{ #[allow(clippy::result_large_err)] pub fn pay( &mut self, @@ -315,6 +320,7 @@ impl Runtime { .ok_or(CompletionError::InconclusiveDerivation)?; let tapret_commitment = output.tapret_commitment()?; self.wallet_mut() + .descriptor_mut() .add_tapret_tweak(terminal, tapret_commitment)?; } @@ -327,7 +333,7 @@ impl Runtime { .position(|output| output.script == s) .ok_or(CompletionError::NoBeneficiaryOutput)?; let vout = Vout::from_u32(vout as u32); - let method = self.wallet().seal_close_method(); + let method = self.wallet().descriptor().seal_close_method(); let seal = XChain::Bitcoin(ExplicitSeal::new(method, Outpoint::new(witness_txid, vout))); (vec![], vec![seal]) diff --git a/src/runtime.rs b/src/runtime.rs index cd83441..54528d8 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -24,12 +24,12 @@ use std::collections::HashMap; use std::convert::Infallible; use std::io; +use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::path::PathBuf; use amplify::IoError; use bpstd::{Network, XpubDerivable}; -use bpwallet::Wallet; use rgbstd::containers::LoadError; use rgbstd::interface::{ AmountChange, BuilderError, ContractError, IfaceOp, IfaceRef, OutpointFilter, WitnessFilter, @@ -40,7 +40,7 @@ use rgbstd::validation::{self}; use rgbstd::{AssignmentWitness, ContractId, XChain, XOutpoint, XWitnessId}; use strict_types::encoding::{DeserializeError, Ident, SerializeError}; -use crate::{DescriptorRgb, RgbDescr}; +use super::{DescriptorRgb, Persisting, WalletProvider}; #[derive(Debug, Display, Error, From)] #[display(inner)] @@ -117,49 +117,63 @@ impl From for RuntimeError { } #[derive(Getters)] -pub struct Runtime = RgbDescr, K = XpubDerivable> { +pub struct Runtime, K = XpubDerivable> +where W::Descr: DescriptorRgb +{ stock_path: PathBuf, #[getter(as_mut)] - // TODO: Parametrize by the stock stock: Stock, - bprt: bpwallet::Runtime, + #[getter(as_mut)] + wallet: W, + _phantom: PhantomData, } -impl, K> Deref for Runtime { +impl> Deref for Runtime +where W::Descr: DescriptorRgb +{ type Target = Stock; fn deref(&self) -> &Self::Target { &self.stock } } -impl, K> DerefMut for Runtime { +impl> DerefMut for Runtime +where W::Descr: DescriptorRgb +{ fn deref_mut(&mut self) -> &mut Self::Target { &mut self.stock } } -impl, K> OutpointFilter for Runtime { +impl> OutpointFilter for Runtime +where W::Descr: DescriptorRgb +{ fn include_outpoint(&self, output: impl Into) -> bool { let output = output.into(); - self.wallet() - .coins() - .any(|utxo| XChain::Bitcoin(utxo.outpoint) == *output) + self.wallet + .outpoints() + .any(|outpoint| XChain::Bitcoin(outpoint) == *output) } } -impl, K> WitnessFilter for Runtime { +impl> WitnessFilter for Runtime +where W::Descr: DescriptorRgb +{ fn include_witness(&self, witness: impl Into) -> bool { let witness = witness.into(); self.wallet() - .transactions() - .keys() - .any(|txid| AssignmentWitness::Present(XWitnessId::Bitcoin(*txid)) == witness) + .txids() + .any(|txid| AssignmentWitness::Present(XWitnessId::Bitcoin(txid)) == witness) } } -pub struct ContractOutpointsFilter<'runtime, D: DescriptorRgb, K> { +pub struct ContractOutpointsFilter<'runtime, K, W: WalletProvider> +where W::Descr: DescriptorRgb +{ pub contract_id: ContractId, - pub filter: &'runtime Runtime, + pub filter: &'runtime Runtime, } -impl<'runtime, D: DescriptorRgb, K> OutpointFilter for ContractOutpointsFilter<'runtime, D, K> { +impl<'runtime, K, W: WalletProvider> OutpointFilter for ContractOutpointsFilter<'runtime, K, W> +where W::Descr: DescriptorRgb +{ fn include_outpoint(&self, output: impl Into) -> bool { let output = output.into(); if !self.filter.include_outpoint(output) { @@ -170,10 +184,35 @@ impl<'runtime, D: DescriptorRgb, K> OutpointFilter for ContractOutpointsFilte } #[cfg(feature = "serde")] -impl, K> Runtime +impl> Runtime where - for<'de> D: serde::Serialize + serde::Deserialize<'de>, - for<'de> bpwallet::WalletDescr: serde::Serialize + serde::Deserialize<'de>, + W::Descr: DescriptorRgb, + W: Persisting, +{ + pub fn load_attach(stock_path: PathBuf, wallet: W) -> Result { + let stock = Self::load_walletless(&stock_path)?; + Ok(Self { + stock_path, + stock, + wallet, + _phantom: PhantomData, + }) + } + + pub fn store(&mut self) { + self.stock + .store(&self.stock_path) + .expect("unable to save stock"); + self.wallet + .try_store(&self.stock_path) + .expect("unable to save wallet data"); + } + + pub fn into_stock(self) -> Stock { self.stock } +} + +impl> Runtime +where W::Descr: DescriptorRgb { pub fn load_walletless(stock_path: &PathBuf) -> Result { use std::io::ErrorKind; @@ -195,36 +234,7 @@ where }) } - pub fn load_attach( - stock_path: PathBuf, - bprt: bpwallet::Runtime, - ) -> Result { - let stock = Self::load_walletless(&stock_path)?; - Ok(Self { - stock_path, - stock, - bprt, - }) - } - - pub fn store(&mut self) { - self.stock - .store(&self.stock_path) - .expect("unable to save stock"); - self.bprt.try_store().expect("unable to save wallet data"); - } - - pub fn into_stock(self) -> Stock { self.stock } -} - -impl, K> Runtime { - pub fn wallet(&self) -> &Wallet { self.bprt.wallet() } - - pub fn wallet_mut(&mut self) -> &mut Wallet { self.bprt.wallet_mut() } - - pub fn attach(&mut self, bprt: bpwallet::Runtime) { self.bprt = bprt } - - pub fn network(&self) -> Network { self.bprt.network() } + pub fn network(&self) -> Network { self.wallet.network() } // TODO: Integrate into BP Wallet `TxRow` as L2 and provide transactional info pub fn fungible_history( diff --git a/src/wallet.rs b/src/wallet.rs new file mode 100644 index 0000000..06e02b7 --- /dev/null +++ b/src/wallet.rs @@ -0,0 +1,59 @@ +// RGB wallet library for smart contracts on Bitcoin & Lightning network +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::error::Error; +use std::ops::DerefMut; +use std::path::Path; + +use bp::{Outpoint, Txid}; +use bpwallet::{Wallet, WalletDescr}; +use psbt::PsbtConstructor; + +use crate::DescriptorRgb; + +pub trait Persisting { + fn try_store(&self, path: &Path) -> Result<(), impl Error>; +} + +pub trait WalletProvider: PsbtConstructor +where Self::Descr: DescriptorRgb +{ + fn descriptor_mut(&mut self) -> &mut Self::Descr; + fn outpoints(&self) -> impl Iterator; + fn txids(&self) -> impl Iterator; +} + +#[cfg(feature = "fs")] +impl> Persisting for Wallet +where + for<'de> WalletDescr: serde::Serialize + serde::Deserialize<'de>, + for<'de> D: serde::Serialize + serde::Deserialize<'de>, +{ + fn try_store(&self, path: &Path) -> Result<(), impl Error> { self.store(path) } +} + +impl> WalletProvider for Wallet { + fn descriptor_mut(&mut self) -> &mut Self::Descr { self.deref_mut() } + + fn outpoints(&self) -> impl Iterator { self.coins().map(|coin| coin.outpoint) } + + fn txids(&self) -> impl Iterator { self.transactions().keys().copied() } +} From 42067ee890dd783ff9a451968fd21210c9617b2e Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 16:40:20 +0200 Subject: [PATCH 11/32] chore: rename rgb_rt into rgb --- Cargo.toml | 2 +- cli/src/args.rs | 2 +- cli/src/command.rs | 23 +++++++++++------------ cli/src/main.rs | 2 +- src/lib.rs | 2 ++ 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index accea3f..1640842 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ edition.workspace = true license.workspace = true [lib] -name = "rgb_rt" +name = "rgb" crate-type = ["cdylib", "rlib"] [dependencies] diff --git a/cli/src/args.rs b/cli/src/args.rs index 5e0ba9b..d98d695 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -23,7 +23,7 @@ use bpstd::{Wpkh, XpubDerivable}; use bpwallet::cli::{Args as BpArgs, Config, DescriptorOpts}; -use rgb_rt::{ +use rgb::{ electrum, esplora_blocking, AnyResolver, AnyResolverError, RgbDescr, Runtime, RuntimeError, TapretKey, }; diff --git a/cli/src/command.rs b/cli/src/command.rs index f743c51..760a9fb 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -30,21 +30,20 @@ use bpstd::Sats; use bpwallet::cli::{BpCommand, Config, Exec}; use ifaces::{IfaceStandard, Rgb20, Rgb21, Rgb25}; use psbt::{Psbt, PsbtVer}; -use rgb_rt::{DescriptorRgb, RgbKeychain, RuntimeError, TransferParams}; -use rgbstd::containers::{ +use rgb::containers::{ BuilderSeal, ContainerVer, ContentId, ContentSigs, Contract, FileContent, Supplement, Terminal, Transfer, UniversalFile, }; -use rgbstd::interface::{AmountChange, FilterExclude, IfaceId}; -use rgbstd::invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet}; -use rgbstd::persistence::fs::StoreFs; -use rgbstd::persistence::StashReadProvider; -use rgbstd::schema::SchemaId; -use rgbstd::validation::Validity; -use rgbstd::vm::RgbIsa; -use rgbstd::{ - BundleId, ContractId, GenesisSeal, GraphSeal, Identity, OutputSeal, StateType, XChain, - XOutputSeal, +use rgb::interface::{AmountChange, FilterExclude, IfaceId}; +use rgb::invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet}; +use rgb::persistence::fs::StoreFs; +use rgb::persistence::StashReadProvider; +use rgb::schema::SchemaId; +use rgb::validation::Validity; +use rgb::vm::RgbIsa; +use rgb::{ + BundleId, ContractId, DescriptorRgb, GenesisSeal, GraphSeal, Identity, OutputSeal, RgbKeychain, + RuntimeError, StateType, TransferParams, XChain, XOutputSeal, }; use seals::txout::CloseMethod; use serde_crate::{Deserialize, Serialize}; diff --git a/cli/src/main.rs b/cli/src/main.rs index 6add484..2ef979b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -38,7 +38,7 @@ use bpstd::XpubDerivable; use bpwallet::cli::{Config, Exec, LogLevel}; use bpwallet::Wallet; use clap::Parser; -use rgb_rt::{RgbDescr, Runtime, RuntimeError}; +use rgb::{RgbDescr, Runtime, RuntimeError}; pub use crate::args::RgbArgs; pub use crate::command::Command; diff --git a/src/lib.rs b/src/lib.rs index 27f808f..6cda078 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ extern crate serde_crate as serde; mod runtime; mod descriptor; mod pay; +#[allow(hidden_glob_reexports)] mod resolvers; mod wallet; @@ -35,5 +36,6 @@ pub use descriptor::{DescriptorRgb, RgbDescr, RgbKeychain, TapTweakAlreadyAssign pub use pay::{CompletionError, CompositionError, PayError, TransferParams}; #[cfg(any(feature = "electrum", feature = "esplora_blocking"))] pub use resolvers::*; +pub use rgbstd::*; pub use runtime::{ContractOutpointsFilter, Runtime, RuntimeError}; pub use wallet::{Persisting, WalletProvider}; From d29f3e7aa5a37407d5e81c37e5b57eab6c28b8f2 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 16:42:30 +0200 Subject: [PATCH 12/32] chore: fix psbt lib name conflict --- psbt/Cargo.toml | 2 +- src/pay.rs | 4 ++-- src/runtime.rs | 2 +- src/wallet.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/psbt/Cargo.toml b/psbt/Cargo.toml index 8d81d02..90b7712 100644 --- a/psbt/Cargo.toml +++ b/psbt/Cargo.toml @@ -13,7 +13,7 @@ rust-version = { workspace = true } readme = "../README.md" [lib] -name = "psbt" +name = "psrgbt" crate-type = ["cdylib", "rlib"] # We need this for WASM [dependencies] diff --git a/src/pay.rs b/src/pay.rs index 2817ae6..e249d6e 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -24,8 +24,8 @@ use std::collections::{BTreeMap, BTreeSet}; use bp::dbc::tapret::TapretProof; use bp::seals::txout::{CloseMethod, ExplicitSeal}; use bp::{Outpoint, Sats, ScriptPubkey, Vout}; -use bpstd::Address; -use psbt::{ +use bpstd::{psbt, Address}; +use psrgbt::{ Beneficiary as BpBeneficiary, CommitError, ConstructionError, EmbedError, Psbt, PsbtMeta, RgbPsbt, TapretKeyError, TxParams, }; diff --git a/src/runtime.rs b/src/runtime.rs index 54528d8..f98ad25 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -68,7 +68,7 @@ pub enum RuntimeError { Contract(ContractError), #[from] - PsbtDecode(psbt::DecodeError), + PsbtDecode(psrgbt::DecodeError), /// wallet with id '{0}' is not known to the system. #[display(doc_comments)] diff --git a/src/wallet.rs b/src/wallet.rs index 06e02b7..8058b2a 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -25,7 +25,7 @@ use std::path::Path; use bp::{Outpoint, Txid}; use bpwallet::{Wallet, WalletDescr}; -use psbt::PsbtConstructor; +use psrgbt::PsbtConstructor; use crate::DescriptorRgb; From 762df872074aaa9d5f207d3a58ed964561f518b4 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 21:13:44 +0200 Subject: [PATCH 13/32] refactoring and optimization --- cli/src/args.rs | 55 +++++---- cli/src/command.rs | 115 +++++++------------ cli/src/main.rs | 8 +- src/errors.rs | 215 +++++++++++++++++++++++++++++++++++ src/lib.rs | 14 ++- src/pay.rs | 212 +++++++++++++++------------------- src/runtime.rs | 275 --------------------------------------------- src/store.rs | 181 +++++++++++++++++++++++++++++ src/wallet.rs | 96 +++++++++++----- 9 files changed, 641 insertions(+), 530 deletions(-) create mode 100644 src/errors.rs delete mode 100644 src/runtime.rs create mode 100644 src/store.rs diff --git a/cli/src/args.rs b/cli/src/args.rs index d98d695..40b75dc 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -19,17 +19,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![allow(clippy::needless_update)] // Caused by the From derivation macro - use bpstd::{Wpkh, XpubDerivable}; use bpwallet::cli::{Args as BpArgs, Config, DescriptorOpts}; +use bpwallet::Wallet; use rgb::{ - electrum, esplora_blocking, AnyResolver, AnyResolverError, RgbDescr, Runtime, RuntimeError, - TapretKey, + electrum, esplora_blocking, AnyResolver, AnyResolverError, RgbDescr, StoredWallet, TapretKey, + WalletError, }; +use rgbstd::persistence::fs::{LoadFs, StoreFs}; use rgbstd::persistence::Stock; +use strict_types::encoding::DeserializeError; -use crate::{CliRuntime, Command}; +use crate::Command; #[derive(Args, Clone, PartialEq, Eq, Debug)] #[group()] @@ -73,29 +74,43 @@ impl Default for RgbArgs { } impl RgbArgs { - pub fn rgb_stock(&self) -> Result { + pub fn rgb_stock(&self) -> Result { if self.verbose > 2 { eprint!("Loading stock ... "); } - let runtime = CliRuntime::load_walletless(&self.general.base_dir())?; - if self.verbose > 2 { - eprintln!("success"); - } + use std::io::ErrorKind; + + use strict_types::encoding::DecodeError; + + let stock_path = self.general.base_dir(); + let stock = Stock::load(&stock_path).map_err(WalletError::from).or_else(|err| { + if matches!(err, WalletError::Deserialize(DeserializeError::Decode(DecodeError::Io(ref err))) if err.kind() == ErrorKind::NotFound) { + #[cfg(feature = "log")] + eprint!("stock file is absent, creating a new one ... "); + let stock = Stock::default(); + std::fs::create_dir_all(&stock_path)?; + stock.store(&stock_path)?; + if self.verbose > 2 { + eprintln!("success"); + } + return Ok(stock) + } + eprintln!("stock file is damaged, failing"); + Err(err) + })?; - Ok(runtime) + Ok(stock) } - pub fn rgb_runtime(&self, config: &Config) -> Result { + pub fn rgb_wallet( + &self, + config: &Config, + ) -> Result>, WalletError> { + let stock = self.rgb_stock()?; let wallet = self.inner.bp_runtime::(config)?.detach(); - if self.verbose > 2 { - eprint!("Loading stock ... "); - } - let runtime = Runtime::load_attach(self.general.base_dir(), wallet)?; - if self.verbose > 2 { - eprintln!("success"); - } + let wallet = StoredWallet::attach(self.general.base_dir(), stock, wallet); - Ok(runtime) + Ok(wallet) } #[allow(clippy::result_large_err)] diff --git a/cli/src/command.rs b/cli/src/command.rs index 760a9fb..97b93a0 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -36,14 +36,13 @@ use rgb::containers::{ }; use rgb::interface::{AmountChange, FilterExclude, IfaceId}; use rgb::invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet}; -use rgb::persistence::fs::StoreFs; use rgb::persistence::StashReadProvider; use rgb::schema::SchemaId; use rgb::validation::Validity; use rgb::vm::RgbIsa; use rgb::{ BundleId, ContractId, DescriptorRgb, GenesisSeal, GraphSeal, Identity, OutputSeal, RgbKeychain, - RuntimeError, StateType, TransferParams, XChain, XOutputSeal, + StateType, TransferParams, WalletError, WalletProvider, XChain, XOutputSeal, }; use seals::txout::CloseMethod; use serde_crate::{Deserialize, Serialize}; @@ -199,8 +198,9 @@ pub enum Command { psbt: Option, }, - /// Prepare consignment for transferring RGB assets. In the most of cases - /// you need to use `transfer` command instead of `prepare` and `consign`. + /// Prepare consignment for transferring RGB assets. In the most of the + /// cases you need to use `transfer` command instead of `prepare` and + /// `consign`. #[display("prepare")] Consign { /// Invoice data @@ -307,42 +307,46 @@ pub enum DebugCommand { } impl Exec for RgbArgs { - type Error = RuntimeError; + type Error = WalletError; const CONF_FILE_NAME: &'static str = "rgb.toml"; - fn exec(self, config: Config, _name: &'static str) -> Result<(), RuntimeError> { - if let Some(stock) = match &self.command { + fn exec(self, config: Config, _name: &'static str) -> Result<(), WalletError> { + match &self.command { Command::General(cmd) => { self.inner.translate(cmd).exec(config, "rgb")?; - None } + Command::Utxos => { + self.inner + .translate(&BpCommand::Balance { + addr: true, + utxo: true, + }) + .exec(config, "rgb")?; + } + Command::Debug(DebugCommand::Taprets) => { let stock = self.rgb_stock()?; for (witness_id, tapret) in stock.as_stash_provider().taprets()? { println!("{witness_id}\t{tapret}"); } - None } Command::Schemata => { let stock = self.rgb_stock()?; for info in stock.schemata()? { print!("{info}"); } - None } Command::Interfaces => { let stock = self.rgb_stock()?; for info in stock.ifaces()? { print!("{info}"); } - None } Command::Contracts { standard: None } => { let stock = self.rgb_stock()?; for info in stock.contracts()? { print!("{info}"); } - None } Command::Contracts { standard: Some(IfaceStandard::Rgb20), @@ -351,7 +355,6 @@ impl Exec for RgbArgs { for info in stock.contracts_by::()? { print!("{info}"); } - None } Command::Contracts { standard: Some(IfaceStandard::Rgb21), @@ -360,7 +363,6 @@ impl Exec for RgbArgs { for info in stock.contracts_by::()? { print!("{info}"); } - None } Command::Contracts { standard: Some(IfaceStandard::Rgb25), @@ -369,23 +371,12 @@ impl Exec for RgbArgs { for info in stock.contracts_by::()? { print!("{info}"); } - None - } - - Command::Utxos => { - self.inner - .translate(&BpCommand::Balance { - addr: true, - utxo: true, - }) - .exec(config, "rgb")?; - None } Command::HistoryFungible { contract_id, iface } => { - let runtime = self.rgb_runtime(&config)?; + let wallet = self.rgb_wallet(&config)?; let iface: TypeName = tn!(iface.clone()); - let history = runtime.fungible_history(*contract_id, iface)?; + let history = wallet.fungible_history(*contract_id, iface)?; println!("Amount\tCounterparty\tWitness Id"); for (id, op) in history { let (cparty, more) = match op.state_change { @@ -407,7 +398,6 @@ impl Exec for RgbArgs { .unwrap_or_else(|| s!("none")); println!("{}\t{}{}\t{}", op.state_change, cparty, more, id); } - None } Command::Import { armored, file } => { @@ -471,7 +461,6 @@ impl Exec for RgbArgs { .into()); } } - Some(stock) } Command::Export { armored: _, @@ -489,13 +478,11 @@ impl Exec for RgbArgs { } else { println!("{contract}"); } - None } Command::Armor { file } => { let content = UniversalFile::load_file(file)?; println!("{content}"); - None } Command::State { @@ -503,10 +490,11 @@ impl Exec for RgbArgs { iface, all, } => { - let runtime = self.rgb_runtime(&config)?; + let wallet = self.rgb_wallet(&config)?; - let iface = runtime.iface(tn!(iface.to_owned()))?.clone(); - let contract = runtime.contract_iface(*contract_id, iface.iface_id())?; + let contract = wallet + .stock() + .contract_iface(*contract_id, tn!(iface.to_owned()))?; println!("Global:"); for global in &contract.iface.global_state { @@ -520,7 +508,9 @@ impl Exec for RgbArgs { println!("\nOwned:"); for owned in &contract.iface.assignments { println!(" {}:", owned.name); - if let Ok(allocations) = contract.fungible(owned.name.clone(), &runtime) { + if let Ok(allocations) = + contract.fungible(owned.name.clone(), wallet.wallet().filter()) + { for allocation in allocations { println!( " amount={}, utxo={}, witness={} # owned by the wallet", @@ -529,8 +519,8 @@ impl Exec for RgbArgs { } } if *all { - if let Ok(allocations) = - contract.fungible(owned.name.clone(), &FilterExclude(&runtime)) + if let Ok(allocations) = contract + .fungible(owned.name.clone(), &FilterExclude(wallet.wallet().filter())) { for allocation in allocations { println!( @@ -542,7 +532,6 @@ impl Exec for RgbArgs { } // TODO: Print out other types of state } - None } Command::Issue { schema: schema_id, @@ -570,12 +559,12 @@ impl Exec for RgbArgs { .iface(iface_name.clone()) .or_else(|_| { let id = IfaceId::from_str(iface_name.as_str())?; - stock.iface(id).map_err(RuntimeError::from) + stock.iface(id).map_err(WalletError::from) })? .clone(); let iface_id = iface.iface_id(); let iface_impl = schema_ifaces.get(iface_id).ok_or_else(|| { - RuntimeError::Custom(format!( + WalletError::Custom(format!( "no known interface implementation for {iface_name}" )) })?; @@ -679,7 +668,6 @@ impl Exec for RgbArgs { "A new contract {id} is issued and added to the stash.\nUse `export` command \ to export the contract." ); - Some(stock) } Command::Invoice { address_based, @@ -687,24 +675,24 @@ impl Exec for RgbArgs { iface, value, } => { - let mut runtime = self.rgb_runtime(&config)?; + let mut wallet = self.rgb_wallet(&config)?; let iface = TypeName::try_from(iface.to_owned()).expect("invalid interface name"); - let outpoint = runtime + let outpoint = wallet .wallet() .coinselect(Sats::ZERO, |utxo| { RgbKeychain::contains_rgb(utxo.terminal.keychain) }) .next(); - let network = runtime.wallet().network(); + let network = wallet.wallet().network(); let beneficiary = match (address_based, outpoint) { (false, None) => { - return Err(RuntimeError::Custom(s!( + return Err(WalletError::Custom(s!( "blinded invoice requested but no suitable outpoint is available" ))); } (true, _) => { - let addr = runtime + let addr = wallet .wallet() .addresses(RgbKeychain::Rgb) .next() @@ -714,11 +702,11 @@ impl Exec for RgbArgs { } (_, Some(outpoint)) => { let seal = XChain::Bitcoin(GraphSeal::new_random( - runtime.wallet().seal_close_method(), + wallet.wallet().seal_close_method(), outpoint.txid, outpoint.vout, )); - runtime.store_secret_seal(seal)?; + wallet.stock_mut().store_secret_seal(seal)?; Beneficiary::BlindedSeal(*seal.to_secret_seal().as_reduced_unsafe()) } }; @@ -728,8 +716,6 @@ impl Exec for RgbArgs { .set_amount_raw(*value) .finish(); println!("{invoice}"); - runtime.store(); - None } Command::Prepare { v2, @@ -739,11 +725,11 @@ impl Exec for RgbArgs { sats, psbt: psbt_file, } => { - let mut runtime = self.rgb_runtime(&config)?; + let mut wallet = self.rgb_wallet(&config)?; // TODO: Support lock time and RBFs let params = TransferParams::with(*fee, *sats); - let (psbt, _) = runtime + let (psbt, _) = wallet .construct_psbt(invoice, *method, params) .map_err(|err| err.to_string())?; @@ -758,25 +744,21 @@ impl Exec for RgbArgs { PsbtVer::V2 => println!("{psbt:#}"), }, } - runtime.store(); - None } Command::Consign { invoice, psbt: psbt_name, consignment: out_file, } => { - let mut runtime = self.rgb_runtime(&config)?; + let mut wallet = self.rgb_wallet(&config)?; let mut psbt_file = File::open(psbt_name)?; let mut psbt = Psbt::decode(&mut psbt_file)?; - let transfer = runtime + let transfer = wallet .transfer(invoice, &mut psbt) .map_err(|err| err.to_string())?; let mut psbt_file = File::create(psbt_name)?; psbt.encode(psbt.version, &mut psbt_file)?; transfer.save_file(out_file)?; - runtime.store(); - None } Command::Transfer { v2, @@ -787,11 +769,11 @@ impl Exec for RgbArgs { psbt: psbt_file, consignment: out_file, } => { - let mut runtime = self.rgb_runtime(&config)?; + let mut wallet = self.rgb_wallet(&config)?; // TODO: Support lock time and RBFs let params = TransferParams::with(*fee, *sats); - let (psbt, _, transfer) = runtime + let (psbt, _, transfer) = wallet .pay(invoice, *method, params) .map_err(|err| err.to_string())?; @@ -808,8 +790,6 @@ impl Exec for RgbArgs { PsbtVer::V2 => println!("{psbt:#}"), }, } - runtime.store(); - None } Command::Inspect { file, dir, path } => { #[derive(Clone, Debug)] @@ -875,7 +855,6 @@ impl Exec for RgbArgs { fs::write(format!("{}/{file}", path.display()), value)?; } } - None } Command::Reconstruct { contract: false, @@ -890,7 +869,6 @@ impl Exec for RgbArgs { transfer.save_file(dst)?; } } - None } Command::Reconstruct { contract: true, @@ -905,7 +883,6 @@ impl Exec for RgbArgs { contract.save_file(dst)?; } } - None } Command::Dump { root_dir } => { let stock = self.rgb_stock()?; @@ -1014,7 +991,6 @@ impl Exec for RgbArgs { serde_yaml::to_string(stock.as_index_provider().debug_terminal_index())?, )?; eprintln!("Dump is successfully generated and saved to '{root_dir}'"); - None } Command::Validate { file } => { let mut resolver = self.resolver()?; @@ -1030,7 +1006,6 @@ impl Exec for RgbArgs { } else { eprintln!("{status}"); } - None } Command::Accept { force: _, file } => { // TODO: Ensure we properly handle unmined terminal transactions @@ -1043,14 +1018,8 @@ impl Exec for RgbArgs { .map_err(|(status, _)| status)?; stock.accept_transfer(valid, &mut resolver)?; eprintln!("Transfer accepted into the stash"); - Some(stock) } - } { - stock - .store(self.general.base_dir()) - .expect("unable to save stock"); } - println!(); Ok(()) diff --git a/cli/src/main.rs b/cli/src/main.rs index 2ef979b..8475d3a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -34,17 +34,13 @@ mod args; use std::process::ExitCode; -use bpstd::XpubDerivable; use bpwallet::cli::{Config, Exec, LogLevel}; -use bpwallet::Wallet; use clap::Parser; -use rgb::{RgbDescr, Runtime, RuntimeError}; +use rgb::WalletError; pub use crate::args::RgbArgs; pub use crate::command::Command; -pub type CliRuntime = Runtime>; - fn main() -> ExitCode { if let Err(err) = run() { eprintln!("Error: {err}"); @@ -54,7 +50,7 @@ fn main() -> ExitCode { } } -fn run() -> Result<(), RuntimeError> { +fn run() -> Result<(), WalletError> { let mut args = RgbArgs::parse(); args.process(); LogLevel::from_verbosity_flag_count(args.verbose).apply(); diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..134b52c --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,215 @@ +// RGB wallet library for smart contracts on Bitcoin & Lightning network +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::result_large_err)] + +use std::convert::Infallible; +use std::io; + +use amplify::IoError; +use psrgbt::{CommitError, ConstructionError, EmbedError, TapretKeyError}; +use rgbstd::containers::LoadError; +use rgbstd::interface::{BuilderError, ContractError}; +use rgbstd::persistence::{ + ComposeError, ConsignError, ContractIfaceError, FasciaError, StockError, StockErrorAll, + StockErrorMem, +}; +use strict_types::encoding::{DeserializeError, Ident, SerializeError}; + +use crate::{validation, TapTweakAlreadyAssigned}; + +#[derive(Debug, Display, Error, From)] +#[display(inner)] +pub enum WalletError { + #[from] + #[from(io::Error)] + Io(IoError), + + #[from] + Serialize(SerializeError), + + #[from] + Deserialize(DeserializeError), + + #[from] + Load(LoadError), + + #[from] + Builder(BuilderError), + + #[from] + History(HistoryError), + + #[from] + Contract(ContractError), + + #[from] + PsbtDecode(psrgbt::DecodeError), + + /// wallet with id '{0}' is not known to the system. + #[display(doc_comments)] + WalletUnknown(Ident), + + #[from] + InvalidConsignment(validation::Status), + + /// invalid identifier. + #[from] + #[display(doc_comments)] + InvalidId(baid64::Baid64ParseError), + + /// the contract source doesn't fit requirements imposed by the used schema. + /// + /// {0} + #[display(doc_comments)] + IncompleteContract(validation::Status), + + #[from] + #[from(bpwallet::LoadError)] + Bp(bpwallet::RuntimeError), + + /// resolver error: {0} + #[cfg(any(feature = "electrum", feature = "esplora_blocking"))] + #[from] + #[display(doc_comments)] + ResolverError(crate::AnyResolverError), + + #[from(StockError)] + #[from(StockErrorAll)] + #[from(StockErrorMem)] + #[display(inner)] + Stock(String), + + #[cfg(feature = "serde_yaml")] + #[from] + Yaml(serde_yaml::Error), + + #[from] + Custom(String), +} + +impl From for WalletError { + fn from(_: Infallible) -> Self { unreachable!() } +} + +#[derive(Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum HistoryError { + /// interface doesn't define default operation + NoDefaultOp, + /// default operation defined by the interface is not a state transition + DefaultOpNotTransition, + /// interface doesn't define default fungible state + NoDefaultAssignment, +} + +#[derive(Debug, Display, Error, From)] +#[display(inner)] +pub enum PayError { + #[from] + Composition(CompositionError), + + #[from] + Completion(CompletionError), +} + +#[derive(Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum CompositionError { + /// unspecified contract. + NoContract, + + /// unspecified interface. + NoIface, + + /// invoice doesn't provide information about the operation, and the used + /// interface do not define default operation. + NoOperation, + + /// invoice doesn't provide information about the assignment type, and the + /// used interface do not define default assignment type. + NoAssignment, + + /// state provided via PSBT inputs is not sufficient to cover invoice state + /// requirements. + InsufficientState, + + /// the invoice has expired. + InvoiceExpired, + + /// one of the RGB assignments spent require presence of tapret output - + /// even this is not a taproot wallet. Unable to create a valid PSBT, manual + /// work is needed. + TapretRequired, + + /// non-fungible state is not yet supported by the invoices. + Unsupported, + + #[from] + #[display(inner)] + Construction(ConstructionError), + + #[from] + #[display(inner)] + Interface(ContractError), + + #[from] + #[display(inner)] + Embed(EmbedError), + + #[from(String)] + #[from(StockError)] + #[from(StockErrorMem)] + #[from(StockErrorMem)] + #[display(inner)] + Stock(String), +} + +#[derive(Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum CompletionError { + /// unspecified contract. + NoContract, + + /// the provided PSBT doesn't pay any sats to the RGB beneficiary address. + NoBeneficiaryOutput, + + /// the provided PSBT has conflicting descriptor in the taptweak output. + InconclusiveDerivation, + + #[from] + #[display(inner)] + MultipleTweaks(TapTweakAlreadyAssigned), + + #[from] + #[display(inner)] + TapretKey(TapretKeyError), + + #[from] + #[display(inner)] + Commit(CommitError), + + #[from(String)] + #[from(StockErrorMem)] + #[from(StockErrorMem)] + #[display(inner)] + Stock(String), +} diff --git a/src/lib.rs b/src/lib.rs index 6cda078..2368e2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,17 +25,21 @@ extern crate amplify; #[macro_use] extern crate serde_crate as serde; -mod runtime; mod descriptor; -mod pay; #[allow(hidden_glob_reexports)] mod resolvers; mod wallet; +pub mod pay; +mod errors; +#[cfg(feature = "fs")] +mod store; pub use descriptor::{DescriptorRgb, RgbDescr, RgbKeychain, TapTweakAlreadyAssigned, TapretKey}; -pub use pay::{CompletionError, CompositionError, PayError, TransferParams}; +pub use errors::{CompletionError, CompositionError, HistoryError, PayError, WalletError}; +pub use pay::{TransferParams, WalletProvider}; #[cfg(any(feature = "electrum", feature = "esplora_blocking"))] pub use resolvers::*; pub use rgbstd::*; -pub use runtime::{ContractOutpointsFilter, Runtime, RuntimeError}; -pub use wallet::{Persisting, WalletProvider}; +#[cfg(feature = "fs")] +pub use store::StoredWallet; +pub use wallet::{WalletStock, WalletWrapper}; diff --git a/src/pay.rs b/src/pay.rs index e249d6e..f93fbcb 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -20,120 +20,26 @@ // limitations under the License. use std::collections::{BTreeMap, BTreeSet}; +use std::marker::PhantomData; +use std::ops::DerefMut; use bp::dbc::tapret::TapretProof; use bp::seals::txout::{CloseMethod, ExplicitSeal}; use bp::{Outpoint, Sats, ScriptPubkey, Vout}; use bpstd::{psbt, Address}; +use bpwallet::Wallet; use psrgbt::{ - Beneficiary as BpBeneficiary, CommitError, ConstructionError, EmbedError, Psbt, PsbtMeta, - RgbPsbt, TapretKeyError, TxParams, + Beneficiary as BpBeneficiary, Psbt, PsbtConstructor, PsbtMeta, RgbPsbt, TapretKeyError, + TxParams, }; use rgbstd::containers::Transfer; -use rgbstd::interface::ContractError; +use rgbstd::interface::{OutpointFilter, WitnessFilter}; use rgbstd::invoice::{Amount, Beneficiary, InvoiceState, RgbInvoice}; -use rgbstd::persistence::{ - ComposeError, ConsignError, ContractIfaceError, FasciaError, StockError, StockErrorAll, - StockErrorMem, -}; -use rgbstd::XChain; - -use crate::{ - ContractOutpointsFilter, DescriptorRgb, RgbKeychain, Runtime, TapTweakAlreadyAssigned, - WalletProvider, -}; - -#[derive(Debug, Display, Error, From)] -#[display(inner)] -pub enum PayError { - #[from] - Composition(CompositionError), - - #[from] - Completion(CompletionError), -} - -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum CompositionError { - /// unspecified contract. - NoContract, - - /// unspecified interface. - NoIface, - - /// invoice doesn't provide information about the operation, and the used - /// interface do not define default operation. - NoOperation, - - /// invoice doesn't provide information about the assignment type, and the - /// used interface do not define default assignment type. - NoAssignment, - - /// state provided via PSBT inputs is not sufficient to cover invoice state - /// requirements. - InsufficientState, - - /// the invoice has expired. - InvoiceExpired, - - /// one of the RGB assignments spent require presence of tapret output - - /// even this is not a taproot wallet. Unable to create a valid PSBT, manual - /// work is needed. - TapretRequired, - - /// non-fungible state is not yet supported by the invoices. - Unsupported, - - #[from] - #[display(inner)] - Construction(ConstructionError), - - #[from] - #[display(inner)] - Interface(ContractError), - - #[from] - #[display(inner)] - Embed(EmbedError), - - #[from] - #[from(StockError)] - #[from(StockErrorMem)] - #[from(StockErrorMem)] - #[display(inner)] - Stock(StockErrorAll), -} +use rgbstd::persistence::{IndexProvider, StashProvider, StateProvider, Stock}; +use rgbstd::{ContractId, XChain, XOutpoint}; -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum CompletionError { - /// unspecified contract. - NoContract, - - /// the provided PSBT doesn't pay any sats to the RGB beneficiary address. - NoBeneficiaryOutput, - - /// the provided PSBT has conflicting descriptor in the taptweak output. - InconclusiveDerivation, - - #[from] - #[display(inner)] - MultipleTweaks(TapTweakAlreadyAssigned), - - #[from] - #[display(inner)] - TapretKey(TapretKeyError), - - #[from] - #[display(inner)] - Commit(CommitError), - - #[from(StockErrorMem)] - #[from(StockErrorMem)] - #[display(inner)] - Stock(StockErrorAll), -} +use crate::wallet::WalletWrapper; +use crate::{CompletionError, CompositionError, DescriptorRgb, PayError, RgbKeychain, Txid}; #[derive(Clone, PartialEq, Debug)] pub struct TransferParams { @@ -150,25 +56,71 @@ impl TransferParams { } } -impl> Runtime +struct ContractOutpointsFilter< + 'stock, + 'wallet, + W: WalletProvider + ?Sized, + K, + S: StashProvider, + H: StateProvider, + P: IndexProvider, +> where W::Descr: DescriptorRgb +{ + contract_id: ContractId, + stock: &'stock Stock, + wallet: &'wallet W, + _phantom: PhantomData, +} + +impl< + 'a, + 'stock, + 'wallet, + W: WalletProvider + ?Sized, + K, + S: StashProvider, + H: StateProvider, + P: IndexProvider, +> OutpointFilter for ContractOutpointsFilter<'stock, 'wallet, W, K, S, H, P> where W::Descr: DescriptorRgb { + fn include_outpoint(&self, output: impl Into) -> bool { + let output = output.into(); + if !self.wallet.filter().include_outpoint(output) { + return false; + } + matches!(self.stock.contract_assignments_for(self.contract_id, [output]), Ok(list) if !list.is_empty()) + } +} + +pub trait WalletProvider: PsbtConstructor +where Self::Descr: DescriptorRgb +{ + type Filter<'a>: Copy + WitnessFilter + OutpointFilter + where Self: 'a; + fn filter(&self) -> Self::Filter<'_>; + fn descriptor_mut(&mut self) -> &mut Self::Descr; + fn outpoints(&self) -> impl Iterator; + fn txids(&self) -> impl Iterator; + #[allow(clippy::result_large_err)] - pub fn pay( + fn pay( &mut self, + stock: &mut Stock, invoice: &RgbInvoice, method: CloseMethod, params: TransferParams, ) -> Result<(Psbt, PsbtMeta, Transfer), PayError> { - let (mut psbt, meta) = self.construct_psbt(invoice, method, params)?; + let (mut psbt, meta) = self.construct_psbt_rgb(stock, invoice, method, params)?; // ... here we pass PSBT around signers, if necessary - let transfer = self.transfer(invoice, &mut psbt)?; + let transfer = self.transfer(stock, invoice, &mut psbt)?; Ok((psbt, meta, transfer)) } #[allow(clippy::result_large_err)] - pub fn construct_psbt( + fn construct_psbt_rgb( &mut self, + stock: &Stock, invoice: &RgbInvoice, method: CloseMethod, mut params: TransferParams, @@ -176,8 +128,10 @@ where W::Descr: DescriptorRgb let contract_id = invoice.contract.ok_or(CompositionError::NoContract)?; let iface_name = invoice.iface.clone().ok_or(CompositionError::NoIface)?; - let iface = self.stock().iface(iface_name.clone())?; - let contract = self.contract_iface(contract_id, iface_name)?; + let iface = stock.iface(iface_name.clone()).map_err(|e| e.to_string())?; + let contract = stock + .contract_iface(contract_id, iface_name) + .map_err(|e| e.to_string())?; let operation = invoice .operation .as_ref() @@ -200,7 +154,9 @@ where W::Descr: DescriptorRgb InvoiceState::Amount(amount) => { let filter = ContractOutpointsFilter { contract_id, - filter: self, + stock, + wallet: self, + _phantom: PhantomData, }; let state: BTreeMap<_, Vec> = contract .fungible(assignment_name, &filter)? @@ -246,8 +202,7 @@ where W::Descr: DescriptorRgb .map(|o| Outpoint::new(o.txid, o.vout)); params.tx.change_keychain = RgbKeychain::for_method(method).into(); let (mut psbt, mut meta) = - self.wallet_mut() - .construct_psbt(prev_outpoints, &beneficiaries, params.tx)?; + self.construct_psbt(prev_outpoints, &beneficiaries, params.tx)?; let beneficiary_script = if let Beneficiary::WitnessVout(addr) = invoice.beneficiary.into_inner() { @@ -288,8 +243,9 @@ where W::Descr: DescriptorRgb } Beneficiary::BlindedSeal(_) => None, }; - let batch = self - .compose(invoice, prev_outputs, method, beneficiary_vout, |_, _, _| meta.change_vout)?; + let batch = stock + .compose(invoice, prev_outputs, method, beneficiary_vout, |_, _, _| meta.change_vout) + .map_err(|e| e.to_string())?; let methods = batch.close_method_set(); if methods.has_opret_first() { @@ -303,8 +259,9 @@ where W::Descr: DescriptorRgb } #[allow(clippy::result_large_err)] - pub fn transfer( + fn transfer( &mut self, + stock: &mut Stock, invoice: &RgbInvoice, psbt: &mut Psbt, ) -> Result { @@ -319,8 +276,7 @@ where W::Descr: DescriptorRgb .terminal_derivation() .ok_or(CompletionError::InconclusiveDerivation)?; let tapret_commitment = output.tapret_commitment()?; - self.wallet_mut() - .descriptor_mut() + self.descriptor_mut() .add_tapret_tweak(terminal, tapret_commitment)?; } @@ -333,7 +289,7 @@ where W::Descr: DescriptorRgb .position(|output| output.script == s) .ok_or(CompletionError::NoBeneficiaryOutput)?; let vout = Vout::from_u32(vout as u32); - let method = self.wallet().descriptor().seal_close_method(); + let method = self.descriptor().seal_close_method(); let seal = XChain::Bitcoin(ExplicitSeal::new(method, Outpoint::new(witness_txid, vout))); (vec![], vec![seal]) @@ -341,11 +297,19 @@ where W::Descr: DescriptorRgb Beneficiary::BlindedSeal(seal) => (vec![XChain::Bitcoin(seal)], vec![]), }; - self.stock_mut().consume_fascia(fascia)?; - let transfer = self - .stock() - .transfer(contract_id, beneficiary2, beneficiary1)?; + stock.consume_fascia(fascia).map_err(|e| e.to_string())?; + let transfer = stock + .transfer(contract_id, beneficiary2, beneficiary1) + .map_err(|e| e.to_string())?; Ok(transfer) } } + +impl> WalletProvider for Wallet { + type Filter<'a> = WalletWrapper<'a, K, D> where Self: 'a; + fn filter(&self) -> Self::Filter<'_> { WalletWrapper(self) } + fn descriptor_mut(&mut self) -> &mut Self::Descr { self.deref_mut() } + fn outpoints(&self) -> impl Iterator { self.coins().map(|coin| coin.outpoint) } + fn txids(&self) -> impl Iterator { self.transactions().keys().copied() } +} diff --git a/src/runtime.rs b/src/runtime.rs deleted file mode 100644 index f98ad25..0000000 --- a/src/runtime.rs +++ /dev/null @@ -1,275 +0,0 @@ -// RGB wallet library for smart contracts on Bitcoin & Lightning network -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2023 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::result_large_err)] - -use std::collections::HashMap; -use std::convert::Infallible; -use std::io; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use std::path::PathBuf; - -use amplify::IoError; -use bpstd::{Network, XpubDerivable}; -use rgbstd::containers::LoadError; -use rgbstd::interface::{ - AmountChange, BuilderError, ContractError, IfaceOp, IfaceRef, OutpointFilter, WitnessFilter, -}; -use rgbstd::persistence::fs::{LoadFs, StoreFs}; -use rgbstd::persistence::{ContractIfaceError, Stock, StockError, StockErrorAll, StockErrorMem}; -use rgbstd::validation::{self}; -use rgbstd::{AssignmentWitness, ContractId, XChain, XOutpoint, XWitnessId}; -use strict_types::encoding::{DeserializeError, Ident, SerializeError}; - -use super::{DescriptorRgb, Persisting, WalletProvider}; - -#[derive(Debug, Display, Error, From)] -#[display(inner)] -pub enum RuntimeError { - #[from] - #[from(io::Error)] - Io(IoError), - - #[from] - Serialize(SerializeError), - - #[from] - Deserialize(DeserializeError), - - #[from] - Load(LoadError), - - #[from] - Builder(BuilderError), - - #[from] - History(HistoryError), - - #[from] - Contract(ContractError), - - #[from] - PsbtDecode(psrgbt::DecodeError), - - /// wallet with id '{0}' is not known to the system. - #[display(doc_comments)] - WalletUnknown(Ident), - - #[from] - InvalidConsignment(validation::Status), - - /// invalid identifier. - #[from] - #[display(doc_comments)] - InvalidId(baid64::Baid64ParseError), - - /// the contract source doesn't fit requirements imposed by the used schema. - /// - /// {0} - #[display(doc_comments)] - IncompleteContract(validation::Status), - - #[from] - #[from(bpwallet::LoadError)] - Bp(bpwallet::RuntimeError), - - /// resolver error: {0} - #[cfg(any(feature = "electrum", feature = "esplora_blocking"))] - #[from] - #[display(doc_comments)] - ResolverError(crate::AnyResolverError), - - #[from] - #[from(StockError)] - #[from(StockErrorMem)] - #[display(inner)] - Stock(StockErrorAll), - - #[cfg(feature = "serde_yaml")] - #[from] - Yaml(serde_yaml::Error), - - #[from] - Custom(String), -} - -impl From for RuntimeError { - fn from(_: Infallible) -> Self { unreachable!() } -} - -#[derive(Getters)] -pub struct Runtime, K = XpubDerivable> -where W::Descr: DescriptorRgb -{ - stock_path: PathBuf, - #[getter(as_mut)] - stock: Stock, - #[getter(as_mut)] - wallet: W, - _phantom: PhantomData, -} - -impl> Deref for Runtime -where W::Descr: DescriptorRgb -{ - type Target = Stock; - - fn deref(&self) -> &Self::Target { &self.stock } -} - -impl> DerefMut for Runtime -where W::Descr: DescriptorRgb -{ - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.stock } -} - -impl> OutpointFilter for Runtime -where W::Descr: DescriptorRgb -{ - fn include_outpoint(&self, output: impl Into) -> bool { - let output = output.into(); - self.wallet - .outpoints() - .any(|outpoint| XChain::Bitcoin(outpoint) == *output) - } -} - -impl> WitnessFilter for Runtime -where W::Descr: DescriptorRgb -{ - fn include_witness(&self, witness: impl Into) -> bool { - let witness = witness.into(); - self.wallet() - .txids() - .any(|txid| AssignmentWitness::Present(XWitnessId::Bitcoin(txid)) == witness) - } -} - -pub struct ContractOutpointsFilter<'runtime, K, W: WalletProvider> -where W::Descr: DescriptorRgb -{ - pub contract_id: ContractId, - pub filter: &'runtime Runtime, -} - -impl<'runtime, K, W: WalletProvider> OutpointFilter for ContractOutpointsFilter<'runtime, K, W> -where W::Descr: DescriptorRgb -{ - fn include_outpoint(&self, output: impl Into) -> bool { - let output = output.into(); - if !self.filter.include_outpoint(output) { - return false; - } - matches!(self.filter.stock.contract_assignments_for(self.contract_id, [output]), Ok(list) if !list.is_empty()) - } -} - -#[cfg(feature = "serde")] -impl> Runtime -where - W::Descr: DescriptorRgb, - W: Persisting, -{ - pub fn load_attach(stock_path: PathBuf, wallet: W) -> Result { - let stock = Self::load_walletless(&stock_path)?; - Ok(Self { - stock_path, - stock, - wallet, - _phantom: PhantomData, - }) - } - - pub fn store(&mut self) { - self.stock - .store(&self.stock_path) - .expect("unable to save stock"); - self.wallet - .try_store(&self.stock_path) - .expect("unable to save wallet data"); - } - - pub fn into_stock(self) -> Stock { self.stock } -} - -impl> Runtime -where W::Descr: DescriptorRgb -{ - pub fn load_walletless(stock_path: &PathBuf) -> Result { - use std::io::ErrorKind; - - use strict_types::encoding::DecodeError; - - Stock::load(stock_path).map_err(RuntimeError::from).or_else(|err| { - if matches!(err, RuntimeError::Deserialize(DeserializeError::Decode(DecodeError::Io(ref err))) if err.kind() == ErrorKind::NotFound) { - #[cfg(feature = "log")] - eprint!("stock file is absent, creating a new one ... "); - let stock = Stock::default(); - std::fs::create_dir_all(stock_path)?; - stock.store(stock_path)?; - eprintln!("success"); - return Ok(stock) - } - eprintln!("stock file is damaged"); - Err(err) - }) - } - - pub fn network(&self) -> Network { self.wallet.network() } - - // TODO: Integrate into BP Wallet `TxRow` as L2 and provide transactional info - pub fn fungible_history( - &self, - contract_id: ContractId, - iface: impl Into, - ) -> Result>, RuntimeError> { - let iref = iface.into(); - let iface = self.stock.iface(iref.clone())?; - let default_op = iface - .default_operation - .as_ref() - .ok_or(HistoryError::NoDefaultOp)?; - let state_name = iface - .transitions - .get(default_op) - .ok_or(HistoryError::DefaultOpNotTransition)? - .default_assignment - .as_ref() - .ok_or(HistoryError::NoDefaultAssignment)? - .clone(); - let contract = self.stock.contract_iface(contract_id, iref)?; - contract - .fungible_ops::(state_name, self, self) - .map_err(RuntimeError::from) - } -} - -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum HistoryError { - /// interface doesn't define default operation - NoDefaultOp, - /// default operation defined by the interface is not a state transition - DefaultOpNotTransition, - /// interface doesn't define default fungible state - NoDefaultAssignment, -} diff --git a/src/store.rs b/src/store.rs new file mode 100644 index 0000000..a9fdaed --- /dev/null +++ b/src/store.rs @@ -0,0 +1,181 @@ +// RGB wallet library for smart contracts on Bitcoin & Lightning network +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::HashMap; +use std::error::Error; +use std::marker::PhantomData; +use std::path::{Path, PathBuf}; + +use bp::seals::txout::CloseMethod; +use bpstd::XpubDerivable; +use bpwallet::{StoreError, Wallet, WalletDescr}; +use psrgbt::{Psbt, PsbtMeta}; +use rgbstd::containers::Transfer; +use rgbstd::interface::{AmountChange, IfaceOp, IfaceRef}; +use rgbstd::persistence::fs::StoreFs; +use rgbstd::persistence::{ + IndexProvider, MemIndex, MemStash, MemState, StashProvider, StateProvider, Stock, +}; + +use super::{ + CompletionError, CompositionError, ContractId, DescriptorRgb, PayError, TransferParams, + WalletError, WalletProvider, WalletStock, XWitnessId, +}; +use crate::invoice::RgbInvoice; + +pub trait Store { + type Err: Error; + fn store(&self, path: impl AsRef) -> Result<(), Self::Err>; +} + +impl> Store for Wallet +where + for<'de> WalletDescr: serde::Serialize + serde::Deserialize<'de>, + for<'de> D: serde::Serialize + serde::Deserialize<'de>, +{ + type Err = StoreError; + fn store(&self, path: impl AsRef) -> Result<(), Self::Err> { self.store(path.as_ref()) } +} + +#[derive(Getters)] +pub struct StoredWallet< + W: WalletProvider, + K = XpubDerivable, + S: StashProvider = MemStash, + H: StateProvider = MemState, + P: IndexProvider = MemIndex, +> where + W::Descr: DescriptorRgb, + W: Store, + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + stock_path: PathBuf, + stock: Stock, + wallet: W, + #[getter(prefix = "is_")] + stock_dirty: bool, + #[getter(prefix = "is_")] + wallet_dirty: bool, + #[getter(skip)] + _phantom: PhantomData, +} + +impl, S: StashProvider, H: StateProvider, P: IndexProvider> + StoredWallet +where + W::Descr: DescriptorRgb, + W: Store, + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + pub fn attach(path: PathBuf, stock: Stock, wallet: W) -> Self { + Self { + stock_path: path, + stock, + wallet, + stock_dirty: false, + wallet_dirty: false, + _phantom: PhantomData, + } + } + + pub fn stock_mut(&mut self) -> &mut Stock { + self.stock_dirty = true; + &mut self.stock + } + + pub fn wallet_mut(&mut self) -> &mut W { + self.wallet_dirty = true; + &mut self.wallet + } + + pub fn fungible_history( + &self, + contract_id: ContractId, + iface: impl Into, + ) -> Result>, WalletError> { + self.stock + .fungible_history(&self.wallet, contract_id, iface) + } + + #[allow(clippy::result_large_err)] + pub fn pay( + &mut self, + invoice: &RgbInvoice, + method: CloseMethod, + params: TransferParams, + ) -> Result<(Psbt, PsbtMeta, Transfer), PayError> { + self.wallet.pay(&mut self.stock, invoice, method, params) + } + + #[allow(clippy::result_large_err)] + pub fn construct_psbt( + &mut self, + invoice: &RgbInvoice, + method: CloseMethod, + params: TransferParams, + ) -> Result<(Psbt, PsbtMeta), CompositionError> { + self.wallet + .construct_psbt_rgb(&self.stock, invoice, method, params) + } + + #[allow(clippy::result_large_err)] + pub fn transfer( + &mut self, + invoice: &RgbInvoice, + psbt: &mut Psbt, + ) -> Result { + self.wallet.transfer(&mut self.stock, invoice, psbt) + } + + pub fn store(&self) { + let r1 = if self.wallet_dirty { + self.stock + .store(&self.stock_path) + .map_err(|e| e.to_string()) + } else { + Ok(()) + }; + let r2 = if self.wallet_dirty { + self.wallet + .store(&self.stock_path) + .map_err(|e| e.to_string()) + } else { + Ok(()) + }; + r1.and(r2).expect("error saving data"); + } +} + +impl, S: StashProvider, H: StateProvider, P: IndexProvider> Drop + for StoredWallet +where + W::Descr: DescriptorRgb, + W: Store, + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + fn drop(&mut self) { self.store() } +} diff --git a/src/wallet.rs b/src/wallet.rs index 8058b2a..1a6b5cc 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -19,41 +19,83 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::error::Error; -use std::ops::DerefMut; -use std::path::Path; +use std::collections::HashMap; -use bp::{Outpoint, Txid}; -use bpwallet::{Wallet, WalletDescr}; -use psrgbt::PsbtConstructor; +use bpwallet::Wallet; +use rgbstd::interface::{AmountChange, IfaceOp, IfaceRef, OutpointFilter, WitnessFilter}; +use rgbstd::persistence::{IndexProvider, StashProvider, StateProvider, Stock}; -use crate::DescriptorRgb; +use crate::{ + AssignmentWitness, ContractId, DescriptorRgb, HistoryError, WalletError, WalletProvider, + XChain, XOutpoint, XWitnessId, +}; -pub trait Persisting { - fn try_store(&self, path: &Path) -> Result<(), impl Error>; -} +pub struct WalletWrapper<'a, K, D: DescriptorRgb>(pub &'a Wallet); -pub trait WalletProvider: PsbtConstructor -where Self::Descr: DescriptorRgb -{ - fn descriptor_mut(&mut self) -> &mut Self::Descr; - fn outpoints(&self) -> impl Iterator; - fn txids(&self) -> impl Iterator; +impl<'a, K, D: DescriptorRgb> Copy for WalletWrapper<'a, K, D> {} +impl<'a, K, D: DescriptorRgb> Clone for WalletWrapper<'a, K, D> { + fn clone(&self) -> Self { WalletWrapper(self.0) } } -#[cfg(feature = "fs")] -impl> Persisting for Wallet -where - for<'de> WalletDescr: serde::Serialize + serde::Deserialize<'de>, - for<'de> D: serde::Serialize + serde::Deserialize<'de>, -{ - fn try_store(&self, path: &Path) -> Result<(), impl Error> { self.store(path) } +impl<'a, K, D: DescriptorRgb> OutpointFilter for WalletWrapper<'a, K, D> { + fn include_outpoint(&self, output: impl Into) -> bool { + let output = output.into(); + self.0 + .outpoints() + .any(|outpoint| XChain::Bitcoin(outpoint) == *output) + } } -impl> WalletProvider for Wallet { - fn descriptor_mut(&mut self) -> &mut Self::Descr { self.deref_mut() } +impl<'a, K, D: DescriptorRgb> WitnessFilter for WalletWrapper<'a, K, D> { + fn include_witness(&self, witness: impl Into) -> bool { + let witness = witness.into(); + self.0 + .txids() + .any(|txid| AssignmentWitness::Present(XWitnessId::Bitcoin(txid)) == witness) + } +} - fn outpoints(&self) -> impl Iterator { self.coins().map(|coin| coin.outpoint) } +pub trait WalletStock, K> +where W::Descr: DescriptorRgb +{ + fn fungible_history( + &self, + wallet: &W, + contract_id: ContractId, + iface: impl Into, + ) -> Result>, WalletError>; +} - fn txids(&self) -> impl Iterator { self.transactions().keys().copied() } +impl, K, S: StashProvider, H: StateProvider, P: IndexProvider> + WalletStock for Stock +where W::Descr: DescriptorRgb +{ + // TODO: Integrate into BP Wallet `TxRow` as L2 and provide transactional info + fn fungible_history( + &self, + wallet: &W, + contract_id: ContractId, + iface: impl Into, + ) -> Result>, WalletError> { + let iref = iface.into(); + let iface = self.iface(iref.clone()).map_err(|e| e.to_string())?; + let default_op = iface + .default_operation + .as_ref() + .ok_or(HistoryError::NoDefaultOp)?; + let state_name = iface + .transitions + .get(default_op) + .ok_or(HistoryError::DefaultOpNotTransition)? + .default_assignment + .as_ref() + .ok_or(HistoryError::NoDefaultAssignment)? + .clone(); + let contract = self + .contract_iface(contract_id, iref) + .map_err(|e| e.to_string())?; + Ok(contract + .fungible_ops::(state_name, wallet.filter(), wallet.filter()) + .map_err(|e| e.to_string())?) + } } From bbf786bdbf2ce46c8d495ede2e9c35cecbbb3383 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 21:14:07 +0200 Subject: [PATCH 14/32] pay: remove redundant seal close method information --- Cargo.lock | 23 +++++++++++------------ cli/src/command.rs | 18 +++--------------- src/pay.rs | 7 +++---- src/store.rs | 8 ++------ 4 files changed, 19 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f6204f..e5d1eba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,7 +29,7 @@ dependencies = [ [[package]] name = "aluvm" version = "0.11.0-beta.5" -source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#d8efe3007a5680a99cf86159b8dcc81cf1ed7278" +source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#25be42a16519383daaa6ba50e65654ff0a1721aa" dependencies = [ "amplify", "ascii-armor", @@ -193,9 +193,9 @@ dependencies = [ [[package]] name = "ascii-armor" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f438560a7273569cd4ab8fcf227d0490c1ff01f7cba5e004791752ae8f96091" +checksum = "673486110323d50d9f33d99f0f526726b4721b1b596284351e75d3692225abe8" dependencies = [ "amplify", "baid64", @@ -955,9 +955,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -1123,7 +1123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -1520,11 +1520,10 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#0d7bbcc45d448b71d6c93beb804a3c7062e6891c" +source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#3fa35c1428796cb607c8a627765aabb2e8329b62" dependencies = [ "aluvm", "amplify", - "ascii-armor", "baid64", "bp-core", "chrono", @@ -1542,7 +1541,7 @@ dependencies = [ [[package]] name = "rgb-interfaces" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#eb10305796ca3efbf92e0b3c171c6996d7461120" +source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#1fb09cb8c23e062c8a059fb9afec7f2f135440ae" dependencies = [ "aluvm", "amplify", @@ -1558,7 +1557,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#cef39a08e3586b59973c1eae038e15f898814be4" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#8ee3144315390b12dad6912b957e8e5e49378762" dependencies = [ "amplify", "baid64", @@ -1618,7 +1617,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#cef39a08e3586b59973c1eae038e15f898814be4" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#8ee3144315390b12dad6912b957e8e5e49378762" dependencies = [ "aluvm", "amplify", @@ -2081,7 +2080,7 @@ dependencies = [ [[package]] name = "strict_types" version = "2.7.0-beta.3" -source = "git+https://github.com/strict-types/strict-types?branch=develop#a2e860f36f24b477712551a6db349edcf08efb3e" +source = "git+https://github.com/strict-types/strict-types?branch=develop#4effa0b28804f7798a17f5dc6b4411ce6515f2f5" dependencies = [ "amplify", "ascii-armor", diff --git a/cli/src/command.rs b/cli/src/command.rs index 97b93a0..cc0c129 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -44,7 +44,6 @@ use rgb::{ BundleId, ContractId, DescriptorRgb, GenesisSeal, GraphSeal, Identity, OutputSeal, RgbKeychain, StateType, TransferParams, WalletError, WalletProvider, XChain, XOutputSeal, }; -use seals::txout::CloseMethod; use serde_crate::{Deserialize, Serialize}; use strict_types::encoding::{FieldName, TypeName}; use strict_types::StrictVal; @@ -179,10 +178,6 @@ pub enum Command { #[clap(short = '2')] v2: bool, - /// Method for single-use-seals - #[clap(long, default_value = "tapret1st")] - method: CloseMethod, - /// Amount of satoshis which should be paid to the address-based /// beneficiary #[clap(long, default_value = "2000")] @@ -220,10 +215,6 @@ pub enum Command { #[clap(short = '2')] v2: bool, - /// Method for single-use-seals - #[clap(long, default_value = "tapret1st")] - method: CloseMethod, - /// Amount of satoshis which should be paid to the address-based /// beneficiary #[clap(long, default_value = "2000")] @@ -719,7 +710,6 @@ impl Exec for RgbArgs { } Command::Prepare { v2, - method, invoice, fee, sats, @@ -730,7 +720,7 @@ impl Exec for RgbArgs { let params = TransferParams::with(*fee, *sats); let (psbt, _) = wallet - .construct_psbt(invoice, *method, params) + .construct_psbt(invoice, params) .map_err(|err| err.to_string())?; let ver = if *v2 { PsbtVer::V2 } else { PsbtVer::V0 }; @@ -762,7 +752,6 @@ impl Exec for RgbArgs { } Command::Transfer { v2, - method, invoice, fee, sats, @@ -773,9 +762,8 @@ impl Exec for RgbArgs { // TODO: Support lock time and RBFs let params = TransferParams::with(*fee, *sats); - let (psbt, _, transfer) = wallet - .pay(invoice, *method, params) - .map_err(|err| err.to_string())?; + let (psbt, _, transfer) = + wallet.pay(invoice, params).map_err(|err| err.to_string())?; transfer.save_file(out_file)?; diff --git a/src/pay.rs b/src/pay.rs index f93fbcb..7151288 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -24,7 +24,7 @@ use std::marker::PhantomData; use std::ops::DerefMut; use bp::dbc::tapret::TapretProof; -use bp::seals::txout::{CloseMethod, ExplicitSeal}; +use bp::seals::txout::ExplicitSeal; use bp::{Outpoint, Sats, ScriptPubkey, Vout}; use bpstd::{psbt, Address}; use bpwallet::Wallet; @@ -108,10 +108,9 @@ where Self::Descr: DescriptorRgb &mut self, stock: &mut Stock, invoice: &RgbInvoice, - method: CloseMethod, params: TransferParams, ) -> Result<(Psbt, PsbtMeta, Transfer), PayError> { - let (mut psbt, meta) = self.construct_psbt_rgb(stock, invoice, method, params)?; + let (mut psbt, meta) = self.construct_psbt_rgb(stock, invoice, params)?; // ... here we pass PSBT around signers, if necessary let transfer = self.transfer(stock, invoice, &mut psbt)?; Ok((psbt, meta, transfer)) @@ -122,10 +121,10 @@ where Self::Descr: DescriptorRgb &mut self, stock: &Stock, invoice: &RgbInvoice, - method: CloseMethod, mut params: TransferParams, ) -> Result<(Psbt, PsbtMeta), CompositionError> { let contract_id = invoice.contract.ok_or(CompositionError::NoContract)?; + let method = self.descriptor().seal_close_method(); let iface_name = invoice.iface.clone().ok_or(CompositionError::NoIface)?; let iface = stock.iface(iface_name.clone()).map_err(|e| e.to_string())?; diff --git a/src/store.rs b/src/store.rs index a9fdaed..6b89112 100644 --- a/src/store.rs +++ b/src/store.rs @@ -24,7 +24,6 @@ use std::error::Error; use std::marker::PhantomData; use std::path::{Path, PathBuf}; -use bp::seals::txout::CloseMethod; use bpstd::XpubDerivable; use bpwallet::{StoreError, Wallet, WalletDescr}; use psrgbt::{Psbt, PsbtMeta}; @@ -123,21 +122,18 @@ where pub fn pay( &mut self, invoice: &RgbInvoice, - method: CloseMethod, params: TransferParams, ) -> Result<(Psbt, PsbtMeta, Transfer), PayError> { - self.wallet.pay(&mut self.stock, invoice, method, params) + self.wallet.pay(&mut self.stock, invoice, params) } #[allow(clippy::result_large_err)] pub fn construct_psbt( &mut self, invoice: &RgbInvoice, - method: CloseMethod, params: TransferParams, ) -> Result<(Psbt, PsbtMeta), CompositionError> { - self.wallet - .construct_psbt_rgb(&self.stock, invoice, method, params) + self.wallet.construct_psbt_rgb(&self.stock, invoice, params) } #[allow(clippy::result_large_err)] From 7128b445d520158c880f19941cf1927f7942a22b Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 21:54:54 +0200 Subject: [PATCH 15/32] chore: fix clippy linys --- cli/src/args.rs | 2 ++ src/descriptor.rs | 2 +- src/pay.rs | 1 - src/store.rs | 1 + src/wallet.rs | 3 ++- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cli/src/args.rs b/cli/src/args.rs index 40b75dc..b73c095 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -19,6 +19,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![allow(clippy::needless_update)] // Required by From derive macro + use bpstd::{Wpkh, XpubDerivable}; use bpwallet::cli::{Args as BpArgs, Config, DescriptorOpts}; use bpwallet::Wallet; diff --git a/src/descriptor.rs b/src/descriptor.rs index 13ac0b8..a101354 100644 --- a/src/descriptor.rs +++ b/src/descriptor.rs @@ -296,7 +296,7 @@ where Self: Derive iter::empty() } - fn xpubs<'a>(&'a self) -> impl Iterator { + fn xpubs(&self) -> impl Iterator { match self { RgbDescr::Wpkh(d) => d.xpubs().collect::>(), RgbDescr::TapretKey(d) => d.xpubs().collect::>(), diff --git a/src/pay.rs b/src/pay.rs index 7151288..7126bcb 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -73,7 +73,6 @@ struct ContractOutpointsFilter< } impl< - 'a, 'stock, 'wallet, W: WalletProvider + ?Sized, diff --git a/src/store.rs b/src/store.rs index 6b89112..2badedf 100644 --- a/src/store.rs +++ b/src/store.rs @@ -109,6 +109,7 @@ where &mut self.wallet } + #[allow(clippy::result_large_err)] pub fn fungible_history( &self, contract_id: ContractId, diff --git a/src/wallet.rs b/src/wallet.rs index 1a6b5cc..bba7f3f 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -34,7 +34,7 @@ pub struct WalletWrapper<'a, K, D: DescriptorRgb>(pub &'a Wallet); impl<'a, K, D: DescriptorRgb> Copy for WalletWrapper<'a, K, D> {} impl<'a, K, D: DescriptorRgb> Clone for WalletWrapper<'a, K, D> { - fn clone(&self) -> Self { WalletWrapper(self.0) } + fn clone(&self) -> Self { *self } } impl<'a, K, D: DescriptorRgb> OutpointFilter for WalletWrapper<'a, K, D> { @@ -58,6 +58,7 @@ impl<'a, K, D: DescriptorRgb> WitnessFilter for WalletWrapper<'a, K, D> { pub trait WalletStock, K> where W::Descr: DescriptorRgb { + #[allow(clippy::result_large_err)] fn fungible_history( &self, wallet: &W, From cb6720c6c48dd8860be1d3a692a5225813482b26 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 21:57:57 +0200 Subject: [PATCH 16/32] chore: fix build features for cli --- cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 92b1718..44664d7 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,7 +27,7 @@ bp-wallet = { workspace = true, features = ["cli"] } psbt = { workspace = true } rgb-std = { workspace = true, features = ["serde"] } rgb-interfaces = { workspace = true } -rgb-runtime = { version = "0.11.0-beta.5", path = "..", features = ["electrum", "esplora_blocking", "log", "serde"] } +rgb-runtime = { version = "0.11.0-beta.5", path = "..", features = ["electrum", "esplora_blocking", "log", "serde", "fs"] } log = { workspace = true } env_logger = "0.10.1" clap = { version = "4.4.8", features = ["derive", "env"] } From ab042eb1aff01ebb1277d68b213e8534566ed00e Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 28 Apr 2024 22:12:24 +0200 Subject: [PATCH 17/32] fix stock saving --- cli/src/args.rs | 42 ++++++++++++++++------------- src/lib.rs | 2 +- src/store.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 19 deletions(-) diff --git a/cli/src/args.rs b/cli/src/args.rs index b73c095..8290a98 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -21,16 +21,20 @@ #![allow(clippy::needless_update)] // Required by From derive macro +use std::fs; +use std::io::ErrorKind; +use std::path::Path; + use bpstd::{Wpkh, XpubDerivable}; use bpwallet::cli::{Args as BpArgs, Config, DescriptorOpts}; use bpwallet::Wallet; use rgb::{ - electrum, esplora_blocking, AnyResolver, AnyResolverError, RgbDescr, StoredWallet, TapretKey, - WalletError, + electrum, esplora_blocking, AnyResolver, AnyResolverError, RgbDescr, StoredStock, StoredWallet, + TapretKey, WalletError, }; use rgbstd::persistence::fs::{LoadFs, StoreFs}; use rgbstd::persistence::Stock; -use strict_types::encoding::DeserializeError; +use strict_types::encoding::{DecodeError, DeserializeError}; use crate::Command; @@ -76,41 +80,43 @@ impl Default for RgbArgs { } impl RgbArgs { - pub fn rgb_stock(&self) -> Result { - if self.verbose > 2 { + fn load_stock(&self, stock_path: &Path) -> Result { + if self.verbose > 1 { eprint!("Loading stock ... "); } - use std::io::ErrorKind; - - use strict_types::encoding::DecodeError; - let stock_path = self.general.base_dir(); - let stock = Stock::load(&stock_path).map_err(WalletError::from).or_else(|err| { + Stock::load(&stock_path).map_err(WalletError::from).or_else(|err| { if matches!(err, WalletError::Deserialize(DeserializeError::Decode(DecodeError::Io(ref err))) if err.kind() == ErrorKind::NotFound) { - #[cfg(feature = "log")] - eprint!("stock file is absent, creating a new one ... "); + if self.verbose > 1 { + eprint!("stock file is absent, creating a new one ... "); + } let stock = Stock::default(); - std::fs::create_dir_all(&stock_path)?; + fs::create_dir_all(&stock_path)?; stock.store(&stock_path)?; - if self.verbose > 2 { + if self.verbose > 1 { eprintln!("success"); } return Ok(stock) } eprintln!("stock file is damaged, failing"); Err(err) - })?; + }) + } - Ok(stock) + pub fn rgb_stock(&self) -> Result { + let stock_path = self.general.base_dir(); + let stock = self.load_stock(&stock_path)?; + Ok(StoredStock::attach(stock_path, stock)) } pub fn rgb_wallet( &self, config: &Config, ) -> Result>, WalletError> { - let stock = self.rgb_stock()?; + let stock_path = self.general.base_dir(); + let stock = self.load_stock(&stock_path)?; let wallet = self.inner.bp_runtime::(config)?.detach(); - let wallet = StoredWallet::attach(self.general.base_dir(), stock, wallet); + let wallet = StoredWallet::attach(stock_path, stock, wallet); Ok(wallet) } diff --git a/src/lib.rs b/src/lib.rs index 2368e2a..561fc89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,5 +41,5 @@ pub use pay::{TransferParams, WalletProvider}; pub use resolvers::*; pub use rgbstd::*; #[cfg(feature = "fs")] -pub use store::StoredWallet; +pub use store::{StoredStock, StoredWallet}; pub use wallet::{WalletStock, WalletWrapper}; diff --git a/src/store.rs b/src/store.rs index 2badedf..4caa713 100644 --- a/src/store.rs +++ b/src/store.rs @@ -22,6 +22,7 @@ use std::collections::HashMap; use std::error::Error; use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use bpstd::XpubDerivable; @@ -54,6 +55,77 @@ where fn store(&self, path: impl AsRef) -> Result<(), Self::Err> { self.store(path.as_ref()) } } +#[derive(Getters)] +pub struct StoredStock< + S: StashProvider = MemStash, + H: StateProvider = MemState, + P: IndexProvider = MemIndex, +> where + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + stock_path: PathBuf, + stock: Stock, + #[getter(prefix = "is_")] + dirty: bool, +} + +impl Deref for StoredStock +where + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + type Target = Stock; + + fn deref(&self) -> &Self::Target { &self.stock } +} + +impl DerefMut for StoredStock +where + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + self.dirty = true; + &mut self.stock + } +} + +impl StoredStock +where + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + pub fn attach(path: PathBuf, stock: Stock) -> Self { + Self { + stock_path: path, + stock, + dirty: false, + } + } + + pub fn store(&self) { + if self.dirty { + self.stock + .store(&self.stock_path) + .expect("error saving data"); + } + } +} + +impl Drop for StoredStock +where + S: StoreFs, + H: StoreFs, + P: StoreFs, +{ + fn drop(&mut self) { self.store() } +} + #[derive(Getters)] pub struct StoredWallet< W: WalletProvider, From 991f81d023fce6763b09d01dee50f5d89ecea7ba Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 29 Apr 2024 20:19:10 +0200 Subject: [PATCH 18/32] examples: fix YAML parse --- Cargo.lock | 18 +++++++------- examples/rgb20-demo.con | 54 ++++++++++++++++++---------------------- examples/rgb20-demo.json | 24 ------------------ examples/rgb20-demo.toml | 24 ------------------ examples/rgb20-demo.yaml | 14 +++++------ 5 files changed, 39 insertions(+), 95 deletions(-) delete mode 100644 examples/rgb20-demo.json delete mode 100644 examples/rgb20-demo.toml diff --git a/Cargo.lock b/Cargo.lock index e5d1eba..8e10258 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -804,9 +804,9 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "flate2" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -1949,9 +1949,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c85f8e96d1d6857f13768fcbd895fcb06225510022a2774ed8b5150581847b0" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ "base64 0.22.0", "chrono", @@ -1967,9 +1967,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8b3a576c4eb2924262d5951a3b737ccaf16c931e39a2810c36f9a7e25575557" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ "darling", "proc-macro2", @@ -2029,9 +2029,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2080,7 +2080,7 @@ dependencies = [ [[package]] name = "strict_types" version = "2.7.0-beta.3" -source = "git+https://github.com/strict-types/strict-types?branch=develop#4effa0b28804f7798a17f5dc6b4411ce6515f2f5" +source = "git+https://github.com/strict-types/strict-types?branch=develop#86486d299bf068c734c406e529d35f0c25805293" dependencies = [ "amplify", "ascii-armor", diff --git a/examples/rgb20-demo.con b/examples/rgb20-demo.con index 2ab5893..a6abe6f 100644 --- a/examples/rgb20-demo.con +++ b/examples/rgb20-demo.con @@ -1,31 +1,25 @@ -contract Test implements RGB20 - spec = ( - naming = ( - ticker = "TEST", - name = "Test Asset" - ), - precision = centiMicro - ) - data = ( - terms = - """ - SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER - EXPRESSLY SET FORTH IN THIS AGREEMENT OR ANY OTHER EXPRESS OBLIGATION OF SELLERS PURSUANT TO THE - TERMS HEREOF, AND ACKNOWLEDGING THE PRIOR USE OF THE PROPERTY AND PURCHASER’S OPPORTUNITY - TO INSPECT THE PROPERTY, PURCHASER AGREES TO PURCHASE THE PROPERTY “AS IS”, “WHERE IS”, - WITH ALL FAULTS AND CONDITIONS THEREON. ANY WRITTEN OR ORAL INFORMATION, REPORTS, STATEMENTS, - DOCUMENTS OR RECORDS CONCERNING THE PROPERTY PROVIDED OR MADE AVAILABLE TO PURCHASER, ITS AGENTS - OR CONSTITUENTS BY ANY SELLER, ANY SELLER’S AGENTS, EMPLOYEES OR THIRD PARTIES REPRESENTING OR - PURPORTING TO REPRESENT ANY SELLER, SHALL NOT BE REPRESENTATIONS OR WARRANTIES, UNLESS - SPECIFICALLY SET FORTH HEREIN. IN PURCHASING THE PROPERTY OR TAKING OTHER ACTION HEREUNDER, - PURCHASER HAS NOT AND SHALL NOT RELY ON ANY SUCH DISCLOSURES, BUT RATHER, PURCHASER SHALL RELY - ONLY ON PURCHASER’S OWN INSPECTION OF THE PROPERTY AND THE REPRESENTATIONS AND WARRANTIES - HEREIN. PURCHASER ACKNOWLEDGES THAT THE PURCHASE PRICE REFLECTS AND TAKES INTO ACCOUNT THAT THE - PROPERTY IS BEING SOLD “AS IS”. - """, - media = ~ - ) - issuedSupply = 1_000_000__000_000_00 - created = 1687969158 +contract Test: RGB20 + spec: + "TEST" "Test Asset" centiMicro + terms: + """ + SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER + EXPRESSLY SET FORTH IN THIS AGREEMENT OR ANY OTHER EXPRESS OBLIGATION OF SELLERS PURSUANT TO THE + TERMS HEREOF, AND ACKNOWLEDGING THE PRIOR USE OF THE PROPERTY AND PURCHASER’S OPPORTUNITY + TO INSPECT THE PROPERTY, PURCHASER AGREES TO PURCHASE THE PROPERTY “AS IS”, “WHERE IS”, + WITH ALL FAULTS AND CONDITIONS THEREON. ANY WRITTEN OR ORAL INFORMATION, REPORTS, STATEMENTS, + DOCUMENTS OR RECORDS CONCERNING THE PROPERTY PROVIDED OR MADE AVAILABLE TO PURCHASER, ITS AGENTS + OR CONSTITUENTS BY ANY SELLER, ANY SELLER’S AGENTS, EMPLOYEES OR THIRD PARTIES REPRESENTING OR + PURPORTING TO REPRESENT ANY SELLER, SHALL NOT BE REPRESENTATIONS OR WARRANTIES, UNLESS + SPECIFICALLY SET FORTH HEREIN. IN PURCHASING THE PROPERTY OR TAKING OTHER ACTION HEREUNDER, + PURCHASER HAS NOT AND SHALL NOT RELY ON ANY SUCH DISCLOSURES, BUT RATHER, PURCHASER SHALL RELY + ONLY ON PURCHASER’S OWN INSPECTION OF THE PROPERTY AND THE REPRESENTATIONS AND WARRANTIES + HEREIN. PURCHASER ACKNOWLEDGES THAT THE PURCHASE PRICE REFLECTS AND TAKES INTO ACCOUNT THAT THE + PROPERTY IS BEING SOLD “AS IS”. + """ - assetOwner = 1_000_000__000_000_00 @ tapret1st:01d46e52c4bdb51931a0eae83e958c78bdef9cac2057b36d55370410edafdd42:0 + issuedSupply: + 1_000_000__000_000_00 + + assetOwner: + 1_000_000__000_000_00 tapret1st:01d46e52c4bdb51931a0eae83e958c78bdef9cac2057b36d55370410edafdd42:0 diff --git a/examples/rgb20-demo.json b/examples/rgb20-demo.json deleted file mode 100644 index a5cec78..0000000 --- a/examples/rgb20-demo.json +++ /dev/null @@ -1,24 +0,0 @@ -{"interface": "RGB20", - "globals": [ - { - "spec": { - "naming": { - "ticker": "TEST", - "name": "Test asset" - }, - "precision": "centiMicro" - }, - "data": { - "terms": "SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER EXPRESSLY SET FORTH IN THIS AGREEMENT OR ANY OTHER EXPRESS OBLIGATION OF SELLERS PURSUANT TO THE TERMS HEREOF, AND ACKNOWLEDGING THE PRIOR USE OF THE PROPERTY AND PURCHASER’S OPPORTUNITY TO INSPECT THE PROPERTY, PURCHASER AGREES TO PURCHASE THE PROPERTY “AS IS”, “WHERE IS”, WITH ALL FAULTS AND CONDITIONS THEREON. ANY WRITTEN OR ORAL INFORMATION, REPORTS, STATEMENTS, DOCUMENTS OR RECORDS CONCERNING THE PROPERTY PROVIDED OR MADE AVAILABLE TO PURCHASER, ITS AGENTS OR CONSTITUENTS BY ANY SELLER, ANY SELLER’S AGENTS, EMPLOYEES OR THIRD PARTIES REPRESENTING OR PURPORTING TO REPRESENT ANY SELLER, SHALL NOT BE REPRESENTATIONS OR WARRANTIES, UNLESS SPECIFICALLY SET FORTH HEREIN. IN PURCHASING THE PROPERTY OR TAKING OTHER ACTION HEREUNDER, PURCHASER HAS NOT AND SHALL NOT RELY ON ANY SUCH DISCLOSURES, BUT RATHER, PURCHASER SHALL RELY ONLY ON PURCHASER’S OWN INSPECTION OF THE PROPERTY AND THE REPRESENTATIONS AND WARRANTIES HEREIN. PURCHASER ACKNOWLEDGES THAT THE PURCHASE PRICE REFLECTS AND TAKES INTO ACCOUNT THAT THE PROPERTY IS BEING SOLD “AS IS”." - }, - "issuedSupply": 100000000000000, - "created": 1687969158 - } - ], -"assignments": [ - { - "assetOwner": { - "tapret1st:01d46e52c4bdb51931a0eae83e958c78bdef9cac2057b36d55370410edafdd42:0": 100000000000000 - } - } -]} diff --git a/examples/rgb20-demo.toml b/examples/rgb20-demo.toml deleted file mode 100644 index 8191282..0000000 --- a/examples/rgb20-demo.toml +++ /dev/null @@ -1,24 +0,0 @@ -interface = "RGB20" - -[global] -spec = { naming = { ticker = "TEST", name = "Test asset" }, precision = "centiMicro" } -data = { terms = """ -SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER -EXPRESSLY SET FORTH IN THIS AGREEMENT OR ANY OTHER EXPRESS OBLIGATION OF SELLERS PURSUANT TO THE -TERMS HEREOF, AND ACKNOWLEDGING THE PRIOR USE OF THE PROPERTY AND PURCHASER’S OPPORTUNITY -TO INSPECT THE PROPERTY, PURCHASER AGREES TO PURCHASE THE PROPERTY “AS IS”, “WHERE IS”, -WITH ALL FAULTS AND CONDITIONS THEREON. ANY WRITTEN OR ORAL INFORMATION, REPORTS, STATEMENTS, -DOCUMENTS OR RECORDS CONCERNING THE PROPERTY PROVIDED OR MADE AVAILABLE TO PURCHASER, ITS AGENTS -OR CONSTITUENTS BY ANY SELLER, ANY SELLER’S AGENTS, EMPLOYEES OR THIRD PARTIES REPRESENTING OR -PURPORTING TO REPRESENT ANY SELLER, SHALL NOT BE REPRESENTATIONS OR WARRANTIES, UNLESS -SPECIFICALLY SET FORTH HEREIN. IN PURCHASING THE PROPERTY OR TAKING OTHER ACTION HEREUNDER, -PURCHASER HAS NOT AND SHALL NOT RELY ON ANY SUCH DISCLOSURES, BUT RATHER, PURCHASER SHALL RELY -ONLY ON PURCHASER’S OWN INSPECTION OF THE PROPERTY AND THE REPRESENTATIONS AND WARRANTIES -HEREIN. PURCHASER ACKNOWLEDGES THAT THE PURCHASE PRICE REFLECTS AND TAKES INTO ACCOUNT THAT THE -PROPERTY IS BEING SOLD “AS IS”. -""" } -issuedSupply = 1_000_000_000_000_00 -created = 1687969158 - -[assignment.assetOwner] -"tapret1st:01d46e52c4bdb51931a0eae83e958c78bdef9cac2057b36d55370410edafdd42:0" = 1_000_000_000_000_00 diff --git a/examples/rgb20-demo.yaml b/examples/rgb20-demo.yaml index 89c828a..6938c47 100644 --- a/examples/rgb20-demo.yaml +++ b/examples/rgb20-demo.yaml @@ -1,14 +1,13 @@ -interface: RGB20 +interface: RGB20Fixed globals: spec: - naming: - ticker: DBG - name: Debug asset - details: "Pay attention: the asset has no value" + ticker: DBG + name: Debug asset + details: "Pay attention: the asset has no value" precision: 2 - data: - terms: > + terms: + text: > SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER EXPRESSLY SET FORTH IN THIS AGREEMENT OR ANY OTHER EXPRESS OBLIGATION OF SELLERS PURSUANT TO THE TERMS HEREOF, AND ACKNOWLEDGING THE PRIOR USE OF THE PROPERTY AND PURCHASER’S OPPORTUNITY @@ -24,7 +23,6 @@ globals: PROPERTY IS BEING SOLD “AS IS”. media: ~ issuedSupply: 100000000 - created: 1687969158 assignments: assetOwner: From 16389a2cd282f529dea579e385cf384857915d71 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 30 Apr 2024 17:48:00 +0200 Subject: [PATCH 19/32] chore: fix build. Closes #184 --- src/errors.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/errors.rs b/src/errors.rs index 134b52c..a6bfc00 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -82,6 +82,7 @@ pub enum WalletError { #[display(doc_comments)] IncompleteContract(validation::Status), + #[cfg(feature = "fs")] #[from] #[from(bpwallet::LoadError)] Bp(bpwallet::RuntimeError), From 4fc24b1ed2585dcebf906286595fac074fca1512 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 1 May 2024 10:04:48 +0200 Subject: [PATCH 20/32] psbt: fix missed transaction in fascia --- Cargo.lock | 24 ++++++++++++------------ psbt/src/lib.rs | 8 +++++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e10258..042aecd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,7 +232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b8b80494235048845f856b267a4a1d97df59fd14ed7ca92652f834ce93becc6" dependencies = [ "amplify", - "base64 0.22.0", + "base64 0.22.1", "mnemonic", "sha2", ] @@ -245,9 +245,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base85" @@ -500,9 +500,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" [[package]] name = "cfg-if" @@ -1167,9 +1167,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libredox" @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#3fa35c1428796cb607c8a627765aabb2e8329b62" +source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#f0469333a36abcb70dff6667938fc1eae438e1d2" dependencies = [ "aluvm", "amplify", @@ -1557,7 +1557,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#8ee3144315390b12dad6912b957e8e5e49378762" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#5d170662ecdb4fffd7f9d7f5fa8c5ce3ac98bbe9" dependencies = [ "amplify", "baid64", @@ -1617,7 +1617,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#8ee3144315390b12dad6912b957e8e5e49378762" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#5d170662ecdb4fffd7f9d7f5fa8c5ce3ac98bbe9" dependencies = [ "aluvm", "amplify", @@ -1953,7 +1953,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -2421,7 +2421,7 @@ version = "2.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "flate2", "log", "once_cell", diff --git a/psbt/src/lib.rs b/psbt/src/lib.rs index 9806976..eae5a16 100644 --- a/psbt/src/lib.rs +++ b/psbt/src/lib.rs @@ -28,8 +28,8 @@ use bp::dbc::opret::OpretProof; use bp::dbc::tapret::TapretProof; pub use psbt::*; pub use rgb::*; -use rgbstd::containers::{AnchorSet, Batch, CloseMethodSet, Fascia}; -use rgbstd::{XChain, XWitnessId}; +use rgbstd::containers::{AnchorSet, Batch, CloseMethodSet, Fascia, PubWitness, XPubWitness}; +use rgbstd::XChain; pub use self::rgb::{ ProprietaryKeyRgb, RgbExt, RgbInExt, RgbOutExt, RgbPsbtError, PSBT_GLOBAL_RGB_TRANSITION, @@ -115,8 +115,10 @@ impl RgbPsbt for Psbt { (None, Some(opret)) => AnchorSet::Opret(opret), (Some(tapret), Some(opret)) => AnchorSet::Double { tapret, opret }, }; + // TODO: Use signed transaction here! + let witness = PubWitness::with(self.to_unsigned_tx().finalize()); Ok(Fascia { - witness_id: XWitnessId::Bitcoin(self.txid()), + witness: XPubWitness::Bitcoin(witness), anchor, bundles, }) From eeb9d557746d3aa1f6763508b6ca1ea759f8d1d8 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 1 May 2024 14:41:10 +0200 Subject: [PATCH 21/32] refactor resolvers API --- Cargo.lock | 6 +- Cargo.toml | 4 +- cli/Cargo.toml | 2 +- cli/src/args.rs | 23 ++-- src/errors.rs | 4 +- src/lib.rs | 2 +- src/resolvers/any.rs | 126 ++++++++++--------- src/resolvers/electrum.rs | 192 ----------------------------- src/resolvers/electrum_blocking.rs | 92 ++++++++++++++ src/resolvers/esplora_blocking.rs | 105 +++------------- src/resolvers/mod.rs | 8 +- 11 files changed, 198 insertions(+), 366 deletions(-) delete mode 100644 src/resolvers/electrum.rs create mode 100644 src/resolvers/electrum_blocking.rs diff --git a/Cargo.lock b/Cargo.lock index 042aecd..8fd5f14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,7 +460,7 @@ dependencies = [ [[package]] name = "bp-wallet" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-wallet?branch=develop#db23c6a1a1e5f7060b68f20c6329abb1377195eb" +source = "git+https://github.com/BP-WG/bp-wallet?branch=develop#e4c1a7c68c28f2963b9699c4de9017581ede39c3" dependencies = [ "amplify", "base64 0.21.7", @@ -1557,7 +1557,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#5d170662ecdb4fffd7f9d7f5fa8c5ce3ac98bbe9" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#75fb0dd098574957478bf6d4bf3533abc325efb5" dependencies = [ "amplify", "baid64", @@ -1617,7 +1617,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#5d170662ecdb4fffd7f9d7f5fa8c5ce3ac98bbe9" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#75fb0dd098574957478bf6d4bf3533abc325efb5" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index 1640842..afbfcc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,10 +82,10 @@ log = { workspace = true, optional = true } [features] default = ["esplora_blocking"] -all = ["esplora_blocking", "electrum", "serde", "log", "fs"] +all = ["esplora_blocking", "electrum_blocking", "serde", "log", "fs"] fs = ["serde", "bp-wallet/fs"] esplora_blocking = ["bp-esplora"] -electrum = ["bp-electrum"] +electrum_blocking = ["bp-electrum"] serde = ["serde_crate", "serde_yaml", "bp-std/serde", "descriptors/serde", "rgb-psbt/serde"] [package.metadata.docs.rs] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 44664d7..4f0740b 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,7 +27,7 @@ bp-wallet = { workspace = true, features = ["cli"] } psbt = { workspace = true } rgb-std = { workspace = true, features = ["serde"] } rgb-interfaces = { workspace = true } -rgb-runtime = { version = "0.11.0-beta.5", path = "..", features = ["electrum", "esplora_blocking", "log", "serde", "fs"] } +rgb-runtime = { version = "0.11.0-beta.5", path = "..", features = ["electrum_blocking", "esplora_blocking", "log", "serde", "fs"] } log = { workspace = true } env_logger = "0.10.1" clap = { version = "4.4.8", features = ["derive", "env"] } diff --git a/cli/src/args.rs b/cli/src/args.rs index 8290a98..9329d5a 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -28,10 +28,7 @@ use std::path::Path; use bpstd::{Wpkh, XpubDerivable}; use bpwallet::cli::{Args as BpArgs, Config, DescriptorOpts}; use bpwallet::Wallet; -use rgb::{ - electrum, esplora_blocking, AnyResolver, AnyResolverError, RgbDescr, StoredStock, StoredWallet, - TapretKey, WalletError, -}; +use rgb::{AnyResolver, RgbDescr, StoredStock, StoredWallet, TapretKey, WalletError}; use rgbstd::persistence::fs::{LoadFs, StoreFs}; use rgbstd::persistence::Stock; use strict_types::encoding::{DecodeError, DeserializeError}; @@ -121,18 +118,12 @@ impl RgbArgs { Ok(wallet) } - #[allow(clippy::result_large_err)] - pub fn resolver(&self) -> Result { - if self.resolver.electrum != bpwallet::cli::DEFAULT_ELECTRUM { - match electrum::Resolver::new(&self.resolver.electrum) { - Ok(c) => Ok(AnyResolver::Electrum(Box::new(c))), - Err(e) => Err(AnyResolverError::Electrum(e)), - } - } else { - match esplora_blocking::Resolver::new(&self.resolver.esplora) { - Ok(c) => Ok(AnyResolver::Esplora(Box::new(c))), - Err(e) => Err(AnyResolverError::Esplora(e)), - } + pub fn resolver(&self) -> Result { + match (&self.resolver.esplora, &self.resolver.electrum) { + (None, Some(url)) => AnyResolver::electrum_blocking(url), + (Some(url), None) => AnyResolver::esplora_blocking(url), + _ => unreachable!("clap is broken"), } + .map_err(WalletError::Resolver) } } diff --git a/src/errors.rs b/src/errors.rs index a6bfc00..0632e29 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -88,10 +88,8 @@ pub enum WalletError { Bp(bpwallet::RuntimeError), /// resolver error: {0} - #[cfg(any(feature = "electrum", feature = "esplora_blocking"))] - #[from] #[display(doc_comments)] - ResolverError(crate::AnyResolverError), + Resolver(String), #[from(StockError)] #[from(StockErrorAll)] diff --git a/src/lib.rs b/src/lib.rs index 561fc89..0602dd4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ mod store; pub use descriptor::{DescriptorRgb, RgbDescr, RgbKeychain, TapTweakAlreadyAssigned, TapretKey}; pub use errors::{CompletionError, CompositionError, HistoryError, PayError, WalletError}; pub use pay::{TransferParams, WalletProvider}; -#[cfg(any(feature = "electrum", feature = "esplora_blocking"))] +#[cfg(any(feature = "electrum_blocking", feature = "esplora_blocking"))] pub use resolvers::*; pub use rgbstd::*; #[cfg(feature = "fs")] diff --git a/src/resolvers/any.rs b/src/resolvers/any.rs index e3da7a8..f4fff79 100644 --- a/src/resolvers/any.rs +++ b/src/resolvers/any.rs @@ -4,6 +4,8 @@ // // Written in 2024 by // Zoe Faltibà +// Rewritten in 2024 by +// Dr Maxim Orlovsky // // Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. // @@ -19,77 +21,79 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::collections::HashMap; + +use bp::Tx; use rgbstd::containers::Consignment; use rgbstd::resolvers::ResolveHeight; use rgbstd::validation::{ResolveWitness, WitnessResolverError}; use rgbstd::{WitnessAnchor, XWitnessId, XWitnessTx}; -#[cfg(feature = "electrum")] -use crate::electrum; -#[cfg(feature = "esplora_blocking")] -use crate::esplora_blocking; +use crate::{Txid, WitnessOrd, XChain}; + +pub trait RgbResolver { + fn resolve_height(&mut self, txid: Txid) -> Result; + fn resolve_pub_witness(&self, txid: Txid) -> Result>; +} /// Type that contains any of the [`Resolver`] types defined by the library #[derive(From)] #[non_exhaustive] -pub enum AnyResolver { - #[cfg(feature = "electrum")] - #[from] - /// Electrum resolver - Electrum(Box), - #[cfg(feature = "esplora_blocking")] - #[from] - /// Esplora resolver - Esplora(Box), +pub struct AnyResolver { + inner: Box, + terminal_txes: HashMap, } -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum AnyResolverError { - #[cfg(feature = "electrum")] - #[display(inner)] - Electrum(::electrum::Error), - #[cfg(feature = "esplora_blocking")] - #[display(inner)] - Esplora(esplora::Error), -} +impl AnyResolver { + #[cfg(feature = "electrum_blocking")] + pub fn electrum_blocking(url: &str) -> Result { + Ok(AnyResolver { + inner: Box::new(electrum::Client::new(url).map_err(|e| e.to_string())?), + terminal_txes: Default::default(), + }) + } -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum AnyAnchorResolverError { - #[cfg(feature = "electrum")] - #[from] - #[display(inner)] - Electrum(electrum::AnchorResolverError), #[cfg(feature = "esplora_blocking")] - #[from] - #[display(inner)] - Esplora(esplora_blocking::AnchorResolverError), -} + pub fn esplora_blocking(url: &str) -> Result { + Ok(AnyResolver { + inner: Box::new( + esplora::Builder::new(url) + .build_blocking() + .map_err(|e| e.to_string())?, + ), + terminal_txes: Default::default(), + }) + } -impl AnyResolver { pub fn add_terminals(&mut self, consignment: &Consignment) { - match self { - #[cfg(feature = "electrum")] - AnyResolver::Electrum(inner) => inner.add_witnesses(consignment), - #[cfg(feature = "esplora_blocking")] - AnyResolver::Esplora(inner) => inner.add_witnesses(consignment), - } + self.terminal_txes.extend( + consignment + .bundles + .iter() + .filter_map(|bw| bw.pub_witness.maybe_map_ref(|w| w.tx.clone())) + .filter_map(|tx| match tx { + XChain::Bitcoin(tx) => Some(tx), + XChain::Liquid(_) | XChain::Other(_) => None, + }) + .map(|tx| (tx.txid(), tx)), + ); } } impl ResolveHeight for AnyResolver { - type Error = AnyAnchorResolverError; + fn resolve_height(&mut self, witness_id: XWitnessId) -> Result { + let XWitnessId::Bitcoin(txid) = witness_id else { + return Err(format!("{} is not supported as layer 1 network", witness_id.layer1())); + }; - fn resolve_height(&mut self, witness_id: XWitnessId) -> Result { - match self { - #[cfg(feature = "electrum")] - AnyResolver::Electrum(inner) => inner.resolve_height(witness_id).map_err(|e| e.into()), - #[cfg(feature = "esplora_blocking")] - AnyResolver::Esplora(inner) => inner.resolve_height(witness_id).map_err(|e| e.into()), + if self.terminal_txes.contains_key(&txid) { + return Ok(WitnessAnchor { + witness_ord: WitnessOrd::OffChain, + witness_id, + }); } + + self.inner.resolve_height(txid) } } @@ -98,11 +102,23 @@ impl ResolveWitness for AnyResolver { &self, witness_id: XWitnessId, ) -> Result { - match self { - #[cfg(feature = "electrum")] - AnyResolver::Electrum(inner) => inner.resolve_pub_witness(witness_id), - #[cfg(feature = "esplora_blocking")] - AnyResolver::Esplora(inner) => inner.resolve_pub_witness(witness_id), + let XWitnessId::Bitcoin(txid) = witness_id else { + return Err(WitnessResolverError::Other( + witness_id, + format!("{} is not supported as layer 1 network", witness_id.layer1()), + )); + }; + + if let Some(tx) = self.terminal_txes.get(&txid) { + return Ok(XWitnessTx::Bitcoin(tx.clone())); } + + self.inner + .resolve_pub_witness(txid) + .map(XWitnessTx::Bitcoin) + .map_err(|e| match e { + None => WitnessResolverError::Unknown(witness_id), + Some(e) => WitnessResolverError::Other(witness_id, e), + }) } } diff --git a/src/resolvers/electrum.rs b/src/resolvers/electrum.rs deleted file mode 100644 index af72748..0000000 --- a/src/resolvers/electrum.rs +++ /dev/null @@ -1,192 +0,0 @@ -// RGB smart contracts for Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2024 by -// Zoe Faltibà -// -// Copyright (C) 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 bp::ConsensusDecode; -use bpstd::{Tx, Txid}; -use electrum::{Client, ElectrumApi, Error, Param}; -use rgbstd::containers::Consignment; -use rgbstd::resolvers::ResolveHeight; -use rgbstd::validation::{ResolveWitness, WitnessResolverError}; -use rgbstd::{Layer1, WitnessAnchor, WitnessOrd, WitnessPos, XChain, XWitnessId, XWitnessTx}; - -pub struct Resolver { - electrum_client: Client, - terminal_txes: HashMap, -} - -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum AnchorResolverError { - #[from] - #[display(inner)] - Error(Error), - - /// impossible conversion - ImpossibleConversion, - - /// unsupported layer 1 {0} - UnsupportedLayer1(Layer1), -} - -impl Resolver { - #[allow(clippy::result_large_err)] - pub fn new(url: &str) -> Result { - let electrum_client = Client::new(url)?; - Ok(Self { - electrum_client, - terminal_txes: none!(), - }) - } - - pub fn add_witnesses(&mut self, consignment: &Consignment) { - self.terminal_txes.extend( - consignment - .bundles - .iter() - .filter_map(|bw| bw.pub_witness.maybe_map_ref(|w| w.tx.clone())) - .filter_map(|tx| match tx { - XChain::Bitcoin(tx) => Some(tx), - XChain::Liquid(_) | XChain::Other(_) => None, - }) - .map(|tx| (tx.txid(), tx)), - ); - } -} - -impl ResolveHeight for Resolver { - type Error = AnchorResolverError; - - fn resolve_height(&mut self, witness_id: XWitnessId) -> Result { - let XWitnessId::Bitcoin(txid) = witness_id else { - return Err(AnchorResolverError::UnsupportedLayer1(witness_id.layer1())); - }; - - if self.terminal_txes.contains_key(&txid) { - return Ok(WitnessAnchor { - witness_ord: WitnessOrd::OffChain, - witness_id, - }); - } - - fn get_block_height(electrum_client: &Client) -> Result { - electrum_client - .block_headers_subscribe()? - .height - .try_into() - .map_err(|_| AnchorResolverError::ImpossibleConversion) - } - - let last_block_height_min = get_block_height(&self.electrum_client)?; - let witness_ord = match self - .electrum_client - .raw_call("blockchain.transaction.get", vec![ - Param::String(txid.to_string()), - Param::Bool(true), - ]) { - Ok(tx_details) => { - if let Some(confirmations) = tx_details.get("confirmations") { - let confirmations = confirmations - .as_u64() - .ok_or(Error::InvalidResponse(tx_details.clone()))?; - let last_block_height_max = get_block_height(&self.electrum_client)?; - let skew = confirmations - 1; - let mut tx_height: u32 = 0; - for height in (last_block_height_min - skew)..=(last_block_height_max - skew) { - if let Ok(get_merkle_res) = self.electrum_client.transaction_get_merkle( - &txid, - height - .try_into() - .map_err(|_| AnchorResolverError::ImpossibleConversion)?, - ) { - tx_height = get_merkle_res - .block_height - .try_into() - .map_err(|_| AnchorResolverError::ImpossibleConversion)?; - break; - } else { - continue; - } - } - let block_time = tx_details - .get("blocktime") - .ok_or(Error::InvalidResponse(tx_details.clone()))? - .as_i64() - .ok_or(Error::InvalidResponse(tx_details.clone()))?; - WitnessOrd::OnChain( - WitnessPos::new(tx_height, block_time) - .ok_or(Error::InvalidResponse(tx_details.clone()))?, - ) - } else { - WitnessOrd::OffChain - } - } - Err(e) - if e.to_string() - .contains("No such mempool or blockchain transaction") => - { - WitnessOrd::OffChain - } - Err(e) => return Err(e.into()), - }; - - Ok(WitnessAnchor { - witness_ord, - witness_id, - }) - } -} - -impl ResolveWitness for Resolver { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - let XWitnessId::Bitcoin(txid) = witness_id else { - return Err(WitnessResolverError::Other( - witness_id, - AnchorResolverError::UnsupportedLayer1(witness_id.layer1()).to_string(), - )); - }; - - if let Some(tx) = self.terminal_txes.get(&txid) { - return Ok(XWitnessTx::Bitcoin(tx.clone())); - } - - match self.electrum_client.transaction_get_raw(&txid) { - Ok(raw_tx) => { - let tx = Tx::consensus_deserialize(raw_tx).map_err(|_| { - WitnessResolverError::Other(witness_id, s!("cannot deserialize raw TX")) - })?; - Ok(XWitnessTx::Bitcoin(tx)) - } - Err(e) - if e.to_string() - .contains("No such mempool or blockchain transaction") => - { - Err(WitnessResolverError::Unknown(witness_id)) - } - Err(e) => Err(WitnessResolverError::Other(witness_id, e.to_string())), - } - } -} diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs new file mode 100644 index 0000000..7ff25cf --- /dev/null +++ b/src/resolvers/electrum_blocking.rs @@ -0,0 +1,92 @@ +// RGB smart contracts for Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2024 by +// Zoe Faltibà +// Rewritten in 2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 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 bp::ConsensusDecode; +use bpstd::{Tx, Txid}; +use electrum::{Client, ElectrumApi, Error, Param}; +use rgbstd::{WitnessAnchor, WitnessOrd, WitnessPos, XWitnessId}; + +use super::RgbResolver; + +impl RgbResolver for Client { + fn resolve_height(&mut self, txid: Txid) -> Result { + let mut witness_anchor = WitnessAnchor { + witness_ord: WitnessOrd::OffChain, + witness_id: XWitnessId::Bitcoin(txid), + }; + + let tx_details = self + .raw_call("blockchain.transaction.get", vec![ + Param::String(txid.to_string()), + Param::Bool(true), + ]) + .map_err(|e| e.to_string())?; + + let Some(confirmations) = tx_details.get("confirmations") else { + return Ok(witness_anchor); + }; + let confirmations = confirmations + .as_u64() + .and_then(|x| u32::try_from(x).ok()) + .ok_or(Error::InvalidResponse(tx_details.clone())) + .map_err(|e| e.to_string())?; + + let header = self.block_headers_subscribe().map_err(|e| e.to_string())?; + let last_block_height_min = + u32::try_from(header.height).map_err(|_| s!("height overflow"))?; + let last_block_height_max = last_block_height_min; + let skew = confirmations - 1; + let mut tx_height: u32 = 0; + for height in (last_block_height_min - skew)..=(last_block_height_max - skew) { + if let Ok(get_merkle_res) = self.transaction_get_merkle(&txid, height as usize) { + tx_height = u32::try_from(get_merkle_res.block_height) + .map_err(|_| s!("height overflow"))?; + break; + } + } + let block_time = tx_details + .get("blocktime") + .and_then(|v| v.as_i64()) + .ok_or(Error::InvalidResponse(tx_details.clone())) + .map_err(|e| e.to_string())?; + witness_anchor.witness_ord = WitnessOrd::OnChain( + WitnessPos::new(tx_height, block_time) + .ok_or(Error::InvalidResponse(tx_details.clone())) + .map_err(|e| e.to_string())?, + ); + + Ok(witness_anchor) + } + + fn resolve_pub_witness(&self, txid: Txid) -> Result> { + let raw_tx = self.transaction_get_raw(&txid).map_err(|e| { + let e = e.to_string(); + if e.contains("No such mempool or blockchain transaction") { + return None; + } + Some(e) + })?; + Tx::consensus_deserialize(raw_tx) + .map_err(|e| Some(format!("cannot deserialize raw TX - {e}"))) + } +} diff --git a/src/resolvers/esplora_blocking.rs b/src/resolvers/esplora_blocking.rs index b167751..4c53c8a 100644 --- a/src/resolvers/esplora_blocking.rs +++ b/src/resolvers/esplora_blocking.rs @@ -19,73 +19,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::HashMap; +use bp::Tx; +use bpstd::Txid; +use esplora::{BlockingClient, Error}; +use rgbstd::{WitnessAnchor, WitnessOrd, WitnessPos}; -use bpstd::{Tx, Txid}; -pub use esplora::Error as ResolverError; -use rgbstd::containers::Consignment; -use rgbstd::resolvers::ResolveHeight; -use rgbstd::validation::{ResolveWitness, WitnessResolverError}; -use rgbstd::{Layer1, WitnessAnchor, WitnessOrd, WitnessPos, XChain, XWitnessId, XWitnessTx}; +use super::RgbResolver; +use crate::XWitnessId; -pub struct Resolver { - esplora_client: esplora::BlockingClient, - terminal_txes: HashMap, -} - -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum AnchorResolverError { - #[from] - #[display(inner)] - Error(esplora::Error), - - /// unsupported layer 1 {0} - UnsupportedLayer1(Layer1), -} - -impl Resolver { - #[allow(clippy::result_large_err)] - pub fn new(url: &str) -> Result { - let esplora_client = esplora::Builder::new(url).build_blocking()?; - Ok(Self { - esplora_client, - terminal_txes: none!(), - }) - } - - pub fn add_witnesses(&mut self, consignment: &Consignment) { - self.terminal_txes.extend( - consignment - .bundles - .iter() - .filter_map(|bw| bw.pub_witness.maybe_map_ref(|w| w.tx.clone())) - .filter_map(|tx| match tx { - XChain::Bitcoin(tx) => Some(tx), - XChain::Liquid(_) | XChain::Other(_) => None, - }) - .map(|tx| (tx.txid(), tx)), - ); - } -} - -impl ResolveHeight for Resolver { - type Error = AnchorResolverError; - - fn resolve_height(&mut self, witness_id: XWitnessId) -> Result { - let XWitnessId::Bitcoin(txid) = witness_id else { - return Err(AnchorResolverError::UnsupportedLayer1(witness_id.layer1())); - }; - - if self.terminal_txes.contains_key(&txid) { - return Ok(WitnessAnchor { - witness_ord: WitnessOrd::OffChain, - witness_id, - }); - } - - let status = self.esplora_client.tx_status(&txid)?; +impl RgbResolver for BlockingClient { + fn resolve_height(&mut self, txid: Txid) -> Result { + let status = self.tx_status(&txid)?; let ord = match status .block_height .and_then(|h| status.block_time.map(|t| (h, t))) @@ -97,31 +41,16 @@ impl ResolveHeight for Resolver { }; Ok(WitnessAnchor { witness_ord: ord, - witness_id, + witness_id: XWitnessId::Bitcoin(txid), }) } -} - -impl ResolveWitness for Resolver { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - let XWitnessId::Bitcoin(txid) = witness_id else { - return Err(WitnessResolverError::Other( - witness_id, - AnchorResolverError::UnsupportedLayer1(witness_id.layer1()).to_string(), - )); - }; - - if let Some(tx) = self.terminal_txes.get(&txid) { - return Ok(XWitnessTx::Bitcoin(tx.clone())); - } - self.esplora_client - .tx(&txid) - .map_err(|err| WitnessResolverError::Other(witness_id, err.to_string()))? - .ok_or(WitnessResolverError::Unknown(witness_id)) - .map(XChain::Bitcoin) + fn resolve_pub_witness(&self, txid: Txid) -> Result> { + self.tx(&txid) + .map_err(|e| match e { + Error::TransactionNotFound(_) => None, + e => Some(e.to_string()), + })? + .ok_or(None) } } diff --git a/src/resolvers/mod.rs b/src/resolvers/mod.rs index 3452915..3ef5322 100644 --- a/src/resolvers/mod.rs +++ b/src/resolvers/mod.rs @@ -19,12 +19,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(any(feature = "electrum", feature = "esplora_blocking"))] mod any; #[cfg(feature = "esplora_blocking")] pub mod esplora_blocking; -#[cfg(feature = "electrum")] -pub mod electrum; +#[cfg(feature = "electrum_blocking")] +pub mod electrum_blocking; -#[cfg(any(feature = "electrum", feature = "esplora_blocking"))] -pub use any::{AnyResolver, AnyResolverError}; +pub use any::{AnyResolver, RgbResolver}; From 8b7506fb7f38ddf98dd0f8779ad7bb431f8a2d2c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 1 May 2024 15:09:35 +0200 Subject: [PATCH 22/32] runtime: fix storing of modified stock and wallet after the payments --- src/store.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/store.rs b/src/store.rs index 4caa713..eeeed8e 100644 --- a/src/store.rs +++ b/src/store.rs @@ -197,6 +197,8 @@ where invoice: &RgbInvoice, params: TransferParams, ) -> Result<(Psbt, PsbtMeta, Transfer), PayError> { + self.stock_dirty = true; + self.wallet_dirty = true; self.wallet.pay(&mut self.stock, invoice, params) } @@ -206,6 +208,7 @@ where invoice: &RgbInvoice, params: TransferParams, ) -> Result<(Psbt, PsbtMeta), CompositionError> { + self.wallet_dirty = true; self.wallet.construct_psbt_rgb(&self.stock, invoice, params) } @@ -215,6 +218,8 @@ where invoice: &RgbInvoice, psbt: &mut Psbt, ) -> Result { + self.stock_dirty = true; + self.wallet_dirty = true; self.wallet.transfer(&mut self.stock, invoice, psbt) } From d6c4228f22e77f84bbf6ceb1867e2e07752b7462 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 1 May 2024 16:14:28 +0200 Subject: [PATCH 23/32] fix wallet serde serialization --- Cargo.lock | 12 ++++++------ src/store.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8fd5f14..a285e36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,7 +369,7 @@ dependencies = [ [[package]] name = "bp-derive" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#3703d406e76d7ce1f85dd811a416569b4fabd889" dependencies = [ "amplify", "bitcoin_hashes", @@ -418,7 +418,7 @@ dependencies = [ [[package]] name = "bp-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#3703d406e76d7ce1f85dd811a416569b4fabd889" dependencies = [ "amplify", "bech32", @@ -446,7 +446,7 @@ dependencies = [ [[package]] name = "bp-std" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#3703d406e76d7ce1f85dd811a416569b4fabd889" dependencies = [ "amplify", "bp-consensus", @@ -460,7 +460,7 @@ dependencies = [ [[package]] name = "bp-wallet" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-wallet?branch=develop#e4c1a7c68c28f2963b9699c4de9017581ede39c3" +source = "git+https://github.com/BP-WG/bp-wallet?branch=develop#03bb754618f99351d56f5f972a62f0580292a8e8" dependencies = [ "amplify", "base64 0.21.7", @@ -713,7 +713,7 @@ dependencies = [ [[package]] name = "descriptors" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#3703d406e76d7ce1f85dd811a416569b4fabd889" dependencies = [ "amplify", "bp-derive", @@ -1383,7 +1383,7 @@ dependencies = [ [[package]] name = "psbt" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-std?branch=develop#987ed3cd2a3cb9619e62b1f887a46b412c52d27a" +source = "git+https://github.com/BP-WG/bp-std?branch=develop#3703d406e76d7ce1f85dd811a416569b4fabd889" dependencies = [ "amplify", "base64 0.21.7", diff --git a/src/store.rs b/src/store.rs index eeeed8e..f3008cd 100644 --- a/src/store.rs +++ b/src/store.rs @@ -224,7 +224,7 @@ where } pub fn store(&self) { - let r1 = if self.wallet_dirty { + let r1 = if self.stock_dirty { self.stock .store(&self.stock_path) .map_err(|e| e.to_string()) From a0076ae0fe1c9d4b4876b1c1144e7f4a660fc4ff Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 1 May 2024 20:52:09 +0200 Subject: [PATCH 24/32] wallet: fix wallet store path --- cli/src/args.rs | 5 +++-- src/store.rs | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cli/src/args.rs b/cli/src/args.rs index 9329d5a..917311a 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -112,8 +112,9 @@ impl RgbArgs { ) -> Result>, WalletError> { let stock_path = self.general.base_dir(); let stock = self.load_stock(&stock_path)?; - let wallet = self.inner.bp_runtime::(config)?.detach(); - let wallet = StoredWallet::attach(stock_path, stock, wallet); + let wallet = self.inner.bp_runtime::(config)?; + let wallet_path = wallet.path().clone(); + let wallet = StoredWallet::attach(stock_path, wallet_path, stock, wallet.detach()); Ok(wallet) } diff --git a/src/store.rs b/src/store.rs index f3008cd..2285255 100644 --- a/src/store.rs +++ b/src/store.rs @@ -141,6 +141,7 @@ pub struct StoredWallet< P: StoreFs, { stock_path: PathBuf, + wallet_path: Option, stock: Stock, wallet: W, #[getter(prefix = "is_")] @@ -160,9 +161,15 @@ where H: StoreFs, P: StoreFs, { - pub fn attach(path: PathBuf, stock: Stock, wallet: W) -> Self { + pub fn attach( + stock_path: PathBuf, + wallet_path: Option, + stock: Stock, + wallet: W, + ) -> Self { Self { - stock_path: path, + stock_path, + wallet_path, stock, wallet, stock_dirty: false, @@ -232,9 +239,11 @@ where Ok(()) }; let r2 = if self.wallet_dirty { - self.wallet - .store(&self.stock_path) - .map_err(|e| e.to_string()) + if let Some(path) = self.wallet_path.as_ref() { + self.wallet.store(path).map_err(|e| e.to_string()) + } else { + Ok(()) + } } else { Ok(()) }; From 790ba4b18bb8097b0f51953097f51d2965528ec5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 1 May 2024 21:50:31 +0200 Subject: [PATCH 25/32] resolver: fix electrum consistency --- src/resolvers/electrum_blocking.rs | 46 +++++++++++++----------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index 7ff25cf..21ec411 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -28,6 +28,12 @@ use rgbstd::{WitnessAnchor, WitnessOrd, WitnessPos, XWitnessId}; use super::RgbResolver; +macro_rules! check { + ($e:expr) => { + $e.map_err(|e| e.to_string())? + }; +} + impl RgbResolver for Client { fn resolve_height(&mut self, txid: Txid) -> Result { let mut witness_anchor = WitnessAnchor { @@ -35,35 +41,23 @@ impl RgbResolver for Client { witness_id: XWitnessId::Bitcoin(txid), }; - let tx_details = self - .raw_call("blockchain.transaction.get", vec![ - Param::String(txid.to_string()), - Param::Bool(true), - ]) - .map_err(|e| e.to_string())?; + let tx_details = check!(self.raw_call("blockchain.transaction.get", vec![ + Param::String(txid.to_string()), + Param::Bool(true), + ])); - let Some(confirmations) = tx_details.get("confirmations") else { - return Ok(witness_anchor); + let mut header = check!(self.block_headers_subscribe()); + let tx_height = loop { + let height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; + let get_merkle_res = check!(self.transaction_get_merkle(&txid, height as usize)); + let tx_height = u32::try_from(get_merkle_res.block_height) + .map_err(|_| s!("impossible height value"))?; + match check!(self.block_headers_pop()) { + None => break tx_height, + Some(h) => header = h, + } }; - let confirmations = confirmations - .as_u64() - .and_then(|x| u32::try_from(x).ok()) - .ok_or(Error::InvalidResponse(tx_details.clone())) - .map_err(|e| e.to_string())?; - let header = self.block_headers_subscribe().map_err(|e| e.to_string())?; - let last_block_height_min = - u32::try_from(header.height).map_err(|_| s!("height overflow"))?; - let last_block_height_max = last_block_height_min; - let skew = confirmations - 1; - let mut tx_height: u32 = 0; - for height in (last_block_height_min - skew)..=(last_block_height_max - skew) { - if let Ok(get_merkle_res) = self.transaction_get_merkle(&txid, height as usize) { - tx_height = u32::try_from(get_merkle_res.block_height) - .map_err(|_| s!("height overflow"))?; - break; - } - } let block_time = tx_details .get("blocktime") .and_then(|v| v.as_i64()) From 594d7f64f4d0f7c9825ffd138e86575c26ec4182 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 1 May 2024 22:22:43 +0200 Subject: [PATCH 26/32] resover: second fix of electrum consistency --- src/resolvers/electrum_blocking.rs | 50 +++++++++++++++++++++--------- src/resolvers/esplora_blocking.rs | 6 ++-- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index 21ec411..0f63dcb 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -41,33 +41,53 @@ impl RgbResolver for Client { witness_id: XWitnessId::Bitcoin(txid), }; + // We get the height of the tip of blockchain + let header = check!(self.block_headers_subscribe()); + + // Now we get and parse transaction information to get the number of + // confirmations let tx_details = check!(self.raw_call("blockchain.transaction.get", vec![ Param::String(txid.to_string()), Param::Bool(true), ])); - let mut header = check!(self.block_headers_subscribe()); + let Some(confirmations) = tx_details.get("confirmations") else { + return Ok(witness_anchor); + }; + let confirmations = check!( + confirmations + .as_u64() + .and_then(|x| u32::try_from(x).ok()) + .ok_or(Error::InvalidResponse(tx_details.clone())) + ); + let block_time = check!( + tx_details + .get("blocktime") + .and_then(|v| v.as_i64()) + .ok_or(Error::InvalidResponse(tx_details.clone())) + ); + + let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; + let mut height: usize = (tip_height + 1 - confirmations) as usize; let tx_height = loop { - let height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; - let get_merkle_res = check!(self.transaction_get_merkle(&txid, height as usize)); - let tx_height = u32::try_from(get_merkle_res.block_height) - .map_err(|_| s!("impossible height value"))?; - match check!(self.block_headers_pop()) { - None => break tx_height, - Some(h) => header = h, + match self.transaction_get_merkle(&txid, height) { + Ok(get_merkle_res) => { + break u32::try_from(get_merkle_res.block_height) + .map_err(|_| s!("impossible height value"))?; + } + Err(Error::Protocol(_)) if self.block_headers_pop().ok().flatten().is_some() => { + height += 1; + continue; + } + Err(err) => return Err(err.to_string()), } }; - let block_time = tx_details - .get("blocktime") - .and_then(|v| v.as_i64()) - .ok_or(Error::InvalidResponse(tx_details.clone())) - .map_err(|e| e.to_string())?; - witness_anchor.witness_ord = WitnessOrd::OnChain( + let pos = check!( WitnessPos::new(tx_height, block_time) .ok_or(Error::InvalidResponse(tx_details.clone())) - .map_err(|e| e.to_string())?, ); + witness_anchor.witness_ord = WitnessOrd::OnChain(pos); Ok(witness_anchor) } diff --git a/src/resolvers/esplora_blocking.rs b/src/resolvers/esplora_blocking.rs index 4c53c8a..d37e874 100644 --- a/src/resolvers/esplora_blocking.rs +++ b/src/resolvers/esplora_blocking.rs @@ -34,9 +34,9 @@ impl RgbResolver for BlockingClient { .block_height .and_then(|h| status.block_time.map(|t| (h, t))) { - Some((h, t)) => WitnessOrd::OnChain( - WitnessPos::new(h, t as i64).ok_or(esplora::Error::InvalidServerData)?, - ), + Some((h, t)) => { + WitnessOrd::OnChain(WitnessPos::new(h, t as i64).ok_or(Error::InvalidServerData)?) + } None => WitnessOrd::OffChain, }; Ok(WitnessAnchor { From e8ad27ab5dc75877c714c3acfd519dd092cae573 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 2 May 2024 10:20:20 +0200 Subject: [PATCH 27/32] resolver: improve electrum performance --- src/resolvers/electrum_blocking.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index 0f63dcb..6cbd187 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -21,6 +21,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::iter; + use bp::ConsensusDecode; use bpstd::{Tx, Txid}; use electrum::{Client, ElectrumApi, Error, Param}; @@ -50,6 +52,7 @@ impl RgbResolver for Client { Param::String(txid.to_string()), Param::Bool(true), ])); + let forward = iter::from_fn(|| self.block_headers_pop().ok().flatten()).count(); let Some(confirmations) = tx_details.get("confirmations") else { return Ok(witness_anchor); @@ -68,20 +71,12 @@ impl RgbResolver for Client { ); let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; - let mut height: usize = (tip_height + 1 - confirmations) as usize; - let tx_height = loop { - match self.transaction_get_merkle(&txid, height) { - Ok(get_merkle_res) => { - break u32::try_from(get_merkle_res.block_height) - .map_err(|_| s!("impossible height value"))?; - } - Err(Error::Protocol(_)) if self.block_headers_pop().ok().flatten().is_some() => { - height += 1; - continue; - } - Err(err) => return Err(err.to_string()), - } - }; + let height: usize = (tip_height + 1 - confirmations) as usize; + let get_merkle_res = (0..=forward) + .find_map(|offset| self.transaction_get_merkle(&txid, height + offset).ok()) + .ok_or_else(|| s!("transaction can't be located in the blockchain"))?; + let tx_height = u32::try_from(get_merkle_res.block_height) + .map_err(|_| s!("impossible height value"))?; let pos = check!( WitnessPos::new(tx_height, block_time) From 750cb893c4a819b582593dfa5ec7ec20b0d9e4f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Fri, 3 May 2024 16:20:56 +0200 Subject: [PATCH 28/32] electrum: add safety margins for tx height check --- src/resolvers/electrum_blocking.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index 6cbd187..b7c0566 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -72,9 +72,16 @@ impl RgbResolver for Client { let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; let height: usize = (tip_height + 1 - confirmations) as usize; - let get_merkle_res = (0..=forward) + // first check from expected min to max height then max + 1 and finally min - 1 + let get_merkle_res = if let Some(res) = (0..=forward + 1) .find_map(|offset| self.transaction_get_merkle(&txid, height + offset).ok()) - .ok_or_else(|| s!("transaction can't be located in the blockchain"))?; + { + res + } else { + self.transaction_get_merkle(&txid, height - 1) + .or_else(|_| Err(s!("transaction can't be located in the blockchain")))? + }; + let tx_height = u32::try_from(get_merkle_res.block_height) .map_err(|_| s!("impossible height value"))?; From f69200e36f1fa7ea2b9ebc34f6b8f061b1b5be1f Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 3 May 2024 17:24:55 +0200 Subject: [PATCH 29/32] resolver: make electrum checks rusty --- src/resolvers/electrum_blocking.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index b7c0566..044df1a 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -71,16 +71,12 @@ impl RgbResolver for Client { ); let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; - let height: usize = (tip_height + 1 - confirmations) as usize; + let height: usize = (tip_height - confirmations) as usize; // first check from expected min to max height then max + 1 and finally min - 1 - let get_merkle_res = if let Some(res) = (0..=forward + 1) + let get_merkle_res = (1..=forward + 1) + .chain([0]) .find_map(|offset| self.transaction_get_merkle(&txid, height + offset).ok()) - { - res - } else { - self.transaction_get_merkle(&txid, height - 1) - .or_else(|_| Err(s!("transaction can't be located in the blockchain")))? - }; + .ok_or_else(|| s!("transaction can't be located in the blockchain"))?; let tx_height = u32::try_from(get_merkle_res.block_height) .map_err(|_| s!("impossible height value"))?; From 765b835511e473f5be8581fb0f1b8a890b0fa5f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 2 May 2024 17:08:06 +0200 Subject: [PATCH 30/32] resolver: implement check --- Cargo.lock | 55 +++++++++++++++++------------- cli/src/args.rs | 6 ++-- src/resolvers/any.rs | 13 +++++++ src/resolvers/electrum_blocking.rs | 32 ++++++++++++++++- src/resolvers/esplora_blocking.rs | 11 +++++- 5 files changed, 89 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a285e36..b049fc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,47 +124,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -323,7 +324,7 @@ dependencies = [ [[package]] name = "bp-consensus" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#289f1d31fd404b76b1ac04edb1024bdbe4386416" dependencies = [ "amplify", "chrono", @@ -337,7 +338,7 @@ dependencies = [ [[package]] name = "bp-core" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#289f1d31fd404b76b1ac04edb1024bdbe4386416" dependencies = [ "amplify", "bp-consensus", @@ -355,7 +356,7 @@ dependencies = [ [[package]] name = "bp-dbc" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#289f1d31fd404b76b1ac04edb1024bdbe4386416" dependencies = [ "amplify", "base85", @@ -430,7 +431,7 @@ dependencies = [ [[package]] name = "bp-seals" version = "0.11.0-beta.5" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#970147b7cfa3dd3013ceec5bc6eacaea7c0d7bb9" +source = "git+https://github.com/BP-WG/bp-core?branch=develop#289f1d31fd404b76b1ac04edb1024bdbe4386416" dependencies = [ "amplify", "baid64", @@ -567,9 +568,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "commit_encoding_derive" @@ -1144,6 +1145,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itoa" version = "1.0.11" @@ -1520,7 +1527,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#f0469333a36abcb70dff6667938fc1eae438e1d2" +source = "git+https://github.com/RGB-WG/rgb-core?branch=develop#b34b2c7b96f669fb8bc7145ec7094cb65d8bbdf3" dependencies = [ "aluvm", "amplify", @@ -1541,7 +1548,7 @@ dependencies = [ [[package]] name = "rgb-interfaces" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#1fb09cb8c23e062c8a059fb9afec7f2f135440ae" +source = "git+https://github.com/RGB-WG/rgb-interfaces?branch=develop#d688b6a98f547f24b7edc7f96b30b6c1e94893ef" dependencies = [ "aluvm", "amplify", @@ -1557,7 +1564,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#75fb0dd098574957478bf6d4bf3533abc325efb5" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#47413dfdda70dcf7963a9b4b03f406e374e15fae" dependencies = [ "amplify", "baid64", @@ -1617,7 +1624,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.5" -source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#75fb0dd098574957478bf6d4bf3533abc325efb5" +source = "git+https://github.com/RGB-WG/rgb-std?branch=develop#47413dfdda70dcf7963a9b4b03f406e374e15fae" dependencies = [ "aluvm", "amplify", @@ -1887,18 +1894,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.199" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", diff --git a/cli/src/args.rs b/cli/src/args.rs index 917311a..b4c5166 100644 --- a/cli/src/args.rs +++ b/cli/src/args.rs @@ -120,11 +120,13 @@ impl RgbArgs { } pub fn resolver(&self) -> Result { - match (&self.resolver.esplora, &self.resolver.electrum) { + let resolver = match (&self.resolver.esplora, &self.resolver.electrum) { (None, Some(url)) => AnyResolver::electrum_blocking(url), (Some(url), None) => AnyResolver::esplora_blocking(url), _ => unreachable!("clap is broken"), } - .map_err(WalletError::Resolver) + .map_err(WalletError::Resolver)?; + resolver.check(self.general.network)?; + Ok(resolver) } } diff --git a/src/resolvers/any.rs b/src/resolvers/any.rs index f4fff79..b85376e 100644 --- a/src/resolvers/any.rs +++ b/src/resolvers/any.rs @@ -24,6 +24,7 @@ use std::collections::HashMap; use bp::Tx; +use bpstd::Network; use rgbstd::containers::Consignment; use rgbstd::resolvers::ResolveHeight; use rgbstd::validation::{ResolveWitness, WitnessResolverError}; @@ -32,6 +33,7 @@ use rgbstd::{WitnessAnchor, XWitnessId, XWitnessTx}; use crate::{Txid, WitnessOrd, XChain}; pub trait RgbResolver { + fn check(&self, network: Network, expected_block_hash: String) -> Result<(), String>; fn resolve_height(&mut self, txid: Txid) -> Result; fn resolve_pub_witness(&self, txid: Txid) -> Result>; } @@ -65,6 +67,17 @@ impl AnyResolver { }) } + pub fn check(&self, network: Network) -> Result<(), String> { + let expected_block_hash = match network { + Network::Mainnet => "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + Network::Testnet3 => "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", + Network::Signet => "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6", + Network::Regtest => "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", + } + .to_string(); + self.inner.check(network, expected_block_hash) + } + pub fn add_terminals(&mut self, consignment: &Consignment) { self.terminal_txes.extend( consignment diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index 6cbd187..6953659 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -24,7 +24,7 @@ use std::iter; use bp::ConsensusDecode; -use bpstd::{Tx, Txid}; +use bpstd::{Network, Tx, Txid}; use electrum::{Client, ElectrumApi, Error, Param}; use rgbstd::{WitnessAnchor, WitnessOrd, WitnessPos, XWitnessId}; @@ -37,6 +37,36 @@ macro_rules! check { } impl RgbResolver for Client { + fn check(&self, network: Network, expected_block_hash: String) -> Result<(), String> { + // check the electrum server is for the correct network + let block_hash = check!(self.block_header(0)).block_hash().to_string(); + if expected_block_hash != block_hash { + return Err(s!("resolver is for a network different from the wallet's one")); + } + // check the electrum server has the required functionality (verbose + // transactions) + let txid = match network { + Network::Mainnet => "33e794d097969002ee05d336686fc03c9e15a597c1b9827669460fac98799036", + Network::Testnet3 => "5e6560fd518aadbed67ee4a55bdc09f19e619544f5511e9343ebba66d2f62653", + Network::Signet => "8153034f45e695453250a8fb7225a5e545144071d8ed7b0d3211efa1f3c92ad8", + Network::Regtest => "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + }; + if let Err(e) = self.raw_call("blockchain.transaction.get", vec![ + Param::String(txid.to_string()), + Param::Bool(true), + ]) { + if !e + .to_string() + .contains("genesis block coinbase is not considered an ordinary transaction") + { + return Err(s!( + "verbose transactions are unsupported by the provided electrum service" + )); + } + } + Ok(()) + } + fn resolve_height(&mut self, txid: Txid) -> Result { let mut witness_anchor = WitnessAnchor { witness_ord: WitnessOrd::OffChain, diff --git a/src/resolvers/esplora_blocking.rs b/src/resolvers/esplora_blocking.rs index d37e874..374c3dd 100644 --- a/src/resolvers/esplora_blocking.rs +++ b/src/resolvers/esplora_blocking.rs @@ -20,7 +20,7 @@ // limitations under the License. use bp::Tx; -use bpstd::Txid; +use bpstd::{Network, Txid}; use esplora::{BlockingClient, Error}; use rgbstd::{WitnessAnchor, WitnessOrd, WitnessPos}; @@ -28,6 +28,15 @@ use super::RgbResolver; use crate::XWitnessId; impl RgbResolver for BlockingClient { + fn check(&self, _network: Network, expected_block_hash: String) -> Result<(), String> { + // check the esplora server is for the correct network + let block_hash = self.block_hash(0)?.to_string(); + if expected_block_hash != block_hash { + return Err(s!("resolver is for a network different from the wallet's one")); + } + Ok(()) + } + fn resolve_height(&mut self, txid: Txid) -> Result { let status = self.tx_status(&txid)?; let ord = match status From ce75db2c62673d70f79bb739d1196b1d8b75d25d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 4 May 2024 11:44:16 +0200 Subject: [PATCH 31/32] resolver: add safety margins to electrum resolver --- src/resolvers/electrum_blocking.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index 044df1a..96d23be 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -52,7 +52,7 @@ impl RgbResolver for Client { Param::String(txid.to_string()), Param::Bool(true), ])); - let forward = iter::from_fn(|| self.block_headers_pop().ok().flatten()).count(); + let forward = iter::from_fn(|| self.block_headers_pop().ok().flatten()).count() as isize; let Some(confirmations) = tx_details.get("confirmations") else { return Ok(witness_anchor); @@ -71,11 +71,14 @@ impl RgbResolver for Client { ); let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; - let height: usize = (tip_height - confirmations) as usize; - // first check from expected min to max height then max + 1 and finally min - 1 + let height: isize = (tip_height - confirmations) as isize; + const SAFETY_MARGIN: isize = 1; + // first check from expected min to max height, then max + 1 and finally min - 1 let get_merkle_res = (1..=forward + 1) - .chain([0]) - .find_map(|offset| self.transaction_get_merkle(&txid, height + offset).ok()) + // we need this under assumption that electrum was lying due to "DB desynchronization" + // since this have a very low probability we do that after everything else + .chain((1..=SAFETY_MARGIN).flat_map(|i| [i + forward + 1, 1 - i])) + .find_map(|offset| self.transaction_get_merkle(&txid, (height + offset) as usize).ok()) .ok_or_else(|| s!("transaction can't be located in the blockchain"))?; let tx_height = u32::try_from(get_merkle_res.block_height) From c58e58da9259d1c2feb7aec5d13db13a8228db63 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 6 May 2024 10:12:03 +0200 Subject: [PATCH 32/32] whatever --- src/resolvers/electrum_blocking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolvers/electrum_blocking.rs b/src/resolvers/electrum_blocking.rs index 96d23be..90f2d47 100644 --- a/src/resolvers/electrum_blocking.rs +++ b/src/resolvers/electrum_blocking.rs @@ -73,7 +73,7 @@ impl RgbResolver for Client { let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; let height: isize = (tip_height - confirmations) as isize; const SAFETY_MARGIN: isize = 1; - // first check from expected min to max height, then max + 1 and finally min - 1 + // first check from expected min to max height let get_merkle_res = (1..=forward + 1) // we need this under assumption that electrum was lying due to "DB desynchronization" // since this have a very low probability we do that after everything else