[package]
name = "lightning"
-version = "0.0.3"
+version = "0.0.4"
authors = ["Matt Corallo"]
license = "Apache-2.0"
repository = "https://github.com/rust-bitcoin/rust-lightning/"
description = """
-A Bitcoin Lightning implementation in Rust.
-Still super-early code-dump quality and is missing large chunks. See README in git repo for suggested projects if you want to contribute. Don't have to bother telling you not to use this for anything serious, because you'd have to finish building it to even try.
+A Bitcoin Lightning library in Rust.
+Does most of the hard work, without implying a specific runtime, requiring clients implement basic network logic, chain interactions and disk storage.
+Still missing tons of error-handling. See GitHub issues for suggested projects if you want to contribute. Don't have to bother telling you not to use this for anything serious, because you'd have to build a client around it to even try.
"""
build = "build.rs"
secp256k1 = "0.9"
[build-dependencies]
-gcc = "0.3"
+cc = "1.0"
[dev-dependencies.bitcoin]
version = "0.13"
-extern crate gcc;
+extern crate cc;
fn main() {
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "arm")))]
{
- let mut cfg = gcc::Build::new();
+ let mut cfg = cc::Build::new();
cfg.file("src/util/rust_crypto_nonstd_arch.c");
cfg.compile("lib_rust_crypto_nonstd_arch.a");
}
afl = { version = "0.3", optional = true }
[build-dependencies]
-gcc = "0.3"
+cc = "1.0"
# Prevent this from interfering with workspaces
[workspace]
use bitcoin::network::constants::Network;
use bitcoin::network::serialize::{serialize, BitcoinHash};
use bitcoin::util::hash::Sha256dHash;
-use bitcoin::util::uint::Uint256;
use crypto::sha2::Sha256;
use crypto::digest::Digest;
let mut should_forward = false;
let mut payments_received = Vec::new();
let mut payments_sent = 0;
- let mut pending_funding_generation: Vec<(Uint256, u64, Script)> = Vec::new();
+ let mut pending_funding_generation: Vec<([u8; 32], u64, Script)> = Vec::new();
let mut pending_funding_signatures = HashMap::new();
let mut pending_funding_relay = Vec::new();
/// events).
pub trait ChainWatchInterface: Sync + Send {
/// Provides a scriptPubKey which much be watched for.
- fn install_watch_script(&self, script_pub_key: Script);
+ fn install_watch_script(&self, script_pub_key: &Script);
/// Provides an outpoint which must be watched for, providing any transactions which spend the
/// given outpoint.
/// Register listener
impl ChainWatchInterface for ChainWatchInterfaceUtil {
- fn install_watch_script(&self, script_pub_key: Script) {
+ fn install_watch_script(&self, script_pub_key: &Script) {
let mut watched = self.watched.lock().unwrap();
- watched.0.push(Script::from(script_pub_key));
+ watched.0.push(script_pub_key.clone());
self.reentered.fetch_add(1, Ordering::Relaxed);
}
}
}
- /// Notify listeners that a block was connected.
+ /// Notify listeners that a block was connected given a full, unfiltered block.
/// Handles re-scanning the block and calling block_connected again if listeners register new
/// watch data during the callbacks for you (see ChainListener::block_connected for more info).
pub fn block_connected_with_filtering(&self, block: &Block, height: u32) {
}
}
- /// Notify listeners that a block was connected.
+ /// Notify listeners that a block was connected, given pre-filtered list of transactions in the
+ /// block which matched the filter (probably using does_match_tx).
/// Returns true if notified listeners registered additional watch data (implying that the
/// block must be re-scanned and this function called again prior to further block_connected
/// calls, see ChainListener::block_connected for more info).
use bitcoin::util::hash::Sha256dHash;
-use bitcoin::util::uint::Uint256;
/// A reference to a transaction output.
/// Differs from bitcoin::blockdata::transaction::TxOutRef as the index is a u16 instead of usize
}
/// Convert an `OutPoint` to a lightning channel id.
- pub fn to_channel_id(&self) -> Uint256 {
- let mut index = [0; 32];
- index[30] = ((self.index >> 8) & 0xff) as u8;
- index[31] = ((self.index >> 0) & 0xff) as u8;
- self.txid.into_le() ^ Sha256dHash::from(&index[..]).into_le()
+ pub fn to_channel_id(&self) -> [u8; 32] {
+ let mut res = [0; 32];
+ res[..].copy_from_slice(&self.txid[..]);
+ res[30] ^= ((self.index >> 8) & 0xff) as u8;
+ res[31] ^= ((self.index >> 0) & 0xff) as u8;
+ res
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use chain::transaction::OutPoint;
+
+ use bitcoin::blockdata::transaction::Transaction;
+ use bitcoin::network::serialize;
+ use bitcoin::util::misc::hex_bytes;
+
+ #[test]
+ fn test_channel_id_calculation() {
+ let tx: Transaction = serialize::deserialize(&hex_bytes("020000000001010e0adef48412e4361325ac1c6e36411299ab09d4f083b9d8ddb55fbc06e1b0c00000000000feffffff0220a1070000000000220020f81d95e040bd0a493e38bae27bff52fe2bb58b93b293eb579c01c31b05c5af1dc072cfee54a3000016001434b1d6211af5551905dc2642d05f5b04d25a8fe80247304402207f570e3f0de50546aad25a872e3df059d277e776dda4269fa0d2cc8c2ee6ec9a022054e7fae5ca94d47534c86705857c24ceea3ad51c69dd6051c5850304880fc43a012103cb11a1bacc223d98d91f1946c6752e358a5eb1a1c983b3e6fb15378f453b76bd00000000").unwrap()[..]).unwrap();
+ assert_eq!(&OutPoint {
+ txid: tx.txid(),
+ index: 0
+ }.to_channel_id(), &hex_bytes("3e88dd7165faf7be58b3c5bb2c9c452aebef682807ea57080f62e6f6e113c25e").unwrap()[..]);
+ assert_eq!(&OutPoint {
+ txid: tx.txid(),
+ index: 1
+ }.to_channel_id(), &hex_bytes("3e88dd7165faf7be58b3c5bb2c9c452aebef682807ea57080f62e6f6e113c25f").unwrap()[..]);
}
}
use bitcoin::blockdata::script::{Script,Builder};
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
use bitcoin::blockdata::opcodes;
-use bitcoin::util::uint::Uint256;
use bitcoin::util::hash::{Sha256dHash, Hash160};
use bitcoin::util::bip143;
use bitcoin::network::serialize::BitcoinHash;
// TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
// has been completed, and then turn into a Channel to get compiler-time enforcement of things like
-// calling get_channel_id() before we're set up or things like get_outbound_funding_signed on an
+// calling channel_id() before we're set up or things like get_outbound_funding_signed on an
// inbound channel.
pub struct Channel {
user_id: u64,
- channel_id: Uint256,
+ channel_id: [u8; 32],
channel_state: u32,
channel_outbound: bool,
secp_ctx: Secp256k1,
match $res {
Ok(key) => key,
//TODO: make the error a parameter
- Err(_) => return Err(HandleError{err: $err, msg: Some(msgs::ErrorAction::DisconnectPeer{})})
+ Err(_) => return Err(HandleError{err: $err, action: Some(msgs::ErrorAction::DisconnectPeer{})})
}
};
}
Channel {
user_id: user_id,
- channel_id: rng::rand_uint256(),
+ channel_id: rng::rand_u832(),
channel_state: ChannelState::OurInitSent as u32,
channel_outbound: true,
secp_ctx: secp_ctx,
fn check_remote_fee(fee_estimator: &FeeEstimator, feerate_per_kw: u32) -> Result<(), HandleError> {
if (feerate_per_kw as u64) < fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::Background) * 250 {
- return Err(HandleError{err: "Peer's feerate much too low", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "Peer's feerate much too low", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if (feerate_per_kw as u64) > fee_estimator.get_est_sat_per_vbyte(ConfirmationTarget::HighPriority) * 375 { // 375 = 250 * 1.5x
- return Err(HandleError{err: "Peer's feerate much too high", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "Peer's feerate much too high", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
Ok(())
}
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 >= MAX_FUNDING_SATOSHIS {
- return Err(HandleError{err: "funding value > 2^24", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "funding value > 2^24", action: 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{})});
+ return Err(HandleError{err: "Bogus channel_reserve_satoshis", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if msg.push_msat > (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000 {
- return Err(HandleError{err: "push_msat more than highest possible value", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "push_msat more than highest possible value", action: 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{})});
+ return Err(HandleError{err: "Peer never wants payout outputs?", action: 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{})});
+ return Err(HandleError{err: "Minimum htlc value is full channel value", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
if msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT {
- return Err(HandleError{err: "They wanted our payments to be delayed by a needlessly long period", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "They wanted our payments to be delayed by a needlessly long period", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if msg.max_accepted_htlcs < 1 {
- return Err(HandleError{err: "0 max_accpted_htlcs makes for a useless channel", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "0 max_accpted_htlcs makes for a useless channel", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
if (msg.channel_flags & 254) != 0 {
- return Err(HandleError{err: "unknown channel_flags", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "unknown channel_flags", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
// Convert things into internal flags and prep our state:
},
&HTLCUpdateAwaitingACK::FailHTLC { ref payment_hash, .. } => {
if payment_hash_calc == *payment_hash {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None});
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
}
},
_ => {}
} 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", msg: None});
+ 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", msg: None});
+ 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);
pub fn get_update_fail_htlc(&mut self, payment_hash_arg: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result<Option<msgs::UpdateFailHTLC>, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Was asked to fail an HTLC when channel was not in an operational state", msg: None});
+ return Err(HandleError{err: "Was asked to fail an HTLC when channel was not in an operational state", action: None});
}
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
match pending_update {
&HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_hash, .. } => {
if *payment_hash_arg == *payment_hash {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None});
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
}
},
&HTLCUpdateAwaitingACK::FailHTLC { ref payment_hash, .. } => {
} 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", msg: None});
+ 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", msg: None});
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
}
Ok(Some(msgs::UpdateFailHTLC {
pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel) -> Result<(), HandleError> {
// Check sanity of message fields:
if !self.channel_outbound {
- return Err(HandleError{err: "Got an accept_channel message from an inbound peer", msg: None});
+ return Err(HandleError{err: "Got an accept_channel message from an inbound peer", action: None});
}
if self.channel_state != ChannelState::OurInitSent as u32 {
- return Err(HandleError{err: "Got an accept_channel message at a strange time", msg: None});
+ return Err(HandleError{err: "Got an accept_channel message at a strange time", action: None});
}
if msg.dust_limit_satoshis > 21000000 * 100000000 {
- return Err(HandleError{err: "Peer never wants payout outputs?", msg: None});
+ return Err(HandleError{err: "Peer never wants payout outputs?", action: None});
}
if msg.channel_reserve_satoshis > self.channel_value_satoshis {
- return Err(HandleError{err: "Bogus channel_reserve_satoshis", msg: None});
+ return Err(HandleError{err: "Bogus channel_reserve_satoshis", action: None});
}
if msg.htlc_minimum_msat >= (self.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000 {
- return Err(HandleError{err: "Minimum htlc value is full channel value", msg: None});
+ return Err(HandleError{err: "Minimum htlc value is full channel value", action: None});
}
//TODO do something with minimum_depth
if msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT {
- return Err(HandleError{err: "They wanted our payments to be delayed by a needlessly long period", msg: None});
+ return Err(HandleError{err: "They wanted our payments to be delayed by a needlessly long period", action: None});
}
if msg.max_accepted_htlcs < 1 {
- return Err(HandleError{err: "0 max_accpted_htlcs makes for a useless channel", msg: None});
+ return Err(HandleError{err: "0 max_accpted_htlcs makes for a useless channel", action: None});
}
self.channel_monitor.set_their_htlc_base_key(&msg.htlc_basepoint);
pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result<(msgs::FundingSigned, ChannelMonitor), HandleError> {
if self.channel_outbound {
- return Err(HandleError{err: "Received funding_created for an outbound channel?", msg: None});
+ return Err(HandleError{err: "Received funding_created for an outbound channel?", action: None});
}
if self.channel_state != (ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32) {
- return Err(HandleError{err: "Received funding_created after we got the channel!", msg: None});
+ return Err(HandleError{err: "Received funding_created after we got the channel!", action: None});
}
if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 1 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed(&mut self, msg: &msgs::FundingSigned) -> Result<ChannelMonitor, HandleError> {
if !self.channel_outbound {
- return Err(HandleError{err: "Received funding_signed for an inbound channel?", msg: None});
+ return Err(HandleError{err: "Received funding_signed for an inbound channel?", action: None});
}
if self.channel_state != ChannelState::FundingCreated as u32 {
- return Err(HandleError{err: "Received funding_signed in strange state!", msg: None});
+ return Err(HandleError{err: "Received funding_signed in strange state!", action: None});
}
if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 2 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
self.channel_update_count += 1;
} else {
- return Err(HandleError{err: "Peer sent a funding_locked at a strange time", msg: None});
+ return Err(HandleError{err: "Peer sent a funding_locked at a strange time", action: None});
}
self.their_prev_commitment_point = Some(self.their_cur_commitment_point);
pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingForwardHTLCInfo) -> Result<(), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None});
+ return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
if msg.amount_msat > self.channel_value_satoshis * 1000 {
- return Err(HandleError{err: "Remote side tried to send more than the total value of the channel", msg: None});
+ return Err(HandleError{err: "Remote side tried to send more than the total value of the channel", action: None});
}
if msg.amount_msat < self.our_htlc_minimum_msat {
- return Err(HandleError{err: "Remote side tried to send less than our minimum HTLC value", msg: None});
+ return Err(HandleError{err: "Remote side tried to send less than our minimum HTLC value", action: None});
}
let (inbound_htlc_count, _, htlc_outbound_value_msat, htlc_inbound_value_msat) = self.get_pending_htlc_stats(true);
if inbound_htlc_count + 1 > OUR_MAX_HTLCS as u32 {
- return Err(HandleError{err: "Remote tried to push more than our max accepted HTLCs", msg: None});
+ return Err(HandleError{err: "Remote tried to push more than our max accepted HTLCs", action: None});
}
//TODO: Spec is unclear if this is per-direction or in total (I assume per direction):
// Check our_max_htlc_value_in_flight_msat
if htlc_inbound_value_msat + msg.amount_msat > Channel::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis) {
- return Err(HandleError{err: "Remote HTLC add would put them over their max HTLC value in flight", msg: None});
+ return Err(HandleError{err: "Remote HTLC add would put them over their max HTLC value in flight", action: None});
}
// Check our_channel_reserve_satoshis (we're getting paid, so they have to at least meet
// the reserve_satoshis we told them to always have as direct payment so that they lose
// something if we punish them for broadcasting an old state).
if htlc_inbound_value_msat + htlc_outbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 {
- return Err(HandleError{err: "Remote HTLC add would put them over their reserve value", msg: None});
+ return Err(HandleError{err: "Remote HTLC add would put them over their reserve value", action: None});
}
if self.next_remote_htlc_id != msg.htlc_id {
- return Err(HandleError{err: "Remote skipped HTLC ID", msg: None});
+ return Err(HandleError{err: "Remote skipped HTLC ID", action: None});
}
if msg.cltv_expiry >= 500000000 {
- return Err(HandleError{err: "Remote provided CLTV expiry in seconds instead of block height", msg: None});
+ return Err(HandleError{err: "Remote provided CLTV expiry in seconds instead of block height", action: None});
}
//TODO: Check msg.cltv_expiry further? Do this in channel manager?
None => {},
Some(payment_hash) =>
if payment_hash != htlc.payment_hash {
- return Err(HandleError{err: "Remote tried to fulfill HTLC with an incorrect preimage", msg: None});
+ return Err(HandleError{err: "Remote tried to fulfill HTLC with an incorrect preimage", action: None});
}
};
if htlc.state == HTLCState::LocalAnnounced {
- return Err(HandleError{err: "Remote tried to fulfill HTLC before it had been committed", msg: None});
+ return Err(HandleError{err: "Remote tried to fulfill HTLC before it had been committed", action: None});
} else if htlc.state == HTLCState::Committed {
htlc.state = HTLCState::RemoteRemoved;
htlc.fail_reason = fail_reason;
} else if htlc.state == HTLCState::AwaitingRemoteRevokeToRemove || htlc.state == HTLCState::AwaitingRemovedRemoteRevoke || htlc.state == HTLCState::RemoteRemoved {
- return Err(HandleError{err: "Remote tried to fulfill HTLC that they'd already fulfilled", msg: None});
+ return Err(HandleError{err: "Remote tried to fulfill HTLC that they'd already fulfilled", action: None});
} else {
panic!("Got a non-outbound state on an outbound HTLC");
}
return Ok(htlc.payment_hash.clone());
}
}
- Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", msg: 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> {
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", msg: None});
+ return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
let mut sha = Sha256::new();
pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<[u8; 32], 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", msg: None});
+ return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))
pub fn update_fail_malformed_htlc(&mut self, msg: &msgs::UpdateFailMalformedHTLC, fail_reason: HTLCFailReason) -> 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", msg: None});
+ return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?;
pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option<msgs::CommitmentSigned>, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Got commitment signed message when channel was not in an operational state", msg: None});
+ return Err(HandleError{err: "Got commitment signed message when channel was not in an operational state", action: None});
}
let funding_script = self.get_funding_redeemscript();
secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey), "Invalid commitment tx signature from peer");
if msg.htlc_signatures.len() != local_commitment_tx.1.len() {
- return Err(HandleError{err: "Got wrong number of HTLC signatures from remote", msg: None});
+ return Err(HandleError{err: "Got wrong number of HTLC signatures from remote", action: None});
}
let mut new_local_commitment_txn = Vec::with_capacity(local_commitment_tx.1.len() + 1);
/// revoke_and_ack message.
pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK) -> Result<(Option<msgs::CommitmentUpdate>, Vec<PendingForwardHTLCInfo>, Vec<([u8; 32], HTLCFailReason)>, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Got revoke/ACK message when channel was not in an operational state", msg: None});
+ return Err(HandleError{err: "Got revoke/ACK message when channel was not in an operational state", action: None});
}
if let Some(their_prev_commitment_point) = self.their_prev_commitment_point {
if PublicKey::from_secret_key(&self.secp_ctx, &secp_call!(SecretKey::from_slice(&self.secp_ctx, &msg.per_commitment_secret), "Peer provided an invalid per_commitment_secret")).unwrap() != their_prev_commitment_point {
- return Err(HandleError{err: "Got a revoke commitment secret which didn't correspond to their current pubkey", msg: None});
+ return Err(HandleError{err: "Got a revoke commitment secret which didn't correspond to their current pubkey", action: None});
}
}
self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number + 1, msg.per_commitment_secret, Some((self.cur_remote_commitment_transaction_number - 1, msg.next_per_commitment_point)))?;
pub fn update_fee(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::UpdateFee) -> Result<(), HandleError> {
if self.channel_outbound {
- return Err(HandleError{err: "Non-funding remote tried to update channel fee", msg: None});
+ return Err(HandleError{err: "Non-funding remote tried to update channel fee", action: None});
}
Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
self.channel_update_count += 1;
}
for htlc in self.pending_htlcs.iter() {
if htlc.state == HTLCState::RemoteAnnounced {
- return Err(HandleError{err: "Got shutdown with remote pending HTLCs", msg: None});
+ return Err(HandleError{err: "Got shutdown with remote pending HTLCs", action: None});
}
}
if (self.channel_state & ChannelState::RemoteShutdownSent as u32) == ChannelState::RemoteShutdownSent as u32 {
- return Err(HandleError{err: "Remote peer sent duplicate shutdown message", msg: None});
+ return Err(HandleError{err: "Remote peer sent duplicate shutdown message", action: None});
}
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
// BOLT 2 says we must only send a scriptpubkey of certain standard forms, which are up to
// 34 bytes in length, so dont let the remote peer feed us some super fee-heavy script.
if self.channel_outbound && msg.scriptpubkey.len() > 34 {
- return Err(HandleError{err: "Got shutdown_scriptpubkey of absurd length from remote peer", msg: None});
+ return Err(HandleError{err: "Got shutdown_scriptpubkey of absurd length from remote peer", action: None});
}
//TODO: Check shutdown_scriptpubkey form as BOLT says we must? WHYYY
if self.their_shutdown_scriptpubkey.is_some() {
if Some(&msg.scriptpubkey) != self.their_shutdown_scriptpubkey.as_ref() {
- return Err(HandleError{err: "Got shutdown request with a scriptpubkey which did not match their previous scriptpubkey", msg: None});
+ return Err(HandleError{err: "Got shutdown request with a scriptpubkey which did not match their previous scriptpubkey", action: None});
}
} else {
self.their_shutdown_scriptpubkey = Some(msg.scriptpubkey.clone());
pub fn closing_signed(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::ClosingSigned) -> Result<(Option<msgs::ClosingSigned>, Option<Transaction>), HandleError> {
if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != BOTH_SIDES_SHUTDOWN_MASK {
- return Err(HandleError{err: "Remote end sent us a closing_signed before both sides provided a shutdown", msg: None});
+ return Err(HandleError{err: "Remote end sent us a closing_signed before both sides provided a shutdown", action: None});
}
if !self.pending_htlcs.is_empty() {
- return Err(HandleError{err: "Remote end sent us a closing_signed while there were still pending HTLCs", msg: None});
+ return Err(HandleError{err: "Remote end sent us a closing_signed while there were still pending HTLCs", action: None});
}
if msg.fee_satoshis > 21000000 * 10000000 {
- return Err(HandleError{err: "Remote tried to send us a closing tx with > 21 million BTC fee", msg: None});
+ return Err(HandleError{err: "Remote tried to send us a closing tx with > 21 million BTC fee", action: None});
}
let funding_redeemscript = self.get_funding_redeemscript();
let (mut closing_tx, used_total_fee) = self.build_closing_transaction(msg.fee_satoshis, false);
if used_total_fee != msg.fee_satoshis {
- return Err(HandleError{err: "Remote sent us a closing_signed with a fee greater than the value they can claim", msg: None});
+ return Err(HandleError{err: "Remote sent us a closing_signed with a fee greater than the value they can claim", action: None});
}
let mut sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
if proposed_sat_per_vbyte > our_max_feerate {
if let Some((last_feerate, _)) = self.last_sent_closing_fee {
if our_max_feerate <= last_feerate {
- return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate", msg: None});
+ return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate", action: None});
}
}
propose_new_feerate!(our_max_feerate);
if proposed_sat_per_vbyte < our_min_feerate {
if let Some((last_feerate, _)) = self.last_sent_closing_fee {
if our_min_feerate >= last_feerate {
- return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate", msg: None});
+ return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate", action: None});
}
}
propose_new_feerate!(our_min_feerate);
// Public utilities:
- pub fn channel_id(&self) -> Uint256 {
+ pub fn channel_id(&self) -> [u8; 32] {
self.channel_id
}
self.channel_update_count
}
+ pub fn should_announce(&self) -> bool {
+ self.announce_publicly
+ }
+
/// Gets the fee we'd want to charge for adding an HTLC output to this Channel
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
panic!("Tried to open a channel for an inbound channel?");
}
if self.channel_state != ChannelState::OurInitSent as u32 {
- return Err(HandleError{err: "Cannot generate an open_channel after we've moved forward", msg: None});
+ return Err(HandleError{err: "Cannot generate an open_channel after we've moved forward", action: None});
}
if self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
/// message can mark the channel disabled.
pub fn get_channel_announcement(&self, our_node_id: PublicKey, chain_hash: Sha256dHash) -> Result<(msgs::UnsignedChannelAnnouncement, Signature), HandleError> {
if !self.announce_publicly {
- return Err(HandleError{err: "Channel is not available for public announcements", msg: None});
+ return Err(HandleError{err: "Channel is not available for public announcements", action: None});
}
if self.channel_state & (ChannelState::ChannelFunded as u32) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Cannot get a ChannelAnnouncement until the channel funding has been locked", msg: None});
+ return Err(HandleError{err: "Cannot get a ChannelAnnouncement until the channel funding has been locked", action: None});
}
let were_node_one = our_node_id.serialize()[..] < self.their_node_id.serialize()[..];
/// HTLCs on the wire or we wouldn't be able to determine what they actually ACK'ed.
pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result<Option<msgs::UpdateAddHTLC>, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Cannot send HTLC until channel is fully established and we haven't started shutting down", msg: None});
+ return Err(HandleError{err: "Cannot send HTLC until channel is fully established and we haven't started shutting down", action: None});
}
if amount_msat > self.channel_value_satoshis * 1000 {
- return Err(HandleError{err: "Cannot send more than the total value of the channel", msg: None});
+ return Err(HandleError{err: "Cannot send more than the total value of the channel", action: None});
}
if amount_msat < self.their_htlc_minimum_msat {
- return Err(HandleError{err: "Cannot send less than their minimum HTLC value", msg: None});
+ return Err(HandleError{err: "Cannot send less than their minimum HTLC value", action: None});
}
let (_, outbound_htlc_count, htlc_outbound_value_msat, htlc_inbound_value_msat) = self.get_pending_htlc_stats(false);
if outbound_htlc_count + 1 > self.their_max_accepted_htlcs as u32 {
- return Err(HandleError{err: "Cannot push more than their max accepted HTLCs", msg: None});
+ return Err(HandleError{err: "Cannot push more than their max accepted HTLCs", action: None});
}
//TODO: Spec is unclear if this is per-direction or in total (I assume per direction):
// Check their_max_htlc_value_in_flight_msat
if htlc_outbound_value_msat + amount_msat > self.their_max_htlc_value_in_flight_msat {
- return Err(HandleError{err: "Cannot send value that would put us over our max HTLC value in flight", msg: None});
+ return Err(HandleError{err: "Cannot send value that would put us over our max HTLC value in flight", action: None});
}
// Check their_channel_reserve_satoshis:
if htlc_inbound_value_msat + htlc_outbound_value_msat + amount_msat + (self.channel_value_satoshis * 1000 - self.value_to_self_msat) > (self.channel_value_satoshis - self.their_channel_reserve_satoshis) * 1000 {
- return Err(HandleError{err: "Cannot send value that would put us over our reserve value", msg: None});
+ return Err(HandleError{err: "Cannot send value that would put us over our reserve value", action: None});
}
//TODO: Check cltv_expiry? Do this in channel manager?
/// Creates a signed commitment transaction to send to the remote peer.
pub fn send_commitment(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
- return Err(HandleError{err: "Cannot create commitment tx until channel is fully established", msg: None});
+ return Err(HandleError{err: "Cannot create commitment tx until channel is fully established", action: None});
}
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
- return Err(HandleError{err: "Cannot create commitment tx until remote revokes their previous commitment", msg: None});
+ return Err(HandleError{err: "Cannot create commitment tx until remote revokes their previous commitment", action: None});
}
let mut have_updates = false; // TODO initialize with "have we sent a fee update?"
for htlc in self.pending_htlcs.iter() {
if have_updates { break; }
}
if !have_updates {
- return Err(HandleError{err: "Cannot create commitment tx until we have some updates to send", msg: None});
+ return Err(HandleError{err: "Cannot create commitment tx until we have some updates to send", action: None});
}
self.send_commitment_no_status_check()
}
pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<[u8; 32]>), HandleError> {
for htlc in self.pending_htlcs.iter() {
if htlc.state == HTLCState::LocalAnnounced {
- return Err(HandleError{err: "Cannot begin shutdown with pending HTLCs, call send_commitment first", msg: None});
+ return Err(HandleError{err: "Cannot begin shutdown with pending HTLCs, call send_commitment first", action: None});
}
}
if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0 {
- return Err(HandleError{err: "Shutdown already in progress", msg: None});
+ return Err(HandleError{err: "Shutdown already in progress", action: None});
}
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
use bitcoin::network::constants::Network;
use bitcoin::network::serialize::BitcoinHash;
use bitcoin::util::hash::Sha256dHash;
-use bitcoin::util::uint::Uint256;
use secp256k1::key::{SecretKey,PublicKey};
use secp256k1::{Secp256k1,Message};
const MIN_HTLC_RELAY_HOLDING_CELL_MILLIS: u32 = 50;
struct ChannelHolder {
- by_id: HashMap<Uint256, Channel>,
- short_to_id: HashMap<u64, Uint256>,
+ by_id: HashMap<[u8; 32], Channel>,
+ short_to_id: HashMap<u64, [u8; 32]>,
next_forward: Instant,
/// short channel id -> forward infos. Key of 0 means payments received
forward_htlcs: HashMap<u64, Vec<PendingForwardHTLCInfo>>,
claimable_htlcs: HashMap<[u8; 32], PendingOutboundHTLC>,
}
struct MutChannelHolder<'a> {
- by_id: &'a mut HashMap<Uint256, Channel>,
- short_to_id: &'a mut HashMap<u64, Uint256>,
+ by_id: &'a mut HashMap<[u8; 32], Channel>,
+ short_to_id: &'a mut HashMap<u64, [u8; 32]>,
next_forward: &'a mut Instant,
/// short channel id -> forward infos. Key of 0 means payments received
forward_htlcs: &'a mut HashMap<u64, Vec<PendingForwardHTLCInfo>>,
match $res {
Ok(key) => key,
//TODO: Make the err a parameter!
- Err(_) => return Err(HandleError{err: "Key error", msg: None})
+ Err(_) => return Err(HandleError{err: "Key error", action: None})
}
};
}
/// thereafter this is the txid of the funding transaction xor the funding transaction output).
/// Note that this means this value is *not* persistent - it can change once during the
/// lifetime of the channel.
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
/// The position of the funding transaction in the chain. None if the funding transaction has
/// not yet been confirmed and the channel fully opened.
pub short_channel_id: Option<u64>,
/// Begins the process of closing a channel. After this call (plus some timeout), no new HTLCs
/// will be accepted on the given channel, and after additional timeout/the closing of all
/// pending HTLCs, the channel will be closed on chain.
- pub fn close_channel(&self, channel_id: &Uint256) -> Result<msgs::Shutdown, HandleError> {
+ pub fn close_channel(&self, channel_id: &[u8; 32]) -> Result<msgs::Shutdown, HandleError> {
let (res, chan_option) = {
let mut channel_state_lock = self.channel_state.lock().unwrap();
let channel_state = channel_state_lock.borrow_parts();
(res, Some(chan_entry.remove_entry().1))
} else { (res, None) }
},
- hash_map::Entry::Vacant(_) => return Err(HandleError{err: "No such channel", msg: None})
+ hash_map::Entry::Vacant(_) => return Err(HandleError{err: "No such channel", action: None})
}
};
for payment_hash in res.1 {
};
cur_value_msat += hop.fee_msat;
if cur_value_msat >= 21000000 * 100000000 * 1000 {
- return Err(HandleError{err: "Channel fees overflowed?!", msg: None});
+ return Err(HandleError{err: "Channel fees overflowed?!", action: None});
}
cur_cltv += hop.cltv_expiry_delta as u32;
if cur_cltv >= 500000000 {
- return Err(HandleError{err: "Channel CLTV overflowed?!", msg: None});
+ return Err(HandleError{err: "Channel CLTV overflowed?!", action: None});
}
last_short_channel_id = hop.short_channel_id;
}
/// only fails if the channel does not yet have an assigned short_id
fn get_channel_update(&self, chan: &Channel) -> Result<msgs::ChannelUpdate, HandleError> {
let short_channel_id = match chan.get_short_channel_id() {
- None => return Err(HandleError{err: "Channel not yet established", msg: None}),
+ None => return Err(HandleError{err: "Channel not yet established", action: None}),
Some(id) => id,
};
/// May generate a SendHTLCs event on success, which should be relayed.
pub fn send_payment(&self, route: Route, payment_hash: [u8; 32]) -> Result<(), HandleError> {
if route.hops.len() < 1 || route.hops.len() > 20 {
- return Err(HandleError{err: "Route didn't go anywhere/had bogus size", msg: None});
+ return Err(HandleError{err: "Route didn't go anywhere/had bogus size", action: None});
}
let our_node_id = self.get_our_node_id();
for (idx, hop) in route.hops.iter().enumerate() {
if idx != route.hops.len() - 1 && hop.pubkey == our_node_id {
- return Err(HandleError{err: "Route went through us but wasn't a simple rebalance loop to us", msg: None});
+ return Err(HandleError{err: "Route went through us but wasn't a simple rebalance loop to us", action: None});
}
}
let (first_hop_node_id, (update_add, commitment_signed, chan_monitor)) = {
let mut channel_state = self.channel_state.lock().unwrap();
let id = match channel_state.short_to_id.get(&route.hops.first().unwrap().short_channel_id) {
- None => return Err(HandleError{err: "No channel available with first hop!", msg: None}),
+ None => return Err(HandleError{err: "No channel available with first hop!", action: None}),
Some(id) => id.clone()
};
let res = {
let chan = channel_state.by_id.get_mut(&id).unwrap();
if chan.get_their_node_id() != route.hops.first().unwrap().pubkey {
- return Err(HandleError{err: "Node ID mismatch on first hop!", msg: None});
+ return Err(HandleError{err: "Node ID mismatch on first hop!", action: None});
}
chan.send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, onion_packet)?
};
/// Call this upon creation of a funding transaction for the given channel.
/// Panics if a funding transaction has already been provided for this channel.
- pub fn funding_transaction_generated(&self, temporary_channel_id: &Uint256, funding_txo: OutPoint) {
+ pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_txo: OutPoint) {
let (chan, msg, chan_monitor) = {
let mut channel_state = self.channel_state.lock().unwrap();
- match channel_state.by_id.remove(&temporary_channel_id) {
+ match channel_state.by_id.remove(temporary_channel_id) {
Some(mut chan) => {
match chan.get_outbound_funding_created(funding_txo) {
Ok(funding_msg) => {
}
fn get_announcement_sigs(&self, chan: &Channel) -> Result<Option<msgs::AnnouncementSignatures>, HandleError> {
- if !chan.is_usable() { return Ok(None) }
+ if !chan.is_usable() || !chan.should_announce() { return Ok(None) }
let (announcement, our_bitcoin_sig) = chan.get_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone())?;
let msghash = Message::from_slice(&Sha256dHash::from_data(&announcement.encode()[..])[..]).unwrap();
}
}
+ /// We force-close the channel without letting our counterparty participate in the shutdown
fn block_disconnected(&self, header: &BlockHeader) {
- let mut channel_state = self.channel_state.lock().unwrap();
- for channel in channel_state.by_id.values_mut() {
- if channel.block_disconnected(header) {
- //TODO Close channel here
+ let mut channel_lock = self.channel_state.lock().unwrap();
+ let channel_state = channel_lock.borrow_parts();
+ let short_to_id = channel_state.short_to_id;
+ channel_state.by_id.retain(|_, v| {
+ if v.block_disconnected(header) {
+ let tx = v.force_shutdown();
+ for broadcast_tx in tx {
+ self.tx_broadcaster.broadcast_transaction(&broadcast_tx);
+ }
+ if let Some(short_id) = v.get_short_channel_id() {
+ short_to_id.remove(&short_id);
+ }
+ false
+ } else {
+ true
}
- }
+ });
}
}
//TODO: Handle errors and close channel (or so)
fn handle_open_channel(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannel) -> Result<msgs::AcceptChannel, HandleError> {
if msg.chain_hash != self.genesis_hash {
- return Err(HandleError{err: "Unknown genesis block hash", msg: None});
+ return Err(HandleError{err: "Unknown genesis block hash", action: None});
}
let mut channel_state = self.channel_state.lock().unwrap();
if channel_state.by_id.contains_key(&msg.temporary_channel_id) {
- return Err(HandleError{err: "temporary_channel_id collision!", msg: None});
+ return Err(HandleError{err: "temporary_channel_id collision!", action: None});
}
let chan_keys = if cfg!(feature = "fuzztarget") {
match channel_state.by_id.get_mut(&msg.temporary_channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.accept_channel(&msg)?;
(chan.get_value_satoshis(), chan.get_funding_redeemscript().to_v0_p2wsh(), chan.get_user_id())
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
let mut pending_events = self.pending_events.lock().unwrap();
match channel_state.by_id.remove(&msg.temporary_channel_id) {
Some(mut chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
match chan.funding_created(msg) {
Ok((funding_msg, monitor_update)) => {
}
}
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
}; // Release channel lock for install_watch_outpoint call,
// note that this means if the remote end is misbehaving and sends a message for the same
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
let chan_monitor = chan.funding_signed(&msg)?;
(chan.get_funding_txo().unwrap(), chan.get_user_id(), chan_monitor)
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor) {
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.funding_locked(&msg)?;
return Ok(self.get_announcement_sigs(chan)?);
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
};
}
match channel_state.by_id.entry(msg.channel_id.clone()) {
hash_map::Entry::Occupied(mut chan_entry) => {
if chan_entry.get().get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
let res = chan_entry.get_mut().shutdown(&*self.fee_estimator, &msg)?;
if chan_entry.get().is_shutdown() {
(res, Some(chan_entry.remove_entry().1))
} else { (res, None) }
},
- hash_map::Entry::Vacant(_) => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ hash_map::Entry::Vacant(_) => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
for payment_hash in res.2 {
match channel_state.by_id.entry(msg.channel_id.clone()) {
hash_map::Entry::Occupied(mut chan_entry) => {
if chan_entry.get().get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
let res = chan_entry.get_mut().closing_signed(&*self.fee_estimator, &msg)?;
if res.1.is_some() {
(res, Some(chan_entry.remove_entry().1))
} else { (res, None) }
},
- hash_map::Entry::Vacant(_) => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ hash_map::Entry::Vacant(_) => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
if let Some(broadcast_tx) = res.1 {
($msg: expr, $err_code: expr, $data: expr) => {
return Err(msgs::HandleError {
err: $msg,
- msg: Some(msgs::ErrorAction::UpdateFailHTLC {
+ action: Some(msgs::ErrorAction::UpdateFailHTLC {
msg: msgs::UpdateFailHTLC {
channel_id: msg.channel_id,
htlc_id: msg.htlc_id,
let (source_short_channel_id, res) = match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
if !chan.is_usable() {
- return Err(HandleError{err: "Channel not yet available for receiving HTLCs", msg: None});
+ return Err(HandleError{err: "Channel not yet available for receiving HTLCs", action: None});
}
let short_channel_id = chan.get_short_channel_id().unwrap();
pending_forward_info.prev_short_channel_id = short_channel_id;
(short_channel_id, chan.update_add_htlc(&msg, pending_forward_info)?)
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}), //TODO: panic?
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None}), //TODO: panic?
};
match claimable_htlcs_entry {
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.update_fulfill_htlc(&msg)?
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor) {
let payment_hash = match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.update_fail_htlc(&msg, HTLCFailReason::ErrorPacket { err: msg.reason.clone() })
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}?;
if let Some(pending_htlc) = channel_state.claimable_htlcs.get(&payment_hash) {
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.update_fail_malformed_htlc(&msg, HTLCFailReason::Reason { failure_code: msg.failure_code, data: Vec::new() })
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
}
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.commitment_signed(&msg)?
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.revoke_and_ack(&msg)?
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) {
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
chan.update_fee(&*self.fee_estimator, &msg)
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
}
match channel_state.by_id.get_mut(&msg.channel_id) {
Some(chan) => {
if chan.get_their_node_id() != *their_node_id {
- return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
+ return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None})
}
if !chan.is_usable() {
- return Err(HandleError{err: "Got an announcement_signatures before we were ready for it", msg: None });
+ return Err(HandleError{err: "Got an announcement_signatures before we were ready for it", action: None });
}
let our_node_id = self.get_our_node_id();
contents: announcement,
}, self.get_channel_update(chan).unwrap()) // can only fail if we're not in a ready state
},
- None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+ None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
}
};
let mut pending_events = self.pending_events.lock().unwrap();
mod tests {
use chain::chaininterface;
use chain::transaction::OutPoint;
+ use chain::chaininterface::ChainListener;
use ln::channelmanager::{ChannelManager,OnionKeys};
use ln::router::{Route, RouteHop, Router};
use ln::msgs;
use bitcoin::util::misc::hex_bytes;
use bitcoin::util::hash::Sha256dHash;
- use bitcoin::util::uint::Uint256;
- use bitcoin::blockdata::block::BlockHeader;
+ use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::blockdata::transaction::{Transaction, TxOut};
use bitcoin::network::constants::Network;
use bitcoin::network::serialize::serialize;
}
fn confirm_transaction(chain: &chaininterface::ChainWatchInterfaceUtil, tx: &Transaction, chan_id: u32) {
+ assert!(chain.does_match_tx(tx));
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
chain.block_connected_checked(&header, 1, &[tx; 1], &[chan_id; 1]);
for i in 2..100 {
}
static mut CHAN_COUNT: u32 = 0;
- fn create_chan_between_nodes(node_a: &Node, node_b: &Node) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate, Uint256, Transaction) {
+ fn create_chan_between_nodes(node_a: &Node, node_b: &Node) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction) {
node_a.node.create_channel(node_b.node.get_our_node_id(), 100000, 42).unwrap();
let events_1 = node_a.node.get_and_clear_pending_events();
((*announcement).clone(), (*as_update).clone(), (*bs_update).clone(), channel_id, tx)
}
- fn create_announced_chan_between_nodes(nodes: &Vec<Node>, a: usize, b: usize) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, Uint256, Transaction) {
+ fn create_announced_chan_between_nodes(nodes: &Vec<Node>, a: usize, b: usize) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction) {
let chan_announcement = create_chan_between_nodes(&nodes[a], &nodes[b]);
for node in nodes {
assert!(node.router.handle_channel_announcement(&chan_announcement.0).unwrap());
(chan_announcement.1, chan_announcement.2, chan_announcement.3, chan_announcement.4)
}
- fn close_channel(outbound_node: &Node, inbound_node: &Node, channel_id: &Uint256, funding_tx: Transaction, close_inbound_first: bool) -> (msgs::ChannelUpdate, msgs::ChannelUpdate) {
+ fn close_channel(outbound_node: &Node, inbound_node: &Node, channel_id: &[u8; 32], funding_tx: Transaction, close_inbound_first: bool) -> (msgs::ChannelUpdate, msgs::ChannelUpdate) {
let (node_a, broadcaster_a) = if close_inbound_first { (&inbound_node.node, &inbound_node.tx_broadcaster) } else { (&outbound_node.node, &outbound_node.tx_broadcaster) };
let (node_b, broadcaster_b) = if close_inbound_first { (&outbound_node.node, &outbound_node.tx_broadcaster) } else { (&inbound_node.node, &inbound_node.tx_broadcaster) };
let (tx_a, tx_b);
#[derive(PartialEq)]
enum HTLCType { NONE, TIMEOUT, SUCCESS }
- fn test_txn_broadcast(node: &Node, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, Uint256, Transaction), commitment_tx: Option<Transaction>, has_htlc_tx: HTLCType) -> Vec<Transaction> {
+ fn test_txn_broadcast(node: &Node, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction), commitment_tx: Option<Transaction>, has_htlc_tx: HTLCType) -> Vec<Transaction> {
let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap();
assert!(node_txn.len() >= if commitment_tx.is_some() { 0 } else { 1 } + if has_htlc_tx == HTLCType::NONE { 0 } else { 1 });
// Simple case with no pending HTLCs:
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), true);
{
- let node_txn = test_txn_broadcast(&nodes[1], &chan_1, None, HTLCType::NONE);
+ let mut node_txn = test_txn_broadcast(&nodes[1], &chan_1, None, HTLCType::NONE);
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- nodes[0].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]);
+ nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![node_txn.drain(..).next().unwrap()] }, 1);
assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 0);
}
get_announce_close_broadcast_events(&nodes, 0, 1);
// Simple case of one pending HTLC to HTLC-Timeout
nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), true);
{
- let node_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT);
+ let mut node_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT);
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- nodes[2].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]);
+ nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![node_txn.drain(..).next().unwrap()] }, 1);
assert_eq!(nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 0);
}
get_announce_close_broadcast_events(&nodes, 1, 2);
claim_funds!(nodes[3], nodes[2], payment_preimage_1);
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- nodes[3].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]);
+ nodes[3].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![node_txn[0].clone()] }, 1);
check_preimage_claim(&nodes[3], &node_txn);
}
test_txn_broadcast(&nodes[4], &chan_4, None, HTLCType::SUCCESS);
header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- nodes[4].chain_monitor.block_connected_checked(&header, TEST_FINAL_CLTV - 5, &[&node_txn[0]; 1], &[4; 1]);
+ nodes[4].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![node_txn[0].clone()] }, TEST_FINAL_CLTV - 5);
check_preimage_claim(&nodes[4], &node_txn);
}
{
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- nodes[1].chain_monitor.block_connected_checked(&header, 1, &vec![&revoked_local_txn[0]; 1], &[4; 1]);
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
{
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 1);
node_txn.clear();
}
- nodes[0].chain_monitor.block_connected_checked(&header, 1, &vec![&revoked_local_txn[0]; 1], &[4; 0]);
+ nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
let node_txn = test_txn_broadcast(&nodes[0], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::TIMEOUT);
header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- nodes[1].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[1]; 1], &[4; 1]);
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![node_txn[1].clone()] }, 1);
//TODO: At this point nodes[1] should claim the revoked HTLC-Timeout output, but that's
//not yet implemented in ChannelMonitor
assert_eq!(node.chan_monitor.added_monitors.lock().unwrap().len(), 0);
}
}
+
+ #[test]
+ fn test_unconf_chan() {
+ // After creating a chan between nodes, we disconnect all blocks previously seen to force a channel close on nodes[0] side
+ let nodes = create_network(2);
+ create_announced_chan_between_nodes(&nodes, 0, 1);
+
+ let channel_state = nodes[0].node.channel_state.lock().unwrap();
+ assert_eq!(channel_state.by_id.len(), 1);
+ assert_eq!(channel_state.short_to_id.len(), 1);
+ mem::drop(channel_state);
+
+ let mut headers = Vec::new();
+ let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ headers.push(header.clone());
+ for _i in 2..100 {
+ header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ headers.push(header.clone());
+ }
+ while !headers.is_empty() {
+ nodes[0].node.block_disconnected(&headers.pop().unwrap());
+ }
+ let channel_state = nodes[0].node.channel_state.lock().unwrap();
+ assert_eq!(channel_state.by_id.len(), 0);
+ assert_eq!(channel_state.short_to_id.len(), 0);
+ }
}
};
match &monitor.funding_txo {
&None => self.chain_monitor.watch_all_txn(),
- &Some((ref outpoint, ref script)) => self.chain_monitor.install_watch_outpoint((outpoint.txid, outpoint.index as u32), script),
+ &Some((ref outpoint, ref script)) => {
+ self.chain_monitor.install_watch_script(script);
+ self.chain_monitor.install_watch_outpoint((outpoint.txid, outpoint.index as u32), script);
+ },
}
monitors.insert(key, monitor);
Ok(())
for i in 0..pos {
let (old_secret, old_idx) = self.old_secrets[i as usize];
if ChannelMonitor::derive_secret(secret, pos, old_idx) != old_secret {
- return Err(HandleError{err: "Previous secret did not match new one", msg: None})
+ return Err(HandleError{err: "Previous secret did not match new one", action: None})
}
}
self.old_secrets[pos as usize] = (secret, idx);
pub fn insert_combine(&mut self, mut other: ChannelMonitor) -> Result<(), HandleError> {
if self.funding_txo.is_some() {
if other.funding_txo.is_some() && other.funding_txo.as_ref().unwrap() != self.funding_txo.as_ref().unwrap() {
- return Err(HandleError{err: "Funding transaction outputs are not identical!", msg: None});
+ return Err(HandleError{err: "Funding transaction outputs are not identical!", action: None});
}
} else {
self.funding_txo = other.funding_txo.take();
}
}
assert!(idx < self.get_min_seen_secret());
- Err(HandleError{err: "idx too low", msg: None})
+ Err(HandleError{err: "idx too low", action: None})
}
pub fn get_min_seen_secret(&self) -> u64 {
pub mod channelmonitor;
pub mod msgs;
pub mod router;
-pub mod peer_channel_encryptor;
pub mod peer_handler;
+#[cfg(feature = "fuzztarget")]
+pub mod peer_channel_encryptor;
+#[cfg(not(feature = "fuzztarget"))]
+pub(crate) mod peer_channel_encryptor;
+
#[cfg(feature = "fuzztarget")]
pub mod channel;
#[cfg(not(feature = "fuzztarget"))]
use secp256k1::key::PublicKey;
use secp256k1::{Secp256k1, Signature};
-use bitcoin::util::uint::Uint256;
use bitcoin::util::hash::Sha256dHash;
use bitcoin::network::serialize::{deserialize,serialize};
use bitcoin::blockdata::script::Script;
pub struct OpenChannel {
pub chain_hash: Sha256dHash,
- pub temporary_channel_id: Uint256,
+ pub temporary_channel_id: [u8; 32],
pub funding_satoshis: u64,
pub push_msat: u64,
pub dust_limit_satoshis: u64,
}
pub struct AcceptChannel {
- pub temporary_channel_id: Uint256,
+ pub temporary_channel_id: [u8; 32],
pub dust_limit_satoshis: u64,
pub max_htlc_value_in_flight_msat: u64,
pub channel_reserve_satoshis: u64,
}
pub struct FundingCreated {
- pub temporary_channel_id: Uint256,
+ pub temporary_channel_id: [u8; 32],
pub funding_txid: Sha256dHash,
pub funding_output_index: u16,
pub signature: Signature,
}
pub struct FundingSigned {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub signature: Signature,
}
pub struct FundingLocked {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub next_per_commitment_point: PublicKey,
}
pub struct Shutdown {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub scriptpubkey: Script,
}
pub struct ClosingSigned {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub fee_satoshis: u64,
pub signature: Signature,
}
#[derive(Clone)]
pub struct UpdateAddHTLC {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub htlc_id: u64,
pub amount_msat: u64,
pub payment_hash: [u8; 32],
#[derive(Clone)]
pub struct UpdateFulfillHTLC {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub htlc_id: u64,
pub payment_preimage: [u8; 32],
}
#[derive(Clone)]
pub struct UpdateFailHTLC {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub htlc_id: u64,
pub reason: OnionErrorPacket,
}
#[derive(Clone)]
pub struct UpdateFailMalformedHTLC {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub htlc_id: u64,
pub sha256_of_onion: [u8; 32],
pub failure_code: u16,
#[derive(Clone)]
pub struct CommitmentSigned {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub signature: Signature,
pub htlc_signatures: Vec<Signature>,
}
pub struct RevokeAndACK {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub per_commitment_secret: [u8; 32],
pub next_per_commitment_point: PublicKey,
}
pub struct UpdateFee {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub feerate_per_kw: u32,
}
pub struct ChannelReestablish {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub next_local_commitment_number: u64,
pub next_remote_commitment_number: u64,
pub your_last_per_commitment_secret: Option<[u8; 32]>,
#[derive(Clone)]
pub struct AnnouncementSignatures {
- pub channel_id: Uint256,
+ pub channel_id: [u8; 32],
pub short_channel_id: u64,
pub node_signature: Signature,
pub bitcoin_signature: Signature,
pub struct HandleError { //TODO: rename me
pub err: &'static str,
- pub msg: Option<ErrorAction>, //TODO: Make this required and rename it
+ pub action: Option<ErrorAction>, //TODO: Make this required
}
/// Struct used to return values from revoke_and_ack messages, containing a bunch of commitment
return Err(DecodeError::WrongLength);
}
+ let mut temporary_channel_id = [0; 32];
+ temporary_channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- temporary_channel_id: deserialize(&v[0..32]).unwrap(),
+ temporary_channel_id,
dust_limit_satoshis: byte_utils::slice_to_be64(&v[32..40]),
max_htlc_value_in_flight_msat: byte_utils::slice_to_be64(&v[40..48]),
channel_reserve_satoshis: byte_utils::slice_to_be64(&v[48..56]),
&Some(ref script) => Vec::with_capacity(270 + 2 + script.len()),
&None => Vec::with_capacity(270),
};
- res.extend_from_slice(&serialize(&self.temporary_channel_id).unwrap()[..]);
+ res.extend_from_slice(&self.temporary_channel_id);
res.extend_from_slice(&byte_utils::be64_to_array(self.dust_limit_satoshis));
res.extend_from_slice(&byte_utils::be64_to_array(self.max_htlc_value_in_flight_msat));
res.extend_from_slice(&byte_utils::be64_to_array(self.channel_reserve_satoshis));
return Err(DecodeError::WrongLength);
}
let ctx = Secp256k1::without_caps();
+ let mut temporary_channel_id = [0; 32];
+ temporary_channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- temporary_channel_id: deserialize(&v[0..32]).unwrap(),
+ temporary_channel_id,
funding_txid: deserialize(&v[32..64]).unwrap(),
funding_output_index: byte_utils::slice_to_be16(&v[64..66]),
signature: secp_signature!(&ctx, &v[66..130]),
impl MsgEncodable for FundingCreated {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+32+2+64);
- res.extend_from_slice(&serialize(&self.temporary_channel_id).unwrap()[..]);
+ res.extend_from_slice(&self.temporary_channel_id);
res.extend_from_slice(&serialize(&self.funding_txid).unwrap()[..]);
res.extend_from_slice(&byte_utils::be16_to_array(self.funding_output_index));
let secp_ctx = Secp256k1::without_caps();
return Err(DecodeError::WrongLength);
}
let ctx = Secp256k1::without_caps();
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
signature: secp_signature!(&ctx, &v[32..96]),
})
}
impl MsgEncodable for FundingSigned {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+64);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&self.signature.serialize_compact(&Secp256k1::without_caps()));
res
}
return Err(DecodeError::WrongLength);
}
let ctx = Secp256k1::without_caps();
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
next_per_commitment_point: secp_pubkey!(&ctx, &v[32..65]),
})
}
impl MsgEncodable for FundingLocked {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+33);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&self.next_per_commitment_point.serialize());
res
}
if v.len() < 32 + 2 + scriptlen {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
scriptpubkey: Script::from(v[34..34 + scriptlen].to_vec()),
})
}
impl MsgEncodable for Shutdown {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32 + 2 + self.scriptpubkey.len());
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be16_to_array(self.scriptpubkey.len() as u16));
res.extend_from_slice(&self.scriptpubkey[..]);
res
return Err(DecodeError::WrongLength);
}
let secp_ctx = Secp256k1::without_caps();
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
fee_satoshis: byte_utils::slice_to_be64(&v[32..40]),
signature: secp_signature!(&secp_ctx, &v[40..104]),
})
impl MsgEncodable for ClosingSigned {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+8+64);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be64_to_array(self.fee_satoshis));
let secp_ctx = Secp256k1::without_caps();
res.extend_from_slice(&self.signature.serialize_compact(&secp_ctx));
if v.len() < 32+8+8+32+4+1+33+20*65+32 {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
let mut payment_hash = [0; 32];
payment_hash.copy_from_slice(&v[48..80]);
Ok(Self{
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
htlc_id: byte_utils::slice_to_be64(&v[32..40]),
amount_msat: byte_utils::slice_to_be64(&v[40..48]),
payment_hash,
impl MsgEncodable for UpdateAddHTLC {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+8+8+32+4+1+1366);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be64_to_array(self.htlc_id));
res.extend_from_slice(&byte_utils::be64_to_array(self.amount_msat));
res.extend_from_slice(&self.payment_hash);
if v.len() < 32+8+32 {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
let mut payment_preimage = [0; 32];
payment_preimage.copy_from_slice(&v[40..72]);
Ok(Self{
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
htlc_id: byte_utils::slice_to_be64(&v[32..40]),
payment_preimage,
})
impl MsgEncodable for UpdateFulfillHTLC {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+8+32);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be64_to_array(self.htlc_id));
res.extend_from_slice(&self.payment_preimage);
res
if v.len() < 32+8 {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self{
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
htlc_id: byte_utils::slice_to_be64(&v[32..40]),
reason: OnionErrorPacket::decode(&v[40..])?,
})
fn encode(&self) -> Vec<u8> {
let reason = self.reason.encode();
let mut res = Vec::with_capacity(32+8+reason.len());
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be64_to_array(self.htlc_id));
res.extend_from_slice(&reason[..]);
res
if v.len() < 32+8+32+2 {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
let mut sha256_of_onion = [0; 32];
sha256_of_onion.copy_from_slice(&v[40..72]);
Ok(Self{
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
htlc_id: byte_utils::slice_to_be64(&v[32..40]),
sha256_of_onion,
failure_code: byte_utils::slice_to_be16(&v[72..74]),
impl MsgEncodable for UpdateFailMalformedHTLC {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+8+32+2);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be64_to_array(self.htlc_id));
res.extend_from_slice(&self.sha256_of_onion);
res.extend_from_slice(&byte_utils::be16_to_array(self.failure_code));
if v.len() < 32+64+2 {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
+
let htlcs = byte_utils::slice_to_be16(&v[96..98]) as usize;
if v.len() < 32+64+2+htlcs*64 {
return Err(DecodeError::WrongLength);
htlc_signatures.push(secp_signature!(&secp_ctx, &v[98+i*64..98+(i+1)*64]));
}
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
signature: secp_signature!(&secp_ctx, &v[32..96]),
htlc_signatures,
})
impl MsgEncodable for CommitmentSigned {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+64+2+self.htlc_signatures.len()*64);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
let secp_ctx = Secp256k1::without_caps();
res.extend_from_slice(&self.signature.serialize_compact(&secp_ctx));
res.extend_from_slice(&byte_utils::be16_to_array(self.htlc_signatures.len() as u16));
if v.len() < 32+32+33 {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
let mut per_commitment_secret = [0; 32];
per_commitment_secret.copy_from_slice(&v[32..64]);
let secp_ctx = Secp256k1::without_caps();
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
per_commitment_secret,
next_per_commitment_point: secp_pubkey!(&secp_ctx, &v[64..97]),
})
impl MsgEncodable for RevokeAndACK {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+32+33);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&self.per_commitment_secret);
res.extend_from_slice(&self.next_per_commitment_point.serialize());
res
if v.len() < 32+4 {
return Err(DecodeError::WrongLength);
}
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
feerate_per_kw: byte_utils::slice_to_be32(&v[32..36]),
})
}
impl MsgEncodable for UpdateFee {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+4);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be32_to_array(self.feerate_per_kw));
res
}
return Err(DecodeError::WrongLength);
}
let secp_ctx = Secp256k1::without_caps();
+ let mut channel_id = [0; 32];
+ channel_id[..].copy_from_slice(&v[0..32]);
Ok(Self {
- channel_id: deserialize(&v[0..32]).unwrap(),
+ channel_id,
short_channel_id: byte_utils::slice_to_be64(&v[32..40]),
node_signature: secp_signature!(&secp_ctx, &v[40..104]),
bitcoin_signature: secp_signature!(&secp_ctx, &v[104..168]),
impl MsgEncodable for AnnouncementSignatures {
fn encode(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(32+8+64*2);
- res.extend_from_slice(&serialize(&self.channel_id).unwrap());
+ res.extend_from_slice(&self.channel_id);
res.extend_from_slice(&byte_utils::be64_to_array(self.short_channel_id));
let secp_ctx = Secp256k1::without_caps();
res.extend_from_slice(&self.node_signature.serialize_compact(&secp_ctx));
let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h);
if !chacha.decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]) {
- return Err(HandleError{err: "Bad MAC", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "Bad MAC", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
Ok(())
}
assert_eq!(act.len(), 50);
if act[0] != 0 {
- return Err(HandleError{err: "Unknown handshake version number", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "Unknown handshake version number", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
let their_pub = match PublicKey::from_slice(secp_ctx, &act[1..34]) {
- Err(_) => return Err(HandleError{err: "Invalid public key", msg: Some(msgs::ErrorAction::DisconnectPeer{})}),
+ Err(_) => return Err(HandleError{err: "Invalid public key", action: Some(msgs::ErrorAction::DisconnectPeer{})}),
Ok(key) => key,
};
panic!("Requested act at wrong step");
}
if act_three[0] != 0 {
- return Err(HandleError{err: "Unknown handshake version number", msg: Some(msgs::ErrorAction::DisconnectPeer{})});
+ return Err(HandleError{err: "Unknown handshake version number", action: Some(msgs::ErrorAction::DisconnectPeer{})});
}
let mut their_node_id = [0; 33];
PeerChannelEncryptor::decrypt_with_ad(&mut their_node_id, 1, &temp_k2.unwrap(), &bidirectional_state.h, &act_three[1..50])?;
self.their_node_id = Some(match PublicKey::from_slice(&self.secp_ctx, &their_node_id) {
Ok(key) => key,
- Err(_) => return Err(HandleError{err: "Bad node_id from peer", msg: Some(msgs::ErrorAction::DisconnectPeer{})}),
+ Err(_) => return Err(HandleError{err: "Bad node_id from peer", action: Some(msgs::ErrorAction::DisconnectPeer{})}),
});
let mut sha = Sha256::new();
}
}
+ /// Get the list of node ids for peers which have completed the initial handshake.
+ /// For outbound connections, this will be the same as the their_node_id parameter passed in to
+ /// new_outbound_connection, however entries will only appear once the initial handshake has
+ /// completed and we are sure the remote peer has the private key for the given node_id.
+ pub fn get_peer_node_ids(&self) -> Vec<PublicKey> {
+ let peers = self.peers.lock().unwrap();
+ peers.peers.values().filter_map(|p| p.their_node_id).collect()
+ }
+
/// Indicates a new outbound connection has been established to a node with the given node_id.
/// Note that if an Err is returned here you MUST NOT call disconnect_event for the new
/// descriptor but must disconnect the connection immediately.
Ok(x) => x,
Err(e) => {
println!("Got error handling message: {}!", e.err);
- if let Some(action) = e.msg {
+ if let Some(action) = e.action {
match action {
msgs::ErrorAction::UpdateFailHTLC { msg } => {
encode_and_send_msg!(msg, 131);
( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr ) => {
match $secp_ctx.verify($msg, $sig, $pubkey) {
Ok(_) => {},
- Err(_) => return Err(HandleError{err: "Invalid signature from remote node", msg: None}),
+ Err(_) => return Err(HandleError{err: "Invalid signature from remote node", action: None}),
}
};
}
let mut network = self.network_map.write().unwrap();
match network.nodes.get_mut(&msg.contents.node_id) {
- None => Err(HandleError{err: "No existing channels for node_announcement", msg: Some(ErrorAction::IgnoreError)}),
+ None => Err(HandleError{err: "No existing channels for node_announcement", action: Some(ErrorAction::IgnoreError)}),
Some(node) => {
if node.last_update >= msg.contents.timestamp {
- return Err(HandleError{err: "Update older than last processed update", msg: Some(ErrorAction::IgnoreError)});
+ return Err(HandleError{err: "Update older than last processed update", action: Some(ErrorAction::IgnoreError)});
}
node.features = msg.contents.features.clone();
//TODO: Only allow bitcoin chain_hash
if msg.contents.features.requires_unknown_bits() {
- return Err(HandleError{err: "Channel announcement required unknown feature flags", msg: None});
+ return Err(HandleError{err: "Channel announcement required unknown feature flags", action: None});
}
let mut network = self.network_map.write().unwrap();
//TODO: because asking the blockchain if short_channel_id is valid is only optional
//in the blockchain API, we need to handle it smartly here, though its unclear
//exactly how...
- return Err(HandleError{err: "Already have knowledge of channel", msg: Some(ErrorAction::IgnoreError)})
+ return Err(HandleError{err: "Already have knowledge of channel", action: Some(ErrorAction::IgnoreError)})
},
Entry::Vacant(entry) => {
entry.insert(ChannelInfo {
let chan_was_enabled;
match network.channels.get_mut(&NetworkMap::get_key(msg.contents.short_channel_id, msg.contents.chain_hash)) {
- None => return Err(HandleError{err: "Couldn't find channel for update", msg: Some(ErrorAction::IgnoreError)}),
+ None => return Err(HandleError{err: "Couldn't find channel for update", action: Some(ErrorAction::IgnoreError)}),
Some(channel) => {
macro_rules! maybe_update_channel_info {
( $target: expr) => {
if $target.last_update >= msg.contents.timestamp {
- return Err(HandleError{err: "Update older than last processed update", msg: Some(ErrorAction::IgnoreError)});
+ return Err(HandleError{err: "Update older than last processed update", action: Some(ErrorAction::IgnoreError)});
}
chan_was_enabled = $target.enabled;
$target.last_update = msg.contents.timestamp;
}
}
+ /// Get network addresses by node id
+ pub fn get_addresses(&self, pubkey: &PublicKey) -> Option<Vec<NetAddress>> {
+ let network = self.network_map.read().unwrap();
+ network.nodes.get(pubkey).map(|n| n.addresses.clone())
+ }
+
/// Marks a node as having failed a route. This will avoid re-using the node in routes for now,
/// with an expotnential decay in node "badness". Note that there is deliberately no
/// mark_channel_bad as a node may simply lie and suggest that an upstream channel from it is
let network = self.network_map.read().unwrap();
if *target == network.our_node_id {
- return Err(HandleError{err: "Cannot generate a route to ourselves", msg: None});
+ return Err(HandleError{err: "Cannot generate a route to ourselves", action: None});
}
// We do a dest-to-source Dijkstra's sorting by each node's distance from the destination
}
}
- Err(HandleError{err: "Failed to find a path to the given destination", msg: None})
+ Err(HandleError{err: "Failed to find a path to the given destination", action: None})
}
}
use chain::transaction::OutPoint;
use bitcoin::blockdata::script::Script;
-use bitcoin::util::uint::Uint256;
use secp256k1::key::PublicKey;
/// parameters and then call ChannelManager::funding_transaction_generated.
/// Generated in ChannelManager message handling.
FundingGenerationReady {
- temporary_channel_id: Uint256,
+ temporary_channel_id: [u8; 32],
channel_value_satoshis: u64,
output_script: Script,
/// The value passed in to ChannelManager::create_channel
-pub mod transaction_utils;
pub mod events;
pub(crate) mod byte_utils;
pub(crate) mod internal_traits;
pub(crate) mod rng;
pub(crate) mod sha2;
+pub(crate) mod transaction_utils;
#[cfg(feature = "fuzztarget")]
pub use self::rng::reset_rng_state;
#[cfg(not(feature = "fuzztarget"))]
mod real_rng {
use rand::{thread_rng,Rng};
- use bitcoin::util::uint::Uint256;
pub fn fill_bytes(data: &mut [u8]) {
let mut rng = thread_rng();
rng.fill_bytes(data);
}
- pub fn rand_uint256() -> Uint256 {
- let mut rng = thread_rng();
- Uint256([rng.gen(), rng.gen(), rng.gen(), rng.gen()])
+ pub fn rand_u832() -> [u8; 32] {
+ let mut res = [0; 32];
+ fill_bytes(&mut res);
+ res
}
pub fn rand_f32() -> f32 {
#[cfg(feature = "fuzztarget")]
mod fuzzy_rng {
- use bitcoin::util::uint::Uint256;
use util::byte_utils;
static mut RNG_ITER: u64 = 0;
data[off..].copy_from_slice(&byte_utils::be64_to_array(rng)[0..rem]);
}
- pub fn rand_uint256() -> Uint256 {
+ pub fn rand_u832() -> [u8; 32] {
let rng = unsafe { RNG_ITER += 1; RNG_ITER - 1 };
- Uint256([rng, rng, rng, rng])
+ let mut res = [0; 32];
+ let data = byte_utils::le64_to_array(rng);
+ res[8*0..8*1].copy_from_slice(&data);
+ res[8*1..8*2].copy_from_slice(&data);
+ res[8*2..8*3].copy_from_slice(&data);
+ res[8*3..8*4].copy_from_slice(&data);
+ res
}
pub fn rand_f32() -> f32 {