commit e11c589766c1fc8df0245d190213aa2d8791beb2
parent 92c4d2638fd272de0b60d759bdbc9f1ada01e27c
Author: Antoine A <>
Date: Fri, 17 Dec 2021 14:17:19 +0100
btc-wire: rpc cleanup
Diffstat:
8 files changed, 168 insertions(+), 179 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -120,17 +120,6 @@ dependencies = [
]
[[package]]
-name = "bitcoincore-rpc-json"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce91de73c61f5776cf938bfa88378c5b404a70e3369b761dacbe6024fea79dd"
-dependencies = [
- "bitcoin",
- "serde",
- "serde_json",
-]
-
-[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -164,7 +153,7 @@ dependencies = [
"argh",
"base64",
"bech32",
- "bitcoincore-rpc-json",
+ "bitcoin",
"criterion",
"fastrand",
"owo-colors",
diff --git a/btc-wire/Cargo.toml b/btc-wire/Cargo.toml
@@ -9,7 +9,10 @@ fail = []
[dependencies]
# Typed bitcoin rpc types
-bitcoincore-rpc-json = "0.14.0"
+bitcoin = { version = "0.27.1", features = [
+ "std",
+ "use-serde",
+], default-features = false }
# Cli args
argh = "0.1.6"
# Bech32 encoding and decoding
diff --git a/btc-wire/src/bin/btc-wire-cli.rs b/btc-wire/src/bin/btc-wire-cli.rs
@@ -1,9 +1,9 @@
use std::path::PathBuf;
-use bitcoincore_rpc_json::bitcoin::{Address, Amount};
+use bitcoin::{Address, Amount, Network};
use btc_wire::{
rpc::BtcRpc,
- rpc_utils::{default_data_dir, Network},
+ rpc_utils::{default_data_dir, rpc_dir},
test::rand_key,
};
@@ -75,7 +75,7 @@ struct App {
impl App {
pub fn start(data_dir: Option<PathBuf>) -> Self {
let data_dir = data_dir.unwrap_or_else(default_data_dir);
- let network = Network::RegTest;
+ let network = Network::Regtest;
let client = BtcRpc::common(&data_dir, network);
Self {
@@ -97,7 +97,7 @@ impl App {
pub fn next_block(&self, wallet: &str) {
match self.network {
- Network::RegTest => {
+ Network::Regtest => {
// Manually mine a block
let (_, addr) = self.auto_wallet(wallet);
self.client.generate(1, &addr).unwrap();
@@ -113,7 +113,7 @@ impl App {
for wallet in ["wire", "client", "reserve"] {
self.client.create_wallet(wallet).ok();
}
- if self.network == Network::RegTest {
+ if self.network == Network::Regtest {
let (client, client_addr) = self.auto_wallet("client");
client.generate(101, &client_addr).unwrap();
}
@@ -128,7 +128,7 @@ fn main() {
let path = args
.datadir
.unwrap_or_else(default_data_dir)
- .join(Network::RegTest.dir());
+ .join(rpc_dir(Network::Regtest));
if path.exists() {
std::fs::remove_dir_all(path).unwrap();
}
diff --git a/btc-wire/src/bin/test.rs b/btc-wire/src/bin/test.rs
@@ -1,13 +1,10 @@
use core::panic;
use std::{collections::HashSet, iter::repeat_with, panic::AssertUnwindSafe};
-use bitcoincore_rpc_json::{
- bitcoin::{Address, Amount, Txid},
- GetTransactionResultDetailCategory as Category,
-};
+use bitcoin::{Address, Amount, Network, Txid};
use btc_wire::{
- rpc::{self, BtcRpc},
- rpc_utils::{default_data_dir, Network, CLIENT, WIRE},
+ rpc::{self, BtcRpc, Category},
+ rpc_utils::{default_data_dir, rpc_dir, CLIENT, WIRE},
test::rand_key,
BounceErr,
};
@@ -20,19 +17,21 @@ pub fn main() {
let test_amount = Amount::from_sat(1500);
let data_dir = default_data_dir();
// Network check
- let network = Network::RegTest;
+ let network = Network::Bitcoin;
match network {
- Network::MainNet => {
+ Network::Bitcoin => {
panic!("Do not run tests on the mainnet, you are going to loose money")
}
- Network::TestNet => println!("{}", "Running on testnet, slow network mining".yellow()),
- Network::RegTest => println!("Running on regtest, fast manual mining"),
+ Network::Testnet | Network::Signet => {
+ println!("{}", "Running on testnet, slow network mining".yellow())
+ }
+ Network::Regtest => println!("Running on regtest, fast manual mining"),
}
// Wallet check
{
let existing_wallets: HashSet<String> =
- std::fs::read_dir(data_dir.join(network.dir()).join("wallets"))
+ std::fs::read_dir(data_dir.join(rpc_dir(network)).join("wallets"))
.unwrap()
.filter_map(|it| it.ok())
.map(|it| it.file_name().to_string_lossy().to_string())
@@ -74,7 +73,7 @@ pub fn main() {
let next_block = || {
match network {
- Network::RegTest => {
+ Network::Regtest => {
// Manually mine a block
reserve_rpc.generate(1, &reserve_addr).unwrap();
}
@@ -89,7 +88,7 @@ pub fn main() {
let mut count = 0;
while txs
.iter()
- .any(|id| rpc.get_tx(id).unwrap().tx.info.confirmations <= 0)
+ .any(|id| rpc.get_tx(id).unwrap().confirmations <= 0)
{
next_block();
if count > 3 {
@@ -122,8 +121,8 @@ pub fn main() {
.yellow()
);
match network {
- Network::MainNet | Network::TestNet => {
- if network == Network::MainNet {
+ Network::Bitcoin | Network::Testnet | Network::Signet => {
+ if network == Network::Bitcoin {
println!("Send coins to this address: {}", client_addr);
} else {
println!("Request coins from a faucet such as https://bitcoinfaucet.uo1.net/send.php to this address: {}", client_addr);
@@ -133,7 +132,7 @@ pub fn main() {
client_rpc.wait_for_new_block(0).ok();
}
}
- Network::RegTest => {
+ Network::Regtest => {
println!("Add 50B to client wallet");
client_rpc
.generate(101 /* Need 100 blocks to validate */, &reserve_addr)
@@ -207,13 +206,13 @@ pub fn main() {
wait_for_tx(&client_rpc, &[send_id]);
let bounce_id = wire_rpc.bounce(&send_id, &bounce_fee).unwrap();
wait_for_tx(&wire_rpc, &[bounce_id]);
- let bounce_tx_fee = wire_rpc.get_tx(&bounce_id).unwrap().tx.details[0]
+ let bounce_tx_fee = wire_rpc.get_tx(&bounce_id).unwrap().details[0]
.fee
.unwrap()
.abs()
.to_unsigned()
.unwrap();
- let send_tx_fee = client_rpc.get_tx(&send_id).unwrap().tx.details[0]
+ let send_tx_fee = client_rpc.get_tx(&send_id).unwrap().details[0]
.fee
.unwrap()
.abs()
@@ -275,13 +274,13 @@ pub fn main() {
let bounce_id = wire_rpc.bounce(&send_id, &bounce_fee).unwrap();
wait_for_tx(&wire_rpc, &[bounce_id]);
let after = client_rpc.get_balance().unwrap();
- let bounce_tx_fee = wire_rpc.get_tx(&bounce_id).unwrap().tx.details[0]
+ let bounce_tx_fee = wire_rpc.get_tx(&bounce_id).unwrap().details[0]
.fee
.unwrap()
.abs()
.to_unsigned()
.unwrap();
- let send_tx_fee = client_rpc.get_tx(&send_id).unwrap().tx.details[0]
+ let send_tx_fee = client_rpc.get_tx(&send_id).unwrap().details[0]
.fee
.unwrap()
.abs()
@@ -298,9 +297,7 @@ pub fn main() {
fn tx_exist(rpc: &BtcRpc, id: &Txid, min_confirmation: i32, detail: Category) -> rpc::Result<bool> {
let result = rpc.list_since_block(None, 1, false).unwrap();
let found = result.transactions.into_iter().any(|tx| {
- tx.detail.category == detail
- && tx.info.confirmations >= min_confirmation
- && tx.info.txid == *id
+ tx.detail.category == detail && tx.confirmations >= min_confirmation && tx.txid == *id
});
Ok(found)
}
diff --git a/btc-wire/src/lib.rs b/btc-wire/src/lib.rs
@@ -1,10 +1,7 @@
use std::str::FromStr;
-use bitcoincore_rpc_json::{
- bitcoin::{hashes::hex::FromHex, Address, Amount, Network, Txid},
- GetTransactionResultDetailCategory, ScriptPubkeyType,
-};
-use rpc::{BtcRpc, GetTransactionFull};
+use bitcoin::{hashes::hex::FromHex, Address, Amount, Network, Txid};
+use rpc::{BtcRpc, Category, TransactionFull};
use rpc_utils::{segwit_min_amount, sender_address};
use segwit::{decode_segwit_msg, encode_segwit_key};
@@ -68,7 +65,7 @@ impl BtcRpc {
pub fn get_tx_segwit_key(
&self,
id: &Txid,
- ) -> Result<(GetTransactionFull, [u8; 32]), GetSegwitErr> {
+ ) -> Result<(TransactionFull, [u8; 32]), GetSegwitErr> {
let full = self.get_tx(id)?;
let addresses: Vec<String> = full
@@ -104,14 +101,14 @@ impl BtcRpc {
pub fn get_tx_op_return(
&self,
id: &Txid,
- ) -> Result<(GetTransactionFull, Vec<u8>), GetOpReturnErr> {
+ ) -> Result<(TransactionFull, Vec<u8>), GetOpReturnErr> {
let full = self.get_tx(id)?;
let op_return_out = full
.decoded
.vout
.iter()
- .find(|it| it.script_pub_key.type_ == ScriptPubkeyType::NullData)
+ .find(|it| it.script_pub_key.asm.starts_with("OP_RETURN"))
.ok_or(GetOpReturnErr::MissingOpReturn)?;
let hex = op_return_out.script_pub_key.asm.split_once(' ').unwrap().1;
@@ -128,8 +125,8 @@ impl BtcRpc {
/// address as a best-effort gesture.
pub fn bounce(&self, id: &Txid, bounce_fee: &Amount) -> Result<Txid, BounceErr> {
let full = self.get_tx(id)?;
- let detail = &full.tx.details[0];
- if detail.category != GetTransactionResultDetailCategory::Receive {
+ let detail = &full.details[0];
+ if detail.category != Category::Receive {
return Err(BounceErr::NotAReceiveTransaction);
}
diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs
@@ -1,8 +1,7 @@
-
-use bitcoincore_rpc_json::{bitcoin::{Address, SignedAmount, Amount as BtcAmount, BlockHash, Txid, hashes::Hash}, GetTransactionResultDetailCategory};
+use bitcoin::{hashes::Hash, Address, Amount as BtcAmount, BlockHash, SignedAmount, Txid, Network};
use btc_wire::{
- rpc::BtcRpc,
- rpc_utils::{default_data_dir, sender_address, Network},
+ rpc::{BtcRpc, Category},
+ rpc_utils::{default_data_dir, sender_address},
segwit::DecodeSegWitErr,
GetOpReturnErr, GetSegwitErr,
};
@@ -268,8 +267,8 @@ fn sender(rpc: BtcRpc, mut db: AutoReloadDb, _config: &Config) {
let txs = rpc.list_since_block(last_hash.as_ref(), 1, false)?;
// Search for a matching unconfirmed transactions
for tx in txs.transactions {
- if tx.detail.category == GetTransactionResultDetailCategory::Send {
- if let Ok((_, bytes)) = rpc.get_tx_op_return(&tx.info.txid) {
+ if tx.detail.category == Category::Send {
+ if let Ok((_, bytes)) = rpc.get_tx_op_return(&tx.txid) {
let (wtid, _) = decode_info(&bytes);
if let Some(pos) = manuals.iter().position(|(_, it)| it == &wtid) {
let (id, wtid) = manuals.swap_remove(pos);
@@ -313,20 +312,20 @@ fn watcher(rpc: BtcRpc, mut db: AutoReloadDb, config: &Config) {
// Get all transactions made since this block
let list = rpc.list_since_block(last_hash.as_ref(), config.confirmation, true)?;
// Keep only confirmed send and receive transactions
- let txs: HashMap<Txid, GetTransactionResultDetailCategory> = list
+ let txs: HashMap<Txid, Category> = list
.transactions
.into_iter()
.filter_map(|tx| {
let cat = tx.detail.category;
- (tx.info.confirmations >= config.confirmation as i32
- && (cat == GetTransactionResultDetailCategory::Send || cat == GetTransactionResultDetailCategory::Receive))
- .then(|| (tx.info.txid, cat))
+ (tx.confirmations >= config.confirmation as i32
+ && (cat == Category::Send || cat == Category::Receive))
+ .then(|| (tx.txid, cat))
})
.collect();
for (id, category) in txs {
match category {
- GetTransactionResultDetailCategory::Send => match rpc.get_tx_op_return(&id) {
+ Category::Send => match rpc.get_tx_op_return(&id) {
Ok((full, bytes)) => {
let (wtid, url) = decode_info(&bytes);
let mut tx = db.transaction()?;
@@ -356,10 +355,9 @@ fn watcher(rpc: BtcRpc, mut db: AutoReloadDb, config: &Config) {
}
} else {
let debit_addr = sender_address(&rpc, &full)?;
- let credit_addr = full.tx.details[0].address.as_ref().unwrap();
- let time = full.tx.info.blocktime.unwrap();
- let date = SystemTime::UNIX_EPOCH + Duration::from_secs(time);
- let amount = btc_amount_to_taler_amount(&full.tx.amount);
+ let credit_addr = full.details[0].address.as_ref().unwrap();
+ let date = SystemTime::UNIX_EPOCH + Duration::from_secs(full.time);
+ let amount = btc_amount_to_taler_amount(&full.amount);
// Generate a random request_uid
let mut request_uid = [0; 64];
OsRng.fill_bytes(&mut request_uid);
@@ -379,13 +377,12 @@ fn watcher(rpc: BtcRpc, mut db: AutoReloadDb, config: &Config) {
err => warn!("send: {} {}", id, err),
},
},
- GetTransactionResultDetailCategory::Receive => match rpc.get_tx_segwit_key(&id) {
+ Category::Receive => match rpc.get_tx_segwit_key(&id) {
Ok((full, reserve_pub)) => {
let debit_addr = sender_address(&rpc, &full)?;
- let credit_addr = full.tx.details[0].address.as_ref().unwrap();
- let time = full.tx.info.blocktime.unwrap();
- let date = SystemTime::UNIX_EPOCH + Duration::from_secs(time);
- let amount = btc_amount_to_taler_amount(&full.tx.amount);
+ let credit_addr = full.details[0].address.as_ref().unwrap();
+ let date = SystemTime::UNIX_EPOCH + Duration::from_secs(full.time);
+ let amount = btc_amount_to_taler_amount(&full.amount);
let nb = db.execute("INSERT INTO tx_in (_date, amount, reserve_pub, debit_acc, credit_acc) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (reserve_pub) DO NOTHING ", &[
&date, &amount.to_string(), &reserve_pub.as_ref(), &btc_payto_url(&debit_addr).as_ref(), &btc_payto_url(credit_addr).as_ref()
])?;
@@ -401,7 +398,7 @@ fn watcher(rpc: BtcRpc, mut db: AutoReloadDb, config: &Config) {
err => warn!("receive: {} {}", id, err),
},
},
- GetTransactionResultDetailCategory::Generate | GetTransactionResultDetailCategory::Immature | GetTransactionResultDetailCategory::Orphan => {}
+ Category::Generate | Category::Immature | Category::Orphan => {}
}
}
// Move last_hash forward if no error have been caught
@@ -455,9 +452,9 @@ fn main() {
let config = taler_config::Config::from_path("test.conf");
let config: &'static Config = Box::leak(Box::new(config));
let network = match config.btc_chain.as_str() {
- "main" => Network::MainNet,
- "test" => Network::TestNet,
- "regtest" => Network::RegTest,
+ "main" => Network::Bitcoin,
+ "test" => Network::Testnet,
+ "regtest" => Network::Regtest,
chain => {
error!("Unsupported chain {}", chain);
std::process::exit(1);
diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs
@@ -1,9 +1,5 @@
-use crate::rpc_utils::{rpc_url, Network};
-use bitcoincore_rpc_json::{
- bitcoin::{hashes::hex::ToHex, Address, Amount, BlockHash, Txid, Wtxid},
- BlockRef, FundRawTransactionResult, GetRawTransactionResultVin, GetTransactionResult,
- ListSinceBlockResult, LoadWalletResult, ScriptPubkeyType, SignRawTransactionResult,
-};
+use crate::rpc_utils::{rpc_dir, rpc_url};
+use bitcoin::{hashes::hex::ToHex, Address, Amount, BlockHash, Network, SignedAmount, Txid};
use serde_json::{json, Value};
use std::{
fmt::Debug,
@@ -56,7 +52,7 @@ pub struct BtcRpc {
impl BtcRpc {
pub fn common(data_dir: &Path, network: Network) -> Self {
- let path = data_dir.join(network.dir()).join(".cookie");
+ let path = data_dir.join(rpc_dir(network)).join(".cookie");
let cookie = std::fs::read(path).unwrap();
let agent = ureq::builder()
@@ -74,7 +70,7 @@ impl BtcRpc {
}
pub fn wallet(data_dir: &Path, network: Network, wallet: &str) -> Self {
- let path = data_dir.join(network.dir()).join(".cookie");
+ let path = data_dir.join(rpc_dir(network)).join(".cookie");
let cookie = std::fs::read(path).unwrap();
let agent = ureq::builder()
@@ -127,11 +123,11 @@ impl BtcRpc {
}
}
- pub fn load_wallet(&self, name: &str) -> Result<LoadWalletResult> {
+ pub fn load_wallet(&self, name: &str) -> Result<Wallet> {
self.call("loadwallet", &[name])
}
- pub fn create_wallet(&self, name: &str) -> Result<LoadWalletResult> {
+ pub fn create_wallet(&self, name: &str) -> Result<Wallet> {
self.call("createwallet", &[name])
}
@@ -143,7 +139,7 @@ impl BtcRpc {
self.call("generatetoaddress", &(nb, address))
}
- pub fn wait_for_new_block(&self, timeout: u64) -> Result<BlockRef> {
+ pub fn wait_for_new_block(&self, timeout: u64) -> Result<()> {
self.call("waitfornewblock", &[timeout])
}
@@ -201,11 +197,11 @@ impl BtcRpc {
],
)
.unwrap();
- let funded: FundRawTransactionResult = self.call("fundrawtransaction", &[hex]).unwrap();
- let signed: SignRawTransactionResult = self
- .call("signrawtransactionwithwallet", &[&funded.hex.to_hex()])
+ let funded: HexWrapper = self.call("fundrawtransaction", &[hex]).unwrap();
+ let signed: HexWrapper = self
+ .call("signrawtransactionwithwallet", &[&funded.hex])
.unwrap();
- self.call("sendrawtransaction", &[&signed.hex.to_hex()])
+ self.call("sendrawtransaction", &[&signed.hex])
}
pub fn list_since_block(
@@ -213,104 +209,126 @@ impl BtcRpc {
hash: Option<&BlockHash>,
confirmation: u8,
include_remove: bool,
- ) -> Result<ListSinceBlockResult> {
+ ) -> Result<ListSinceBlock> {
self.call("listsinceblock", &(hash, confirmation, (), include_remove))
}
- pub fn get_tx(&self, id: &Txid) -> Result<GetTransactionFull> {
+ pub fn get_tx(&self, id: &Txid) -> Result<TransactionFull> {
self.call("gettransaction", &(id, (), true))
}
- pub fn get_raw(&self, id: &Txid) -> Result<GetRawTransactionResult22> {
+ pub fn get_raw(&self, id: &Txid) -> Result<RawTransaction> {
self.call("getrawtransaction", &(id, true))
}
}
-/// v22.0 replace "reqSigs" and "addresses" for the saner "address"
-#[derive(Clone, PartialEq, Eq, Debug, serde::Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct GetRawTransactionResultVoutScriptPubKey22 {
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct Wallet {
+ pub name: String,
+ pub warning: Option<String>,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct VoutScriptPubKey {
pub asm: String,
- #[serde(with = "bitcoincore_rpc_json::serde_hex")]
- pub hex: Vec<u8>,
- #[serde(rename = "type")]
- pub type_: ScriptPubkeyType,
+ // nulldata do not have an address
pub address: Option<Address>,
}
-#[derive(Clone, PartialEq, Eq, Debug, serde::Deserialize)]
+#[derive(Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
-pub struct GetRawTransactionResultVout22 {
- #[serde(with = "bitcoincore_rpc_json::bitcoin::util::amount::serde::as_btc")]
+pub struct Vout {
+ #[serde(with = "bitcoin::util::amount::serde::as_btc")]
pub value: Amount,
pub n: u32,
- pub script_pub_key: GetRawTransactionResultVoutScriptPubKey22,
+ pub script_pub_key: VoutScriptPubKey,
}
-#[derive(Clone, PartialEq, Eq, Debug, serde::Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct GetRawTransactionResult22 {
- #[serde(rename = "in_active_chain")]
- pub in_active_chain: Option<bool>,
- #[serde(with = "bitcoincore_rpc_json::serde_hex")]
- pub hex: Vec<u8>,
- pub txid: Txid,
- pub hash: Wtxid,
- pub size: usize,
- pub vsize: usize,
- pub version: u32,
- pub locktime: u32,
- pub vin: Vec<GetRawTransactionResultVin>,
- pub vout: Vec<GetRawTransactionResultVout22>,
- pub blockhash: Option<BlockHash>,
- pub confirmations: Option<u32>,
- pub time: Option<usize>,
- pub blocktime: Option<usize>,
+#[derive(Debug, serde::Deserialize)]
+pub struct Vin {
+ pub sequence: u32,
+ /// Not provided for coinbase txs.
+ pub txid: Option<Txid>,
+ /// Not provided for coinbase txs.
+ pub vout: Option<u32>,
}
-/// Decoded raw transtion from"gettransaction" verbose does not return field already given in the simple form
-#[derive(Clone, PartialEq, Eq, Debug, serde::Deserialize)]
-pub struct TransactionDecoded {
- pub txid: Txid,
- pub hash: Wtxid,
- pub size: usize,
- pub vsize: usize,
- pub version: u32,
- pub locktime: u32,
- pub vin: Vec<GetRawTransactionResultVin>,
- pub vout: Vec<GetRawTransactionResultVout22>,
+/// Enum to represent the category of a transaction.
+#[derive(Copy, PartialEq, Eq, Clone, Debug, serde::Deserialize)]
+#[serde(rename_all = "lowercase")]
+pub enum Category {
+ Send,
+ Receive,
+ Generate,
+ Immature,
+ Orphan,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct TransactionDetail {
+ pub address: Option<Address>,
+ pub category: Category,
+ #[serde(with = "bitcoin::util::amount::serde::as_btc")]
+ pub amount: SignedAmount,
+ pub vout: u32,
+ #[serde(default, with = "bitcoin::util::amount::serde::as_btc::opt")]
+ pub fee: Option<SignedAmount>,
+ /// Ony for send transaction
+ pub abandoned: Option<bool>,
}
-/// "gettransaction" with decoded raw transaction
-#[derive(Clone, PartialEq, Eq, Debug, serde::Deserialize)]
-pub struct GetTransactionFull {
+#[derive(Debug, serde::Deserialize)]
+pub struct ListTransaction {
+ pub confirmations: i32,
+ pub txid: Txid,
+ pub time: u64,
#[serde(flatten)]
- pub tx: GetTransactionResult,
- pub decoded: TransactionDecoded,
+ pub detail: TransactionDetail,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct ListSinceBlock {
+ pub transactions: Vec<ListTransaction>,
+ #[serde(default)]
+ pub removed: Vec<ListTransaction>,
+ pub lastblock: BlockHash,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct RawTransaction {
+ pub vin: Vec<Vin>,
+ pub vout: Vec<Vout>,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct TransactionFull {
+ pub confirmations: i32,
+ pub time: u64,
+ #[serde(with = "bitcoin::util::amount::serde::as_btc")]
+ pub amount: SignedAmount,
+ #[serde(default, with = "bitcoin::util::amount::serde::as_btc::opt")]
+ pub fee: Option<SignedAmount>,
+ pub details: Vec<TransactionDetail>,
+ pub decoded: RawTransaction,
+}
+
+#[derive(Debug, serde::Deserialize)]
+pub struct HexWrapper {
+ pub hex: String,
}
/// Bitcoin RPC error codes <https://github.com/bitcoin/bitcoin/blob/master/src/rpc/protocol.h>
-#[derive(
- Debug, Clone, Copy, PartialEq, Eq, serde_repr::Serialize_repr, serde_repr::Deserialize_repr,
-)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, serde_repr::Deserialize_repr)]
#[repr(i32)]
pub enum ErrorCode {
- // Standard JSON-RPC 2.0 errors
- // RPC_INVALID_REQUEST is internally mapped to HTTP_BAD_REQUEST (400).
- // It should not be used for application-layer errors.
RpcInvalidRequest = -32600,
- // RPC_METHOD_NOT_FOUND is internally mapped to HTTP_NOT_FOUND (404).
- // It should not be used for application-layer errors.
RpcMethodNotFound = -32601,
RpcInvalidParams = -32602,
- // RPC_INTERNAL_ERROR should only be used for genuine errors in bitcoind
- // (for example datadir corruption).
RpcInternalError = -32603,
RpcParseError = -32700,
- // General application defined errors
/// std::exception thrown in command handling
RpcMiscError = -1,
-
/// Unexpected type was passed as parameter
RpcTypeError = -3,
/// Invalid address or key
@@ -333,7 +351,6 @@ pub enum ErrorCode {
RpcInWarmup = -28,
/// RPC method is deprecated
RpcMethodDeprecated = -32,
- // P2P client errors
/// Bitcoin is not connected
RpcClientNotConnected = -9,
/// Still downloading initial blocks
@@ -350,10 +367,8 @@ pub enum ErrorCode {
RpcClientP2pDisabled = -31,
/// Max number of outbound or block-relay connections already open
RpcClientNodeCapacityReached = -34,
- // Chain errors
- RpcClientMempoolDisabled = -33,
/// No mempool instance found
- // Wallet errors
+ RpcClientMempoolDisabled = -33,
/// Unspecified problem with wallet (key not found etc.)
RpcWalletError = -4,
/// Not enough funds in wallet or account
@@ -378,7 +393,6 @@ pub enum ErrorCode {
RpcWalletNotSpecified = -19,
/// This same wallet is already loaded
RpcWalletAlreadyLoaded = -35,
- // Unused reserved codes, kept around for backwards compatibility. Do not reuse.
/// Server is in safe mode, and command is not allowed in safe mode
RpcForbiddenBySafeMode = -2,
}
diff --git a/btc-wire/src/rpc_utils.rs b/btc-wire/src/rpc_utils.rs
@@ -1,35 +1,27 @@
use std::{path::PathBuf, str::FromStr};
-use bitcoincore_rpc_json::bitcoin::{Address, Amount};
+use bitcoin::{Address, Amount, Network};
-use crate::rpc::{self, BtcRpc, GetTransactionFull};
+use crate::rpc::{self, BtcRpc, TransactionFull};
pub const CLIENT: &str = "client";
pub const WIRE: &str = "wire";
-/// Bitcoin networks
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Network {
- MainNet,
- TestNet,
- RegTest,
-}
-
-impl Network {
- pub fn dir(&self) -> &'static str {
- match self {
- Network::MainNet => "main",
- Network::TestNet => "testnet3",
- Network::RegTest => "regtest",
- }
+pub fn rpc_dir(network: Network) -> &'static str {
+ match network {
+ Network::Bitcoin => "main",
+ Network::Testnet => "testnet3",
+ Network::Regtest => "regtest",
+ _ => unreachable!("Unsupported network"),
}
}
pub fn rpc_url(network: Network) -> String {
let port = match network {
- Network::MainNet => 8332,
- Network::TestNet => 18332,
- Network::RegTest => 18443,
+ Network::Bitcoin => 8332,
+ Network::Testnet => 18332,
+ Network::Regtest => 18443,
+ _ => unreachable!("Unsupported network"),
};
format!("http://127.0.0.1:{}", port)
}
@@ -63,7 +55,7 @@ pub fn check_address(addr: &str) -> bool {
}
/// Get the first sender address from a raw transaction
-pub fn sender_address(rpc: &BtcRpc, full: &GetTransactionFull) -> rpc::Result<Address> {
+pub fn sender_address(rpc: &BtcRpc, full: &TransactionFull) -> rpc::Result<Address> {
let first = &full.decoded.vin[0];
let tx = rpc.get_raw(&first.txid.unwrap())?;
Ok(tx