Skip to content

Commit 976e8a2

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 e0bbd59 commit 976e8a2

File tree

3 files changed

+270
-3
lines changed

3 files changed

+270
-3
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,191 @@ impl Readable for IrrevocablyResolvedHTLC {
764764
}
765765
}
766766

767+
/// [StubChannel] is the smallest unit of [OurPeerStorage], it contains
768+
/// information about a single channel using which we can recover on-chain funds.
769+
#[derive(Clone, PartialEq, Eq)]
770+
pub struct StubChannel {
771+
pub channel_id: ChannelId,
772+
pub funding_outpoint: OutPoint,
773+
pub channel_value_stoshis: u64,
774+
pub channel_keys_id: [u8;32],
775+
pub commitment_secrets: CounterpartyCommitmentSecrets,
776+
pub counterparty_node_id: PublicKey,
777+
pub counterparty_delayed_payment_base_key: DelayedPaymentBasepoint,
778+
pub counterparty_htlc_base_key: HtlcBasepoint,
779+
pub on_counterparty_tx_csv: u16,
780+
pub obscure_factor: u64,
781+
pub(crate) latest_state: HashMap<Txid, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
782+
pub their_cur_per_commitment_points: Option<(u64, PublicKey, Option<PublicKey>)>,
783+
pub features: ChannelTypeFeatures,
784+
}
785+
786+
impl StubChannel {
787+
pub(crate) fn new(channel_id: ChannelId, funding_outpoint: OutPoint, channel_value_stoshis: u64, channel_keys_id: [u8; 32],
788+
commitment_secrets: CounterpartyCommitmentSecrets, counterparty_node_id: PublicKey, counterparty_delayed_payment_base_key: DelayedPaymentBasepoint, counterparty_htlc_base_key: HtlcBasepoint, on_counterparty_tx_csv: u16,
789+
obscure_factor: u64, latest_state: HashMap<Txid, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>, their_cur_per_commitment_points: Option<(u64, PublicKey, Option<PublicKey>)>,
790+
features: ChannelTypeFeatures) -> Self {
791+
StubChannel {
792+
channel_id,
793+
funding_outpoint,
794+
channel_value_stoshis,
795+
channel_keys_id,
796+
commitment_secrets,
797+
counterparty_node_id,
798+
counterparty_delayed_payment_base_key,
799+
counterparty_htlc_base_key,
800+
on_counterparty_tx_csv,
801+
obscure_factor,
802+
latest_state,
803+
their_cur_per_commitment_points,
804+
features,
805+
}
806+
}
807+
}
808+
809+
impl_writeable_tlv_based!(StubChannel, {
810+
(0, channel_id, required),
811+
(2, channel_keys_id, required),
812+
(4, channel_value_stoshis, required),
813+
(6, funding_outpoint, required),
814+
(8, commitment_secrets, required),
815+
(10, counterparty_node_id, required),
816+
(12, counterparty_delayed_payment_base_key, required),
817+
(14, counterparty_htlc_base_key, required),
818+
(16, on_counterparty_tx_csv, required),
819+
(18, obscure_factor, required),
820+
(20, latest_state, required),
821+
(22, their_cur_per_commitment_points, option),
822+
(24, features, required),
823+
});
824+
825+
/// [OurPeerStorage] is used to store our channels using which we
826+
/// can create our PeerStorage Backup.
827+
/// This includes timestamp to compare between two given
828+
/// [OurPeerStorage] and version defines the structure.
829+
#[derive(Clone, PartialEq, Eq)]
830+
pub struct OurPeerStorage {
831+
pub version: u32,
832+
pub timestamp: u32,
833+
pub channels: Vec<StubChannel>,
834+
}
835+
836+
impl OurPeerStorage {
837+
pub fn new() -> Self {
838+
let duration_since_epoch = std::time::SystemTime::now()
839+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
840+
.expect("Time must be > 1970");
841+
842+
Self {
843+
version: 1,
844+
timestamp: duration_since_epoch.as_secs() as u32,
845+
channels: Vec::new(),
846+
}
847+
}
848+
849+
pub fn stub_channel(&mut self, chan: StubChannel) {
850+
self.channels.push(chan);
851+
}
852+
853+
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>)>) {
854+
for stub_channel in &mut self.channels {
855+
if stub_channel.channel_id == cid {
856+
let mut latest_state = HashMap::new();
857+
latest_state.insert(txid, htlc_data);
858+
stub_channel.latest_state = latest_state;
859+
stub_channel.their_cur_per_commitment_points = their_cur_per_commitment_points;
860+
return;
861+
}
862+
}
863+
}
864+
865+
pub(crate) fn provide_secret(&mut self, cid: ChannelId, idx:u64, secret: [u8; 32]) -> Result<(), ()> {
866+
for stub_channel in &mut self.channels {
867+
if stub_channel.channel_id == cid {
868+
return stub_channel.commitment_secrets.provide_secret(idx, secret);
869+
}
870+
}
871+
return Err(());
872+
}
873+
874+
pub(crate) fn update_state_from_monitor_update(&mut self, cid: ChannelId, monitor_update: ChannelMonitorUpdate) -> Result<(),()> {
875+
for update in monitor_update.updates.iter() {
876+
match update {
877+
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number,
878+
their_per_commitment_point, .. } => {
879+
let stub_channels = &self.channels;
880+
let mut cur_per_commitment_points = None;
881+
for stub_channel in stub_channels {
882+
if stub_channel.channel_id == cid {
883+
match stub_channel.their_cur_per_commitment_points {
884+
Some(old_points) => {
885+
if old_points.0 == commitment_number + 1 {
886+
cur_per_commitment_points = Some((old_points.0, old_points.1, Some(*their_per_commitment_point)));
887+
} else if old_points.0 == commitment_number + 2 {
888+
if let Some(old_second_point) = old_points.2 {
889+
cur_per_commitment_points = Some((old_points.0 - 1, old_second_point, Some(*their_per_commitment_point)));
890+
} else {
891+
cur_per_commitment_points = Some((*commitment_number, *their_per_commitment_point, None));
892+
}
893+
} else {
894+
cur_per_commitment_points = Some((*commitment_number, *their_per_commitment_point, None));
895+
}
896+
},
897+
None => {
898+
cur_per_commitment_points = Some((*commitment_number, *their_per_commitment_point, None));
899+
}
900+
}
901+
}
902+
}
903+
let mut htlc_data = htlc_outputs.clone();
904+
for htlc in &mut htlc_data {
905+
htlc.1 = None;
906+
}
907+
self.update_latest_state(cid, *commitment_txid, htlc_data, cur_per_commitment_points);
908+
return Ok(());
909+
}
910+
_ => {}
911+
}
912+
}
913+
Err(())
914+
}
915+
916+
pub fn encrypt_our_peer_storage(&self, key: [u8; 32]) -> Vec<u8> {
917+
let n = 0u64;
918+
let mut peer_storage = VecWriter(Vec::new());
919+
self.write(&mut peer_storage).unwrap();
920+
let mut res = vec![0;peer_storage.0.len() + 16];
921+
922+
let plaintext = &peer_storage.0[..];
923+
let mut nonce = [0; 12];
924+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
925+
926+
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, b"");
927+
let mut tag = [0; 16];
928+
chacha.encrypt(plaintext, &mut res[0..plaintext.len()], &mut tag);
929+
res[plaintext.len()..].copy_from_slice(&tag);
930+
res
931+
}
932+
933+
pub fn decrypt_our_peer_storage(&self, res: &mut[u8], cyphertext: &[u8], key: [u8; 32]) -> Result<(), ()> {
934+
let n = 0u64;
935+
let mut nonce = [0; 12];
936+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
937+
938+
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, b"");
939+
if chacha.variable_time_decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]).is_err() {
940+
return Err(());
941+
}
942+
Ok(())
943+
}
944+
}
945+
946+
impl_writeable_tlv_based!(OurPeerStorage, {
947+
(0, version, (default_value, 1)),
948+
(2, timestamp, required),
949+
(4, channels, optional_vec),
950+
});
951+
767952
/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
768953
/// on-chain transactions to ensure no loss of funds occurs.
769954
///
@@ -1439,6 +1624,19 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
14391624
self.inner.lock().unwrap().get_latest_update_id()
14401625
}
14411626

1627+
/// Gets the latest claiming info from the ChannelMonitor to update our PeerStorageBackup.
1628+
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>)>)> {
1629+
let lock = self.inner.lock().unwrap();
1630+
if let Some(latest_txid) = lock.current_counterparty_commitment_txid {
1631+
return Some((
1632+
latest_txid, lock.counterparty_claimable_outpoints.get(&latest_txid).unwrap().clone(),
1633+
lock.their_cur_per_commitment_points
1634+
))
1635+
}
1636+
1637+
None
1638+
}
1639+
14421640
/// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for.
14431641
pub fn get_funding_txo(&self) -> (OutPoint, ScriptBuf) {
14441642
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
@@ -2050,6 +2050,18 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
20502050
self.update_time_counter
20512051
}
20522052

2053+
pub fn get_commitment_secret(&self) -> CounterpartyCommitmentSecrets {
2054+
self.commitment_secrets.clone()
2055+
}
2056+
2057+
pub fn get_channel_keys_id(&self) -> [u8;32] {
2058+
self.channel_keys_id
2059+
}
2060+
2061+
pub fn get_commitment_txn_number_obscure_factor(&self) -> u64 {
2062+
get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound())
2063+
}
2064+
20532065
pub fn get_latest_monitor_update_id(&self) -> u64 {
20542066
self.latest_monitor_update_id
20552067
}
@@ -2348,7 +2360,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
23482360
height.checked_sub(self.funding_tx_confirmation_height).map_or(0, |c| c + 1)
23492361
}
23502362

2351-
fn get_holder_selected_contest_delay(&self) -> u16 {
2363+
pub fn get_holder_selected_contest_delay(&self) -> u16 {
23522364
self.channel_transaction_parameters.holder_selected_contest_delay
23532365
}
23542366

lightning/src/ln/channelmanager.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, Paym
3838
use crate::chain;
3939
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
4040
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
41-
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};
41+
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};
4242
use crate::chain::transaction::{OutPoint, TransactionData};
4343
use crate::events;
4444
use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, PaymentFailureReason};
@@ -2206,6 +2206,7 @@ where
22062206
entropy_source: ES,
22072207
node_signer: NS,
22082208
signer_provider: SP,
2209+
our_peer_storage: FairRwLock<OurPeerStorage>,
22092210
peer_storage: Mutex<HashMap<PublicKey, Vec<u8>>>,
22102211
logger: L,
22112212
}
@@ -2985,6 +2986,7 @@ where
29852986
entropy_source,
29862987
node_signer,
29872988
signer_provider,
2989+
our_peer_storage: FairRwLock::new(OurPeerStorage::new()),
29882990
peer_storage: Mutex::new(new_hash_map()),
29892991
logger,
29902992
}
@@ -6415,6 +6417,8 @@ where
64156417
if let Some(raa_blocker) = raa_blocker_opt {
64166418
peer_state.actions_blocking_raa_monitor_updates.entry(chan_id).or_insert_with(Vec::new).push(raa_blocker);
64176419
}
6420+
6421+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
64186422
if !during_init {
64196423
handle_new_monitor_update!(self, prev_hop.outpoint, monitor_update, peer_state_lock,
64206424
peer_state, per_peer_state, chan);
@@ -7517,7 +7521,17 @@ where
75177521
let mut pending_events = self.pending_events.lock().unwrap();
75187522
emit_channel_ready_event!(pending_events, chan);
75197523
}
7520-
7524+
// Update Peer Storage.
7525+
let counterparty_channel_parameters = chan.context.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap();
7526+
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
7527+
let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint;
7528+
let stub_chan = StubChannel::new(chan.context.channel_id(), chan.context.get_funding_txo().unwrap(), chan.context.get_value_satoshis(),
7529+
chan.context.get_channel_keys_id(), chan.context.get_commitment_secret(),
7530+
chan.context.get_counterparty_node_id(), counterparty_delayed_payment_base_key, counterparty_htlc_base_key,
7531+
chan.context.get_holder_selected_contest_delay(),
7532+
chan.context.get_commitment_txn_number_obscure_factor(), new_hash_map(),
7533+
None, chan.context.channel_transaction_parameters.channel_type_features.clone());
7534+
self.our_peer_storage.write().unwrap().stub_channel(stub_chan);
75217535
Ok(())
75227536
} else {
75237537
try_chan_phase_entry!(self, Err(ChannelError::close(
@@ -7864,6 +7878,7 @@ where
78647878
let funding_txo = chan.context.get_funding_txo();
78657879
let monitor_update_opt = try_chan_phase_entry!(self, chan.commitment_signed(&msg, &&logger), chan_phase_entry);
78667880
if let Some(monitor_update) = monitor_update_opt {
7881+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
78677882
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update, peer_state_lock,
78687883
peer_state, per_peer_state, chan);
78697884
}
@@ -8064,9 +8079,15 @@ where
80648079
} else { false };
80658080
let (htlcs_to_fail, monitor_update_opt) = try_chan_phase_entry!(self,
80668081
chan.revoke_and_ack(&msg, &self.fee_estimator, &&logger, mon_update_blocked), chan_phase_entry);
8082+
8083+
let mut our_peer_storage = self.our_peer_storage.write().unwrap();
8084+
let _ = our_peer_storage.provide_secret(chan.context.channel_id(), chan.get_cur_counterparty_commitment_transaction_number() + 1, msg.per_commitment_secret);
80678085
if let Some(monitor_update) = monitor_update_opt {
80688086
let funding_txo = funding_txo_opt
80698087
.expect("Funding outpoint must have been set for RAA handling to succeed");
8088+
8089+
let _ = our_peer_storage.update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
8090+
80708091
handle_new_monitor_update!(self, funding_txo, monitor_update,
80718092
peer_state_lock, peer_state, per_peer_state, chan);
80728093
}
@@ -8410,6 +8431,7 @@ where
84108431
}
84118432
if let Some(monitor_update) = monitor_opt {
84128433
has_monitor_update = true;
8434+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
84138435

84148436
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
84158437
peer_state_lock, peer_state, per_peer_state, chan);
@@ -11652,6 +11674,8 @@ where
1165211674
let mut channel_closures = VecDeque::new();
1165311675
let mut close_background_events = Vec::new();
1165411676
let mut funding_txo_to_channel_id = hash_map_with_capacity(channel_count as usize);
11677+
let mut our_peer_storage: OurPeerStorage = OurPeerStorage::new();
11678+
1165511679
for _ in 0..channel_count {
1165611680
let mut channel: Channel<SP> = Channel::read(reader, (
1165711681
&args.entropy_source, &args.signer_provider, best_block_height, &provided_channel_type_features(&args.default_config)
@@ -11660,7 +11684,39 @@ where
1166011684
let funding_txo = channel.context.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
1166111685
funding_txo_to_channel_id.insert(funding_txo, channel.context.channel_id());
1166211686
funding_txo_set.insert(funding_txo.clone());
11687+
let counterparty_channel_parameters = channel.context.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap();
11688+
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
11689+
let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint;
11690+
11691+
let stub_chan = StubChannel::new(
11692+
channel.context.channel_id(),
11693+
funding_txo,
11694+
channel.context.get_value_satoshis(),
11695+
channel.context.get_channel_keys_id(),
11696+
channel.context.get_commitment_secret(),
11697+
channel.context.get_counterparty_node_id(),
11698+
counterparty_delayed_payment_base_key,
11699+
counterparty_htlc_base_key,
11700+
channel.context.get_holder_selected_contest_delay(),
11701+
channel.context.get_commitment_txn_number_obscure_factor(),
11702+
new_hash_map(),
11703+
None,
11704+
channel.context.channel_transaction_parameters.channel_type_features.clone(),
11705+
);
11706+
our_peer_storage.stub_channel(stub_chan);
1166311707
if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
11708+
if let Some(latest_commitment_txn_info) = monitor.get_latest_commitment_txn_and_its_claiming_info() {
11709+
11710+
let mut htlc_data = latest_commitment_txn_info.1;
11711+
11712+
// We do not need HTLCSource to be backed up.
11713+
for htlc in &mut htlc_data {
11714+
htlc.1 = None;
11715+
}
11716+
11717+
our_peer_storage.update_latest_state(monitor.channel_id(), latest_commitment_txn_info.0, htlc_data, latest_commitment_txn_info.2);
11718+
}
11719+
1166411720
if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() ||
1166511721
channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() ||
1166611722
channel.get_cur_counterparty_commitment_transaction_number() > monitor.get_cur_counterparty_commitment_number() ||
@@ -12509,6 +12565,7 @@ where
1250912565

1251012566
last_days_feerates: Mutex::new(VecDeque::new()),
1251112567

12568+
our_peer_storage: FairRwLock::new(our_peer_storage),
1251212569
peer_storage: Mutex::new(peer_storage),
1251312570
logger: args.logger,
1251412571
default_configuration: args.default_config,

0 commit comments

Comments
 (0)