Skip to content

Commit

Permalink
add get_merkle method, use tx index to confirm it
Browse files Browse the repository at this point in the history
  • Loading branch information
shamardy committed Dec 9, 2021
1 parent 6ab6a97 commit 4996e6f
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
53 changes: 36 additions & 17 deletions mm2src/coins/lightning/ln_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,17 +536,6 @@ impl ConfirmedTransactionInfo {
}
}

// Used to order 2 transactions if one spends the other by the spent transaction first
#[cfg(not(target_arch = "wasm32"))]
fn cmp_txs_for_spending(spent_tx: &Transaction, spending_tx: &Transaction) -> Ordering {
for tx_in in &spending_tx.input {
if spent_tx.txid() == tx_in.previous_output.txid {
return Ordering::Less;
}
}
Ordering::Equal
}

#[cfg(not(target_arch = "wasm32"))]
async fn process_tx_for_unconfirmation(txid: Txid, filter: Arc<PlatformFields>, channel_manager: Arc<ChannelManager>) {
if let Err(err) = filter
Expand Down Expand Up @@ -620,7 +609,7 @@ async fn process_txs_confirmations(
continue;
},
};
for (index, vout) in transaction.output.iter().enumerate() {
for (_, vout) in transaction.output.iter().enumerate() {
if scripts.contains(&vout.script_pubkey) {
let script_hash = hex::encode(electrum_script_hash(vout.script_pubkey.as_ref()));
let history = client
Expand All @@ -629,7 +618,7 @@ async fn process_txs_confirmations(
.await
.unwrap_or_default();
for item in history {
if item.tx_hash == rpc_txid {
if item.tx_hash == rpc_txid.clone() {
// If a new block mined the transaction while running process_txs_confirmations it will be confirmed later in ln_best_block_update_loop
if item.height > 0 && item.height <= current_height as i64 {
let height: u64 = match item.height.try_into() {
Expand All @@ -649,6 +638,20 @@ async fn process_txs_confirmations(
},
Err(_) => continue,
};
let index = match client
.blockchain_transaction_get_merkle(rpc_txid.clone(), height)
.compat()
.await
{
Ok(merkle_branch) => merkle_branch.pos,
Err(e) => {
log::error!(
"Error getting transaction position in the block: {}",
e.to_string()
);
continue;
},
};
let confirmed_transaction_info = ConfirmedTransactionInfo::new(
txid,
header,
Expand Down Expand Up @@ -686,8 +689,20 @@ async fn process_txs_confirmations(
continue;
},
};
if let Some((header, index, tx, height)) = result {
if let Some((header, _, tx, height)) = result {
if !transactions_to_confirm.iter().any(|info| info.txid == tx.txid()) {
let rpc_txid = H256::from(tx.txid().as_hash().into_inner()).reversed();
let index = match client
.blockchain_transaction_get_merkle(rpc_txid, height)
.compat()
.await
{
Ok(merkle_branch) => merkle_branch.pos,
Err(e) => {
log::error!("Error getting transaction position in the block: {}", e.to_string());
continue;
},
};
let confirmed_transaction_info =
ConfirmedTransactionInfo::new(tx.txid(), header, index, tx, height as u32);
transactions_to_confirm.push(confirmed_transaction_info);
Expand All @@ -698,9 +713,13 @@ async fn process_txs_confirmations(
registered_outputs.retain(|output| !outputs_to_remove.contains(output));
drop(registered_outputs);

transactions_to_confirm.sort_by(|a, b| a.height.cmp(&b.height));
// If a transaction spends another in the same block, the spent transaction should be confirmed first
transactions_to_confirm.sort_by(|a, b| cmp_txs_for_spending(&a.transaction, &b.transaction));
transactions_to_confirm.sort_by(|a, b| {
let block_order = a.height.cmp(&b.height);
match block_order {
Ordering::Equal => a.index.cmp(&b.index),
_ => block_order,
}
});

for confirmed_transaction_info in transactions_to_confirm {
channel_manager.transactions_confirmed(
Expand Down
13 changes: 13 additions & 0 deletions mm2src/coins/utxo/rpc_clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,14 @@ pub enum ElectrumBlockHeader {
V14(ElectrumBlockHeaderV14),
}

/// The merkle branch of a confirmed transaction
#[derive(Clone, Debug, Deserialize)]
pub struct TxMerkleBranch {
pub merkle: Vec<H256Json>,
pub block_height: u64,
pub pos: usize,
}

#[derive(Debug, PartialEq)]
pub struct BestBlock {
pub height: u64,
Expand Down Expand Up @@ -1600,6 +1608,11 @@ impl ElectrumClient {
pub fn blockchain_block_headers(&self, start_height: u64, count: NonZeroU64) -> RpcRes<ElectrumBlockHeadersRes> {
rpc_func!(self, "blockchain.block.headers", start_height, count)
}

/// https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get-merkle
pub fn blockchain_transaction_get_merkle(&self, txid: H256Json, height: u64) -> RpcRes<TxMerkleBranch> {
rpc_func!(self, "blockchain.transaction.get_merkle", txid, height)
}
}

#[cfg_attr(test, mockable)]
Expand Down

0 comments on commit 4996e6f

Please sign in to comment.