1- #! [ cfg ( feature = "miniscript" ) ]
1+ //! Transaction templates for constructing complex transaction histories for testing purposes.
22
3- use bdk_testenv :: utils:: DESCRIPTORS ;
4- use rand :: distributions :: { Alphanumeric , DistString } ;
5- use std :: collections :: HashMap ;
6-
7- use bdk_chain :: { spk_txout :: SpkTxOutIndex , tx_graph :: TxGraph , Anchor , CanonicalizationParams } ;
3+ use crate :: utils:: DESCRIPTORS ;
4+ use bdk_chain :: {
5+ miniscript :: Descriptor , spk_txout :: SpkTxOutIndex , tx_graph :: TxGraph , Anchor ,
6+ CanonicalizationParams ,
7+ } ;
88use bitcoin:: {
99 locktime:: absolute:: LockTime , secp256k1:: Secp256k1 , transaction, Amount , OutPoint , ScriptBuf ,
1010 Sequence , Transaction , TxIn , TxOut , Txid , Witness ,
1111} ;
12- use miniscript:: Descriptor ;
12+ use rand:: distributions:: { Alphanumeric , DistString } ;
13+ use std:: collections:: HashMap ;
1314
14- /// Template for creating a transaction in `TxGraph`.
15+ /// Template for creating a transaction in a [ `TxGraph`] .
1516///
16- /// The incentive for transaction templates is to create a transaction history in a simple manner to
17- /// avoid having to explicitly hash previous transactions to form previous outpoints of later
18- /// transactions .
17+ /// This is the main building block for constructing complex transaction histories
18+ /// for tests. It allows you to refer to previous transactions by name instead of
19+ /// manually managing txids and outpoints .
1920#[ derive( Clone , Copy , Default ) ]
2021pub struct TxTemplate < ' a , A > {
21- /// Uniquely identifies the transaction, before it can have a txid .
22+ /// A unique name used to refer to this transaction in other templates .
2223 pub tx_name : & ' a str ,
24+
25+ /// The inputs of this transaction.
2326 pub inputs : & ' a [ TxInTemplate < ' a > ] ,
27+
28+ /// The outputs of this transaction.
2429 pub outputs : & ' a [ TxOutTemplate ] ,
30+
31+ /// Anchors (confirmations) for this transaction.
2532 pub anchors : & ' a [ A ] ,
33+
34+ /// Unix timestamp when this transaction was last seen in the mempool.
2635 pub last_seen : Option < u64 > ,
36+
37+ /// If `true`, this transaction will be treated as canonical regardless of
38+ /// conflict resolution rules (used for testing forced canonicalization).
2739 pub assume_canonical : bool ,
2840}
2941
42+ /// Describes how an input is created in a [`TxTemplate`].
3043#[ allow( dead_code) ]
3144pub enum TxInTemplate < ' a > {
32- /// This will give a random txid and vout .
45+ /// A random (bogus) previous output. Useful when the actual prevout doesn't matter .
3346 Bogus ,
3447
35- /// This is used for coinbase transactions because they do not have previous outputs .
48+ /// A coinbase input (no previous output) .
3649 Coinbase ,
3750
38- /// Contains the `tx_name` and `vout` that we are spending. The rule is that we must only spend
39- /// from tx of a previous `TxTemplate`.
51+ /// Spends from a previous transaction defined in the template list.
52+ ///
53+ /// The rule is that the referenced transaction (`prev_name`) must appear
54+ /// earlier in the list passed to [`init_graph`].
4055 PrevTx ( & ' a str , usize ) ,
4156}
4257
58+ /// Describes an output in a [`TxTemplate`].
4359pub struct TxOutTemplate {
60+ /// Value in satoshis.
4461 pub value : u64 ,
45- pub spk_index : Option < u32 > , // some = get spk from SpkTxOutIndex, none = random spk
62+ /// If `Some(index)`, the output will use the script pubkey at that index
63+ /// from the test descriptor set. If `None`, a random (empty) script is used.
64+ pub spk_index : Option < u32 > ,
4665}
4766
48- #[ allow( unused) ]
4967impl TxOutTemplate {
5068 pub fn new ( value : u64 , spk_index : Option < u32 > ) -> Self {
5169 TxOutTemplate { value, spk_index }
5270 }
5371}
5472
73+ /// The result of calling [`init_graph`].
74+ ///
75+ /// Contains the built [`TxGraph`], the associated indexer, and a mapping from
76+ /// template names to their final txids.
5577#[ allow( dead_code) ]
5678pub struct TxTemplateEnv < ' a , A > {
5779 pub tx_graph : TxGraph < A > ,
@@ -60,14 +82,21 @@ pub struct TxTemplateEnv<'a, A> {
6082 pub canonicalization_params : CanonicalizationParams ,
6183}
6284
63- #[ allow( dead_code) ]
85+ /// Builds a [`TxGraph`] (and associated indexer) from a list of [`TxTemplate`]s.
86+ ///
87+ /// This is the main entry point for using transaction templates in tests.
88+ /// It handles txid generation, outpoint wiring, anchor insertion, and last-seen
89+ /// timestamps automatically.
6490pub fn init_graph < ' a , A : Anchor + Clone + ' a > (
6591 tx_templates : impl IntoIterator < Item = & ' a TxTemplate < ' a , A > > ,
6692) -> TxTemplateEnv < ' a , A > {
6793 let ( descriptor, _) =
6894 Descriptor :: parse_descriptor ( & Secp256k1 :: signing_only ( ) , DESCRIPTORS [ 2 ] ) . unwrap ( ) ;
95+
6996 let mut tx_graph = TxGraph :: < A > :: default ( ) ;
7097 let mut indexer = SpkTxOutIndex :: default ( ) ;
98+
99+ // Pre-populate the indexer with 10 script pubkeys from the test descriptor
71100 ( 0 ..10 ) . for_each ( |index| {
72101 indexer. insert_spk (
73102 index,
@@ -77,9 +106,10 @@ pub fn init_graph<'a, A: Anchor + Clone + 'a>(
77106 . script_pubkey ( ) ,
78107 ) ;
79108 } ) ;
80- let mut txid_to_name = HashMap :: < & ' a str , Txid > :: new ( ) ;
81109
110+ let mut txid_to_name = HashMap :: < & ' a str , Txid > :: new ( ) ;
82111 let mut canonicalization_params = CanonicalizationParams :: default ( ) ;
112+
83113 for ( bogus_txin_vout, tx_tmp) in tx_templates. into_iter ( ) . enumerate ( ) {
84114 let tx = Transaction {
85115 version : transaction:: Version :: non_standard ( 0 ) ,
@@ -137,19 +167,24 @@ pub fn init_graph<'a, A: Anchor + Clone + 'a>(
137167 } ;
138168
139169 let txid = tx. compute_txid ( ) ;
170+
140171 if tx_tmp. assume_canonical {
141172 canonicalization_params. assume_canonical . push ( txid) ;
142173 }
174+
143175 txid_to_name. insert ( tx_tmp. tx_name , txid) ;
144176 indexer. scan ( & tx) ;
145177 let _ = tx_graph. insert_tx ( tx. clone ( ) ) ;
178+
146179 for anchor in tx_tmp. anchors . iter ( ) {
147180 let _ = tx_graph. insert_anchor ( txid, anchor. clone ( ) ) ;
148181 }
182+
149183 if let Some ( last_seen) = tx_tmp. last_seen {
150184 let _ = tx_graph. insert_seen_at ( txid, last_seen) ;
151185 }
152186 }
187+
153188 TxTemplateEnv {
154189 tx_graph,
155190 indexer,
0 commit comments