Merge branch 'master' into verifcation-refactor

This commit is contained in:
Steve Myers 2022-02-21 17:47:09 -08:00
commit ad65dd5c23
No known key found for this signature in database
GPG Key ID: 8105A46B22C2D051
6 changed files with 106 additions and 47 deletions

View File

@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Pin tokio dependency version to ~1.14 to prevent errors due to their new MSRV 1.49.0
- Removed default verification from `wallet::sync`. sync-time verification is added in `script_sync` and is activated by `verify` feature flag.
- `verify` flag removed from `TransactionDetails`.

View File

@ -42,7 +42,7 @@ bitcoincore-rpc = { version = "0.14", optional = true }
# Platform-specific dependencies
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = ["rt"] }
tokio = { version = "~1.14", features = ["rt"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
async-trait = "0.1"

View File

@ -257,9 +257,11 @@ impl Blockchain for RpcBlockchain {
for input in tx.input.iter() {
if let Some(previous_output) = db.get_previous_output(&input.previous_output)? {
if db.is_mine(&previous_output.script_pubkey)? {
sent += previous_output.value;
}
}
}
let td = TransactionDetails {
transaction: Some(tx),

View File

@ -17,13 +17,13 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use std::ops::Deref;
use bitcoin::util::bip32::{
ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint, KeySource,
};
use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
use bitcoin::util::psbt;
use bitcoin::{Network, PublicKey, Script, TxOut};
use miniscript::descriptor::{DescriptorPublicKey, DescriptorType, DescriptorXKey, Wildcard};
use miniscript::descriptor::{
DescriptorPublicKey, DescriptorType, DescriptorXKey, InnerXKey, Wildcard,
};
pub use miniscript::{descriptor::KeyMap, Descriptor, Legacy, Miniscript, ScriptContext, Segwitv0};
use miniscript::{DescriptorTrait, ForEachKey, TranslatePk};
@ -267,41 +267,10 @@ pub(crate) trait XKeyUtils {
fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint;
}
// FIXME: `InnerXKey` was made private in rust-miniscript, so we have to implement this manually on
// both `ExtendedPubKey` and `ExtendedPrivKey`.
//
// Revert back to using the trait once https://github.com/rust-bitcoin/rust-miniscript/pull/230 is
// released
impl XKeyUtils for DescriptorXKey<ExtendedPubKey> {
fn full_path(&self, append: &[ChildNumber]) -> DerivationPath {
let full_path = match self.origin {
Some((_, ref path)) => path
.into_iter()
.chain(self.derivation_path.into_iter())
.cloned()
.collect(),
None => self.derivation_path.clone(),
};
if self.wildcard != Wildcard::None {
full_path
.into_iter()
.chain(append.iter())
.cloned()
.collect()
} else {
full_path
}
}
fn root_fingerprint(&self, _: &SecpCtx) -> Fingerprint {
match self.origin {
Some((fingerprint, _)) => fingerprint,
None => self.xkey.fingerprint(),
}
}
}
impl XKeyUtils for DescriptorXKey<ExtendedPrivKey> {
impl<T> XKeyUtils for DescriptorXKey<T>
where
T: InnerXKey,
{
fn full_path(&self, append: &[ChildNumber]) -> DerivationPath {
let full_path = match self.origin {
Some((_, ref path)) => path
@ -326,7 +295,7 @@ impl XKeyUtils for DescriptorXKey<ExtendedPrivKey> {
fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint {
match self.origin {
Some((fingerprint, _)) => fingerprint,
None => self.xkey.fingerprint(secp),
None => self.xkey.xkey_fingerprint(secp),
}
}
}

View File

@ -90,13 +90,19 @@ impl TestClient {
map.insert(out.to_address.clone(), Amount::from_sat(out.value));
}
let input: Vec<_> = meta_tx
.input
.into_iter()
.map(|x| x.into_raw_tx_input())
.collect();
if self.get_balance(None, None).unwrap() < Amount::from_sat(required_balance) {
panic!("Insufficient funds in bitcoind. Please generate a few blocks with: `bitcoin-cli generatetoaddress 10 {}`", self.get_new_address(None, None).unwrap());
}
// FIXME: core can't create a tx with two outputs to the same address
let tx = self
.create_raw_transaction_hex(&[], &map, meta_tx.locktime, meta_tx.replaceable)
.create_raw_transaction_hex(&input, &map, meta_tx.locktime, meta_tx.replaceable)
.unwrap();
let tx = self.fund_raw_transaction(tx, None, None).unwrap();
let mut tx: Transaction = deserialize(&tx.hex).unwrap();
@ -353,7 +359,7 @@ macro_rules! bdk_blockchain_tests {
fn $_fn_name:ident ( $( $test_client:ident : &TestClient )? $(,)? ) -> $blockchain:ty $block:block) => {
#[cfg(test)]
mod bdk_blockchain_tests {
use $crate::bitcoin::Network;
use $crate::bitcoin::{Transaction, Network};
use $crate::testutils::blockchain_tests::TestClient;
use $crate::blockchain::noop_progress;
use $crate::database::MemoryDatabase;
@ -1073,6 +1079,49 @@ macro_rules! bdk_blockchain_tests {
let taproot_balance = taproot_wallet_client.get_balance(None, None).unwrap();
assert_eq!(taproot_balance.as_sat(), 25_000, "node has incorrect taproot wallet balance");
}
#[test]
fn test_tx_chain() {
use bitcoincore_rpc::RpcApi;
use bitcoin::consensus::encode::deserialize;
use $crate::wallet::AddressIndex;
// Here we want to test that we set correctly the send and receive
// fields in the transaction object. For doing so, we create two
// different txs, the second one spending from the first:
// 1.
// Core (#1) -> Core (#2)
// -> Us (#3)
// 2.
// Core (#2) -> Us (#4)
let (wallet, _, mut test_client) = init_single_sig();
let bdk_address = wallet.get_address(AddressIndex::New).unwrap().address;
let core_address = test_client.get_new_address(None, None).unwrap();
let tx = testutils! {
@tx ( (@addr bdk_address.clone()) => 50_000, (@addr core_address.clone()) => 40_000 )
};
// Tx one: from Core #1 to Core #2 and Us #3.
let txid_1 = test_client.receive(tx);
let tx_1: Transaction = deserialize(&test_client.get_transaction(&txid_1, None).unwrap().hex).unwrap();
let vout_1 = tx_1.output.into_iter().position(|o| o.script_pubkey == core_address.script_pubkey()).unwrap() as u32;
wallet.sync(noop_progress(), None).unwrap();
let tx_1 = wallet.list_transactions(false).unwrap().into_iter().find(|tx| tx.txid == txid_1).unwrap();
assert_eq!(tx_1.received, 50_000);
assert_eq!(tx_1.sent, 0);
// Tx two: from Core #2 to Us #4.
let tx = testutils! {
@tx ( (@addr bdk_address) => 10_000 ) ( @inputs (txid_1,vout_1))
};
let txid_2 = test_client.receive(tx);
wallet.sync(noop_progress(), None).unwrap();
let tx_2 = wallet.list_transactions(false).unwrap().into_iter().find(|tx| tx.txid == txid_2).unwrap();
assert_eq!(tx_2.received, 10_000);
assert_eq!(tx_2.sent, 0);
}
}
};

View File

@ -15,11 +15,37 @@
pub mod blockchain_tests;
use bitcoin::secp256k1::{Secp256k1, Verification};
use bitcoin::{Address, PublicKey};
use bitcoin::{Address, PublicKey, Txid};
use miniscript::descriptor::DescriptorPublicKey;
use miniscript::{Descriptor, MiniscriptKey, TranslatePk};
#[derive(Clone, Debug)]
pub struct TestIncomingInput {
pub txid: Txid,
pub vout: u32,
pub sequence: Option<u32>,
}
impl TestIncomingInput {
pub fn new(txid: Txid, vout: u32, sequence: Option<u32>) -> Self {
Self {
txid,
vout,
sequence,
}
}
#[cfg(feature = "test-blockchains")]
pub fn into_raw_tx_input(self) -> bitcoincore_rpc::json::CreateRawTransactionInput {
bitcoincore_rpc::json::CreateRawTransactionInput {
txid: self.txid,
vout: self.vout,
sequence: self.sequence,
}
}
}
#[derive(Clone, Debug)]
pub struct TestIncomingOutput {
pub value: u64,
@ -37,6 +63,7 @@ impl TestIncomingOutput {
#[derive(Clone, Debug)]
pub struct TestIncomingTx {
pub input: Vec<TestIncomingInput>,
pub output: Vec<TestIncomingOutput>,
pub min_confirmations: Option<u64>,
pub locktime: Option<i64>,
@ -45,12 +72,14 @@ pub struct TestIncomingTx {
impl TestIncomingTx {
pub fn new(
input: Vec<TestIncomingInput>,
output: Vec<TestIncomingOutput>,
min_confirmations: Option<u64>,
locktime: Option<i64>,
replaceable: Option<bool>,
) -> Self {
Self {
input,
output,
min_confirmations,
locktime,
@ -58,6 +87,10 @@ impl TestIncomingTx {
}
}
pub fn add_input(&mut self, input: TestIncomingInput) {
self.input.push(input);
}
pub fn add_output(&mut self, output: TestIncomingOutput) {
self.output.push(output);
}
@ -123,16 +156,21 @@ macro_rules! testutils {
});
( @e $descriptors:expr, $child:expr ) => ({ testutils!(@external $descriptors, $child) });
( @i $descriptors:expr, $child:expr ) => ({ testutils!(@internal $descriptors, $child) });
( @addr $addr:expr ) => ({ $addr });
( @tx ( $( ( $( $addr:tt )* ) => $amount:expr ),+ ) $( ( @locktime $locktime:expr ) )? $( ( @confirmations $confirmations:expr ) )? $( ( @replaceable $replaceable:expr ) )? ) => ({
( @tx ( $( ( $( $addr:tt )* ) => $amount:expr ),+ ) $( ( @inputs $( ($txid:expr, $vout:expr) ),+ ) )? $( ( @locktime $locktime:expr ) )? $( ( @confirmations $confirmations:expr ) )? $( ( @replaceable $replaceable:expr ) )? ) => ({
let outs = vec![$( $crate::testutils::TestIncomingOutput::new($amount, testutils!( $($addr)* ))),+];
let _ins: Vec<$crate::testutils::TestIncomingInput> = vec![];
$(
let _ins = vec![$( $crate::testutils::TestIncomingInput { txid: $txid, vout: $vout, sequence: None }),+];
)?
let locktime = None::<i64>$(.or(Some($locktime)))?;
let min_confirmations = None::<u64>$(.or(Some($confirmations)))?;
let replaceable = None::<bool>$(.or(Some($replaceable)))?;
$crate::testutils::TestIncomingTx::new(outs, min_confirmations, locktime, replaceable)
$crate::testutils::TestIncomingTx::new(_ins, outs, min_confirmations, locktime, replaceable)
});
( @literal $key:expr ) => ({