From 94b51b6629980c49b71f0e2a7c1982343db0226e Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 16 Dec 2023 00:30:28 +0800 Subject: [PATCH 1/2] Use pre-segwit tx serialization for fundrawtransaction --- src/lib.rs | 14 +++++++++++++- test-bitcoincore-rpc/src/lib.rs | 2 ++ test-bitcoincore-rpc/src/server.rs | 9 ++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7b8921141f..c18bf58866 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,15 +160,27 @@ fn fund_raw_transaction( fee_rate: FeeRate, unfunded_transaction: &Transaction, ) -> Result> { + let mut buffer = Vec::new(); + + { + unfunded_transaction.version.consensus_encode(&mut buffer)?; + unfunded_transaction.input.consensus_encode(&mut buffer)?; + unfunded_transaction.output.consensus_encode(&mut buffer)?; + unfunded_transaction + .lock_time + .consensus_encode(&mut buffer)?; + } + Ok( client .fund_raw_transaction( - unfunded_transaction, + &buffer, Some(&bitcoincore_rpc::json::FundRawTransactionOptions { // NB. This is `fundrawtransaction`'s `feeRate`, which is fee per kvB // and *not* fee per vB. So, we multiply the fee rate given by the user // by 1000. fee_rate: Some(Amount::from_sat((fee_rate.n() * 1000.0).ceil() as u64)), + change_position: Some(unfunded_transaction.output.len().try_into()?), ..Default::default() }), Some(false), diff --git a/test-bitcoincore-rpc/src/lib.rs b/test-bitcoincore-rpc/src/lib.rs index 3a3a1560a2..b12cf61fbf 100644 --- a/test-bitcoincore-rpc/src/lib.rs +++ b/test-bitcoincore-rpc/src/lib.rs @@ -162,6 +162,8 @@ impl From for JsonOutPoint { struct FundRawTransactionOptions { #[serde(with = "bitcoin::amount::serde::as_btc::opt")] fee_rate: Option, + #[serde(skip_serializing_if = "Option::is_none")] + change_position: Option, } #[derive(Deserialize, Clone, PartialEq, Eq, Debug, Serialize)] diff --git a/test-bitcoincore-rpc/src/server.rs b/test-bitcoincore-rpc/src/server.rs index 4655939f92..93b67a7bdc 100644 --- a/test-bitcoincore-rpc/src/server.rs +++ b/test-bitcoincore-rpc/src/server.rs @@ -243,8 +243,15 @@ impl Api for Server { options: Option, _is_witness: Option, ) -> Result { + let options = options.unwrap(); + let mut transaction: Transaction = deserialize(&hex::decode(tx).unwrap()).unwrap(); + assert_eq!( + options.change_position, + Some(transaction.output.len().try_into().unwrap()) + ); + let state = self.state(); let output_value = transaction @@ -294,7 +301,7 @@ impl Api for Server { script_pubkey: ScriptBuf::new(), }); - let fee = if let Some(fee_rate) = options.and_then(|options| options.fee_rate) { + let fee = if let Some(fee_rate) = options.fee_rate { // increase vsize to account for the witness that `fundrawtransaction` will add let funded_vsize = transaction.vsize() as f64 + 68.0 / 4.0; let funded_kwu = funded_vsize / 1000.0; From 301dcc23429682e50106caafbf8ed0f315277bd6 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 16 Dec 2023 08:59:39 +0800 Subject: [PATCH 2/2] Implement decoding --- test-bitcoincore-rpc/src/server.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test-bitcoincore-rpc/src/server.rs b/test-bitcoincore-rpc/src/server.rs index 93b67a7bdc..3ec18b188d 100644 --- a/test-bitcoincore-rpc/src/server.rs +++ b/test-bitcoincore-rpc/src/server.rs @@ -1,9 +1,11 @@ use { super::*, bitcoin::{ + consensus::Decodable, secp256k1::{rand, KeyPair, Secp256k1, XOnlyPublicKey}, Witness, }, + std::io::Cursor, }; pub(crate) struct Server { @@ -245,7 +247,19 @@ impl Api for Server { ) -> Result { let options = options.unwrap(); - let mut transaction: Transaction = deserialize(&hex::decode(tx).unwrap()).unwrap(); + let mut cursor = Cursor::new(hex::decode(tx).unwrap()); + + let version = i32::consensus_decode_from_finite_reader(&mut cursor).unwrap(); + let input = Vec::::consensus_decode_from_finite_reader(&mut cursor).unwrap(); + let output = Decodable::consensus_decode_from_finite_reader(&mut cursor).unwrap(); + let lock_time = Decodable::consensus_decode_from_finite_reader(&mut cursor).unwrap(); + + let mut transaction = Transaction { + version, + input, + output, + lock_time, + }; assert_eq!( options.change_position,