local_keys: ChannelKeys,
+ // Our commitment numbers start at 2^48-1 and count down, whereas the ones used in transaction
+ // generation start at 0 and count up...this simplifies some parts of implementation at the
+ // cost of others, but should really just be changed.
+
cur_local_commitment_transaction_number: u64,
cur_remote_commitment_transaction_number: u64,
value_to_self_msat: u64, // Excluding all pending_htlcs, excluding fees
const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172;
const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4, script len: 1, witness lengths: (3+1)/4, sig: 73/4, if-selector: 1, redeemScript: (6 ops + 2*33 pubkeys + 1*2 delay)/4
const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: 4, script len: 1, witness lengths: 3/4, sig: 73/4, pubkey: 33/4, output: 31 (TODO: Wrong? Useless?)
+/// Maximmum `funding_satoshis` value, according to the BOLT #2 specification
+/// it's 2^24.
+pub const MAX_FUNDING_SATOSHIS: u64 = (1 << 24);
macro_rules! secp_call {
( $res: expr, $err: expr ) => {
/// Guaranteed to return a value no larger than channel_value_satoshis
fn get_our_channel_reserve_satoshis(channel_value_satoshis: u64) -> u64 {
- cmp::min(channel_value_satoshis, 10) //TODO
+ cmp::min(channel_value_satoshis, 1000) //TODO
}
fn derive_our_dust_limit_satoshis(at_open_background_feerate: u64) -> u64 {
// Constructors:
- /// panics if channel_value_satoshis is >= (1 << 24)
+ /// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`
pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, announce_publicly: bool, user_id: u64) -> Channel {
- if channel_value_satoshis >= (1 << 24) {
+ if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
panic!("funding value > 2^24");
}
/// that we're rejecting the new channel.
pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, announce_publicly: bool) -> Result<Channel, HandleError> {
// Check sanity of message fields:
- if msg.funding_satoshis >= (1 << 24) {
+ if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(HandleError{err: "funding value > 2^24", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
- if msg.funding_satoshis > 21000000 * 100000000 {
- return Err(HandleError{err: "More funding_satoshis than there are satoshis!", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
- }
if msg.channel_reserve_satoshis > msg.funding_satoshis {
return Err(HandleError{err: "Bogus channel_reserve_satoshis", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if msg.dust_limit_satoshis > msg.funding_satoshis {
return Err(HandleError{err: "Peer never wants payout outputs?", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
- if msg.max_htlc_value_in_flight_msat > msg.funding_satoshis * 1000 {
- return Err(HandleError{err: "Bogus max_htlc_value_in_flight_satoshis", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
- }
if msg.htlc_minimum_msat >= (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000 {
return Err(HandleError{err: "Minimum htlc value is full channel value", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
}
channel_value_satoshis: msg.funding_satoshis,
their_dust_limit_satoshis: msg.dust_limit_satoshis,
our_dust_limit_satoshis: Channel::derive_our_dust_limit_satoshis(background_feerate),
- their_max_htlc_value_in_flight_msat: msg.max_htlc_value_in_flight_msat,
+ their_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
their_channel_reserve_satoshis: msg.channel_reserve_satoshis,
their_htlc_minimum_msat: msg.htlc_minimum_msat,
our_htlc_minimum_msat: Channel::derive_our_htlc_minimum_msat(msg.feerate_per_kw as u64),
/// which peer generated this transaction and "to whom" this transaction flows.
#[inline]
fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool) -> (Transaction, Vec<HTLCOutputInCommitment>) {
- let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ commitment_number;
+ let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (0xffffffffffff - commitment_number);
let txins = {
let mut ins: Vec<TxIn> = Vec::new();
if msg.dust_limit_satoshis > 21000000 * 100000000 {
return Err(HandleError{err: "Peer never wants payout outputs?", msg: None});
}
- if msg.max_htlc_value_in_flight_msat > self.channel_value_satoshis * 1000 {
- return Err(HandleError{err: "Bogus max_htlc_value_in_flight_satoshis", msg: None});
- }
if msg.channel_reserve_satoshis > self.channel_value_satoshis {
return Err(HandleError{err: "Bogus channel_reserve_satoshis", msg: None});
}
self.channel_monitor.set_their_htlc_base_key(&msg.htlc_basepoint);
self.their_dust_limit_satoshis = msg.dust_limit_satoshis;
- self.their_max_htlc_value_in_flight_msat = msg.max_htlc_value_in_flight_msat;
+ self.their_max_htlc_value_in_flight_msat = cmp::min(msg.max_htlc_value_in_flight_msat, self.channel_value_satoshis * 1000);
self.their_channel_reserve_satoshis = msg.channel_reserve_satoshis;
self.their_htlc_minimum_msat = msg.htlc_minimum_msat;
self.their_to_self_delay = msg.to_self_delay;
}
let funding_txo = OutPoint::new(msg.funding_txid, msg.funding_output_index);
- self.channel_monitor.set_funding_info(funding_txo);
+ let funding_txo_script = self.get_funding_redeemscript().to_v0_p2wsh();
+ self.channel_monitor.set_funding_info((funding_txo, funding_txo_script));
let (remote_initial_commitment_tx, our_signature) = match self.funding_created_signature(&msg.signature) {
Ok(res) => res,
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
- self.channel_monitor.set_funding_info(funding_txo);
+ let funding_txo_script = self.get_funding_redeemscript().to_v0_p2wsh();
+ self.channel_monitor.set_funding_info((funding_txo, funding_txo_script));
let (our_signature, commitment_tx) = match self.get_outbound_funding_created_signature() {
Ok(res) => res,
use bitcoin::util::hash::Sha256dHash;
use bitcoin::util::bip143;
use bitcoin::network::serialize::serialize;
+ use bitcoin::blockdata::script::Script;
use bitcoin::blockdata::transaction::Transaction;
use ln::channel::{Channel,ChannelKeys,HTLCOutput,HTLCState,HTLCOutputInCommitment,TxCreationKeys};
+ use ln::channel::MAX_FUNDING_SATOSHIS;
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use chain::transaction::OutPoint;
}
}
+ #[test]
+ fn test_max_funding_satoshis() {
+ assert!(MAX_FUNDING_SATOSHIS <= 21_000_000 * 100_000_000,
+ "MAX_FUNDING_SATOSHIS is greater than all satoshis on existence");
+ }
+
#[test]
fn outbound_commitment_test() {
// Test vectors from BOLT 3 Appendix C:
chan.our_dust_limit_satoshis = 546;
let funding_info = OutPoint::new(Sha256dHash::from_hex("8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be").unwrap(), 0);
- chan.channel_monitor.set_funding_info(funding_info);
+ chan.channel_monitor.set_funding_info((funding_info, Script::new()));
chan.their_payment_basepoint = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex_bytes("4444444444444444444444444444444444444444444444444444444444444444").unwrap()[..]).unwrap()).unwrap();
assert_eq!(chan.their_payment_basepoint.serialize()[..],
macro_rules! test_commitment {
( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
- unsigned_tx = chan.build_commitment_transaction(42, &keys, true, false);
+ unsigned_tx = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false);
let their_signature = Signature::from_der(&secp_ctx, &hex_bytes($their_sig_hex).unwrap()[..]).unwrap();
let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &chan.get_funding_redeemscript(), chan.channel_value_satoshis)[..]).unwrap();
secp_ctx.verify(&sighash, &their_signature, &chan.their_funding_pubkey).unwrap();