Skip to content

Commit f49f2e5

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 c0c9606 commit f49f2e5

File tree

3 files changed

+236
-2
lines changed

3 files changed

+236
-2
lines changed

lightning/src/chain/channelmonitor.rs

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

1609+
/// Gets the latest claiming info from the ChannelMonitor to update our PeerStorageBackup.
1610+
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>)>)> {
1611+
let lock = self.inner.lock().unwrap();
1612+
if let Some(latest_txid) = lock.current_counterparty_commitment_txid {
1613+
return Some((
1614+
latest_txid, lock.counterparty_claimable_outpoints.get(&latest_txid).unwrap().clone(),
1615+
lock.their_cur_per_commitment_points
1616+
))
1617+
}
1618+
1619+
None
1620+
}
1621+
14421622
/// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for.
14431623
pub fn get_funding_txo(&self) -> (OutPoint, ScriptBuf) {
14441624
self.inner.lock().unwrap().get_funding_txo().clone()

lightning/src/ln/channel.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,6 +2000,18 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
20002000
self.update_time_counter
20012001
}
20022002

2003+
pub fn get_commitment_secret(&self) -> CounterpartyCommitmentSecrets {
2004+
self.commitment_secrets.clone()
2005+
}
2006+
2007+
pub fn get_channel_keys_id(&self) -> [u8;32] {
2008+
self.channel_keys_id
2009+
}
2010+
2011+
pub fn get_commitment_txn_number_obscure_factor(&self) -> u64 {
2012+
get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound())
2013+
}
2014+
20032015
pub fn get_latest_monitor_update_id(&self) -> u64 {
20042016
self.latest_monitor_update_id
20052017
}

lightning/src/ln/channelmanager.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, Paym
3737
use crate::chain;
3838
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
3939
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
40-
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};
40+
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};
4141
use crate::chain::transaction::{OutPoint, TransactionData};
4242
use crate::events;
4343
use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, PaymentFailureReason};
@@ -2122,6 +2122,7 @@ where
21222122
entropy_source: ES,
21232123
node_signer: NS,
21242124
signer_provider: SP,
2125+
our_peer_storage: FairRwLock<OurPeerStorage>,
21252126
peer_storage: Mutex<HashMap<PublicKey, Vec<u8>>>,
21262127
logger: L,
21272128
}
@@ -2901,6 +2902,7 @@ where
29012902
entropy_source,
29022903
node_signer,
29032904
signer_provider,
2905+
our_peer_storage: FairRwLock::new(OurPeerStorage::new()),
29042906
peer_storage: Mutex::new(new_hash_map()),
29052907
logger,
29062908
}
@@ -6286,6 +6288,8 @@ where
62866288
chan_id, action);
62876289
peer_state.monitor_update_blocked_actions.entry(chan_id).or_insert(Vec::new()).push(action);
62886290
}
6291+
6292+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
62896293
if !during_init {
62906294
handle_new_monitor_update!(self, prev_hop.outpoint, monitor_update, peer_state_lock,
62916295
peer_state, per_peer_state, chan);
@@ -7294,7 +7298,12 @@ where
72947298
let mut pending_events = self.pending_events.lock().unwrap();
72957299
emit_channel_ready_event!(pending_events, chan);
72967300
}
7297-
7301+
// Update Peer Storage.
7302+
let stub_chan = StubChannel::new(chan.context.channel_id(), chan.context.get_funding_txo().unwrap(), chan.context.get_value_satoshis(),
7303+
chan.context.get_channel_keys_id(), chan.context.get_commitment_secret(),
7304+
chan.context.get_counterparty_node_id(), chan.context.get_commitment_txn_number_obscure_factor(), new_hash_map(),
7305+
None, chan.context.channel_transaction_parameters.channel_type_features.clone());
7306+
self.our_peer_storage.write().unwrap().stub_channel(stub_chan);
72987307
Ok(())
72997308
} else {
73007309
try_chan_phase_entry!(self, Err(ChannelError::close(
@@ -7641,6 +7650,7 @@ where
76417650
let funding_txo = chan.context.get_funding_txo();
76427651
let monitor_update_opt = try_chan_phase_entry!(self, chan.commitment_signed(&msg, &&logger), chan_phase_entry);
76437652
if let Some(monitor_update) = monitor_update_opt {
7653+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
76447654
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update, peer_state_lock,
76457655
peer_state, per_peer_state, chan);
76467656
}
@@ -7837,6 +7847,9 @@ where
78377847
if let Some(monitor_update) = monitor_update_opt {
78387848
let funding_txo = funding_txo_opt
78397849
.expect("Funding outpoint must have been set for RAA handling to succeed");
7850+
7851+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
7852+
78407853
handle_new_monitor_update!(self, funding_txo, monitor_update,
78417854
peer_state_lock, peer_state, per_peer_state, chan);
78427855
}
@@ -8180,6 +8193,7 @@ where
81808193
}
81818194
if let Some(monitor_update) = monitor_opt {
81828195
has_monitor_update = true;
8196+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
81838197

81848198
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
81858199
peer_state_lock, peer_state, per_peer_state, chan);
@@ -11363,6 +11377,8 @@ where
1136311377
let mut channel_closures = VecDeque::new();
1136411378
let mut close_background_events = Vec::new();
1136511379
let mut funding_txo_to_channel_id = hash_map_with_capacity(channel_count as usize);
11380+
let mut our_peer_storage: OurPeerStorage = OurPeerStorage::new();
11381+
1136611382
for _ in 0..channel_count {
1136711383
let mut channel: Channel<SP> = Channel::read(reader, (
1136811384
&args.entropy_source, &args.signer_provider, best_block_height, &provided_channel_type_features(&args.default_config)
@@ -11371,7 +11387,32 @@ where
1137111387
let funding_txo = channel.context.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
1137211388
funding_txo_to_channel_id.insert(funding_txo, channel.context.channel_id());
1137311389
funding_txo_set.insert(funding_txo.clone());
11390+
let stub_chan = StubChannel::new(
11391+
channel.context.channel_id(),
11392+
funding_txo,
11393+
channel.context.get_value_satoshis(),
11394+
channel.context.get_channel_keys_id(),
11395+
channel.context.get_commitment_secret(),
11396+
channel.context.get_counterparty_node_id(),
11397+
channel.context.get_commitment_txn_number_obscure_factor(),
11398+
new_hash_map(),
11399+
None,
11400+
channel.context.channel_transaction_parameters.channel_type_features.clone(),
11401+
);
11402+
our_peer_storage.stub_channel(stub_chan);
1137411403
if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
11404+
if let Some(latest_commitment_txn_info) = monitor.get_latest_commitment_txn_and_its_claiming_info() {
11405+
11406+
let mut htlc_data = latest_commitment_txn_info.1;
11407+
11408+
// We do not need HTLCSource to be backed up.
11409+
for htlc in &mut htlc_data {
11410+
htlc.1 = None;
11411+
}
11412+
11413+
our_peer_storage.update_latest_state(monitor.channel_id(), latest_commitment_txn_info.0, htlc_data, latest_commitment_txn_info.2);
11414+
}
11415+
1137511416
if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() ||
1137611417
channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() ||
1137711418
channel.get_cur_counterparty_commitment_transaction_number() > monitor.get_cur_counterparty_commitment_number() ||
@@ -12215,6 +12256,7 @@ where
1221512256

1221612257
last_days_feerates: Mutex::new(VecDeque::new()),
1221712258

12259+
our_peer_storage: FairRwLock::new(our_peer_storage),
1221812260
peer_storage: Mutex::new(peer_storage),
1221912261
logger: args.logger,
1222012262
default_configuration: args.default_config,

0 commit comments

Comments
 (0)