Skip to content

Commit b2f521d

Browse files
committed
Sort txs according to position within block
1 parent 167eb7d commit b2f521d

File tree

1 file changed

+69
-10
lines changed

1 file changed

+69
-10
lines changed

src/chain_access.rs

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,7 @@ impl LipaChainAccess {
7272
debug!("{} confirmed transactions", confirmed_txs.len());
7373
debug!("Confirmed transaction list: {:?}", confirmed_txs);
7474

75-
// Sort all confirmed transactions by block height and feed them to the interface
76-
// in order.
77-
confirmed_txs.sort_unstable_by(|(_, block_height1, _, _), (_, block_height2, _, _)| {
78-
block_height1.cmp(block_height2)
79-
});
80-
81-
// todo also sort within block
82-
// From the Confirm trait documentation:
83-
// Dependent transactions within the same block must be given in topological order, possibly in separate calls
75+
sort_txs(&mut confirmed_txs);
8476

8577
for (tx, block_height, block_header, pos) in confirmed_txs {
8678
for c in &confirmables {
@@ -368,6 +360,16 @@ impl LipaChainAccess {
368360
}
369361
}
370362

363+
// Sorting by blocks and by transaction position within the each block
364+
// From the Confirm trait documentation:
365+
// - Transactions confirmed in a block must be given before transactions confirmed in a later
366+
// block.
367+
// - Dependent transactions within the same block must be given in topological order, possibly in
368+
// separate calls.
369+
fn sort_txs(txs: &mut [(Transaction, u32, BlockHeader, usize)]) {
370+
txs.sort_unstable_by_key(|tx| (tx.1, tx.3));
371+
}
372+
371373
impl Filter for LipaChainAccess {
372374
fn register_tx(&self, txid: &Txid, script_pubkey: &Script) {
373375
self.queued_txs
@@ -388,10 +390,11 @@ impl Filter for LipaChainAccess {
388390

389391
#[cfg(test)]
390392
mod tests {
393+
use crate::chain_access::sort_txs;
391394
use crate::LipaChainAccess;
392395
use bitcoin::consensus::deserialize;
393396
use bitcoin::hashes::hex::FromHex;
394-
use bitcoin::Transaction;
397+
use bitcoin::{BlockHeader, Transaction};
395398
use esplora_client::Builder;
396399
use lightning::chain::transaction::OutPoint;
397400
use lightning::chain::{Filter, WatchedOutput};
@@ -417,6 +420,17 @@ mod tests {
417420
tx.unwrap()
418421
}
419422

423+
fn build_default_block_header() -> BlockHeader {
424+
BlockHeader {
425+
version: 0,
426+
prev_blockhash: Default::default(),
427+
merkle_root: Default::default(),
428+
time: 0,
429+
bits: 0,
430+
nonce: 0,
431+
}
432+
}
433+
420434
#[test]
421435
fn filter_is_initialised_empty() {
422436
let filter = build_filter();
@@ -480,4 +494,49 @@ mod tests {
480494
assert_eq!(filter_output.outpoint, output.outpoint);
481495
assert_eq!(filter_output.block_hash, output.block_hash);
482496
}
497+
498+
#[test]
499+
fn txs_are_sorted_by_block_and_position_within_block() {
500+
let mut txs = vec![
501+
(
502+
build_sample_tx(),
503+
10, // block height
504+
build_default_block_header(),
505+
10, // position within block
506+
),
507+
(
508+
build_sample_tx(),
509+
5, // block height
510+
build_default_block_header(),
511+
5, // position within block
512+
),
513+
(
514+
build_sample_tx(),
515+
10, // block height
516+
build_default_block_header(),
517+
5, // position within block
518+
),
519+
(
520+
build_sample_tx(),
521+
5, // block height
522+
build_default_block_header(),
523+
10, // position within block
524+
),
525+
];
526+
527+
let unsorted: Vec<(u32, usize)> = txs
528+
.iter()
529+
.map(|(_, block_height, _, pos_within_block)| (*block_height, *pos_within_block))
530+
.collect();
531+
532+
sort_txs(&mut txs);
533+
534+
let sorted: Vec<(u32, usize)> = txs
535+
.iter()
536+
.map(|(_, block_height, _, pos_within_block)| (*block_height, *pos_within_block))
537+
.collect();
538+
539+
assert_eq!(unsorted, vec![(10, 10), (5, 5), (10, 5), (5, 10)]);
540+
assert_eq!(sorted, vec![(5, 5), (5, 10), (10, 5), (10, 10)]);
541+
}
483542
}

0 commit comments

Comments
 (0)