2020-08-31 11:26:36 +02:00
|
|
|
// Magical Bitcoin Library
|
|
|
|
// Written in 2020 by
|
|
|
|
// Alekos Filini <alekos.filini@gmail.com>
|
|
|
|
//
|
|
|
|
// Copyright (c) 2020 Magical Bitcoin
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
// SOFTWARE.
|
|
|
|
|
2020-08-10 10:49:34 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate quote;
|
|
|
|
|
|
|
|
use proc_macro::TokenStream;
|
|
|
|
|
|
|
|
use syn::spanned::Spanned;
|
|
|
|
use syn::{parse, parse2, Ident, ReturnType};
|
|
|
|
|
|
|
|
#[proc_macro_attribute]
|
2020-09-14 14:25:38 +02:00
|
|
|
pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream {
|
2020-08-10 10:49:34 +02:00
|
|
|
let root_ident = if !attr.is_empty() {
|
|
|
|
match parse::<syn::ExprPath>(attr) {
|
|
|
|
Ok(parsed) => parsed,
|
|
|
|
Err(e) => {
|
|
|
|
let error_string = e.to_string();
|
|
|
|
return (quote! {
|
|
|
|
compile_error!("Invalid crate path: {:?}", #error_string)
|
|
|
|
})
|
|
|
|
.into();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-09-14 14:25:38 +02:00
|
|
|
parse2::<syn::ExprPath>(quote! { bdk }).unwrap()
|
2020-08-10 10:49:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
match parse::<syn::ItemFn>(item) {
|
|
|
|
Err(_) => (quote! {
|
2020-09-14 14:25:38 +02:00
|
|
|
compile_error!("#[bdk_blockchain_tests] can only be used on `fn`s")
|
2020-08-10 10:49:34 +02:00
|
|
|
})
|
|
|
|
.into(),
|
|
|
|
Ok(parsed) => {
|
|
|
|
let parsed_sig_ident = parsed.sig.ident.clone();
|
|
|
|
let mod_name = Ident::new(
|
|
|
|
&format!("generated_tests_{}", parsed_sig_ident.to_string()),
|
|
|
|
parsed.span(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let return_type = match parsed.sig.output {
|
|
|
|
ReturnType::Type(_, ref t) => t.clone(),
|
|
|
|
ReturnType::Default => {
|
|
|
|
return (quote! {
|
2020-09-09 18:17:49 +02:00
|
|
|
compile_error!("The tagged function must return a type that impl `Blockchain`")
|
2020-08-10 10:49:34 +02:00
|
|
|
}).into();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let output = quote! {
|
|
|
|
|
|
|
|
#parsed
|
|
|
|
|
|
|
|
mod #mod_name {
|
|
|
|
use bitcoin::Network;
|
|
|
|
|
|
|
|
use miniscript::Descriptor;
|
|
|
|
|
|
|
|
use testutils::{TestClient, serial};
|
|
|
|
|
2020-09-09 18:17:49 +02:00
|
|
|
use #root_ident::blockchain::{Blockchain, noop_progress};
|
2020-08-10 10:49:34 +02:00
|
|
|
use #root_ident::descriptor::ExtendedDescriptor;
|
|
|
|
use #root_ident::database::MemoryDatabase;
|
|
|
|
use #root_ident::types::ScriptType;
|
2020-08-31 10:49:44 +02:00
|
|
|
use #root_ident::{Wallet, TxBuilder, FeeRate};
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
fn get_blockchain() -> #return_type {
|
|
|
|
#parsed_sig_ident()
|
|
|
|
}
|
|
|
|
|
2020-08-12 12:51:50 +02:00
|
|
|
fn get_wallet_from_descriptors(descriptors: &(String, Option<String>)) -> Wallet<#return_type, MemoryDatabase> {
|
|
|
|
Wallet::new(&descriptors.0.to_string(), descriptors.1.as_deref(), Network::Regtest, MemoryDatabase::new(), get_blockchain()).unwrap()
|
2020-08-10 10:49:34 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 12:51:50 +02:00
|
|
|
fn init_single_sig() -> (Wallet<#return_type, MemoryDatabase>, (String, Option<String>), TestClient) {
|
2020-08-10 10:49:34 +02:00
|
|
|
let descriptors = testutils! {
|
|
|
|
@descriptors ( "wpkh(Alice)" ) ( "wpkh(Alice)" ) ( @keys ( "Alice" => (@generate_xprv "/44'/0'/0'/0/*", "/44'/0'/0'/1/*") ) )
|
|
|
|
};
|
|
|
|
|
|
|
|
let test_client = TestClient::new();
|
|
|
|
let wallet = get_wallet_from_descriptors(&descriptors);
|
|
|
|
|
|
|
|
(wallet, descriptors, test_client)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_simple() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
|
|
|
let tx = testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 )
|
|
|
|
};
|
2020-08-12 12:51:50 +02:00
|
|
|
println!("{:?}", tx);
|
2020-08-10 10:49:34 +02:00
|
|
|
let txid = test_client.receive(tx);
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
assert_eq!(wallet.list_unspent().unwrap()[0].is_internal, false);
|
|
|
|
|
|
|
|
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
|
|
|
|
assert_eq!(list_tx_item.txid, txid);
|
|
|
|
assert_eq!(list_tx_item.received, 50_000);
|
|
|
|
assert_eq!(list_tx_item.sent, 0);
|
|
|
|
assert_eq!(list_tx_item.height, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_stop_gap_20() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 5) => 50_000 )
|
|
|
|
});
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 25) => 50_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 100_000);
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_before_and_after_receive() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 0);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_multiple_outputs_same_tx() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
|
|
|
let txid = test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000, (@external descriptors, 5) => 30_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 105_000);
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
|
|
|
|
assert_eq!(wallet.list_unspent().unwrap().len(), 3);
|
|
|
|
|
|
|
|
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
|
|
|
|
assert_eq!(list_tx_item.txid, txid);
|
|
|
|
assert_eq!(list_tx_item.received, 105_000);
|
|
|
|
assert_eq!(list_tx_item.sent, 0);
|
|
|
|
assert_eq!(list_tx_item.height, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_receive_multi() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 )
|
|
|
|
});
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 5) => 25_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 75_000);
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
|
|
|
|
assert_eq!(wallet.list_unspent().unwrap().len(), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_address_reuse() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 25_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 75_000);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_receive_rbf_replaced() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
|
|
|
let txid = test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 ) ( @replaceable true )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
|
|
|
|
assert_eq!(wallet.list_unspent().unwrap().len(), 1);
|
|
|
|
|
|
|
|
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
|
|
|
|
assert_eq!(list_tx_item.txid, txid);
|
|
|
|
assert_eq!(list_tx_item.received, 50_000);
|
|
|
|
assert_eq!(list_tx_item.sent, 0);
|
|
|
|
assert_eq!(list_tx_item.height, None);
|
|
|
|
|
|
|
|
let new_txid = test_client.bump_fee(&txid);
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
|
|
|
|
assert_eq!(wallet.list_unspent().unwrap().len(), 1);
|
|
|
|
|
|
|
|
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
|
|
|
|
assert_eq!(list_tx_item.txid, new_txid);
|
|
|
|
assert_eq!(list_tx_item.received, 50_000);
|
|
|
|
assert_eq!(list_tx_item.sent, 0);
|
|
|
|
assert_eq!(list_tx_item.height, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_reorg_block() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
|
|
|
|
let txid = test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 ) ( @confirmations 1 ) ( @replaceable true )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
|
|
|
|
assert_eq!(wallet.list_unspent().unwrap().len(), 1);
|
|
|
|
|
|
|
|
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
|
|
|
|
assert_eq!(list_tx_item.txid, txid);
|
|
|
|
assert!(list_tx_item.height.is_some());
|
|
|
|
|
|
|
|
// Invalidate 1 block
|
|
|
|
test_client.invalidate(1);
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
|
|
|
|
let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
|
|
|
|
assert_eq!(list_tx_item.txid, txid);
|
|
|
|
assert_eq!(list_tx_item.height, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_after_send() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
2020-08-12 12:51:50 +02:00
|
|
|
println!("{}", descriptors.0);
|
2020-08-10 10:49:34 +02:00
|
|
|
let node_addr = test_client.get_node_address(None);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
|
2020-09-04 15:45:11 +02:00
|
|
|
let (psbt, details) = wallet.create_tx(TxBuilder::with_recipients(vec![(node_addr.script_pubkey(), 25_000)])).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
let (psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
2020-08-12 12:51:50 +02:00
|
|
|
let tx = psbt.extract_tx();
|
|
|
|
println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
|
|
|
|
wallet.broadcast(tx).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), details.received);
|
|
|
|
|
|
|
|
assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
|
|
|
|
assert_eq!(wallet.list_unspent().unwrap().len(), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_outgoing_from_scratch() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
let node_addr = test_client.get_node_address(None);
|
|
|
|
|
|
|
|
let received_txid = test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
|
2020-09-04 15:45:11 +02:00
|
|
|
let (psbt, details) = wallet.create_tx(TxBuilder::with_recipients(vec![(node_addr.script_pubkey(), 25_000)])).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
let (psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
let sent_txid = wallet.broadcast(psbt.extract_tx()).unwrap();
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), details.received);
|
|
|
|
|
|
|
|
// empty wallet
|
|
|
|
let wallet = get_wallet_from_descriptors(&descriptors);
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
|
|
|
|
|
|
|
|
let received = tx_map.get(&received_txid).unwrap();
|
|
|
|
assert_eq!(received.received, 50_000);
|
|
|
|
assert_eq!(received.sent, 0);
|
|
|
|
|
|
|
|
let sent = tx_map.get(&sent_txid).unwrap();
|
|
|
|
assert_eq!(sent.received, details.received);
|
|
|
|
assert_eq!(sent.sent, details.sent);
|
|
|
|
assert_eq!(sent.fees, details.fees);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_long_change_chain() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
let node_addr = test_client.get_node_address(None);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 )
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
|
|
|
|
let mut total_sent = 0;
|
|
|
|
for _ in 0..5 {
|
2020-09-04 15:45:11 +02:00
|
|
|
let (psbt, details) = wallet.create_tx(TxBuilder::with_recipients(vec![(node_addr.script_pubkey().clone(), 5_000)])).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
let (psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(psbt.extract_tx()).unwrap();
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
|
|
|
|
total_sent += 5_000 + details.fees;
|
|
|
|
}
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent);
|
|
|
|
|
|
|
|
// empty wallet
|
|
|
|
let wallet = get_wallet_from_descriptors(&descriptors);
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-10 10:49:34 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent);
|
|
|
|
}
|
2020-08-13 16:51:27 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_bump_fee() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
let node_addr = test_client.get_node_address(None);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
|
2020-09-04 15:45:11 +02:00
|
|
|
let (psbt, details) = wallet.create_tx(TxBuilder::with_recipients(vec![(node_addr.script_pubkey().clone(), 5_000)]).enable_rbf()).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
let (psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fees - 5_000);
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), details.received);
|
|
|
|
|
|
|
|
let (new_psbt, new_details) = wallet.bump_fee(&details.txid, TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(2.1))).unwrap();
|
|
|
|
let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(new_psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000 - new_details.fees - 5_000);
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), new_details.received);
|
|
|
|
|
|
|
|
assert!(new_details.fees > details.fees);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_bump_fee_remove_change() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
let node_addr = test_client.get_node_address(None);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 50_000);
|
|
|
|
|
2020-09-04 15:45:11 +02:00
|
|
|
let (psbt, details) = wallet.create_tx(TxBuilder::with_recipients(vec![(node_addr.script_pubkey().clone(), 49_000)]).enable_rbf()).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
let (psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 1_000 - details.fees);
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), details.received);
|
|
|
|
|
|
|
|
let (new_psbt, new_details) = wallet.bump_fee(&details.txid, TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(5.0))).unwrap();
|
|
|
|
|
|
|
|
let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(new_psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 0);
|
|
|
|
assert_eq!(new_details.received, 0);
|
|
|
|
|
|
|
|
assert!(new_details.fees > details.fees);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_bump_fee_add_input() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
let node_addr = test_client.get_node_address(None);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 75_000);
|
|
|
|
|
2020-09-04 15:45:11 +02:00
|
|
|
let (psbt, details) = wallet.create_tx(TxBuilder::with_recipients(vec![(node_addr.script_pubkey().clone(), 49_000)]).enable_rbf()).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
let (psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees);
|
|
|
|
assert_eq!(details.received, 1_000 - details.fees);
|
|
|
|
|
|
|
|
let (new_psbt, new_details) = wallet.bump_fee(&details.txid, TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(10.0))).unwrap();
|
|
|
|
|
|
|
|
let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(new_psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(new_details.sent, 75_000);
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), new_details.received);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_sync_bump_fee_add_input_no_change() {
|
|
|
|
let (wallet, descriptors, mut test_client) = init_single_sig();
|
|
|
|
let node_addr = test_client.get_node_address(None);
|
|
|
|
|
|
|
|
test_client.receive(testutils! {
|
|
|
|
@tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
|
|
|
|
});
|
|
|
|
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 75_000);
|
|
|
|
|
2020-09-04 15:45:11 +02:00
|
|
|
let (psbt, details) = wallet.create_tx(TxBuilder::with_recipients(vec![(node_addr.script_pubkey().clone(), 49_000)]).enable_rbf()).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
let (psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees);
|
|
|
|
assert_eq!(details.received, 1_000 - details.fees);
|
|
|
|
|
|
|
|
let (new_psbt, new_details) = wallet.bump_fee(&details.txid, TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(123.0))).unwrap();
|
|
|
|
println!("{:#?}", new_details);
|
|
|
|
|
|
|
|
let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap();
|
|
|
|
assert!(finalized, "Cannot finalize transaction");
|
|
|
|
wallet.broadcast(new_psbt.extract_tx()).unwrap();
|
2020-08-25 16:07:26 +02:00
|
|
|
wallet.sync(noop_progress(), None).unwrap();
|
2020-08-13 16:51:27 +02:00
|
|
|
assert_eq!(new_details.sent, 75_000);
|
|
|
|
assert_eq!(wallet.get_balance().unwrap(), 0);
|
|
|
|
assert_eq!(new_details.received, 0);
|
|
|
|
}
|
2020-08-10 10:49:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
output.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|