diff --git a/client/Cargo.toml b/client/Cargo.toml index 90b92fdc..8e76eb00 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bitcoincore-rpc" +name = "ord-bitcoincore-rpc" version = "0.19.0" authors = [ "Steven Roose ", @@ -20,10 +20,10 @@ path = "src/lib.rs" [features] default = ["rand"] -rand = ["bitcoincore-rpc-json/rand"] +rand = ["ord-bitcoincore-rpc-json/rand"] [dependencies] -bitcoincore-rpc-json = { version = "0.19.0", path = "../json" } +ord-bitcoincore-rpc-json = { version = "0.19.0", path = "../json" } log = "0.4.5" jsonrpc = { version = "0.18.0", features = ["minreq_http"] } diff --git a/client/src/client.rs b/client/src/client.rs index 2f809a79..51e229e3 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -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}; @@ -667,9 +667,9 @@ pub trait RpcApi: Sized { fn import_descriptors( &self, - req: json::ImportDescriptors, + req: &[json::ImportDescriptors], ) -> Result> { - let json_request = vec![serde_json::to_value(req)?]; + let json_request = serde_json::to_value(req)?; self.call("importdescriptors", handle_defaults(&mut [json_request.into()], &[null()])) } @@ -1076,8 +1076,42 @@ pub trait RpcApi: Sized { self.call("ping", &[]) } - fn send_raw_transaction(&self, tx: R) -> Result { - 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( + &self, + tx: R, + maxfeerate: Option, + maxburnamount: Option, + ) -> Result { + 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( @@ -1360,10 +1394,10 @@ mod tests { let client = Client::new("http://localhost/".into(), Auth::None).unwrap(); let tx: bitcoin::Transaction = encode::deserialize(&Vec::::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<()> { diff --git a/integration_test/Cargo.toml b/integration_test/Cargo.toml index 9103310a..35457f04 100644 --- a/integration_test/Cargo.toml +++ b/integration_test/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Steven Roose "] edition = "2018" [dependencies] -bitcoincore-rpc = { path = "../client", features = ["rand"] } +ord-bitcoincore-rpc = { path = "../client", features = ["rand"] } bitcoin = { version = "0.32.0", features = ["serde", "rand"] } lazy_static = "1.4.0" log = "0.4" diff --git a/integration_test/src/main.rs b/integration_test/src/main.rs index c3236bb9..4f4b31db 100644 --- a/integration_test/src/main.rs +++ b/integration_test/src/main.rs @@ -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, @@ -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) { diff --git a/json/Cargo.toml b/json/Cargo.toml index b7be19e1..f905c250 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bitcoincore-rpc-json" +name = "ord-bitcoincore-rpc-json" version = "0.19.0" authors = [ "Steven Roose ", diff --git a/json/src/lib.rs b/json/src/lib.rs index 25f3508e..bfc87c15 100644 --- a/json/src/lib.rs +++ b/json/src/lib.rs @@ -1017,6 +1017,7 @@ pub enum StringOrStringArray { pub struct GetBlockchainInfoResult { /// Current network name as defined in BIP70 (main, test, signet, regtest) #[serde(deserialize_with = "deserialize_bip70_network")] + #[serde(serialize_with = "serialize_bip70_network")] pub chain: Network, /// The current number of blocks processed in the server pub blocks: u64, @@ -2190,6 +2191,13 @@ where Ok(Some(res)) } +fn serialize_bip70_network(network: &Network, serializer: S) -> Result +where + S: serde::Serializer, +{ + serializer.serialize_str(network.to_core_arg()) +} + /// deserialize_bip70_network deserializes a Bitcoin Core network according to BIP70 /// The accepted input variants are: {"main", "test", "signet", "regtest"} fn deserialize_bip70_network<'de, D>(deserializer: D) -> Result