[bdk_chain_redesign] Introduce BlockAnchor trait
* Introduce `GraphedTx` struct to access transaction data of graphed transactions. * Ability to insert/access anchors and "seen at" values for graphed transactions. * `Additions` now records changes to anchors and last_seen_at.
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
#[macro_use]
|
||||
mod common;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use bdk_chain::{
|
||||
chain_graph::*,
|
||||
collections::HashSet,
|
||||
sparse_chain,
|
||||
tx_graph::{self, TxGraph},
|
||||
tx_graph::{self, GraphedTx, TxGraph},
|
||||
BlockId, TxHeight,
|
||||
};
|
||||
use bitcoin::{OutPoint, PackedLockTime, Script, Sequence, Transaction, TxIn, TxOut, Witness};
|
||||
use bitcoin::{
|
||||
BlockHash, OutPoint, PackedLockTime, Script, Sequence, Transaction, TxIn, TxOut, Witness,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_spent_by() {
|
||||
@@ -43,7 +47,7 @@ fn test_spent_by() {
|
||||
output: vec![],
|
||||
};
|
||||
|
||||
let mut cg1 = ChainGraph::default();
|
||||
let mut cg1 = ChainGraph::<(u32, BlockHash), _>::default();
|
||||
let _ = cg1
|
||||
.insert_tx(tx1, TxHeight::Unconfirmed)
|
||||
.expect("should insert");
|
||||
@@ -124,7 +128,7 @@ fn update_evicts_conflicting_tx() {
|
||||
cg
|
||||
};
|
||||
|
||||
let changeset = ChangeSet::<TxHeight> {
|
||||
let changeset = ChangeSet::<(u32, BlockHash), TxHeight> {
|
||||
chain: sparse_chain::ChangeSet {
|
||||
checkpoints: Default::default(),
|
||||
txids: [
|
||||
@@ -133,9 +137,10 @@ fn update_evicts_conflicting_tx() {
|
||||
]
|
||||
.into(),
|
||||
},
|
||||
graph: tx_graph::Additions {
|
||||
graph: tx_graph::Additions::<(u32, BlockHash)> {
|
||||
tx: [tx_b2.clone()].into(),
|
||||
txout: [].into(),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
@@ -149,7 +154,7 @@ fn update_evicts_conflicting_tx() {
|
||||
|
||||
{
|
||||
let cg1 = {
|
||||
let mut cg = ChainGraph::default();
|
||||
let mut cg = ChainGraph::<(u32, BlockHash), _>::default();
|
||||
let _ = cg.insert_checkpoint(cp_a).expect("should insert cp");
|
||||
let _ = cg.insert_checkpoint(cp_b).expect("should insert cp");
|
||||
let _ = cg
|
||||
@@ -203,7 +208,7 @@ fn update_evicts_conflicting_tx() {
|
||||
cg
|
||||
};
|
||||
|
||||
let changeset = ChangeSet::<TxHeight> {
|
||||
let changeset = ChangeSet::<(u32, BlockHash), TxHeight> {
|
||||
chain: sparse_chain::ChangeSet {
|
||||
checkpoints: [(1, Some(h!("B'")))].into(),
|
||||
txids: [
|
||||
@@ -212,9 +217,10 @@ fn update_evicts_conflicting_tx() {
|
||||
]
|
||||
.into(),
|
||||
},
|
||||
graph: tx_graph::Additions {
|
||||
graph: tx_graph::Additions::<(u32, BlockHash)> {
|
||||
tx: [tx_b2].into(),
|
||||
txout: [].into(),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
@@ -250,7 +256,7 @@ fn chain_graph_new_missing() {
|
||||
(tx_b.txid(), TxHeight::Confirmed(0))
|
||||
]
|
||||
);
|
||||
let mut graph = TxGraph::default();
|
||||
let mut graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
|
||||
let mut expected_missing = HashSet::new();
|
||||
expected_missing.insert(tx_a.txid());
|
||||
@@ -287,7 +293,7 @@ fn chain_graph_new_missing() {
|
||||
|
||||
let new_graph = ChainGraph::new(update.clone(), graph.clone()).unwrap();
|
||||
let expected_graph = {
|
||||
let mut cg = ChainGraph::<TxHeight>::default();
|
||||
let mut cg = ChainGraph::<(u32, BlockHash), TxHeight>::default();
|
||||
let _ = cg
|
||||
.insert_checkpoint(update.latest_checkpoint().unwrap())
|
||||
.unwrap();
|
||||
@@ -342,7 +348,7 @@ fn chain_graph_new_conflicts() {
|
||||
]
|
||||
);
|
||||
|
||||
let graph = TxGraph::new([tx_a, tx_b, tx_b2]);
|
||||
let graph = TxGraph::<(u32, BlockHash)>::new([tx_a, tx_b, tx_b2]);
|
||||
|
||||
assert!(matches!(
|
||||
ChainGraph::new(chain, graph),
|
||||
@@ -352,7 +358,7 @@ fn chain_graph_new_conflicts() {
|
||||
|
||||
#[test]
|
||||
fn test_get_tx_in_chain() {
|
||||
let mut cg = ChainGraph::default();
|
||||
let mut cg = ChainGraph::<(u32, BlockHash), _>::default();
|
||||
let tx = Transaction {
|
||||
version: 0x01,
|
||||
lock_time: PackedLockTime(0),
|
||||
@@ -363,13 +369,21 @@ fn test_get_tx_in_chain() {
|
||||
let _ = cg.insert_tx(tx.clone(), TxHeight::Unconfirmed).unwrap();
|
||||
assert_eq!(
|
||||
cg.get_tx_in_chain(tx.txid()),
|
||||
Some((&TxHeight::Unconfirmed, &tx))
|
||||
Some((
|
||||
&TxHeight::Unconfirmed,
|
||||
GraphedTx {
|
||||
txid: tx.txid(),
|
||||
tx: &tx,
|
||||
anchors: &BTreeSet::new(),
|
||||
last_seen: 0
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate_transactions() {
|
||||
let mut cg = ChainGraph::default();
|
||||
let mut cg = ChainGraph::<BlockId, _>::default();
|
||||
let txs = (0..3)
|
||||
.map(|i| Transaction {
|
||||
version: i,
|
||||
@@ -395,9 +409,18 @@ fn test_iterate_transactions() {
|
||||
assert_eq!(
|
||||
cg.transactions_in_chain().collect::<Vec<_>>(),
|
||||
vec![
|
||||
(&TxHeight::Confirmed(0), &txs[2]),
|
||||
(&TxHeight::Confirmed(1), &txs[0]),
|
||||
(&TxHeight::Unconfirmed, &txs[1]),
|
||||
(
|
||||
&TxHeight::Confirmed(0),
|
||||
GraphedTx::from_tx(&txs[2], &BTreeSet::new())
|
||||
),
|
||||
(
|
||||
&TxHeight::Confirmed(1),
|
||||
GraphedTx::from_tx(&txs[0], &BTreeSet::new())
|
||||
),
|
||||
(
|
||||
&TxHeight::Unconfirmed,
|
||||
GraphedTx::from_tx(&txs[1], &BTreeSet::new())
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -457,7 +480,7 @@ fn test_apply_changes_reintroduce_tx() {
|
||||
|
||||
// block1, block2a, tx1, tx2a
|
||||
let mut cg = {
|
||||
let mut cg = ChainGraph::default();
|
||||
let mut cg = ChainGraph::<(u32, BlockHash), _>::default();
|
||||
let _ = cg.insert_checkpoint(block1).unwrap();
|
||||
let _ = cg.insert_checkpoint(block2a).unwrap();
|
||||
let _ = cg.insert_tx(tx1, TxHeight::Confirmed(1)).unwrap();
|
||||
@@ -613,7 +636,7 @@ fn test_evict_descendants() {
|
||||
let txid_conflict = tx_conflict.txid();
|
||||
|
||||
let cg = {
|
||||
let mut cg = ChainGraph::<TxHeight>::default();
|
||||
let mut cg = ChainGraph::<(u32, BlockHash), TxHeight>::default();
|
||||
let _ = cg.insert_checkpoint(block_1);
|
||||
let _ = cg.insert_checkpoint(block_2a);
|
||||
let _ = cg.insert_tx(tx_1, TxHeight::Confirmed(1));
|
||||
@@ -625,7 +648,7 @@ fn test_evict_descendants() {
|
||||
};
|
||||
|
||||
let update = {
|
||||
let mut cg = ChainGraph::<TxHeight>::default();
|
||||
let mut cg = ChainGraph::<(u32, BlockHash), TxHeight>::default();
|
||||
let _ = cg.insert_checkpoint(block_1);
|
||||
let _ = cg.insert_checkpoint(block_2b);
|
||||
let _ = cg.insert_tx(tx_conflict.clone(), TxHeight::Confirmed(2));
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
#![cfg(feature = "miniscript")]
|
||||
#[macro_use]
|
||||
mod common;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use bdk_chain::{
|
||||
keychain::{Balance, KeychainTracker},
|
||||
miniscript::{
|
||||
bitcoin::{secp256k1::Secp256k1, OutPoint, PackedLockTime, Transaction, TxOut},
|
||||
Descriptor,
|
||||
},
|
||||
tx_graph::GraphedTx,
|
||||
BlockId, ConfirmationTime, TxHeight,
|
||||
};
|
||||
use bitcoin::TxIn;
|
||||
use bitcoin::{BlockHash, TxIn};
|
||||
|
||||
#[test]
|
||||
fn test_insert_tx() {
|
||||
let mut tracker = KeychainTracker::default();
|
||||
let mut tracker = KeychainTracker::<_, BlockId, _>::default();
|
||||
let secp = Secp256k1::new();
|
||||
let (descriptor, _) = Descriptor::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
|
||||
tracker.add_keychain((), descriptor.clone());
|
||||
@@ -40,7 +43,10 @@ fn test_insert_tx() {
|
||||
.chain_graph()
|
||||
.transactions_in_chain()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(&ConfirmationTime::Unconfirmed, &tx)]
|
||||
vec![(
|
||||
&ConfirmationTime::Unconfirmed,
|
||||
GraphedTx::from_tx(&tx, &BTreeSet::new())
|
||||
)]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -66,7 +72,7 @@ fn test_balance() {
|
||||
One,
|
||||
Two,
|
||||
}
|
||||
let mut tracker = KeychainTracker::<Keychain, TxHeight>::default();
|
||||
let mut tracker = KeychainTracker::<Keychain, (u32, BlockHash), TxHeight>::default();
|
||||
let one = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)#rg247h69").unwrap();
|
||||
let two = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/1/*)#ju05rz2a").unwrap();
|
||||
tracker.add_keychain(Keychain::One, one);
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
mod common;
|
||||
use bdk_chain::{
|
||||
collections::*,
|
||||
tx_graph::{Additions, TxGraph},
|
||||
tx_graph::{Additions, GraphedTx, TxGraph},
|
||||
BlockId,
|
||||
};
|
||||
use bitcoin::{
|
||||
hashes::Hash, BlockHash, OutPoint, PackedLockTime, Script, Transaction, TxIn, TxOut, Txid,
|
||||
};
|
||||
use bitcoin::{hashes::Hash, OutPoint, PackedLockTime, Script, Transaction, TxIn, TxOut, Txid};
|
||||
use core::iter;
|
||||
|
||||
#[test]
|
||||
@@ -35,7 +38,7 @@ fn insert_txouts() {
|
||||
)];
|
||||
|
||||
let mut graph = {
|
||||
let mut graph = TxGraph::default();
|
||||
let mut graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
for (outpoint, txout) in &original_ops {
|
||||
assert_eq!(
|
||||
graph.insert_txout(*outpoint, txout.clone()),
|
||||
@@ -69,6 +72,7 @@ fn insert_txouts() {
|
||||
Additions {
|
||||
tx: [].into(),
|
||||
txout: update_ops.into(),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
@@ -90,7 +94,7 @@ fn insert_tx_graph_doesnt_count_coinbase_as_spent() {
|
||||
output: vec![],
|
||||
};
|
||||
|
||||
let mut graph = TxGraph::default();
|
||||
let mut graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
let _ = graph.insert_tx(tx);
|
||||
assert!(graph.outspends(OutPoint::null()).is_empty());
|
||||
assert!(graph.tx_outspends(Txid::all_zeros()).next().is_none());
|
||||
@@ -120,8 +124,8 @@ fn insert_tx_graph_keeps_track_of_spend() {
|
||||
output: vec![],
|
||||
};
|
||||
|
||||
let mut graph1 = TxGraph::default();
|
||||
let mut graph2 = TxGraph::default();
|
||||
let mut graph1 = TxGraph::<(u32, BlockHash)>::default();
|
||||
let mut graph2 = TxGraph::<(u32, BlockHash)>::default();
|
||||
|
||||
// insert in different order
|
||||
let _ = graph1.insert_tx(tx1.clone());
|
||||
@@ -149,14 +153,17 @@ fn insert_tx_can_retrieve_full_tx_from_graph() {
|
||||
output: vec![TxOut::default()],
|
||||
};
|
||||
|
||||
let mut graph = TxGraph::default();
|
||||
let mut graph = TxGraph::<BlockId>::default();
|
||||
let _ = graph.insert_tx(tx.clone());
|
||||
assert_eq!(graph.get_tx(tx.txid()), Some(&tx));
|
||||
assert_eq!(
|
||||
graph.get_tx(tx.txid()),
|
||||
Some(GraphedTx::from_tx(&tx, &BTreeSet::new()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_tx_displaces_txouts() {
|
||||
let mut tx_graph = TxGraph::default();
|
||||
let mut tx_graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
let tx = Transaction {
|
||||
version: 0x01,
|
||||
lock_time: PackedLockTime(0),
|
||||
@@ -212,7 +219,7 @@ fn insert_tx_displaces_txouts() {
|
||||
|
||||
#[test]
|
||||
fn insert_txout_does_not_displace_tx() {
|
||||
let mut tx_graph = TxGraph::default();
|
||||
let mut tx_graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
let tx = Transaction {
|
||||
version: 0x01,
|
||||
lock_time: PackedLockTime(0),
|
||||
@@ -268,7 +275,7 @@ fn insert_txout_does_not_displace_tx() {
|
||||
|
||||
#[test]
|
||||
fn test_calculate_fee() {
|
||||
let mut graph = TxGraph::default();
|
||||
let mut graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
let intx1 = Transaction {
|
||||
version: 0x01,
|
||||
lock_time: PackedLockTime(0),
|
||||
@@ -362,7 +369,7 @@ fn test_calculate_fee_on_coinbase() {
|
||||
output: vec![TxOut::default()],
|
||||
};
|
||||
|
||||
let graph = TxGraph::default();
|
||||
let graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
|
||||
assert_eq!(graph.calculate_fee(&tx), Some(0));
|
||||
}
|
||||
@@ -404,7 +411,7 @@ fn test_conflicting_descendants() {
|
||||
let txid_a = tx_a.txid();
|
||||
let txid_b = tx_b.txid();
|
||||
|
||||
let mut graph = TxGraph::default();
|
||||
let mut graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
let _ = graph.insert_tx(tx_a);
|
||||
let _ = graph.insert_tx(tx_b);
|
||||
|
||||
@@ -480,7 +487,7 @@ fn test_descendants_no_repeat() {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut graph = TxGraph::default();
|
||||
let mut graph = TxGraph::<(u32, BlockHash)>::default();
|
||||
let mut expected_txids = BTreeSet::new();
|
||||
|
||||
// these are NOT descendants of `tx_a`
|
||||
|
||||
Reference in New Issue
Block a user