Skip to content

Commit

Permalink
Sort txs according to position within block
Browse files Browse the repository at this point in the history
  • Loading branch information
gcomte committed Oct 10, 2022
1 parent 167eb7d commit b2f521d
Showing 1 changed file with 69 additions and 10 deletions.
79 changes: 69 additions & 10 deletions src/chain_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,7 @@ impl LipaChainAccess {
debug!("{} confirmed transactions", confirmed_txs.len());
debug!("Confirmed transaction list: {:?}", confirmed_txs);

// Sort all confirmed transactions by block height and feed them to the interface
// in order.
confirmed_txs.sort_unstable_by(|(_, block_height1, _, _), (_, block_height2, _, _)| {
block_height1.cmp(block_height2)
});

// todo also sort within block
// From the Confirm trait documentation:
// Dependent transactions within the same block must be given in topological order, possibly in separate calls
sort_txs(&mut confirmed_txs);

for (tx, block_height, block_header, pos) in confirmed_txs {
for c in &confirmables {
Expand Down Expand Up @@ -368,6 +360,16 @@ impl LipaChainAccess {
}
}

// Sorting by blocks and by transaction position within the each block
// From the Confirm trait documentation:
// - Transactions confirmed in a block must be given before transactions confirmed in a later
// block.
// - Dependent transactions within the same block must be given in topological order, possibly in
// separate calls.
fn sort_txs(txs: &mut [(Transaction, u32, BlockHeader, usize)]) {
txs.sort_unstable_by_key(|tx| (tx.1, tx.3));
}

impl Filter for LipaChainAccess {
fn register_tx(&self, txid: &Txid, script_pubkey: &Script) {
self.queued_txs
Expand All @@ -388,10 +390,11 @@ impl Filter for LipaChainAccess {

#[cfg(test)]
mod tests {
use crate::chain_access::sort_txs;
use crate::LipaChainAccess;
use bitcoin::consensus::deserialize;
use bitcoin::hashes::hex::FromHex;
use bitcoin::Transaction;
use bitcoin::{BlockHeader, Transaction};
use esplora_client::Builder;
use lightning::chain::transaction::OutPoint;
use lightning::chain::{Filter, WatchedOutput};
Expand All @@ -417,6 +420,17 @@ mod tests {
tx.unwrap()
}

fn build_default_block_header() -> BlockHeader {
BlockHeader {
version: 0,
prev_blockhash: Default::default(),
merkle_root: Default::default(),
time: 0,
bits: 0,
nonce: 0,
}
}

#[test]
fn filter_is_initialised_empty() {
let filter = build_filter();
Expand Down Expand Up @@ -480,4 +494,49 @@ mod tests {
assert_eq!(filter_output.outpoint, output.outpoint);
assert_eq!(filter_output.block_hash, output.block_hash);
}

#[test]
fn txs_are_sorted_by_block_and_position_within_block() {
let mut txs = vec![
(
build_sample_tx(),
10, // block height
build_default_block_header(),
10, // position within block
),
(
build_sample_tx(),
5, // block height
build_default_block_header(),
5, // position within block
),
(
build_sample_tx(),
10, // block height
build_default_block_header(),
5, // position within block
),
(
build_sample_tx(),
5, // block height
build_default_block_header(),
10, // position within block
),
];

let unsorted: Vec<(u32, usize)> = txs
.iter()
.map(|(_, block_height, _, pos_within_block)| (*block_height, *pos_within_block))
.collect();

sort_txs(&mut txs);

let sorted: Vec<(u32, usize)> = txs
.iter()
.map(|(_, block_height, _, pos_within_block)| (*block_height, *pos_within_block))
.collect();

assert_eq!(unsorted, vec![(10, 10), (5, 5), (10, 5), (5, 10)]);
assert_eq!(sorted, vec![(5, 5), (5, 10), (10, 5), (10, 10)]);
}
}

0 comments on commit b2f521d

Please sign in to comment.