Skip to content

Commit

Permalink
Add support for maxfeerate and maxburnamount to sendrawtransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
casey committed Nov 9, 2024
1 parent 06a6c15 commit e77628a
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 9 deletions.
48 changes: 41 additions & 7 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::bitcoin::address::{NetworkUnchecked, NetworkChecked};
use crate::bitcoin::hashes::hex::FromHex;
use crate::bitcoin::secp256k1::ecdsa::Signature;
use crate::bitcoin::{
Address, Amount, Block, OutPoint, PrivateKey, PublicKey, Script, Transaction,
Address, Amount, Block, OutPoint, PrivateKey, PublicKey, Script, Transaction, FeeRate,
};
use log::Level::{Debug, Trace, Warn};

Expand Down Expand Up @@ -1076,8 +1076,42 @@ pub trait RpcApi: Sized {
self.call("ping", &[])
}

fn send_raw_transaction<R: RawTx>(&self, tx: R) -> Result<bitcoin::Txid> {
self.call("sendrawtransaction", &[tx.raw_hex().into()])
// Submit a raw transaction to local node and network.
//
// # Arguments
//
// 1. `tx`: Transaction to submit
// 2. `maxfeerate`: Reject transaction whose fee rate is higher than the
// specified value Available in Bitcoin Core 0.19.0 and later.
// 3. `maxburnamount`: Reject transactions with provably unspendable
// outputs (e.g. 'datacarrier' outputs that use the OP_RETURN opcode)
// greater than the specified value, expressed in BTC. If burning funds
// through unspendable outputs is desired, increase this value. This
// check is based on heuristics and does not guarantee spendability of
// outputs. Available in Bitcoin Core 25.0.0 and later.
fn send_raw_transaction<R: RawTx>(
&self,
tx: R,
maxfeerate: Option<FeeRate>,
maxburnamount: Option<Amount>,
) -> Result<bitcoin::Txid> {
fn fee_rate_to_btc_per_kvb(fee_rate: FeeRate) -> f64 {
let sat_per_kwu = fee_rate.to_sat_per_kwu() as f64;
let sat_per_kvb = sat_per_kwu * 4.0;
let btc_per_kvb = sat_per_kvb / Amount::ONE_BTC.to_sat() as f64;
btc_per_kvb
}

let mut args = [
into_json(tx.raw_hex())?,
opt_into_json(maxfeerate.map(fee_rate_to_btc_per_kvb))?,
opt_into_json(maxburnamount.map(|amount| amount.to_btc()))?,
];

self.call(
"sendrawtransaction",
handle_defaults(&mut args, &[null(), null(), null()]),
)
}

fn estimate_smart_fee(
Expand Down Expand Up @@ -1360,10 +1394,10 @@ mod tests {
let client = Client::new("http://localhost/".into(), Auth::None).unwrap();
let tx: bitcoin::Transaction = encode::deserialize(&Vec::<u8>::from_hex("0200000001586bd02815cf5faabfec986a4e50d25dbee089bd2758621e61c5fab06c334af0000000006b483045022100e85425f6d7c589972ee061413bcf08dc8c8e589ce37b217535a42af924f0e4d602205c9ba9cb14ef15513c9d946fa1c4b797883e748e8c32171bdf6166583946e35c012103dae30a4d7870cd87b45dd53e6012f71318fdd059c1c2623b8cc73f8af287bb2dfeffffff021dc4260c010000001976a914f602e88b2b5901d8aab15ebe4a97cf92ec6e03b388ac00e1f505000000001976a914687ffeffe8cf4e4c038da46a9b1d37db385a472d88acfd211500").unwrap()).unwrap();

assert!(client.send_raw_transaction(&tx).is_err());
assert!(client.send_raw_transaction(&encode::serialize(&tx)).is_err());
assert!(client.send_raw_transaction("deadbeef").is_err());
assert!(client.send_raw_transaction("deadbeef".to_owned()).is_err());
assert!(client.send_raw_transaction(&tx, None, None).is_err());
assert!(client.send_raw_transaction(&encode::serialize(&tx), None, None).is_err());
assert!(client.send_raw_transaction("deadbeef", None, None).is_err());
assert!(client.send_raw_transaction("deadbeef".to_owned(), None, None).is_err());
}

fn test_handle_defaults_inner() -> Result<()> {
Expand Down
4 changes: 2 additions & 2 deletions integration_test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ fn test_sign_raw_transaction_with_send_raw_transaction(cl: &Client) {
};
let res = cl.sign_raw_transaction_with_wallet(&tx, Some(&[input]), None).unwrap();
assert!(res.complete);
let txid = cl.send_raw_transaction(&res.transaction().unwrap()).unwrap();
let txid = cl.send_raw_transaction(&res.transaction().unwrap(), None, None).unwrap();

let tx = Transaction {
version: transaction::Version::ONE,
Expand All @@ -637,7 +637,7 @@ fn test_sign_raw_transaction_with_send_raw_transaction(cl: &Client) {
.sign_raw_transaction_with_key(&tx, &[sk], None, Some(sighash::EcdsaSighashType::All.into()))
.unwrap();
assert!(res.complete);
let _ = cl.send_raw_transaction(&res.transaction().unwrap()).unwrap();
let _ = cl.send_raw_transaction(&res.transaction().unwrap(), None, None).unwrap();
}

fn test_invalidate_block_reconsider_block(cl: &Client) {
Expand Down

0 comments on commit e77628a

Please sign in to comment.