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..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 { @@ -243,7 +245,26 @@ impl Api for Server { options: Option, _is_witness: Option, ) -> Result { - let mut transaction: Transaction = deserialize(&hex::decode(tx).unwrap()).unwrap(); + let options = options.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, + Some(transaction.output.len().try_into().unwrap()) + ); let state = self.state(); @@ -294,7 +315,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;