Skip to content

Commit 3dd99eb

Browse files
committed
Factor out low-level build_closing_transaction
1 parent 4c4d99b commit 3dd99eb

File tree

2 files changed

+62
-45
lines changed

2 files changed

+62
-45
lines changed

lightning/src/ln/chan_utils.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use bitcoin::hash_types::{Txid, PubkeyHash};
2323
use ln::{PaymentHash, PaymentPreimage};
2424
use ln::msgs::DecodeError;
2525
use util::ser::{Readable, Writeable, Writer};
26-
use util::byte_utils;
26+
use util::{byte_utils, transaction_utils};
2727

2828
use bitcoin::hash_types::WPubkeyHash;
2929
use bitcoin::secp256k1::key::{SecretKey, PublicKey};
@@ -80,6 +80,50 @@ pub fn build_commitment_secret(commitment_seed: &[u8; 32], idx: u64) -> [u8; 32]
8080
res
8181
}
8282

83+
/// Build a closing transaction
84+
pub fn build_closing_transaction(value_to_holder: u64, value_to_counterparty: u64, holder_shutdown_script: Script, counterparty_shutdown_script: Script, funding_outpoint: OutPoint) -> Transaction {
85+
let txins = {
86+
let mut ins: Vec<TxIn> = Vec::new();
87+
ins.push(TxIn {
88+
previous_output: funding_outpoint,
89+
script_sig: Script::new(),
90+
sequence: 0xffffffff,
91+
witness: Vec::new(),
92+
});
93+
ins
94+
};
95+
96+
let mut txouts: Vec<(TxOut, ())> = Vec::new();
97+
98+
if value_to_counterparty > 0 {
99+
txouts.push((TxOut {
100+
script_pubkey: counterparty_shutdown_script,
101+
value: value_to_counterparty
102+
}, ()));
103+
}
104+
105+
if value_to_holder > 0 {
106+
txouts.push((TxOut {
107+
script_pubkey: holder_shutdown_script,
108+
value: value_to_holder
109+
}, ()));
110+
}
111+
112+
transaction_utils::sort_outputs(&mut txouts, |_, _| { cmp::Ordering::Equal }); // Ordering doesnt matter if they used our pubkey...
113+
114+
let mut outputs: Vec<TxOut> = Vec::new();
115+
for out in txouts.drain(..) {
116+
outputs.push(out.0);
117+
}
118+
119+
Transaction {
120+
version: 2,
121+
lock_time: 0,
122+
input: txins,
123+
output: outputs,
124+
}
125+
}
126+
83127
/// Implements the per-commitment secret storage scheme from
84128
/// [BOLT 3](https://github.com/lightningnetwork/lightning-rfc/blob/dcbf8583976df087c79c3ce0b535311212e6812d/03-transactions.md#efficient-per-commitment-secret-storage).
85129
///

lightning/src/ln/channel.rs

Lines changed: 17 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// licenses.
99

1010
use bitcoin::blockdata::script::{Script,Builder};
11-
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
11+
use bitcoin::blockdata::transaction::{Transaction, SigHashType};
1212
use bitcoin::util::bip143;
1313
use bitcoin::consensus::encode;
1414

@@ -28,14 +28,13 @@ use ln::msgs;
2828
use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
2929
use ln::script::ShutdownScript;
3030
use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
31-
use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor};
31+
use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, build_closing_transaction};
3232
use ln::chan_utils;
3333
use chain::BestBlock;
3434
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
3535
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER};
3636
use chain::transaction::{OutPoint, TransactionData};
3737
use chain::keysinterface::{Sign, KeysInterface};
38-
use util::transaction_utils;
3938
use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
4039
use util::logger::Logger;
4140
use util::errors::APIError;
@@ -1287,62 +1286,36 @@ impl<Signer: Sign> Channel<Signer> {
12871286

12881287
#[inline]
12891288
fn build_closing_transaction(&self, proposed_total_fee_satoshis: u64, skip_remote_output: bool) -> (Transaction, u64) {
1290-
let txins = {
1291-
let mut ins: Vec<TxIn> = Vec::new();
1292-
ins.push(TxIn {
1293-
previous_output: self.funding_outpoint().into_bitcoin_outpoint(),
1294-
script_sig: Script::new(),
1295-
sequence: 0xffffffff,
1296-
witness: Vec::new(),
1297-
});
1298-
ins
1299-
};
1300-
13011289
assert!(self.pending_inbound_htlcs.is_empty());
13021290
assert!(self.pending_outbound_htlcs.is_empty());
13031291
assert!(self.pending_update_fee.is_none());
1304-
let mut txouts: Vec<(TxOut, ())> = Vec::new();
13051292

13061293
let mut total_fee_satoshis = proposed_total_fee_satoshis;
1307-
let value_to_self: i64 = (self.value_to_self_msat as i64) / 1000 - if self.is_outbound() { total_fee_satoshis as i64 } else { 0 };
1308-
let value_to_remote: i64 = ((self.channel_value_satoshis * 1000 - self.value_to_self_msat) as i64 / 1000) - if self.is_outbound() { 0 } else { total_fee_satoshis as i64 };
1294+
let mut value_to_holder: i64 = (self.value_to_self_msat as i64) / 1000 - if self.is_outbound() { total_fee_satoshis as i64 } else { 0 };
1295+
let mut value_to_counterparty: i64 = ((self.channel_value_satoshis * 1000 - self.value_to_self_msat) as i64 / 1000) - if self.is_outbound() { 0 } else { total_fee_satoshis as i64 };
13091296

1310-
if value_to_self < 0 {
1297+
if value_to_holder < 0 {
13111298
assert!(self.is_outbound());
1312-
total_fee_satoshis += (-value_to_self) as u64;
1313-
} else if value_to_remote < 0 {
1299+
total_fee_satoshis += (-value_to_holder) as u64;
1300+
} else if value_to_counterparty < 0 {
13141301
assert!(!self.is_outbound());
1315-
total_fee_satoshis += (-value_to_remote) as u64;
1302+
total_fee_satoshis += (-value_to_counterparty) as u64;
13161303
}
13171304

1318-
if !skip_remote_output && value_to_remote as u64 > self.holder_dust_limit_satoshis {
1319-
txouts.push((TxOut {
1320-
script_pubkey: self.counterparty_shutdown_scriptpubkey.clone().unwrap(),
1321-
value: value_to_remote as u64
1322-
}, ()));
1305+
if skip_remote_output || value_to_counterparty as u64 <= self.holder_dust_limit_satoshis {
1306+
value_to_counterparty = 0;
13231307
}
13241308

1325-
assert!(self.shutdown_scriptpubkey.is_some());
1326-
if value_to_self as u64 > self.holder_dust_limit_satoshis {
1327-
txouts.push((TxOut {
1328-
script_pubkey: self.get_closing_scriptpubkey(),
1329-
value: value_to_self as u64
1330-
}, ()));
1309+
if value_to_holder as u64 <= self.holder_dust_limit_satoshis {
1310+
value_to_holder = 0;
13311311
}
13321312

1333-
transaction_utils::sort_outputs(&mut txouts, |_, _| { cmp::Ordering::Equal }); // Ordering doesnt matter if they used our pubkey...
1334-
1335-
let mut outputs: Vec<TxOut> = Vec::new();
1336-
for out in txouts.drain(..) {
1337-
outputs.push(out.0);
1338-
}
1313+
assert!(self.shutdown_scriptpubkey.is_some());
1314+
let holder_shutdown_script = self.get_closing_scriptpubkey();
1315+
let counterparty_shutdown_script = self.counterparty_shutdown_scriptpubkey.clone().unwrap();
1316+
let funding_outpoint = self.funding_outpoint().into_bitcoin_outpoint();
13391317

1340-
(Transaction {
1341-
version: 2,
1342-
lock_time: 0,
1343-
input: txins,
1344-
output: outputs,
1345-
}, total_fee_satoshis)
1318+
(build_closing_transaction(value_to_holder as u64, value_to_counterparty as u64, holder_shutdown_script, counterparty_shutdown_script, funding_outpoint), total_fee_satoshis)
13461319
}
13471320

13481321
fn funding_outpoint(&self) -> OutPoint {

0 commit comments

Comments
 (0)