From fd510291976ab66c91cbc538f5d005a3cb734001 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Wed, 27 Oct 2021 16:34:33 +0200 Subject: [PATCH 1/4] add method add_data as a shortcut to create an OP_RETURN output, fix the dust check to consider only spendable output --- src/wallet/mod.rs | 2 +- src/wallet/tx_builder.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 1f6353cd2..b8d1196d9 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -601,7 +601,7 @@ where let recipients = params.recipients.iter().map(|(r, v)| (r, *v)); for (index, (script_pubkey, value)) in recipients.enumerate() { - if value.is_dust() { + if value.is_dust() && !script_pubkey.is_provably_unspendable() { return Err(Error::OutputBelowDustLimit(index)); } diff --git a/src/wallet/tx_builder.rs b/src/wallet/tx_builder.rs index a0ed93cbe..0c7f7f857 100644 --- a/src/wallet/tx_builder.rs +++ b/src/wallet/tx_builder.rs @@ -560,6 +560,13 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm> TxBuilder<'a, B, D, self } + /// Add data as an output, using OP_RETURN + pub fn add_data(&mut self, data: &[u8]) -> &mut Self { + let script = Script::new_op_return(data); + self.add_recipient(script, 0u64); + self + } + /// Sets the address to *drain* excess coins to. /// /// Usually, when there are excess coins they are sent to a change address generated by the From b2d7412d6d03431f9066000bd92842f780ca61c8 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Wed, 27 Oct 2021 16:56:46 +0200 Subject: [PATCH 2/4] add test for add_data --- src/testutils/blockchain_tests.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/testutils/blockchain_tests.rs b/src/testutils/blockchain_tests.rs index 02276548f..e2d7df365 100644 --- a/src/testutils/blockchain_tests.rs +++ b/src/testutils/blockchain_tests.rs @@ -849,6 +849,37 @@ macro_rules! bdk_blockchain_tests { assert_eq!(new_details.received, 0, "incorrect received after add input"); } + + #[test] + fn test_add_data() { + let (wallet, descriptors, mut test_client) = init_single_sig(); + let node_addr = test_client.get_node_address(None); + let _ = test_client.receive(testutils! { + @tx ( (@external descriptors, 0) => 50_000 ) + }); + + wallet.sync(noop_progress(), None).unwrap(); + assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance"); + + let mut builder = wallet.build_tx(); + let data = [42u8;80]; + builder.add_data(&data); + let (mut psbt, details) = builder.finish().unwrap(); + + let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); + assert!(finalized, "Cannot finalize transaction"); + let tx = psbt.extract_tx(); + let serialized_tx = bitcoin::consensus::encode::serialize(&tx); + assert!(serialized_tx.windows(data.len()).any(|e| e==data), "cannot find op_return data in transaction"); + let sent_txid = wallet.broadcast(tx).unwrap(); + test_client.generate(1, Some(node_addr)); + wallet.sync(noop_progress(), None).unwrap(); + assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fee.unwrap_or(0), "incorrect balance after send"); + + let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::>(); + let _ = tx_map.get(&sent_txid).unwrap(); + } + #[test] fn test_sync_receive_coinbase() { let (wallet, _, mut test_client) = init_single_sig(); From 8010d692e9394d50a7ff31ec13e4e70fe6e5c964 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Thu, 28 Oct 2021 10:06:52 +0200 Subject: [PATCH 3/4] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddb80403c..757baaa34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - BIP39 implementation dependency, in `keys::bip39` changed from tiny-bip39 to rust-bip39. +- Add new method on the `TxBuilder` to embed data in the transaction via `OP_RETURN`. To allow that a fix to check the dust only on spendable output has been introduced. ## [v0.13.0] - [v0.12.0] From aa075f0b2f070173c6e9bf9f4160b08ad3124940 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 9 Nov 2021 15:35:34 +0100 Subject: [PATCH 4/4] fix after merge changing borrow of tx in broadcast --- src/testutils/blockchain_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testutils/blockchain_tests.rs b/src/testutils/blockchain_tests.rs index e2d7df365..b44a97182 100644 --- a/src/testutils/blockchain_tests.rs +++ b/src/testutils/blockchain_tests.rs @@ -871,7 +871,7 @@ macro_rules! bdk_blockchain_tests { let tx = psbt.extract_tx(); let serialized_tx = bitcoin::consensus::encode::serialize(&tx); assert!(serialized_tx.windows(data.len()).any(|e| e==data), "cannot find op_return data in transaction"); - let sent_txid = wallet.broadcast(tx).unwrap(); + let sent_txid = wallet.broadcast(&tx).unwrap(); test_client.generate(1, Some(node_addr)); wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fee.unwrap_or(0), "incorrect balance after send");