@@ -43,8 +43,52 @@ impl BroadcastPackage {
4343 }
4444
4545 /// Consumes the package into its transactions, ready for the chain client.
46- pub ( crate ) fn into_transactions ( self ) -> Vec < Transaction > {
47- self . 0 . into_iter ( ) . map ( |( tx, _) | tx) . collect ( )
46+ pub ( crate ) fn into_sorted_transactions ( self ) -> SortedTransactions {
47+ let txs = self . 0 . into_iter ( ) . map ( |( tx, _) | tx) . collect ( ) ;
48+ SortedTransactions :: sort_parents_child_package_topologically ( txs)
49+ }
50+ }
51+
52+ pub ( crate ) struct SortedTransactions ( Vec < Transaction > ) ;
53+
54+ impl SortedTransactions {
55+ pub ( crate ) fn sort_parents_child_package_topologically (
56+ mut txs : Vec < Transaction > ,
57+ ) -> SortedTransactions {
58+ if txs. len ( ) == 0 || txs. len ( ) == 1 {
59+ return SortedTransactions ( txs) ;
60+ }
61+ let txids: Vec < _ > = txs. iter ( ) . map ( |tx| tx. compute_txid ( ) ) . collect ( ) ;
62+ let any_spends_from_package = |tx : & Transaction | -> bool {
63+ tx. input . iter ( ) . any ( |input| txids. contains ( & input. previous_output . txid ) )
64+ } ;
65+ txs. sort_by_key ( any_spends_from_package) ;
66+
67+ #[ cfg( debug_assertions) ]
68+ {
69+ let child = txs. last ( ) . expect ( "txs is not empty" ) ;
70+ let child_input_txids: Vec < _ > =
71+ child. input . iter ( ) . map ( |input| input. previous_output . txid ) . collect ( ) ;
72+ let parents = & txs[ ..txs. len ( ) - 1 ] ;
73+ let parent_txids: Vec < _ > = parents. iter ( ) . map ( |parent| parent. compute_txid ( ) ) . collect ( ) ;
74+ // Make sure all the parent txids are parents of the child transaction
75+ debug_assert ! ( parent_txids. iter( ) . all( |txid| child_input_txids. contains( & txid) ) ) ;
76+ // Make sure there are no grandparents
77+ debug_assert_eq ! ( txs. iter( ) . filter( |tx| any_spends_from_package( tx) ) . count( ) , 1 ) ;
78+ }
79+
80+ SortedTransactions ( txs)
81+ }
82+
83+ pub ( crate ) fn into_inner ( self ) -> Vec < Transaction > {
84+ self . 0
85+ }
86+ }
87+
88+ impl Deref for SortedTransactions {
89+ type Target = Vec < Transaction > ;
90+ fn deref ( & self ) -> & Self :: Target {
91+ & self . 0
4892 }
4993}
5094
@@ -123,3 +167,151 @@ where
123167 } ) ;
124168 }
125169}
170+
171+ #[ cfg( test) ]
172+ mod tests {
173+ use bitcoin:: hashes:: Hash ;
174+ use bitcoin:: { Amount , OutPoint , ScriptBuf , Sequence , Transaction , TxIn , TxOut , Txid , Witness } ;
175+
176+ use super :: SortedTransactions ;
177+
178+ fn txin ( txid : Txid , vout : u32 ) -> TxIn {
179+ TxIn {
180+ previous_output : OutPoint { txid, vout } ,
181+ script_sig : ScriptBuf :: new ( ) ,
182+ sequence : Sequence :: MAX ,
183+ witness : Witness :: new ( ) ,
184+ }
185+ }
186+
187+ fn txout ( value_sat : u64 ) -> TxOut {
188+ TxOut { value : Amount :: from_sat ( value_sat) , script_pubkey : ScriptBuf :: new ( ) }
189+ }
190+
191+ fn parent_tx ( seed : u8 ) -> Transaction {
192+ Transaction {
193+ version : bitcoin:: transaction:: Version :: TWO ,
194+ lock_time : bitcoin:: absolute:: LockTime :: ZERO ,
195+ input : vec ! [ txin( Txid :: from_byte_array( [ seed; 32 ] ) , 0 ) ] ,
196+ output : vec ! [ txout( 1_000 + u64 :: from( seed) ) ] ,
197+ }
198+ }
199+
200+ fn child_tx ( parents : & [ & Transaction ] ) -> Transaction {
201+ Transaction {
202+ version : bitcoin:: transaction:: Version :: TWO ,
203+ lock_time : bitcoin:: absolute:: LockTime :: ZERO ,
204+ input : parents
205+ . iter ( )
206+ . enumerate ( )
207+ . map ( |( idx, parent) | txin ( parent. compute_txid ( ) , idx as u32 ) )
208+ . collect ( ) ,
209+ output : vec ! [ txout( 1_000 ) ] ,
210+ }
211+ }
212+
213+ fn assert_parents_before_child (
214+ txs : & [ Transaction ] , expected_child : Txid , expected_parents : & [ Txid ] ,
215+ ) {
216+ assert_eq ! ( txs. last( ) . map( Transaction :: compute_txid) , Some ( expected_child) ) ;
217+ assert_eq ! ( txs. len( ) , expected_parents. len( ) + 1 ) ;
218+
219+ let parent_txids =
220+ txs[ ..txs. len ( ) - 1 ] . iter ( ) . map ( Transaction :: compute_txid) . collect :: < Vec < _ > > ( ) ;
221+ for expected_parent in expected_parents {
222+ assert ! ( parent_txids. contains( expected_parent) ) ;
223+ }
224+ }
225+
226+ #[ test]
227+ fn topological_sort_leaves_sorted_package_unchanged ( ) {
228+ let parent_a = parent_tx ( 1 ) ;
229+ let parent_b = parent_tx ( 2 ) ;
230+ let child = child_tx ( & [ & parent_a, & parent_b] ) ;
231+
232+ let original_txids =
233+ [ parent_a. compute_txid ( ) , parent_b. compute_txid ( ) , child. compute_txid ( ) ] ;
234+ let txs = vec ! [ parent_a, parent_b, child] ;
235+
236+ let package = SortedTransactions :: sort_parents_child_package_topologically ( txs) ;
237+
238+ assert_eq ! (
239+ package. iter( ) . map( Transaction :: compute_txid) . collect:: <Vec <_>>( ) ,
240+ original_txids
241+ ) ;
242+ }
243+
244+ #[ test]
245+ fn topological_sort_moves_single_parent_child_from_front_to_end ( ) {
246+ let parent = parent_tx ( 1 ) ;
247+ let child = child_tx ( & [ & parent] ) ;
248+ let parent_txids = [ parent. compute_txid ( ) ] ;
249+ let child_txid = child. compute_txid ( ) ;
250+ let txs = vec ! [ child, parent] ;
251+
252+ let package = SortedTransactions :: sort_parents_child_package_topologically ( txs) ;
253+
254+ assert_parents_before_child ( & package, child_txid, & parent_txids) ;
255+ }
256+
257+ #[ test]
258+ fn topological_sort_moves_child_from_front_to_end ( ) {
259+ let parent_a = parent_tx ( 1 ) ;
260+ let parent_b = parent_tx ( 2 ) ;
261+ let child = child_tx ( & [ & parent_a, & parent_b] ) ;
262+ let parent_txids = [ parent_a. compute_txid ( ) , parent_b. compute_txid ( ) ] ;
263+ let child_txid = child. compute_txid ( ) ;
264+ let txs = vec ! [ child, parent_a, parent_b] ;
265+
266+ let package = SortedTransactions :: sort_parents_child_package_topologically ( txs) ;
267+
268+ assert_parents_before_child ( & package, child_txid, & parent_txids) ;
269+ }
270+
271+ #[ test]
272+ fn topological_sort_moves_child_from_front_with_multiple_parents_to_end ( ) {
273+ let parent_a = parent_tx ( 1 ) ;
274+ let parent_b = parent_tx ( 2 ) ;
275+ let parent_c = parent_tx ( 3 ) ;
276+ let child = child_tx ( & [ & parent_a, & parent_b, & parent_c] ) ;
277+ let parent_txids =
278+ [ parent_a. compute_txid ( ) , parent_b. compute_txid ( ) , parent_c. compute_txid ( ) ] ;
279+ let child_txid = child. compute_txid ( ) ;
280+ let txs = vec ! [ child, parent_a, parent_b, parent_c] ;
281+
282+ let package = SortedTransactions :: sort_parents_child_package_topologically ( txs) ;
283+
284+ assert_parents_before_child ( & package, child_txid, & parent_txids) ;
285+ }
286+
287+ #[ test]
288+ fn topological_sort_moves_child_from_middle_to_end ( ) {
289+ let parent_a = parent_tx ( 1 ) ;
290+ let parent_b = parent_tx ( 2 ) ;
291+ let child = child_tx ( & [ & parent_a, & parent_b] ) ;
292+ let parent_txids = [ parent_a. compute_txid ( ) , parent_b. compute_txid ( ) ] ;
293+ let child_txid = child. compute_txid ( ) ;
294+ let txs = vec ! [ parent_a, child, parent_b] ;
295+
296+ let package = SortedTransactions :: sort_parents_child_package_topologically ( txs) ;
297+
298+ assert_parents_before_child ( & package, child_txid, & parent_txids) ;
299+ }
300+
301+ #[ test]
302+ fn topological_sort_leaves_single_transaction_package_unchanged ( ) {
303+ let parent = parent_tx ( 1 ) ;
304+ let parent_txid = parent. compute_txid ( ) ;
305+ let txs = vec ! [ parent] ;
306+
307+ let package = SortedTransactions :: sort_parents_child_package_topologically ( txs) ;
308+
309+ assert_eq ! ( package. len( ) , 1 ) ;
310+ assert_eq ! ( package[ 0 ] . compute_txid( ) , parent_txid) ;
311+ }
312+
313+ #[ test]
314+ fn topological_sort_accepts_empty_vec ( ) {
315+ SortedTransactions :: sort_parents_child_package_topologically ( Vec :: new ( ) ) ;
316+ }
317+ }
0 commit comments