Skip to content

Commit ededeb5

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 dd85c77 commit ededeb5

File tree

3 files changed

+280
-3
lines changed

3 files changed

+280
-3
lines changed

lightning/src/chain/channelmonitor.rs

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

1656+
/// Gets the latest claiming info from the ChannelMonitor to update our PeerStorageBackup.
1657+
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>)>)> {
1658+
let lock = self.inner.lock().unwrap();
1659+
if let Some(latest_txid) = lock.current_counterparty_commitment_txid {
1660+
return Some((
1661+
latest_txid, lock.counterparty_claimable_outpoints.get(&latest_txid).unwrap().clone(),
1662+
lock.their_cur_per_commitment_points
1663+
))
1664+
}
1665+
1666+
None
1667+
}
1668+
14611669
/// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for.
14621670
pub fn get_funding_txo(&self) -> (OutPoint, ScriptBuf) {
14631671
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, ReplayEvent};
@@ -2232,6 +2232,7 @@ where
22322232
entropy_source: ES,
22332233
node_signer: NS,
22342234
signer_provider: SP,
2235+
our_peer_storage: FairRwLock<OurPeerStorage>,
22352236
peer_storage: Mutex<HashMap<PublicKey, Vec<u8>>>,
22362237
logger: L,
22372238
}
@@ -3022,6 +3023,7 @@ where
30223023
entropy_source,
30233024
node_signer,
30243025
signer_provider,
3026+
our_peer_storage: FairRwLock::new(OurPeerStorage::new()),
30253027
peer_storage: Mutex::new(new_hash_map()),
30263028
logger,
30273029
}
@@ -6452,6 +6454,8 @@ where
64526454
if let Some(raa_blocker) = raa_blocker_opt {
64536455
peer_state.actions_blocking_raa_monitor_updates.entry(chan_id).or_insert_with(Vec::new).push(raa_blocker);
64546456
}
6457+
6458+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
64556459
if !during_init {
64566460
handle_new_monitor_update!(self, prev_hop.outpoint, monitor_update, peer_state_lock,
64576461
peer_state, per_peer_state, chan);
@@ -7555,7 +7559,17 @@ where
75557559
let mut pending_events = self.pending_events.lock().unwrap();
75567560
emit_channel_ready_event!(pending_events, chan);
75577561
}
7558-
7562+
// Update Peer Storage.
7563+
let counterparty_channel_parameters = chan.context.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap();
7564+
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
7565+
let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint;
7566+
let stub_chan = StubChannel::new(chan.context.channel_id(), chan.context.get_funding_txo().unwrap(), chan.context.get_value_satoshis(),
7567+
chan.context.get_channel_keys_id(), chan.context.get_commitment_secret(),
7568+
chan.context.get_counterparty_node_id(), counterparty_delayed_payment_base_key, counterparty_htlc_base_key,
7569+
chan.context.get_holder_selected_contest_delay(),
7570+
chan.context.get_commitment_txn_number_obscure_factor(), new_hash_map(),
7571+
None, chan.context.channel_transaction_parameters.channel_type_features.clone());
7572+
self.our_peer_storage.write().unwrap().stub_channel(stub_chan);
75597573
Ok(())
75607574
} else {
75617575
try_chan_phase_entry!(self, Err(ChannelError::close(
@@ -7902,6 +7916,7 @@ where
79027916
let funding_txo = chan.context.get_funding_txo();
79037917
let monitor_update_opt = try_chan_phase_entry!(self, chan.commitment_signed(&msg, &&logger), chan_phase_entry);
79047918
if let Some(monitor_update) = monitor_update_opt {
7919+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
79057920
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update, peer_state_lock,
79067921
peer_state, per_peer_state, chan);
79077922
}
@@ -8102,9 +8117,15 @@ where
81028117
} else { false };
81038118
let (htlcs_to_fail, monitor_update_opt) = try_chan_phase_entry!(self,
81048119
chan.revoke_and_ack(&msg, &self.fee_estimator, &&logger, mon_update_blocked), chan_phase_entry);
8120+
8121+
let mut our_peer_storage = self.our_peer_storage.write().unwrap();
8122+
let _ = our_peer_storage.provide_secret(chan.context.channel_id(), chan.get_cur_counterparty_commitment_transaction_number() + 1, msg.per_commitment_secret);
81058123
if let Some(monitor_update) = monitor_update_opt {
81068124
let funding_txo = funding_txo_opt
81078125
.expect("Funding outpoint must have been set for RAA handling to succeed");
8126+
8127+
let _ = our_peer_storage.update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
8128+
81088129
handle_new_monitor_update!(self, funding_txo, monitor_update,
81098130
peer_state_lock, peer_state, per_peer_state, chan);
81108131
}
@@ -8448,6 +8469,7 @@ where
84488469
}
84498470
if let Some(monitor_update) = monitor_opt {
84508471
has_monitor_update = true;
8472+
let _ = self.our_peer_storage.write().unwrap().update_state_from_monitor_update(chan.context.channel_id(), monitor_update.clone());
84518473

84528474
handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
84538475
peer_state_lock, peer_state, per_peer_state, chan);
@@ -11690,6 +11712,8 @@ where
1169011712
let mut channel_closures = VecDeque::new();
1169111713
let mut close_background_events = Vec::new();
1169211714
let mut funding_txo_to_channel_id = hash_map_with_capacity(channel_count as usize);
11715+
let mut our_peer_storage: OurPeerStorage = OurPeerStorage::new();
11716+
1169311717
for _ in 0..channel_count {
1169411718
let mut channel: Channel<SP> = Channel::read(reader, (
1169511719
&args.entropy_source, &args.signer_provider, best_block_height, &provided_channel_type_features(&args.default_config)
@@ -11698,7 +11722,39 @@ where
1169811722
let funding_txo = channel.context.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
1169911723
funding_txo_to_channel_id.insert(funding_txo, channel.context.channel_id());
1170011724
funding_txo_set.insert(funding_txo.clone());
11725+
let counterparty_channel_parameters = channel.context.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap();
11726+
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
11727+
let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint;
11728+
11729+
let stub_chan = StubChannel::new(
11730+
channel.context.channel_id(),
11731+
funding_txo,
11732+
channel.context.get_value_satoshis(),
11733+
channel.context.get_channel_keys_id(),
11734+
channel.context.get_commitment_secret(),
11735+
channel.context.get_counterparty_node_id(),
11736+
counterparty_delayed_payment_base_key,
11737+
counterparty_htlc_base_key,
11738+
channel.context.get_holder_selected_contest_delay(),
11739+
channel.context.get_commitment_txn_number_obscure_factor(),
11740+
new_hash_map(),
11741+
None,
11742+
channel.context.channel_transaction_parameters.channel_type_features.clone(),
11743+
);
11744+
our_peer_storage.stub_channel(stub_chan);
1170111745
if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
11746+
if let Some(latest_commitment_txn_info) = monitor.get_latest_commitment_txn_and_its_claiming_info() {
11747+
11748+
let mut htlc_data = latest_commitment_txn_info.1;
11749+
11750+
// We do not need HTLCSource to be backed up.
11751+
for htlc in &mut htlc_data {
11752+
htlc.1 = None;
11753+
}
11754+
11755+
our_peer_storage.update_latest_state(monitor.channel_id(), latest_commitment_txn_info.0, htlc_data, latest_commitment_txn_info.2);
11756+
}
11757+
1170211758
if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() ||
1170311759
channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() ||
1170411760
channel.get_cur_counterparty_commitment_transaction_number() > monitor.get_cur_counterparty_commitment_number() ||
@@ -12542,6 +12598,7 @@ where
1254212598

1254312599
last_days_feerates: Mutex::new(VecDeque::new()),
1254412600

12601+
our_peer_storage: FairRwLock::new(our_peer_storage),
1254512602
peer_storage: Mutex::new(peer_storage),
1254612603
logger: args.logger,
1254712604
default_configuration: args.default_config,

0 commit comments

Comments
 (0)