Skip to content

Commit 98906dc

Browse files
channelmanager: add fake_scid module
XXX
1 parent fa56136 commit 98906dc

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,103 @@ mod inbound_payment {
338338
}
339339
}
340340

341+
mod fake_scid {
342+
use bitcoin::blockdata::constants::genesis_block;
343+
use bitcoin::hash_types::BlockHash;
344+
use bitcoin::network::constants::Network;
345+
use chain::keysinterface::{Sign, KeysInterface};
346+
use ln::channelmanager::DecodeError;
347+
use util::scid_utils;
348+
use util::ser::Readable;
349+
350+
use core::convert::TryInto;
351+
use core::ops::Deref;
352+
353+
const TEST_SEGWIT_ACTIVATION_HEIGHT: u32 = 0;
354+
const MAINNET_SEGWIT_ACTIVATION_HEIGHT: u32 = 481_824;
355+
const MAX_TX_INDEX: u32 = 2_500;
356+
const MAX_VOUT: u16 = 10_000;
357+
const MAX_NAMESPACES: u8 = 8;
358+
const NAMESPACE_TYPE_BITMASK: u8 = 0b111;
359+
360+
pub(super) enum Namespace {
361+
Phantom(u8),
362+
// Coming soon: a variant for the zero-conf scid namespace
363+
}
364+
365+
impl Namespace {
366+
pub(super) fn get_fake_scid<Signer: Sign, K: Deref>(&self, highest_seen_blockheight: u32, genesis_hash: &BlockHash, keys_manager: &K) -> u64
367+
where K::Target: KeysInterface<Signer = Signer>,
368+
{
369+
let scid_namespace = self.as_u8();
370+
let rand_bytes = keys_manager.get_secure_random_bytes();
371+
372+
let valid_block_range = highest_seen_blockheight - segwit_activation_height(genesis_hash);
373+
let rand_value_for_height = u32::from_be_bytes(rand_bytes[..4].try_into().unwrap());
374+
let fake_scid_height = segwit_activation_height(genesis_hash) + rand_value_for_height % valid_block_range;
375+
376+
let rand_i32 = i32::from_be_bytes(rand_bytes[4..8].try_into().unwrap()).abs();
377+
let rand_tx_index = rand_i32 % (MAX_TX_INDEX as i32);
378+
let offset = (scid_namespace as i32 - rand_tx_index) % (MAX_NAMESPACES as i32);
379+
let fake_scid_tx_index: u64 = (rand_tx_index + offset) as u64;
380+
381+
let rand_value_for_vout = u16::from_be_bytes(rand_bytes[8..10].try_into().unwrap());
382+
let fake_scid_vout_index = rand_value_for_vout % MAX_VOUT;
383+
scid_utils::scid_from_parts(fake_scid_height as u64, fake_scid_tx_index, fake_scid_vout_index as u64).unwrap()
384+
}
385+
386+
fn as_u8(&self) -> u8 {
387+
match self {
388+
Namespace::Phantom(namespace) => *namespace,
389+
}
390+
}
391+
392+
pub(super) fn phantom<Signer: Sign, K: Deref>(keys_manager: &K) -> Namespace
393+
where K::Target: KeysInterface<Signer = Signer>,
394+
{
395+
let phantom_scid_namespace_rand_bytes = keys_manager.get_secure_random_bytes();
396+
let phantom_scid_namespace = phantom_scid_namespace_rand_bytes[0] & NAMESPACE_TYPE_BITMASK;
397+
Namespace::Phantom(phantom_scid_namespace)
398+
}
399+
}
400+
401+
// XXX test
402+
fn segwit_activation_height(genesis: &BlockHash) -> u32 {
403+
if genesis_block(Network::Bitcoin).header.block_hash() == *genesis {
404+
MAINNET_SEGWIT_ACTIVATION_HEIGHT
405+
} else {
406+
TEST_SEGWIT_ACTIVATION_HEIGHT
407+
}
408+
}
409+
410+
// XXX docs, test
411+
pub(super) fn is_valid(namespace: &Namespace, scid: u64) -> bool {
412+
scid_utils::tx_index_from_scid(&scid) % MAX_NAMESPACES as u32 == namespace.as_u8() as u32
413+
}
414+
415+
impl_writeable_tlv_based_enum!(Namespace, ;
416+
(0, Phantom),
417+
);
418+
419+
#[cfg(test)]
420+
mod tests {
421+
use bitcoin::network::constants::Network;
422+
use ln::channelmanager::fake_scid::{Namespace, NAMESPACE_TYPE_BITMASK};
423+
use util::test_utils;
424+
use sync::Arc;
425+
426+
#[test]
427+
fn namespace_is_within_range() {
428+
let seed = [0 as u8; 32];
429+
let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet));
430+
let Namespace::Phantom(ns) = Namespace::phantom(&keys_manager);
431+
assert!(ns <= NAMESPACE_TYPE_BITMASK);
432+
}
433+
// XXX tests for get_fake_scid
434+
}
435+
}
436+
437+
341438
// We hold various information about HTLC relay in the HTLC objects in Channel itself:
342439
//
343440
// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
@@ -960,6 +1057,8 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
9601057

9611058
inbound_payment_key: inbound_payment::ExpandedKey,
9621059

1060+
phantom_scid_namespace: fake_scid::Namespace,
1061+
9631062
/// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
9641063
/// value increases strictly since we don't assume access to a time source.
9651064
last_node_announcement_serial: AtomicUsize,
@@ -1655,6 +1754,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
16551754
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
16561755
let inbound_pmt_key_material = keys_manager.get_inbound_payment_key_material();
16571756
let expanded_inbound_key = inbound_payment::ExpandedKey::new(&inbound_pmt_key_material);
1757+
let phantom_scid_namespace = fake_scid::Namespace::phantom(&keys_manager);
16581758
ChannelManager {
16591759
default_configuration: config.clone(),
16601760
genesis_hash: genesis_block(params.network).header.block_hash(),
@@ -1680,6 +1780,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
16801780

16811781
inbound_payment_key: expanded_inbound_key,
16821782

1783+
phantom_scid_namespace,
1784+
16831785
last_node_announcement_serial: AtomicUsize::new(0),
16841786
highest_seen_timestamp: AtomicUsize::new(0),
16851787

@@ -6145,6 +6247,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
61456247
write_tlv_fields!(writer, {
61466248
(1, pending_outbound_payments_no_retry, required),
61476249
(3, pending_outbound_payments, required),
6250+
(5, self.phantom_scid_namespace, required),
61486251
});
61496252

61506253
Ok(())
@@ -6439,10 +6542,16 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
64396542
// pending_outbound_payments_no_retry is for compatibility with 0.0.101 clients.
64406543
let mut pending_outbound_payments_no_retry: Option<HashMap<PaymentId, HashSet<[u8; 32]>>> = None;
64416544
let mut pending_outbound_payments = None;
6545+
let mut phantom_scid_namespace: Option<fake_scid::Namespace> = None;
64426546
read_tlv_fields!(reader, {
64436547
(1, pending_outbound_payments_no_retry, option),
64446548
(3, pending_outbound_payments, option),
6549+
(5, phantom_scid_namespace, option),
64456550
});
6551+
if phantom_scid_namespace.is_none() {
6552+
phantom_scid_namespace = Some(fake_scid::Namespace::phantom(&args.keys_manager));
6553+
}
6554+
64466555
if pending_outbound_payments.is_none() && pending_outbound_payments_no_retry.is_none() {
64476556
pending_outbound_payments = Some(pending_outbound_payments_compat);
64486557
} else if pending_outbound_payments.is_none() {
@@ -6525,6 +6634,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
65256634
inbound_payment_key: expanded_inbound_key,
65266635
pending_inbound_payments: Mutex::new(pending_inbound_payments),
65276636
pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
6637+
phantom_scid_namespace: phantom_scid_namespace.unwrap(),
65286638

65296639
our_network_key: args.keys_manager.get_node_secret(),
65306640
our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()),

0 commit comments

Comments
 (0)