From 972683554ce11037a8de3227df243e6fac3580a9 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 24 Mar 2024 19:24:00 +0100 Subject: [PATCH 1/2] pay: fix duplicated inputs --- src/pay.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/pay.rs b/src/pay.rs index 8cfde6a..43e039a 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -19,6 +19,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::collections::{BTreeMap, BTreeSet}; use std::convert::Infallible; use amplify::confinement::Confined; @@ -200,30 +201,37 @@ impl Runtime { .cloned() .ok_or(CompositionError::NoAssignment)?; - let outputs = match invoice.owned_state { + let prev_outputs = match invoice.owned_state { InvoiceState::Amount(amount) => { let filter = ContractOutpointsFilter { contract_id, filter: self, }; - let mut state = contract + let state: BTreeMap<_, Vec> = contract .fungible(assignment_name, &filter)? - .collect::>(); - state.sort_by_key(|a| a.state); + .fold(bmap![], |mut set, a| { + set.entry(a.seal).or_default().push(a.state); + set + }); + let mut state: Vec<_> = state + .into_iter() + .map(|(seal, vals)| (vals.iter().copied().sum::(), seal, vals)) + .collect(); + state.sort_by_key(|(sum, _, _)| *sum); let mut sum = Amount::ZERO; state .iter() .rev() - .take_while(|a| { + .take_while(|(val, _, _)| { if sum >= amount { false } else { - sum += a.state; + sum += *val; true } }) - .map(|a| a.seal) - .collect::>() + .map(|(_, seal, _)| *seal) + .collect::>() } _ => return Err(CompositionError::Unsupported), }; @@ -236,14 +244,15 @@ impl Runtime { )] } }; - let outpoints = outputs + let prev_outpoints = prev_outputs .iter() + // TODO: Support liquid .map(|o| o.as_reduced_unsafe()) .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(outpoints, &beneficiaries, params.tx)?; + .construct_psbt(prev_outpoints, &beneficiaries, params.tx)?; let beneficiary_script = if let Beneficiary::WitnessVout(addr) = invoice.beneficiary.into_inner() { @@ -284,8 +293,8 @@ impl Runtime { } Beneficiary::BlindedSeal(_) => None, }; - let batch = - self.compose(invoice, outputs, method, beneficiary_vout, |_, _, _| meta.change_vout)?; + let batch = self + .compose(invoice, prev_outputs, method, beneficiary_vout, |_, _, _| meta.change_vout)?; let methods = batch.close_method_set(); if methods.has_opret_first() { From ee782e28ebc8e7c7ed6e370e388066cd3132d1df Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 27 Mar 2024 11:23:17 +0100 Subject: [PATCH 2/2] psbt: fix issue with duplicated inputs --- Cargo.lock | 19 +++++++++++-------- Cargo.toml | 9 +++------ psbt/src/lib.rs | 11 ++++------- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6e8736..2f9de93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -466,8 +466,9 @@ dependencies = [ [[package]] name = "bp-util" -version = "0.11.0-beta.4" -source = "git+https://github.com/BP-WG/bp-wallet?branch=master#690d8f6bfe76f0f6cd8dbb0039368b1b9fcf45e7" +version = "0.11.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecf9b988b0c9536f1b95268b592d5425584527006027c38ed172e85bc71bdd85" dependencies = [ "amplify", "base64", @@ -489,8 +490,9 @@ dependencies = [ [[package]] name = "bp-wallet" -version = "0.11.0-beta.4" -source = "git+https://github.com/BP-WG/bp-wallet?branch=master#690d8f6bfe76f0f6cd8dbb0039368b1b9fcf45e7" +version = "0.11.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4552e90fad2ed01b091b499b891e7a5d9e03f3c74e718e0e4801b01056fc247" dependencies = [ "amplify", "bp-electrum", @@ -1568,8 +1570,9 @@ dependencies = [ [[package]] name = "rgb-core" -version = "0.11.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-core?branch=master#2e01d873e0f586e48452e2c74debc8d76a7406bd" +version = "0.11.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "377bc5d01d9b22fef51da1ab83cfc743bf29827ce11fc4a2616894282a95c6a8" dependencies = [ "aluvm", "amplify", @@ -1591,7 +1594,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-std?branch=master#9cb960452b46c9bd24bc57128f018a5954d2afa5" +source = "git+https://github.com/RGB-WG/rgb-std?branch=dups#f793a738ee1d1ce10f1a0fae4e1cd3d8189f074e" dependencies = [ "amplify", "baid58", @@ -1661,7 +1664,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-std?branch=master#9cb960452b46c9bd24bc57128f018a5954d2afa5" +source = "git+https://github.com/RGB-WG/rgb-std?branch=dups#f793a738ee1d1ce10f1a0fae4e1cd3d8189f074e" dependencies = [ "amplify", "ascii-armor", diff --git a/Cargo.toml b/Cargo.toml index af7994e..e7b3966 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,8 @@ strict_types = "2.7.0-beta.2" 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.4" -bp-util = "0.11.0-beta.4" +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" @@ -96,7 +96,4 @@ serde = ["serde_crate", "serde_with", "serde_yaml", "bp-std/serde", "bp-wallet/s features = ["all"] [patch.crates-io] -bp-util = { git = "https://github.com/BP-WG/bp-wallet", branch = "master" } -bp-wallet = { git = "https://github.com/BP-WG/bp-wallet", branch = "master" } -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "master" } -rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "master" } +rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "dups" } diff --git a/psbt/src/lib.rs b/psbt/src/lib.rs index fb16c45..33547d4 100644 --- a/psbt/src/lib.rs +++ b/psbt/src/lib.rs @@ -77,13 +77,10 @@ impl RgbPsbt for Psbt { let contract_id = info.transition.contract_id; let mut inputs = info.inputs.into_inner(); for input in self.inputs_mut() { - let outpoint = input.prevout().outpoint(); - if let Some(pos) = inputs.iter().position(|i| **i == XChain::Bitcoin(outpoint)) { - inputs.remove(pos); - input - .set_rgb_consumer(contract_id, info.id) - .map_err(|_| EmbedError::PsbtRepeatedInputs)?; - } + inputs.remove(&XChain::Bitcoin(input.prevout().outpoint())); + input + .set_rgb_consumer(contract_id, info.id) + .map_err(|_| EmbedError::PsbtRepeatedInputs)?; } if !inputs.is_empty() { return Err(EmbedError::AbsentInputs);