Skip to content

Revocation enforcement #764

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 43 additions & 16 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use lightning::chain::keysinterface::{KeysInterface, InMemoryChannelKeys};
use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret, PaymentSendFailure, ChannelManagerReadArgs};
use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, DecodeError, ErrorAction, UpdateAddHTLC, Init};
use lightning::util::enforcing_trait_impls::EnforcingChannelKeys;
use lightning::util::enforcing_trait_impls::{EnforcingChannelKeys, INITIAL_REVOKED_COMMITMENT_NUMBER};
use lightning::util::errors::APIError;
use lightning::util::events;
use lightning::util::logger::Logger;
Expand Down Expand Up @@ -146,6 +146,7 @@ impl chain::Watch for TestChainMonitor {
struct KeyProvider {
node_id: u8,
rand_bytes_id: atomic::AtomicU8,
revoked_commitments: Mutex<HashMap<[u8;32], Arc<Mutex<u64>>>>,
}
impl KeysInterface for KeyProvider {
type ChanKeySigner = EnforcingChannelKeys;
Expand All @@ -168,26 +169,52 @@ impl KeysInterface for KeyProvider {

fn get_channel_keys(&self, _inbound: bool, channel_value_satoshis: u64) -> EnforcingChannelKeys {
let secp_ctx = Secp256k1::signing_only();
EnforcingChannelKeys::new(InMemoryChannelKeys::new(
let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed);
let keys = InMemoryChannelKeys::new(
&secp_ctx,
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, self.node_id]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, self.node_id]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, self.node_id]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, self.node_id]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, self.node_id]).unwrap(),
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_id],
[id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_id],
channel_value_satoshis,
(0, 0),
))
);
let revoked_commitment = self.make_revoked_commitment_cell(keys.commitment_seed);
EnforcingChannelKeys::new_with_revoked(keys, revoked_commitment, false)
}

fn get_secure_random_bytes(&self) -> [u8; 32] {
let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed);
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, id, 11, self.node_id]
}

fn read_chan_signer(&self, data: &[u8]) -> Result<EnforcingChannelKeys, DecodeError> {
EnforcingChannelKeys::read(&mut std::io::Cursor::new(data))
fn read_chan_signer(&self, buffer: &[u8]) -> Result<Self::ChanKeySigner, DecodeError> {
let mut reader = std::io::Cursor::new(buffer);

let inner: InMemoryChannelKeys = Readable::read(&mut reader)?;
let revoked_commitment = self.make_revoked_commitment_cell(inner.commitment_seed);

let last_commitment_number = Readable::read(&mut reader)?;

Ok(EnforcingChannelKeys {
inner,
last_commitment_number: Arc::new(Mutex::new(last_commitment_number)),
revoked_commitment,
disable_revocation_policy_check: false,
})
}
}

impl KeyProvider {
fn make_revoked_commitment_cell(&self, commitment_seed: [u8; 32]) -> Arc<Mutex<u64>> {
let mut revoked_commitments = self.revoked_commitments.lock().unwrap();
if !revoked_commitments.contains_key(&commitment_seed) {
revoked_commitments.insert(commitment_seed, Arc::new(Mutex::new(INITIAL_REVOKED_COMMITMENT_NUMBER)));
}
let cell = revoked_commitments.get(&commitment_seed).unwrap();
Arc::clone(cell)
}
}

Expand Down Expand Up @@ -288,22 +315,22 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone()));
let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), fee_est.clone(), Arc::new(TestPersister{})));

let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0) });
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0), revoked_commitments: Mutex::new(HashMap::new()) });
let mut config = UserConfig::default();
config.channel_options.fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
config.peer_channel_config_limits.min_dust_limit_satoshis = 0;
(ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0),
monitor)
monitor, keys_manager)
} }
}

macro_rules! reload_node {
($ser: expr, $node_id: expr, $old_monitors: expr) => { {
($ser: expr, $node_id: expr, $old_monitors: expr, $keys_manager: expr) => { {
let keys_manager = Arc::clone(& $keys_manager);
let logger: Arc<dyn Logger> = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone()));
let chain_monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), fee_est.clone(), Arc::new(TestPersister{})));

let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0) });
let mut config = UserConfig::default();
config.channel_options.fee_proportional_millionths = 0;
config.channel_options.announced_channel = true;
Expand Down Expand Up @@ -440,9 +467,9 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {

// 3 nodes is enough to hit all the possible cases, notably unknown-source-unknown-dest
// forwarding.
let (node_a, mut monitor_a) = make_node!(0);
let (node_b, mut monitor_b) = make_node!(1);
let (node_c, mut monitor_c) = make_node!(2);
let (node_a, mut monitor_a, keys_manager_a) = make_node!(0);
let (node_b, mut monitor_b, keys_manager_b) = make_node!(1);
let (node_c, mut monitor_c, keys_manager_c) = make_node!(2);

let mut nodes = [node_a, node_b, node_c];

Expand Down Expand Up @@ -793,7 +820,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
chan_a_disconnected = true;
drain_msg_events_on_disconnect!(0);
}
let (new_node_a, new_monitor_a) = reload_node!(node_a_ser, 0, monitor_a);
let (new_node_a, new_monitor_a) = reload_node!(node_a_ser, 0, monitor_a, keys_manager_a);
nodes[0] = new_node_a;
monitor_a = new_monitor_a;
},
Expand All @@ -810,7 +837,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
nodes[2].get_and_clear_pending_msg_events();
bc_events.clear();
}
let (new_node_b, new_monitor_b) = reload_node!(node_b_ser, 1, monitor_b);
let (new_node_b, new_monitor_b) = reload_node!(node_b_ser, 1, monitor_b, keys_manager_b);
nodes[1] = new_node_b;
monitor_b = new_monitor_b;
},
Expand All @@ -820,7 +847,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
chan_b_disconnected = true;
drain_msg_events_on_disconnect!(2);
}
let (new_node_c, new_monitor_c) = reload_node!(node_c_ser, 2, monitor_c);
let (new_node_c, new_monitor_c) = reload_node!(node_c_ser, 2, monitor_c, keys_manager_c);
nodes[2] = new_node_c;
monitor_c = new_monitor_c;
},
Expand Down
4 changes: 2 additions & 2 deletions lightning-persister/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ mod tests {
let persister_1 = FilesystemPersister::new("test_filesystem_persister_1".to_string());
let chanmon_cfgs = create_chanmon_cfgs(2);
let mut node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let chain_mon_0 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &persister_0);
let chain_mon_1 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[1].chain_source), &chanmon_cfgs[1].tx_broadcaster, &chanmon_cfgs[1].logger, &chanmon_cfgs[1].fee_estimator, &persister_1);
let chain_mon_0 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &persister_0, &node_cfgs[0].keys_manager);
let chain_mon_1 = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[1].chain_source), &chanmon_cfgs[1].tx_broadcaster, &chanmon_cfgs[1].logger, &chanmon_cfgs[1].fee_estimator, &persister_1, &node_cfgs[1].keys_manager);
node_cfgs[0].chain_monitor = chain_mon_0;
node_cfgs[1].chain_monitor = chain_mon_1;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
Expand Down
16 changes: 10 additions & 6 deletions lightning/src/chain/keysinterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ pub trait ChannelKeys : Send+Clone + Writeable {
/// state. Thus, needs its own method as sign_holder_commitment may enforce that we only ever
/// get called once.
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
fn unsafe_sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
fn unsafe_sign_holder_commitment_and_htlcs<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;

/// Create a signature for the given input in a transaction spending an HTLC or commitment
/// transaction output when our counterparty broadcasts an old state.
Expand Down Expand Up @@ -499,18 +499,22 @@ impl ChannelKeys for InMemoryChannelKeys {
fn sign_holder_commitment_and_htlcs<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
let sig = commitment_tx.trust().built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx);
let channel_parameters = self.get_channel_parameters();
let trusted_tx = commitment_tx.trust();
let sig = trusted_tx.built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx);
let channel_parameters = self.get_channel_parameters();
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?;
Ok((sig, htlc_sigs))
}

#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
fn unsafe_sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
fn unsafe_sign_holder_commitment_and_htlcs<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
Ok(commitment_tx.trust().built_transaction().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
let trusted_tx = commitment_tx.trust();
let sig = trusted_tx.built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx);
let channel_parameters = self.get_channel_parameters();
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?;
Ok((sig, htlc_sigs))
}

fn sign_justice_transaction<T: secp256k1::Signing + secp256k1::Verification>(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option<HTLCOutputInCommitment>, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/chanmon_update_fail_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fn test_monitor_and_persister_update_fail() {
let new_monitor = <(BlockHash, ChannelMonitor<EnforcingChannelKeys>)>::read(
&mut ::std::io::Cursor::new(&w.0), &test_utils::OnlyReadsKeysInterface {}).unwrap().1;
assert!(new_monitor == *monitor);
let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister);
let chain_mon = test_utils::TestChainMonitor::new(Some(&chain_source), &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator, &persister, &node_cfgs[0].keys_manager);
assert!(chain_mon.watch_channel(outpoint, new_monitor).is_ok());
chain_mon
};
Expand Down
21 changes: 12 additions & 9 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use ln::msgs;
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler};
use util::enforcing_trait_impls::EnforcingChannelKeys;
use util::test_utils;
use util::test_utils::{TestChainMonitor, OnlyReadsKeysInterface};
use util::test_utils::TestChainMonitor;
use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
use util::errors::APIError;
use util::config::UserConfig;
Expand Down Expand Up @@ -96,14 +96,15 @@ pub struct TestChanMonCfg {
pub chain_source: test_utils::TestChainSource,
pub persister: test_utils::TestPersister,
pub logger: test_utils::TestLogger,
pub keys_manager: test_utils::TestKeysInterface,
}

pub struct NodeCfg<'a> {
pub chain_source: &'a test_utils::TestChainSource,
pub tx_broadcaster: &'a test_utils::TestBroadcaster,
pub fee_estimator: &'a test_utils::TestFeeEstimator,
pub chain_monitor: test_utils::TestChainMonitor<'a>,
pub keys_manager: test_utils::TestKeysInterface,
pub keys_manager: &'a test_utils::TestKeysInterface,
pub logger: &'a test_utils::TestLogger,
pub node_seed: [u8; 32],
}
Expand Down Expand Up @@ -172,7 +173,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
let mut w = test_utils::TestVecWriter(Vec::new());
old_monitor.write(&mut w).unwrap();
let (_, deserialized_monitor) = <(BlockHash, ChannelMonitor<EnforcingChannelKeys>)>::read(
&mut ::std::io::Cursor::new(&w.0), &OnlyReadsKeysInterface {}).unwrap();
&mut ::std::io::Cursor::new(&w.0), self.keys_manager).unwrap();
deserialized_monitors.push(deserialized_monitor);
}
}
Expand Down Expand Up @@ -205,7 +206,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
txn_broadcasted: Mutex::new(self.tx_broadcaster.txn_broadcasted.lock().unwrap().clone())
};
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &broadcaster, &self.logger, &feeest, &persister);
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chain_source), &broadcaster, &self.logger, &feeest, &persister, &self.keys_manager);
for deserialized_monitor in deserialized_monitors.drain(..) {
if let Err(_) = chain_monitor.watch_channel(deserialized_monitor.get_funding_txo().0, deserialized_monitor) {
panic!();
Expand Down Expand Up @@ -1132,7 +1133,10 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec<TestChanMonCfg> {
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
let logger = test_utils::TestLogger::with_id(format!("node {}", i));
let persister = test_utils::TestPersister::new();
chan_mon_cfgs.push(TestChanMonCfg{ tx_broadcaster, fee_estimator, chain_source, logger, persister });
let seed = [i as u8; 32];
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);

chan_mon_cfgs.push(TestChanMonCfg{ tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager });
}

chan_mon_cfgs
Expand All @@ -1142,10 +1146,9 @@ pub fn create_node_cfgs<'a>(node_count: usize, chanmon_cfgs: &'a Vec<TestChanMon
let mut nodes = Vec::new();

for i in 0..node_count {
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[i].chain_source), &chanmon_cfgs[i].tx_broadcaster, &chanmon_cfgs[i].logger, &chanmon_cfgs[i].fee_estimator, &chanmon_cfgs[i].persister, &chanmon_cfgs[i].keys_manager);
let seed = [i as u8; 32];
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[i].chain_source), &chanmon_cfgs[i].tx_broadcaster, &chanmon_cfgs[i].logger, &chanmon_cfgs[i].fee_estimator, &chanmon_cfgs[i].persister);
nodes.push(NodeCfg { chain_source: &chanmon_cfgs[i].chain_source, logger: &chanmon_cfgs[i].logger, tx_broadcaster: &chanmon_cfgs[i].tx_broadcaster, fee_estimator: &chanmon_cfgs[i].fee_estimator, chain_monitor, keys_manager, node_seed: seed });
nodes.push(NodeCfg { chain_source: &chanmon_cfgs[i].chain_source, logger: &chanmon_cfgs[i].logger, tx_broadcaster: &chanmon_cfgs[i].tx_broadcaster, fee_estimator: &chanmon_cfgs[i].fee_estimator, chain_monitor, keys_manager: &chanmon_cfgs[i].keys_manager, node_seed: seed });
}

nodes
Expand All @@ -1158,7 +1161,7 @@ pub fn create_node_chanmgrs<'a, 'b>(node_count: usize, cfgs: &'a Vec<NodeCfg<'b>
default_config.channel_options.announced_channel = true;
default_config.peer_channel_config_limits.force_announced_channel_preference = false;
default_config.own_channel_config.our_htlc_minimum_msat = 1000; // sanitization being done by the sender, to exerce receiver logic we need to lift of limit
let node = ChannelManager::new(Network::Testnet, cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger, &cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { default_config }, 0);
let node = ChannelManager::new(Network::Testnet, cfgs[i].fee_estimator, &cfgs[i].chain_monitor, cfgs[i].tx_broadcaster, cfgs[i].logger, cfgs[i].keys_manager, if node_config[i].is_some() { node_config[i].clone().unwrap() } else { default_config }, 0);
chanmgrs.push(node);
}

Expand Down
Loading