use crypto::hkdf::{hkdf_extract,hkdf_expand};
use ln::msgs;
-use ln::msgs::{HandleError, MsgEncodable};
+use ln::msgs::{ErrorAction, HandleError, MsgEncodable};
use ln::channelmonitor::ChannelMonitor;
use ln::channelmanager::{PendingForwardHTLCInfo, HTLCFailReason};
use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
use chain::transaction::OutPoint;
use util::{transaction_utils,rng};
use util::sha2::Sha256;
+use util::logger::{Logger, Record};
+use std;
use std::default::Default;
use std::{cmp,mem};
use std::time::Instant;
+use std::sync::{Arc};
pub struct ChannelKeys {
pub funding_key: SecretKey,
/// anyway).
LocalRemoved,
/// Removed by us, sent a new commitment_signed and got a revoke_and_ack. Just waiting on an
- /// updated local commitment transaction.
+ /// updated local commitment transaction. Implies local_removed_fulfilled.
LocalRemovedAwaitingCommitment,
}
/// to detect unconfirmation after a serialize-unserialize roudtrip where we may not see a full
/// series of block_connected/block_disconnected calls. Obviously this is not a guarantee as we
/// could miss the funding_tx_confirmed_in block as well, but it serves as a useful fallback.
- funding_tx_confirmed_in: Sha256dHash,
+ funding_tx_confirmed_in: Option<Sha256dHash>,
short_channel_id: Option<u64>,
/// Used to deduplicate block_connected callbacks
last_block_connected: Sha256dHash,
their_shutdown_scriptpubkey: Option<Script>,
channel_monitor: ChannelMonitor,
+
+ logger: Arc<Logger>,
}
const OUR_MAX_HTLCS: u16 = 5; //TODO
// Constructors:
/// 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 {
+ pub fn new_outbound(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, channel_value_satoshis: u64, announce_publicly: bool, user_id: u64, logger: Arc<Logger>) -> Channel {
if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
panic!("funding value > 2^24");
}
last_sent_closing_fee: None,
- funding_tx_confirmed_in: Default::default(),
+ funding_tx_confirmed_in: None,
short_channel_id: None,
last_block_connected: Default::default(),
funding_tx_confirmations: 0,
their_shutdown_scriptpubkey: None,
channel_monitor: channel_monitor,
+
+ logger,
}
}
/// Assumes chain_hash has already been checked and corresponds with what we expect!
/// Generally prefers to take the DisconnectPeer action on failure, as a notice to the sender
/// 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> {
+ pub fn new_from_req(fee_estimator: &FeeEstimator, chan_keys: ChannelKeys, their_node_id: PublicKey, msg: &msgs::OpenChannel, user_id: u64, require_announce: bool, allow_announce: bool, logger: Arc<Logger>) -> Result<Channel, HandleError> {
// Check sanity of message fields:
if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS {
return Err(HandleError{err: "funding value > 2^24", action: Some(msgs::ErrorAction::DisconnectPeer{ msg: None })});
// Convert things into internal flags and prep our state:
let their_announce = if (msg.channel_flags & 1) == 1 { true } else { false };
+ if require_announce && !their_announce {
+ return Err(HandleError{err: "Peer tried to open unannounced channel, but we require public ones", action: Some(msgs::ErrorAction::IgnoreError) });
+ }
+ if !allow_announce && their_announce {
+ return Err(HandleError{err: "Peer tried to open announced channel, but we require private ones", action: Some(msgs::ErrorAction::IgnoreError) });
+ }
let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32),
channel_outbound: false,
secp_ctx: secp_ctx,
- announce_publicly: their_announce && announce_publicly,
+ announce_publicly: their_announce,
local_keys: chan_keys,
cur_local_commitment_transaction_number: (1 << 48) - 1,
last_sent_closing_fee: None,
- funding_tx_confirmed_in: Default::default(),
+ funding_tx_confirmed_in: None,
short_channel_id: None,
last_block_connected: Default::default(),
funding_tx_confirmations: 0,
their_shutdown_scriptpubkey: None,
channel_monitor: channel_monitor,
+
+ logger,
};
let obscure_factor = chan.get_commitment_transaction_number_obscure_factor();
} else {
match htlc.state {
HTLCState::AwaitingRemoteRevokeToRemove|HTLCState::AwaitingRemovedRemoteRevoke => {
- if generated_by_local && htlc.fail_reason.is_none() {
+ if htlc.fail_reason.is_none() {
value_to_self_msat_offset -= htlc.amount_msat as i64;
}
},
}
},
HTLCState::LocalRemovedAwaitingCommitment => {
+ assert!(htlc.local_removed_fulfilled);
value_to_self_msat_offset += htlc.amount_msat as i64;
},
_ => {},
Ok(our_sig)
}
- pub fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result<Option<(msgs::UpdateFulfillHTLC, ChannelMonitor)>, HandleError> {
+ fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result<(Option<msgs::UpdateFulfillHTLC>, Option<ChannelMonitor>), HandleError> {
// Either ChannelFunded got set (which means it wont bet unset) or there is no way any
// caller thought we could have something claimed (cause we wouldn't have accepted in an
// incoming HTLC anyway). If we got to ShutdownComplete, callers aren't allowed to call us,
let mut payment_hash_calc = [0; 32];
sha.result(&mut payment_hash_calc);
+ let mut pending_idx = std::usize::MAX;
+ for (idx, htlc) in self.pending_htlcs.iter().enumerate() {
+ if !htlc.outbound && htlc.payment_hash == payment_hash_calc {
+ if pending_idx != std::usize::MAX {
+ panic!("Duplicate HTLC payment_hash, you probably re-used payment preimages, NEVER DO THIS!");
+ }
+ pending_idx = idx;
+ }
+ }
+ if pending_idx == std::usize::MAX {
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+ }
+
// Now update local state:
+ //
+ // We have to put the payment_preimage in the channel_monitor right away here to ensure we
+ // can claim it even if the channel hits the chain before we see their next commitment.
+ self.channel_monitor.provide_payment_preimage(&payment_hash_calc, &payment_preimage_arg);
+
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
for pending_update in self.holding_cell_htlc_updates.iter() {
match pending_update {
&HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, .. } => {
if payment_preimage_arg == *payment_preimage {
- return Ok(None);
+ return Ok((None, None));
}
},
&HTLCUpdateAwaitingACK::FailHTLC { ref payment_hash, .. } => {
self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::ClaimHTLC {
payment_preimage: payment_preimage_arg, payment_hash: payment_hash_calc,
});
- return Ok(None);
- }
-
- let mut htlc_id = 0;
- let mut htlc_amount_msat = 0;
- for htlc in self.pending_htlcs.iter_mut() {
- if !htlc.outbound && htlc.payment_hash == payment_hash_calc {
- if htlc_id != 0 {
- panic!("Duplicate HTLC payment_hash, you probably re-used payment preimages, NEVER DO THIS!");
- }
- htlc_id = htlc.htlc_id;
- htlc_amount_msat += htlc.amount_msat;
- if htlc.state == HTLCState::Committed {
- htlc.state = HTLCState::LocalRemoved;
- htlc.local_removed_fulfilled = true;
- } else if htlc.state == HTLCState::RemoteAnnounced {
- panic!("Somehow forwarded HTLC prior to remote revocation!");
- } else if htlc.state == HTLCState::LocalRemoved || htlc.state == HTLCState::LocalRemovedAwaitingCommitment {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
- } else {
- panic!("Have an inbound HTLC when not awaiting remote revoke that had a garbage state");
- }
+ return Ok((None, Some(self.channel_monitor.clone())));
+ }
+
+ let htlc_id = {
+ let htlc = &mut self.pending_htlcs[pending_idx];
+ if htlc.state == HTLCState::Committed {
+ htlc.state = HTLCState::LocalRemoved;
+ htlc.local_removed_fulfilled = true;
+ } else if htlc.state == HTLCState::RemoteAnnounced {
+ panic!("Somehow forwarded HTLC prior to remote revocation!");
+ } else if htlc.state == HTLCState::LocalRemoved || htlc.state == HTLCState::LocalRemovedAwaitingCommitment {
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+ } else {
+ panic!("Have an inbound HTLC when not awaiting remote revoke that had a garbage state");
}
- }
- if htlc_amount_msat == 0 {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
- }
- self.channel_monitor.provide_payment_preimage(&payment_hash_calc, &payment_preimage_arg);
+ htlc.htlc_id
+ };
- Ok(Some((msgs::UpdateFulfillHTLC {
+ Ok((Some(msgs::UpdateFulfillHTLC {
channel_id: self.channel_id(),
htlc_id: htlc_id,
payment_preimage: payment_preimage_arg,
- }, self.channel_monitor.clone())))
+ }), Some(self.channel_monitor.clone())))
}
- pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result<Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
+ pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result<(Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)>, Option<ChannelMonitor>), HandleError> {
match self.get_update_fulfill_htlc(payment_preimage)? {
- Some(update_fulfill_htlc) => {
+ (Some(update_fulfill_htlc), _) => {
let (commitment, monitor_update) = self.send_commitment_no_status_check()?;
- Ok(Some((update_fulfill_htlc.0, commitment, monitor_update)))
+ Ok((Some((update_fulfill_htlc, commitment)), Some(monitor_update)))
},
- None => Ok(None)
+ (None, Some(channel_monitor)) => Ok((None, Some(channel_monitor))),
+ (None, None) => Ok((None, None))
}
}
Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", action: None})
}
- pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<ChannelMonitor, HandleError> {
+ pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
let mut payment_hash = [0; 32];
sha.result(&mut payment_hash);
- self.channel_monitor.provide_payment_preimage(&payment_hash, &msg.payment_preimage);
self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)?;
- Ok(self.channel_monitor.clone())
+ Ok(())
}
pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<[u8; 32], HandleError> {
},
&HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage, .. } => {
match self.get_update_fulfill_htlc(payment_preimage) {
- Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.unwrap().0),
+ Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.0.unwrap()),
Err(e) => {
err = Some(e);
}
match self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey) {
Ok(_) => {},
- Err(_) => {
+ Err(_e) => {
// The remote end may have decided to revoke their output due to inconsistent dust
// limits, so check for that case by re-checking the signature here.
closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0;
self.user_id
}
+ /// May only be called after funding has been initiated (ie is_funding_initiated() is true)
pub fn channel_monitor(&self) -> ChannelMonitor {
if self.channel_state < ChannelState::FundingCreated as u32 {
panic!("Can't get a channel monitor until funding has been created");
/// Guaranteed to be Some after both FundingLocked messages have been exchanged (and, thus,
/// is_usable() returns true).
+ /// Allowed in any state (including after shutdown)
pub fn get_short_channel_id(&self) -> Option<u64> {
self.short_channel_id
}
self.channel_monitor.get_funding_txo()
}
+ /// Allowed in any state (including after shutdown)
pub fn get_their_node_id(&self) -> PublicKey {
self.their_node_id
}
+ /// Allowed in any state (including after shutdown)
pub fn get_our_htlc_minimum_msat(&self) -> u64 {
self.our_htlc_minimum_msat
}
self.channel_value_satoshis
}
+ /// Allowed in any state (including after shutdown)
pub fn get_channel_update_count(&self) -> u32 {
self.channel_update_count
}
}
/// Gets the fee we'd want to charge for adding an HTLC output to this Channel
+ /// Allowed in any state (including after shutdown)
pub fn get_our_fee_base_msat(&self, fee_estimator: &FeeEstimator) -> u32 {
// For lack of a better metric, we calculate what it would cost to consolidate the new HTLC
// output value back into a transaction with the regular channel output:
}
/// Returns true if this channel is fully established and not known to be closing.
+ /// Allowed in any state (including after shutdown)
pub fn is_usable(&self) -> bool {
let mask = ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK;
(self.channel_state & mask) == (ChannelState::ChannelFunded as u32)
/// Returns true if this channel is currently available for use. This is a superset of
/// is_usable() and considers things like the channel being temporarily disabled.
+ /// Allowed in any state (including after shutdown)
pub fn is_live(&self) -> bool {
self.is_usable()
}
+ /// Returns true if funding_created was sent/received.
+ pub fn is_funding_initiated(&self) -> bool {
+ self.channel_state >= ChannelState::FundingCreated as u32
+ }
+
/// Returns true if this channel is fully shut down. True here implies that no further actions
/// may/will be taken on this channel, and thus this object should be freed. Any future changes
/// will be handled appropriately by the chain monitor.
/// Called by channelmanager based on chain blocks being connected.
/// Note that we only need to use this to detect funding_signed, anything else is handled by
/// the channel_monitor.
- pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Option<msgs::FundingLocked> {
+ /// In case of Err, the channel may have been closed, at which point the standard requirements
+ /// apply - no calls may be made except those explicitly stated to be allowed post-shutdown.
+ /// Only returns an ErrorAction of DisconnectPeer, if Err.
+ pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, HandleError> {
let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK);
if self.funding_tx_confirmations > 0 {
if header.bitcoin_hash() != self.last_block_connected {
self.last_block_connected = header.bitcoin_hash();
self.funding_tx_confirmations += 1;
if self.funding_tx_confirmations == CONF_TARGET as u64 {
- if non_shutdown_state == ChannelState::FundingSent as u32 {
+ let need_commitment_update = if non_shutdown_state == ChannelState::FundingSent as u32 {
self.channel_state |= ChannelState::OurFundingLocked as u32;
+ true
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
self.channel_update_count += 1;
- //TODO: Something about a state where we "lost confirmation"
+ true
+ } else if self.channel_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
+ // We got a reorg but not enough to trigger a force close, just update
+ // funding_tx_confirmed_in and return.
+ false
} else if self.channel_state < ChannelState::ChannelFunded as u32 {
- panic!("Started confirming a channel in a state pre-FundingSent?");
- }
- self.funding_tx_confirmed_in = header.bitcoin_hash();
+ panic!("Started confirming a channel in a state pre-FundingSent?: {}", self.channel_state);
+ } else {
+ // We got a reorg but not enough to trigger a force close, just update
+ // funding_tx_confirmed_in and return.
+ false
+ };
+ self.funding_tx_confirmed_in = Some(header.bitcoin_hash());
//TODO: Note that this must be a duplicate of the previous commitment point they sent us,
//as otherwise we will have a commitment transaction that they can't revoke (well, kinda,
//they can by sending two revoke_and_acks back-to-back, but not really). This appears to be
//a protocol oversight, but I assume I'm just missing something.
- let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
- let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret).unwrap();
- return Some(msgs::FundingLocked {
- channel_id: self.channel_id,
- next_per_commitment_point: next_per_commitment_point,
- });
+ if need_commitment_update {
+ let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
+ let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret).unwrap();
+ return Ok(Some(msgs::FundingLocked {
+ channel_id: self.channel_id,
+ next_per_commitment_point: next_per_commitment_point,
+ }));
+ }
}
}
}
tx.output[txo_idx].value != self.channel_value_satoshis {
self.channel_state = ChannelState::ShutdownComplete as u32;
self.channel_update_count += 1;
+ return Err(HandleError{err: "funding tx had wrong script/value", action: Some(ErrorAction::DisconnectPeer{msg: None})});
} else {
self.funding_tx_confirmations = 1;
self.short_channel_id = Some(((height as u64) << (5*8)) |
}
}
}
- None
+ Ok(None)
}
/// Called by channelmanager based on chain blocks being disconnected.
return true;
}
}
- if header.bitcoin_hash() == self.funding_tx_confirmed_in {
+ if Some(header.bitcoin_hash()) == self.funding_tx_confirmed_in {
self.funding_tx_confirmations = CONF_TARGET as u64 - 1;
}
false
let (our_signature, commitment_tx) = match self.get_outbound_funding_created_signature() {
Ok(res) => res,
Err(e) => {
+ log_error!(self, "Got bad signatures: {}!", e.err);
self.channel_monitor.unset_funding_info();
return Err(e);
}
}
/// Gets the latest commitment transaction and any dependant transactions for relay (forcing
- /// shutdown of this channel - no more calls into this Channel may be made afterwards.
- pub fn force_shutdown(&mut self) -> Vec<Transaction> {
+ /// shutdown of this channel - no more calls into this Channel may be made afterwards except
+ /// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
+ /// Also returns the list of payment_hashes for channels which we can safely fail backwards
+ /// immediately (others we will have to allow to time out).
+ pub fn force_shutdown(&mut self) -> (Vec<Transaction>, Vec<[u8; 32]>) {
assert!(self.channel_state != ChannelState::ShutdownComplete as u32);
+
+ // We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and
+ // return them to fail the payment.
+ let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
+ for htlc_update in self.holding_cell_htlc_updates.drain(..) {
+ match htlc_update {
+ HTLCUpdateAwaitingACK::AddHTLC { payment_hash, .. } => {
+ dropped_outbound_htlcs.push(payment_hash);
+ },
+ _ => {}
+ }
+ }
+
+ for htlc in self.pending_htlcs.drain(..) {
+ if htlc.state == HTLCState::LocalAnnounced {
+ dropped_outbound_htlcs.push(htlc.payment_hash);
+ }
+ //TODO: Do something with the remaining HTLCs
+ //(we need to have the ChannelManager monitor them so we can claim the inbound HTLCs
+ //which correspond)
+ }
+
self.channel_state = ChannelState::ShutdownComplete as u32;
self.channel_update_count += 1;
let mut res = Vec::new();
mem::swap(&mut res, &mut self.last_local_commitment_txn);
- res
+ (res, dropped_outbound_htlcs)
}
}
#[cfg(test)]
mod tests {
- use bitcoin::util::misc::hex_bytes;
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 hex;
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;
+ use util::test_utils;
+ use util::logger::Logger;
use secp256k1::{Secp256k1,Message,Signature};
use secp256k1::key::{SecretKey,PublicKey};
use crypto::sha2::Sha256;
use crypto::digest::Digest;
+ use std::sync::Arc;
struct TestFeeEstimator {
fee_est: u64
fn outbound_commitment_test() {
// Test vectors from BOLT 3 Appendix C:
let feeest = TestFeeEstimator{fee_est: 15000};
+ let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
let secp_ctx = Secp256k1::new();
let chan_keys = ChannelKeys {
- funding_key: SecretKey::from_slice(&secp_ctx, &hex_bytes("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749").unwrap()[..]).unwrap(),
- payment_base_key: SecretKey::from_slice(&secp_ctx, &hex_bytes("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(),
- delayed_payment_base_key: SecretKey::from_slice(&secp_ctx, &hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()[..]).unwrap(),
- htlc_base_key: SecretKey::from_slice(&secp_ctx, &hex_bytes("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(),
+ funding_key: SecretKey::from_slice(&secp_ctx, &hex::decode("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749").unwrap()[..]).unwrap(),
+ payment_base_key: SecretKey::from_slice(&secp_ctx, &hex::decode("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(),
+ delayed_payment_base_key: SecretKey::from_slice(&secp_ctx, &hex::decode("3333333333333333333333333333333333333333333333333333333333333333").unwrap()[..]).unwrap(),
+ htlc_base_key: SecretKey::from_slice(&secp_ctx, &hex::decode("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(),
// These aren't set in the test vectors:
- revocation_base_key: SecretKey::from_slice(&secp_ctx, &hex_bytes("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
- channel_close_key: SecretKey::from_slice(&secp_ctx, &hex_bytes("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
- channel_monitor_claim_key: SecretKey::from_slice(&secp_ctx, &hex_bytes("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
+ revocation_base_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
+ channel_close_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
+ channel_monitor_claim_key: SecretKey::from_slice(&secp_ctx, &hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
commitment_seed: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
};
assert_eq!(PublicKey::from_secret_key(&secp_ctx, &chan_keys.funding_key).unwrap().serialize()[..],
- hex_bytes("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
+ hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
- let mut chan = Channel::new_outbound(&feeest, chan_keys, PublicKey::new(), 10000000, false, 42); // Nothing uses their network key in this test
+ let mut chan = Channel::new_outbound(&feeest, chan_keys, PublicKey::new(), 10000000, false, 42, Arc::clone(&logger)); // Nothing uses their network key in this test
chan.their_to_self_delay = 144;
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, Script::new()));
- chan.their_payment_basepoint = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex_bytes("4444444444444444444444444444444444444444444444444444444444444444").unwrap()[..]).unwrap()).unwrap();
+ chan.their_payment_basepoint = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("4444444444444444444444444444444444444444444444444444444444444444").unwrap()[..]).unwrap()).unwrap();
assert_eq!(chan.their_payment_basepoint.serialize()[..],
- hex_bytes("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]);
+ hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]);
- chan.their_funding_pubkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex_bytes("1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13").unwrap()[..]).unwrap()).unwrap();
+ chan.their_funding_pubkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13").unwrap()[..]).unwrap()).unwrap();
assert_eq!(chan.their_funding_pubkey.serialize()[..],
- hex_bytes("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1").unwrap()[..]);
+ hex::decode("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1").unwrap()[..]);
- chan.their_htlc_basepoint = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex_bytes("4444444444444444444444444444444444444444444444444444444444444444").unwrap()[..]).unwrap()).unwrap();
+ chan.their_htlc_basepoint = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex::decode("4444444444444444444444444444444444444444444444444444444444444444").unwrap()[..]).unwrap()).unwrap();
assert_eq!(chan.their_htlc_basepoint.serialize()[..],
- hex_bytes("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]);
+ hex::decode("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]);
- chan.their_revocation_basepoint = PublicKey::from_slice(&secp_ctx, &hex_bytes("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27").unwrap()[..]).unwrap();
+ chan.their_revocation_basepoint = PublicKey::from_slice(&secp_ctx, &hex::decode("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27").unwrap()[..]).unwrap();
// We can't just use build_local_transaction_keys here as the per_commitment_secret is not
// derived from a commitment_seed, so instead we copy it here and call
// build_commitment_transaction.
let delayed_payment_base = PublicKey::from_secret_key(&secp_ctx, &chan.local_keys.delayed_payment_base_key).unwrap();
- let per_commitment_secret = SecretKey::from_slice(&secp_ctx, &hex_bytes("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
+ let per_commitment_secret = SecretKey::from_slice(&secp_ctx, &hex::decode("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret).unwrap();
let htlc_basepoint = PublicKey::from_secret_key(&secp_ctx, &chan.local_keys.htlc_base_key).unwrap();
let keys = TxCreationKeys::new(&secp_ctx, &per_commitment_point, &delayed_payment_base, &htlc_basepoint, &chan.their_revocation_basepoint, &chan.their_payment_basepoint, &chan.their_htlc_basepoint).unwrap();
macro_rules! test_commitment {
( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
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 their_signature = Signature::from_der(&secp_ctx, &hex::decode($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();
chan.sign_commitment_transaction(&mut unsigned_tx.0, &their_signature);
assert_eq!(serialize(&unsigned_tx.0).unwrap()[..],
- hex_bytes($tx_hex).unwrap()[..]);
+ hex::decode($tx_hex).unwrap()[..]);
};
}
macro_rules! test_htlc_output {
( $htlc_idx: expr, $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr ) => {
- let remote_signature = Signature::from_der(&secp_ctx, &hex_bytes($their_sig_hex).unwrap()[..]).unwrap();
+ let remote_signature = Signature::from_der(&secp_ctx, &hex::decode($their_sig_hex).unwrap()[..]).unwrap();
let ref htlc = unsigned_tx.1[$htlc_idx];
let mut htlc_tx = chan.build_htlc_transaction(&unsigned_tx.0.txid(), &htlc, true, &keys);
chan.sign_htlc_transaction(&mut htlc_tx, &remote_signature, &preimage, &htlc, &keys).unwrap();
assert_eq!(serialize(&htlc_tx).unwrap()[..],
- hex_bytes($tx_hex).unwrap()[..]);
+ hex::decode($tx_hex).unwrap()[..]);
};
}
pending_forward_state: None,
};
let mut sha = Sha256::new();
- sha.input(&hex_bytes("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
+ sha.input(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
sha.result(&mut out.payment_hash);
out
});
pending_forward_state: None,
};
let mut sha = Sha256::new();
- sha.input(&hex_bytes("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
+ sha.input(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
sha.result(&mut out.payment_hash);
out
});
pending_forward_state: None,
};
let mut sha = Sha256::new();
- sha.input(&hex_bytes("0202020202020202020202020202020202020202020202020202020202020202").unwrap());
+ sha.input(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap());
sha.result(&mut out.payment_hash);
out
});
pending_forward_state: None,
};
let mut sha = Sha256::new();
- sha.input(&hex_bytes("0303030303030303030303030303030303030303030303030303030303030303").unwrap());
+ sha.input(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap());
sha.result(&mut out.payment_hash);
out
});
pending_forward_state: None,
};
let mut sha = Sha256::new();
- sha.input(&hex_bytes("0404040404040404040404040404040404040404040404040404040404040404").unwrap());
+ sha.input(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap());
sha.result(&mut out.payment_hash);
out
});
// Test vectors from BOLT 3 Appendix D:
let mut seed = [0; 32];
- seed[0..32].clone_from_slice(&hex_bytes("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
+ seed[0..32].clone_from_slice(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
assert_eq!(chan_utils::build_commitment_secret(seed, 281474976710655),
- hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()[..]);
+ hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()[..]);
- seed[0..32].clone_from_slice(&hex_bytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap());
+ seed[0..32].clone_from_slice(&hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap());
assert_eq!(chan_utils::build_commitment_secret(seed, 281474976710655),
- hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()[..]);
+ hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()[..]);
assert_eq!(chan_utils::build_commitment_secret(seed, 0xaaaaaaaaaaa),
- hex_bytes("56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528").unwrap()[..]);
+ hex::decode("56f4008fb007ca9acf0e15b054d5c9fd12ee06cea347914ddbaed70d1c13a528").unwrap()[..]);
assert_eq!(chan_utils::build_commitment_secret(seed, 0x555555555555),
- hex_bytes("9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31").unwrap()[..]);
+ hex::decode("9015daaeb06dba4ccc05b91b2f73bd54405f2be9f217fbacd3c5ac2e62327d31").unwrap()[..]);
- seed[0..32].clone_from_slice(&hex_bytes("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
+ seed[0..32].clone_from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
assert_eq!(chan_utils::build_commitment_secret(seed, 1),
- hex_bytes("915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c").unwrap()[..]);
+ hex::decode("915c75942a26bb3a433a8ce2cb0427c29ec6c1775cfc78328b57f6ba7bfeaa9c").unwrap()[..]);
}
#[test]
// Test vectors from BOLT 3 Appendix E:
let secp_ctx = Secp256k1::new();
- let base_secret = SecretKey::from_slice(&secp_ctx, &hex_bytes("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap()[..]).unwrap();
- let per_commitment_secret = SecretKey::from_slice(&secp_ctx, &hex_bytes("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
+ let base_secret = SecretKey::from_slice(&secp_ctx, &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap()[..]).unwrap();
+ let per_commitment_secret = SecretKey::from_slice(&secp_ctx, &hex::decode("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
let base_point = PublicKey::from_secret_key(&secp_ctx, &base_secret).unwrap();
- assert_eq!(base_point.serialize()[..], hex_bytes("036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2").unwrap()[..]);
+ assert_eq!(base_point.serialize()[..], hex::decode("036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2").unwrap()[..]);
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret).unwrap();
- assert_eq!(per_commitment_point.serialize()[..], hex_bytes("025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486").unwrap()[..]);
+ assert_eq!(per_commitment_point.serialize()[..], hex::decode("025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486").unwrap()[..]);
assert_eq!(chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &base_point).unwrap().serialize()[..],
- hex_bytes("0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5").unwrap()[..]);
+ hex::decode("0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5").unwrap()[..]);
assert_eq!(chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &base_secret).unwrap(),
- SecretKey::from_slice(&secp_ctx, &hex_bytes("cbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f").unwrap()[..]).unwrap());
+ SecretKey::from_slice(&secp_ctx, &hex::decode("cbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f").unwrap()[..]).unwrap());
assert_eq!(chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &base_point).unwrap().serialize()[..],
- hex_bytes("02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0").unwrap()[..]);
+ hex::decode("02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0").unwrap()[..]);
assert_eq!(chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_secret, &base_secret).unwrap(),
- SecretKey::from_slice(&secp_ctx, &hex_bytes("d09ffff62ddb2297ab000cc85bcb4283fdeb6aa052affbc9dddcf33b61078110").unwrap()[..]).unwrap());
+ SecretKey::from_slice(&secp_ctx, &hex::decode("d09ffff62ddb2297ab000cc85bcb4283fdeb6aa052affbc9dddcf33b61078110").unwrap()[..]).unwrap());
}
}