Skip to content

Commit c2ee142

Browse files
Aditya SharmaAditya Sharma
authored andcommitted
lightning: Add struct for building OurPeerStorage, it gets updated everytime a LatestCounterpartyCommitmentTxn update is sent. It would be encrypted and sent to our peers.
1 parent f2c34dc commit c2ee142

File tree

3 files changed

+287
-3
lines changed

3 files changed

+287
-3
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,208 @@ impl Readable for IrrevocablyResolvedHTLC {
832832
}
833833
}
834834

835+
/// [StubChannel] is the smallest unit of [OurPeerStorage], it contains
836+
/// information about a single channel using which we can recover on-chain funds.
837+
#[derive(Clone, PartialEq, Eq)]
838+
pub struct StubChannel {
839+
pub(crate) channel_id: ChannelId,
840+
pub(crate) funding_outpoint: OutPoint,
841+
pub(crate) channel_value_stoshis: u64,
842+
pub(crate) channel_keys_id: [u8;32],
843+
pub(crate) commitment_secrets: CounterpartyCommitmentSecrets,
844+
pub(crate) counterparty_node_id: PublicKey,
845+
pub(crate) counterparty_delayed_payment_base_key: DelayedPaymentBasepoint,
846+
pub(crate) counterparty_htlc_base_key: HtlcBasepoint,
847+
pub(crate) on_counterparty_tx_csv: u16,
848+
pub(crate) obscure_factor: u64,
849+
pub(crate) latest_state: HashMap<Txid, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
850+
pub(crate) their_cur_per_commitment_points: Option<(u64, PublicKey, Option<PublicKey>)>,
851+
pub(crate) features: ChannelTypeFeatures,
852+
}
853+
854+
impl StubChannel {
855+
pub(crate) fn new(channel_id: ChannelId, funding_outpoint: OutPoint, channel_value_stoshis: u64, channel_keys_id: [u8; 32],
856+
commitment_secrets: CounterpartyCommitmentSecrets, counterparty_node_id: PublicKey, counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, counterparty_htlc_base_key: HtlcBasepoint, on_counterparty_tx_csv: u16,
857+
obscure_factor: u64, latest_state: HashMap<Txid, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>, their_cur_per_commitment_points: Option<(u64, PublicKey, Option<PublicKey>)>,
858+
features: ChannelTypeFeatures) -> Self {
859+
StubChannel {
860+
channel_id,
861+
funding_outpoint,
862+
channel_value_stoshis,
863+
channel_keys_id,
864+
commitment_secrets,
865+
counterparty_node_id,
866+
counterparty_delayed_payment_base_key,
867+
counterparty_htlc_base_key,
868+
on_counterparty_tx_csv,
869+
obscure_factor,
870+
latest_state,
871+
their_cur_per_commitment_points,
872+
features,
873+
}
874+
}
875+
876+
/// Get the min seen secret from the commitment secrets.
877+
pub fn get_min_seen_secret(&self) -> u64 {
878+
return self.commitment_secrets.get_min_seen_secret();
879+
}
880+
}
881+
882+
impl_writeable_tlv_based!(StubChannel, {
883+
(0, channel_id, required),
884+
(2, channel_keys_id, required),
885+
(4, channel_value_stoshis, required),
886+
(6, funding_outpoint, required),
887+
(8, commitment_secrets, required),
888+
(10, counterparty_node_id, required),
889+
(12, counterparty_delayed_payment_base_key, required),
890+
(14, counterparty_htlc_base_key, required),
891+
(16, on_counterparty_tx_csv, required),
892+
(18, obscure_factor, required),
893+
(20, latest_state, required),
894+
(22, their_cur_per_commitment_points, option),
895+
(24, features, required),
896+
});
897+
898+
/// [`OurPeerStorage`] is used to store our channels using which we
899+
/// can create our PeerStorage Backup.
900+
/// This includes timestamp to compare between two given
901+
/// [`OurPeerStorage`] and version defines the structure.
902+
#[derive(Clone, PartialEq, Eq)]
903+
pub struct OurPeerStorage {
904+
version: u32,
905+
timestamp: u32,
906+
channels: Vec<StubChannel>,
907+
}
908+
909+
impl OurPeerStorage {
910+
/// Returns a [`OurPeerStorage`] with version 1 and current timestamp.
911+
pub fn new() -> Self {
912+
let duration_since_epoch = std::time::SystemTime::now()
913+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
914+
.expect("Time must be > 1970");
915+
916+
Self {
917+
version: 1,
918+
timestamp: duration_since_epoch.as_secs() as u32,
919+
channels: Vec::new(),
920+
}
921+
}
922+
923+
/// Stubs a channel inside [`OurPeerStorage`]
924+
pub fn stub_channel(&mut self, chan: StubChannel) {
925+
self.channels.push(chan);
926+
}
927+
928+
/// Get a reference of `channels` array from [`StubChannel::channels`]
929+
pub fn get_channels(&self) -> &Vec<StubChannel> {
930+
self.channels.as_ref()
931+
}
932+
933+
pub(crate) fn update_latest_state(&mut self, cid: ChannelId, txid: Txid, htlc_data: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>, their_cur_per_commitment_points: Option<(u64, PublicKey, Option<PublicKey>)>) {
934+
for stub_channel in &mut self.channels {
935+
if stub_channel.channel_id == cid {
936+
let mut latest_state = HashMap::new();
937+
latest_state.insert(txid, htlc_data);
938+
stub_channel.latest_state = latest_state;
939+
stub_channel.their_cur_per_commitment_points = their_cur_per_commitment_points;
940+
return;
941+
}
942+
}
943+
}
944+
945+
pub(crate) fn provide_secret(&mut self, cid: ChannelId, idx:u64, secret: [u8; 32]) -> Result<(), ()> {
946+
for stub_channel in &mut self.channels {
947+
if stub_channel.channel_id == cid {
948+
return stub_channel.commitment_secrets.provide_secret(idx, secret);
949+
}
950+
}
951+
return Err(());
952+
}
953+
954+
/// This is called to update the data of the latest state inside [`OurPeerStorage`] using
955+
/// [`ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo`]
956+
pub(crate) fn update_state_from_monitor_update(&mut self, cid: ChannelId, monitor_update: ChannelMonitorUpdate) -> Result<(),()> {
957+
for update in monitor_update.updates.iter() {
958+
match update {
959+
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number,
960+
their_per_commitment_point, .. } => {
961+
let stub_channels = &self.channels;
962+
let mut cur_per_commitment_points = None;
963+
for stub_channel in stub_channels {
964+
if stub_channel.channel_id == cid {
965+
match stub_channel.their_cur_per_commitment_points {
966+
Some(old_points) => {
967+
if old_points.0 == commitment_number + 1 {
968+
cur_per_commitment_points = Some((old_points.0, old_points.1, Some(*their_per_commitment_point)));
969+
} else if old_points.0 == commitment_number + 2 {
970+
if let Some(old_second_point) = old_points.2 {
971+
cur_per_commitment_points = Some((old_points.0 - 1, old_second_point, Some(*their_per_commitment_point)));
972+
} else {
973+
cur_per_commitment_points = Some((*commitment_number, *their_per_commitment_point, None));
974+
}
975+
} else {
976+
cur_per_commitment_points = Some((*commitment_number, *their_per_commitment_point, None));
977+
}
978+
},
979+
None => {
980+
cur_per_commitment_points = Some((*commitment_number, *their_per_commitment_point, None));
981+
}
982+
}
983+
}
984+
}
985+
let mut htlc_data = htlc_outputs.clone();
986+
for htlc in &mut htlc_data {
987+
htlc.1 = None;
988+
}
989+
self.update_latest_state(cid, *commitment_txid, htlc_data, cur_per_commitment_points);
990+
return Ok(());
991+
}
992+
_ => {}
993+
}
994+
}
995+
Err(())
996+
}
997+
998+
/// Encrypt [`OurPeerStorage`] using the `key` and return a Vec<u8> containing the result.
999+
pub fn encrypt_our_peer_storage(&self, key: [u8; 32]) -> Vec<u8> {
1000+
let n = 0u64;
1001+
let mut peer_storage = VecWriter(Vec::new());
1002+
self.write(&mut peer_storage).unwrap();
1003+
let mut res = vec![0;peer_storage.0.len() + 16];
1004+
1005+
let plaintext = &peer_storage.0[..];
1006+
let mut nonce = [0; 12];
1007+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
1008+
1009+
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, b"");
1010+
let mut tag = [0; 16];
1011+
chacha.encrypt(plaintext, &mut res[0..plaintext.len()], &mut tag);
1012+
res[plaintext.len()..].copy_from_slice(&tag);
1013+
res
1014+
}
1015+
1016+
/// Decrypt `OurPeerStorage` using the `key`, result is stored inside the `res`.
1017+
/// Returns an error if the the `cyphertext` is not correct.
1018+
pub fn decrypt_our_peer_storage(&self, res: &mut[u8], cyphertext: &[u8], key: [u8; 32]) -> Result<(), ()> {
1019+
let n = 0u64;
1020+
let mut nonce = [0; 12];
1021+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
1022+
1023+
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, b"");
1024+
if chacha.variable_time_decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]).is_err() {
1025+
return Err(());
1026+
}
1027+
Ok(())
1028+
}
1029+
}
1030+
1031+
impl_writeable_tlv_based!(OurPeerStorage, {
1032+
(0, version, (default_value, 1)),
1033+
(2, timestamp, required),
1034+
(4, channels, optional_vec),
1035+
});
1036+
8351037
/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
8361038
/// on-chain transactions to ensure no loss of funds occurs.
8371039
///
@@ -1532,6 +1734,19 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
15321734
self.inner.lock().unwrap().get_latest_update_id()
15331735
}
15341736

1737+
/// Gets the latest claiming info from the ChannelMonitor to update our PeerStorageBackup.
1738+
pub(crate) fn get_latest_commitment_txn_and_its_claiming_info(&self) -> Option<(Txid, Vec<(HTLCOutputInCommitment, Option<std::boxed::Box<HTLCSource>>)>, Option<(u64, PublicKey, Option<PublicKey>)>)> {
1739+
let lock = self.inner.lock().unwrap();
1740+
if let Some(latest_txid) = lock.current_counterparty_commitment_txid {
1741+
return Some((
1742+
latest_txid, lock.counterparty_claimable_outpoints.get(&latest_txid).unwrap().clone(),
1743+
lock.their_cur_per_commitment_points
1744+
))
1745+
}
1746+
1747+
None
1748+
}
1749+
15351750
/// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for.
15361751
pub fn get_funding_txo(&self) -> (OutPoint, ScriptBuf) {
15371752
self.inner.lock().unwrap().get_funding_txo().clone()

lightning/src/ln/channel.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2073,6 +2073,18 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
20732073
self.update_time_counter
20742074
}
20752075

2076+
pub fn get_commitment_secret(&self) -> CounterpartyCommitmentSecrets {
2077+
self.commitment_secrets.clone()
2078+
}
2079+
2080+
pub fn get_channel_keys_id(&self) -> [u8;32] {
2081+
self.channel_keys_id
2082+
}
2083+
2084+
pub fn get_commitment_txn_number_obscure_factor(&self) -> u64 {
2085+
get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound())
2086+
}
2087+
20762088
pub fn get_latest_monitor_update_id(&self) -> u64 {
20772089
self.latest_monitor_update_id
20782090
}
@@ -2371,7 +2383,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
23712383
height.checked_sub(self.funding_tx_confirmation_height).map_or(0, |c| c + 1)
23722384
}
23732385

2374-
fn get_holder_selected_contest_delay(&self) -> u16 {
2386+
pub fn get_holder_selected_contest_delay(&self) -> u16 {
23752387
self.channel_transaction_parameters.holder_selected_contest_delay
23762388
}
23772389

lightning/src/ln/channelmanager.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt1
4040
use crate::chain;
4141
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
4242
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
43-
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, WithChannelMonitor, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
43+
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, StubChannelMonitor, StubChannel, OurPeerStorage, WithChannelMonitor, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
4444
use crate::chain::transaction::{OutPoint, TransactionData};
4545
use crate::events;
4646
use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, PaymentFailureReason, ReplayEvent};
@@ -2303,6 +2303,7 @@ where
23032303
entropy_source: ES,
23042304
node_signer: NS,
23052305
signer_provider: SP,
2306+
our_peer_storage: FairRwLock<OurPeerStorage>,
23062307
peer_storage: Mutex<HashMap<PublicKey, Vec<u8>>>,
23072308
logger: L,
23082309
}
@@ -3108,6 +3109,7 @@ where
31083109
entropy_source,
31093110
node_signer,
31103111
signer_provider,
3112+
our_peer_storage: FairRwLock::new(OurPeerStorage::new()),
31113113
peer_storage: Mutex::new(new_hash_map()),
31123114
logger,
31133115
}
@@ -6624,6 +6626,8 @@ where
66246626
if let Some(raa_blocker) = raa_blocker_opt {
66256627
peer_state.actions_blocking_raa_monitor_updates.entry(chan_id).or_insert_with(Vec::new).push(raa_blocker);
66266628
}
6629+
6630+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
66276631
if !during_init {
66286632
handle_new_monitor_update!(self, prev_hop.outpoint, monitor_update, peer_state_lock,
66296633
peer_state, per_peer_state, chan);
@@ -7744,7 +7748,17 @@ where
77447748
let mut pending_events = self.pending_events.lock().unwrap();
77457749
emit_channel_ready_event!(pending_events, chan);
77467750
}
7747-
7751+
// Update Peer Storage.
7752+
let counterparty_channel_parameters = chan.context.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap();
7753+
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
7754+
let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint;
7755+
let stub_chan = StubChannel::new(chan.context.channel_id(), chan.context.get_funding_txo().unwrap(), chan.context.get_value_satoshis(),
7756+
chan.context.get_channel_keys_id(), chan.context.get_commitment_secret(),
7757+
chan.context.get_counterparty_node_id(), counterparty_delayed_payment_base_key, counterparty_htlc_base_key,
7758+
chan.context.get_holder_selected_contest_delay(),
7759+
chan.context.get_commitment_txn_number_obscure_factor(), new_hash_map(),
7760+
None, chan.context.channel_transaction_parameters.channel_type_features.clone());
7761+
self.our_peer_storage.write().unwrap().stub_channel(stub_chan);
77487762
Ok(())
77497763
} else {
77507764
try_chan_phase_entry!(self, Err(ChannelError::close(
@@ -8092,6 +8106,7 @@ where
80928106
let funding_txo = chan.context.get_funding_txo();
80938107
let monitor_update_opt = try_chan_phase_entry!(self, chan.commitment_signed(&msg, &&logger), chan_phase_entry);
80948108
if let Some(monitor_update) = monitor_update_opt {
8109+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
80958110
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update, peer_state_lock,
80968111
peer_state, per_peer_state, chan);
80978112
}
@@ -8292,9 +8307,15 @@ where
82928307
} else { false };
82938308
let (htlcs_to_fail, monitor_update_opt) = try_chan_phase_entry!(self,
82948309
chan.revoke_and_ack(&msg, &self.fee_estimator, &&logger, mon_update_blocked), chan_phase_entry);
8310+
8311+
let mut our_peer_storage = self.our_peer_storage.write().unwrap();
8312+
let _ = our_peer_storage.provide_secret(chan.context.channel_id(), chan.get_cur_counterparty_commitment_transaction_number() + 1, msg.per_commitment_secret);
82958313
if let Some(monitor_update) = monitor_update_opt {
82968314
let funding_txo = funding_txo_opt
82978315
.expect("Funding outpoint must have been set for RAA handling to succeed");
8316+
8317+
let _ = our_peer_storage.update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
8318+
82988319
handle_new_monitor_update!(self, funding_txo, monitor_update,
82998320
peer_state_lock, peer_state, per_peer_state, chan);
83008321
}
@@ -8638,6 +8659,7 @@ where
86388659
}
86398660
if let Some(monitor_update) = monitor_opt {
86408661
has_monitor_update = true;
8662+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
86418663

86428664
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
86438665
peer_state_lock, peer_state, per_peer_state, chan);
@@ -11944,6 +11966,8 @@ where
1194411966
let mut channel_closures = VecDeque::new();
1194511967
let mut close_background_events = Vec::new();
1194611968
let mut funding_txo_to_channel_id = hash_map_with_capacity(channel_count as usize);
11969+
let mut our_peer_storage: OurPeerStorage = OurPeerStorage::new();
11970+
1194711971
for _ in 0..channel_count {
1194811972
let mut channel: Channel<SP> = Channel::read(reader, (
1194911973
&args.entropy_source, &args.signer_provider, best_block_height, &provided_channel_type_features(&args.default_config)
@@ -11952,7 +11976,39 @@ where
1195211976
let funding_txo = channel.context.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
1195311977
funding_txo_to_channel_id.insert(funding_txo, channel.context.channel_id());
1195411978
funding_txo_set.insert(funding_txo.clone());
11979+
let counterparty_channel_parameters = channel.context.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap();
11980+
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
11981+
let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint;
11982+
11983+
let stub_chan = StubChannel::new(
11984+
channel.context.channel_id(),
11985+
funding_txo,
11986+
channel.context.get_value_satoshis(),
11987+
channel.context.get_channel_keys_id(),
11988+
channel.context.get_commitment_secret(),
11989+
channel.context.get_counterparty_node_id(),
11990+
counterparty_delayed_payment_base_key,
11991+
counterparty_htlc_base_key,
11992+
channel.context.get_holder_selected_contest_delay(),
11993+
channel.context.get_commitment_txn_number_obscure_factor(),
11994+
new_hash_map(),
11995+
None,
11996+
channel.context.channel_transaction_parameters.channel_type_features.clone(),
11997+
);
11998+
our_peer_storage.stub_channel(stub_chan);
1195511999
if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
12000+
if let Some(latest_commitment_txn_info) = monitor.get_latest_commitment_txn_and_its_claiming_info() {
12001+
12002+
let mut htlc_data = latest_commitment_txn_info.1;
12003+
12004+
// We do not need HTLCSource to be backed up.
12005+
for htlc in &mut htlc_data {
12006+
htlc.1 = None;
12007+
}
12008+
12009+
our_peer_storage.update_latest_state(monitor.channel_id(), latest_commitment_txn_info.0, htlc_data, latest_commitment_txn_info.2);
12010+
}
12011+
1195612012
if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() ||
1195712013
channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() ||
1195812014
channel.get_cur_counterparty_commitment_transaction_number() > monitor.get_cur_counterparty_commitment_number() ||
@@ -12796,6 +12852,7 @@ where
1279612852

1279712853
last_days_feerates: Mutex::new(VecDeque::new()),
1279812854

12855+
our_peer_storage: FairRwLock::new(our_peer_storage),
1279912856
peer_storage: Mutex::new(peer_storage),
1280012857
logger: args.logger,
1280112858
default_configuration: args.default_config,

0 commit comments

Comments
 (0)