1use crate::channel::{ChannelUpdateChannelFlags, ChannelUpdateMessageFlags};
8use crate::gen::fiber as molecule_fiber;
9use crate::gen::gossip as molecule_gossip;
10use crate::primitives::u8_32_as_byte_32;
11use crate::serde_utils::EntityHex;
12use crate::UdtCfgInfos;
13use crate::{Hash256, Privkey, Pubkey};
14use ckb_types::packed::{BytesVec, OutPoint, Script};
15use ckb_types::prelude::Pack;
16use molecule::prelude::{Builder, Byte, Entity};
17use musig2::LiftedSignature;
18use serde::{Deserialize, Deserializer, Serialize, Serializer};
19use serde_with::serde_as;
20use std::cmp::Ordering;
21use std::time::Duration;
22
23pub const CURSOR_SIZE: usize = 45;
25pub use feature_bits::*;
26
27type Secp256k1Signature = secp256k1::ecdsa::Signature;
28
29#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
31pub struct EcdsaSignature(pub Secp256k1Signature);
32
33impl EcdsaSignature {
34 pub fn verify(&self, pubkey: &Pubkey, message: &[u8; 32]) -> bool {
35 let message = secp256k1::Message::from_digest(*message);
36 let pk = secp256k1::PublicKey::from_slice(&pubkey.0)
37 .expect("Pubkey should always contain valid serialized public key");
38 secp256k1::SECP256K1
39 .verify_ecdsa(&message, &self.0, &pk)
40 .is_ok()
41 }
42}
43
44impl From<EcdsaSignature> for Secp256k1Signature {
45 fn from(sig: EcdsaSignature) -> Self {
46 sig.0
47 }
48}
49
50impl From<Secp256k1Signature> for EcdsaSignature {
51 fn from(sig: Secp256k1Signature) -> Self {
52 Self(sig)
53 }
54}
55
56impl From<EcdsaSignature> for molecule_fiber::EcdsaSignature {
59 fn from(signature: EcdsaSignature) -> molecule_fiber::EcdsaSignature {
60 molecule_fiber::EcdsaSignature::new_builder()
61 .set(
62 signature
63 .0
64 .serialize_compact()
65 .into_iter()
66 .map(Into::into)
67 .collect::<Vec<Byte>>()
68 .try_into()
69 .expect("Signature serialized to correct length"),
70 )
71 .build()
72 }
73}
74
75impl TryFrom<molecule_fiber::EcdsaSignature> for EcdsaSignature {
76 type Error = secp256k1::Error;
77
78 fn try_from(signature: molecule_fiber::EcdsaSignature) -> Result<Self, Self::Error> {
79 let signature = signature.raw_data();
80 Secp256k1Signature::from_compact(&signature).map(Into::into)
81 }
82}
83
84#[derive(Eq, PartialEq, Copy, Clone, Default, Hash)]
88pub struct AnnouncedNodeName(pub [u8; 32]);
89
90impl AnnouncedNodeName {
91 pub fn as_bytes(&self) -> &[u8; 32] {
92 &self.0
93 }
94
95 pub fn from_slice(slice: &[u8]) -> Result<Self, String> {
96 if slice.len() > 32 {
97 return Err("Node Alias can not be longer than 32 bytes".to_string());
98 }
99 let end = slice.iter().position(|&b| b == 0).unwrap_or(slice.len());
100 let name = std::str::from_utf8(&slice[..end]).map_err(|err| err.to_string())?;
101 if name.chars().any(|c| c.is_control()) {
102 return Err("Node announce name can not contain control chars".to_string());
103 }
104
105 let mut bytes = [0; 32];
106 bytes[..slice.len()].copy_from_slice(slice);
107 Ok(Self(bytes))
108 }
109
110 pub fn from_string(value: &str) -> Result<Self, String> {
111 let str_bytes = value.as_bytes();
112 Self::from_slice(str_bytes)
113 }
114
115 fn try_as_str(&self) -> Result<&str, std::str::Utf8Error> {
116 let end = self.0.iter().position(|&b| b == 0).unwrap_or(self.0.len());
117 if end == 0 {
118 return Ok("");
119 }
120 std::str::from_utf8(&self.0[..end])
121 }
122
123 pub fn as_str(&self) -> &str {
124 self.try_as_str().unwrap_or_default()
125 }
126}
127
128impl std::fmt::Display for AnnouncedNodeName {
129 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
130 write!(f, "{}", self.as_str())
131 }
132}
133
134impl std::fmt::Debug for AnnouncedNodeName {
135 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
136 write!(f, "AnnouncedNodeName({})", self)
137 }
138}
139
140impl<'s> From<&'s str> for AnnouncedNodeName {
141 fn from(value: &'s str) -> Self {
142 Self::from_string(value).expect("Valid announced node name")
143 }
144}
145
146impl Serialize for AnnouncedNodeName {
147 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
148 where
149 S: Serializer,
150 {
151 serializer.serialize_str(self.try_as_str().map_err(serde::ser::Error::custom)?)
152 }
153}
154
155impl<'de> Deserialize<'de> for AnnouncedNodeName {
156 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
157 where
158 D: Deserializer<'de>,
159 {
160 let s = String::deserialize(deserializer)?;
161 Self::from_string(&s).map_err(serde::de::Error::custom)
162 }
163}
164
165pub type FeatureBit = u16;
167
168#[macro_export]
176macro_rules! declare_feature_bits_and_methods {
177 (
178 $( $name:ident, $odd:expr; )*
179 ) => {
180 paste::paste! {
181 $(
182 pub const [<$name _REQUIRED>]: u16 = $odd - 1;
184 pub const [<$name _OPTIONAL>]: u16 = $odd;
186 )*
187
188 pub const MAX_FEATURE_BIT: u16 = {
189 let mut max = 0;
190 $(
191 if $odd % 2 == 0 || $odd <= max {
192 panic!("feature base bit must be defined as increasing odd numbers");
193 }
194 max = $odd;
195 )*
196 max
197 };
198
199 pub fn feature_bit_name(bit: FeatureBit) -> &'static str {
200 match bit {
201 $(
202 [<$name _REQUIRED>] => stringify!([<$name _REQUIRED>]),
203 [<$name _OPTIONAL>] => stringify!([<$name _OPTIONAL>]),
204 )*
205 _ => "Unknown Feature",
206 }
207 }
208
209 impl FeatureVector {
210 $(
211 pub fn [<set_ $name:lower _required>](&mut self) {
212 self.set([<$name _REQUIRED>], true);
213 }
214 pub fn [<set_ $name:lower _optional>](&mut self) {
215 self.set([<$name _OPTIONAL>], true);
216 }
217 pub fn [<unset_ $name:lower _required>](&mut self) {
218 self.set([<$name _REQUIRED>], false);
219 }
220 pub fn [<unset_ $name:lower _optional>](&mut self) {
221 self.set([<$name _OPTIONAL>], false);
222 }
223 pub fn [<requires_ $name:lower>](&self) -> bool {
224 self.requires_feature([<$name _REQUIRED>])
225 }
226 pub fn [<supports_ $name:lower>](&self) -> bool {
227 self.supports_feature([<$name _OPTIONAL>])
228 }
229 )*
230 }
231 }
232 };
233}
234
235pub mod feature_bits {
241 use super::*;
242 declare_feature_bits_and_methods! {
243 GOSSIP_QUERIES, 1;
244 BASIC_MPP, 3;
245 TRAMPOLINE_ROUTING, 5;
246 }
248}
249
250#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
252pub struct FeatureVector {
253 inner: Vec<u8>,
254}
255
256impl Default for FeatureVector {
257 fn default() -> Self {
258 let mut feature = Self::new();
259 feature.set_gossip_queries_required();
260 feature.set_basic_mpp_required();
261 feature.set_trampoline_routing_required();
262
263 feature
267 }
268}
269
270impl FeatureVector {
271 pub fn new() -> Self {
272 let len = (feature_bits::MAX_FEATURE_BIT / 8) as usize + 1;
273 Self {
274 inner: vec![0; len],
275 }
276 }
277
278 pub fn from(bytes: Vec<u8>) -> Self {
279 Self { inner: bytes }
280 }
281
282 pub fn bytes(&self) -> Vec<u8> {
283 self.inner.clone()
284 }
285
286 fn is_set(&self, bit: FeatureBit) -> bool {
287 let idx = (bit / 8) as usize;
288 if idx >= self.inner.len() {
289 return false;
290 }
291 self.inner
292 .get(idx)
293 .map(|&byte| (byte >> (bit % 8)) & 1 == 1)
294 .unwrap_or(false)
295 }
296
297 fn set(&mut self, bit: FeatureBit, set: bool) {
298 let idx = (bit / 8) as usize;
299 if self.inner.len() <= idx {
300 self.inner.resize(idx + 1, 0);
301 }
302 let mask = 1 << (bit % 8);
303 if set {
304 self.inner[idx] |= mask;
305 } else {
306 self.inner[idx] &= !mask;
307 }
308 }
309
310 pub fn enabled_features(&self) -> Vec<FeatureBit> {
311 (0..(self.inner.len() * 8) as FeatureBit)
312 .filter(|&bit| self.is_set(bit))
313 .collect()
314 }
315
316 pub fn enabled_features_names(&self) -> Vec<String> {
317 self.enabled_features()
318 .into_iter()
319 .map(feature_bits::feature_bit_name)
320 .map(|name| name.to_string())
321 .collect()
322 }
323
324 pub fn is_empty(&self) -> bool {
325 self.inner.iter().all(|&b| b == 0)
326 }
327
328 pub fn set_feature(&mut self, bit: FeatureBit) {
329 self.set(bit, true);
330 }
331
332 pub fn unset_feature(&mut self, bit: FeatureBit) {
333 self.set(bit, false);
334 }
335
336 pub fn requires_feature(&self, bit: FeatureBit) -> bool {
337 self.is_set(bit) && bit.is_multiple_of(2)
338 }
339
340 pub fn supports_feature(&self, bit: FeatureBit) -> bool {
341 self.is_set(bit) || self.is_set(bit ^ 1)
342 }
343
344 pub fn compatible_with(&self, other: &Self) -> bool {
345 if self
346 .enabled_features()
347 .iter()
348 .any(|&bit| self.requires_feature(bit) && !other.supports_feature(bit))
349 {
350 return false;
351 }
352 true
353 }
354}
355
356impl std::fmt::Debug for FeatureVector {
357 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358 f.debug_struct("FeatureVector")
359 .field("features", &self.enabled_features_names())
360 .finish()
361 }
362}
363
364#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
366pub struct SchnorrSignature(pub secp256k1::schnorr::Signature);
367
368impl SchnorrSignature {
369 pub fn inner(&self) -> &secp256k1::schnorr::Signature {
371 &self.0
372 }
373
374 pub fn to_byte_array(&self) -> [u8; 64] {
376 self.0.to_byte_array()
377 }
378
379 pub fn from_slice(data: &[u8]) -> Result<Self, secp256k1::Error> {
381 secp256k1::schnorr::Signature::from_slice(data).map(SchnorrSignature)
382 }
383}
384
385impl std::ops::Deref for SchnorrSignature {
386 type Target = secp256k1::schnorr::Signature;
387
388 fn deref(&self) -> &Self::Target {
389 &self.0
390 }
391}
392
393impl From<SchnorrSignature> for secp256k1::schnorr::Signature {
394 fn from(sig: SchnorrSignature) -> Self {
395 sig.0
396 }
397}
398
399impl From<secp256k1::schnorr::Signature> for SchnorrSignature {
400 fn from(sig: secp256k1::schnorr::Signature) -> Self {
401 Self(sig)
402 }
403}
404
405impl From<LiftedSignature> for SchnorrSignature {
406 fn from(sig: LiftedSignature) -> Self {
407 Self(secp256k1::schnorr::Signature::from(sig))
408 }
409}
410
411impl From<SchnorrSignature> for molecule_gossip::SchnorrSignature {
414 fn from(signature: SchnorrSignature) -> molecule_gossip::SchnorrSignature {
415 molecule_gossip::SchnorrSignature::new_builder()
416 .set(
417 signature
418 .0
419 .to_byte_array()
420 .into_iter()
421 .map(Into::into)
422 .collect::<Vec<Byte>>()
423 .try_into()
424 .expect("Signature serialized to correct length"),
425 )
426 .build()
427 }
428}
429
430impl TryFrom<molecule_gossip::SchnorrSignature> for SchnorrSignature {
431 type Error = secp256k1::Error;
432
433 fn try_from(signature: molecule_gossip::SchnorrSignature) -> Result<Self, Self::Error> {
434 secp256k1::schnorr::Signature::from_slice(signature.as_slice()).map(Into::into)
435 }
436}
437
438#[serde_as]
443#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)]
444pub struct ChannelAnnouncement {
445 pub node1_signature: Option<EcdsaSignature>,
447 pub node2_signature: Option<EcdsaSignature>,
449 pub ckb_signature: Option<SchnorrSignature>,
451 pub features: u64,
453 pub chain_hash: Hash256,
455 #[serde_as(as = "EntityHex")]
457 pub channel_outpoint: OutPoint,
458 pub node1_id: Pubkey,
460 pub node2_id: Pubkey,
462 pub ckb_key: secp256k1::XOnlyPublicKey,
464 pub capacity: u128,
466 #[serde_as(as = "Option<EntityHex>")]
468 pub udt_type_script: Option<Script>,
469}
470
471impl ChannelAnnouncement {
472 pub fn is_signed(&self) -> bool {
474 self.node1_signature.is_some()
475 && self.node2_signature.is_some()
476 && self.ckb_signature.is_some()
477 }
478
479 pub fn out_point(&self) -> &OutPoint {
481 &self.channel_outpoint
482 }
483
484 pub fn new_unsigned(
486 node1_pubkey: &Pubkey,
487 node2_pubkey: &Pubkey,
488 channel_outpoint: OutPoint,
489 chain_hash: Hash256,
490 ckb_pubkey: &secp256k1::XOnlyPublicKey,
491 capacity: u128,
492 udt_type_script: Option<Script>,
493 ) -> Self {
494 Self {
495 node1_signature: None,
496 node2_signature: None,
497 ckb_signature: None,
498 features: Default::default(),
499 chain_hash,
500 channel_outpoint,
501 node1_id: *node1_pubkey,
502 node2_id: *node2_pubkey,
503 ckb_key: *ckb_pubkey,
504 capacity,
505 udt_type_script,
506 }
507 }
508}
509
510#[serde_as]
515#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Hash)]
516pub struct ChannelUpdate {
517 pub signature: Option<EcdsaSignature>,
519 pub chain_hash: Hash256,
521 #[serde_as(as = "EntityHex")]
523 pub channel_outpoint: OutPoint,
524 pub timestamp: u64,
526 pub message_flags: ChannelUpdateMessageFlags,
528 pub channel_flags: ChannelUpdateChannelFlags,
530 pub tlc_expiry_delta: u64,
532 pub tlc_minimum_value: u128,
534 pub tlc_fee_proportional_millionths: u128,
536}
537
538impl ChannelUpdate {
539 pub fn is_update_of_node_1(&self) -> bool {
541 !self.is_update_of_node_2()
542 }
543
544 pub fn is_update_of_node_2(&self) -> bool {
546 self.message_flags
547 .contains(ChannelUpdateMessageFlags::UPDATE_OF_NODE2)
548 }
549
550 pub fn is_disabled(&self) -> bool {
552 self.channel_flags
553 .contains(ChannelUpdateChannelFlags::DISABLED)
554 }
555
556 pub fn message_to_sign(&self) -> [u8; 32] {
558 let unsigned_update = ChannelUpdate {
559 signature: None,
560 chain_hash: self.chain_hash,
561 channel_outpoint: self.channel_outpoint.clone(),
562 timestamp: self.timestamp,
563 message_flags: self.message_flags,
564 channel_flags: self.channel_flags,
565 tlc_expiry_delta: self.tlc_expiry_delta,
566 tlc_minimum_value: self.tlc_minimum_value,
567 tlc_fee_proportional_millionths: self.tlc_fee_proportional_millionths,
568 };
569 deterministically_hash(&molecule_fiber::ChannelUpdate::from(unsigned_update))
570 }
571
572 pub fn cursor(&self) -> Cursor {
574 Cursor::new(
575 self.timestamp,
576 BroadcastMessageID::ChannelUpdate(self.channel_outpoint.clone()),
577 )
578 }
579}
580
581impl ChannelAnnouncement {
582 pub fn message_to_sign(&self) -> [u8; 32] {
584 let unsigned_announcement = Self {
585 node1_signature: None,
586 node2_signature: None,
587 ckb_signature: None,
588 features: self.features,
589 chain_hash: self.chain_hash,
590 channel_outpoint: self.channel_outpoint.clone(),
591 node1_id: self.node1_id,
592 node2_id: self.node2_id,
593 ckb_key: self.ckb_key,
594 capacity: self.capacity,
595 udt_type_script: self.udt_type_script.clone(),
596 };
597 deterministically_hash(&molecule_gossip::ChannelAnnouncement::from(
598 unsigned_announcement,
599 ))
600 }
601}
602
603impl NodeAnnouncement {
604 #[allow(clippy::too_many_arguments)]
609 pub fn new_unsigned(
610 node_name: AnnouncedNodeName,
611 features: FeatureVector,
612 addresses: Vec<tentacle_multiaddr::Multiaddr>,
613 node_id: Pubkey,
614 chain_hash: Hash256,
615 timestamp: u64,
616 auto_accept_min_ckb_funding_amount: u64,
617 udt_cfg_infos: UdtCfgInfos,
618 version: String,
619 ) -> Self {
620 Self {
621 signature: None,
622 features,
623 timestamp,
624 node_id,
625 version,
626 node_name,
627 chain_hash,
628 addresses,
629 auto_accept_min_ckb_funding_amount,
630 udt_cfg_infos,
631 }
632 }
633
634 #[allow(clippy::too_many_arguments)]
639 pub fn new_signed(
640 node_name: AnnouncedNodeName,
641 features: FeatureVector,
642 addresses: Vec<tentacle_multiaddr::Multiaddr>,
643 private_key: &Privkey,
644 chain_hash: Hash256,
645 timestamp: u64,
646 auto_accept_min_ckb_funding_amount: u64,
647 udt_cfg_infos: UdtCfgInfos,
648 version: String,
649 ) -> Self {
650 let mut unsigned = Self::new_unsigned(
651 node_name,
652 features,
653 addresses,
654 private_key.pubkey(),
655 chain_hash,
656 timestamp,
657 auto_accept_min_ckb_funding_amount,
658 udt_cfg_infos,
659 version,
660 );
661 unsigned.signature = Some(private_key.sign(unsigned.message_to_sign()));
662 unsigned
663 }
664
665 pub fn message_to_sign(&self) -> [u8; 32] {
667 let unsigned_announcement = NodeAnnouncement {
668 signature: None,
669 features: self.features.clone(),
670 timestamp: self.timestamp,
671 node_id: self.node_id,
672 version: self.version.clone(),
673 node_name: self.node_name,
674 chain_hash: self.chain_hash,
675 addresses: self.addresses.clone(),
676 auto_accept_min_ckb_funding_amount: self.auto_accept_min_ckb_funding_amount,
677 udt_cfg_infos: self.udt_cfg_infos.clone(),
678 };
679 deterministically_hash(&molecule_gossip::NodeAnnouncement::from(
680 unsigned_announcement,
681 ))
682 }
683
684 pub fn cursor(&self) -> Cursor {
686 Cursor::new(
687 self.timestamp,
688 BroadcastMessageID::NodeAnnouncement(self.node_id),
689 )
690 }
691
692 pub fn verify(&self) -> bool {
694 let message = self.message_to_sign();
695 match self.signature {
696 Some(ref signature) => signature.verify(&self.node_id, &message),
697 _ => false,
698 }
699 }
700}
701
702pub(crate) fn deterministically_hash<T: Entity>(v: &T) -> [u8; 32] {
704 ckb_hash::blake2b_256(v.as_slice())
705}
706
707#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
712pub enum BroadcastMessage {
713 NodeAnnouncement(NodeAnnouncement),
715 ChannelAnnouncement(ChannelAnnouncement),
717 ChannelUpdate(ChannelUpdate),
719}
720
721impl BroadcastMessage {
722 pub fn cursor(&self) -> Option<Cursor> {
724 match self {
725 BroadcastMessage::ChannelAnnouncement(_) => None,
726 BroadcastMessage::ChannelUpdate(channel_update) => Some(channel_update.cursor()),
727 BroadcastMessage::NodeAnnouncement(node_announcement) => {
728 Some(node_announcement.cursor())
729 }
730 }
731 }
732
733 pub fn message_id(&self) -> BroadcastMessageID {
735 match self {
736 BroadcastMessage::NodeAnnouncement(node_announcement) => {
737 BroadcastMessageID::NodeAnnouncement(node_announcement.node_id)
738 }
739 BroadcastMessage::ChannelAnnouncement(channel_announcement) => {
740 BroadcastMessageID::ChannelAnnouncement(
741 channel_announcement.channel_outpoint.clone(),
742 )
743 }
744 BroadcastMessage::ChannelUpdate(channel_update) => {
745 BroadcastMessageID::ChannelUpdate(channel_update.channel_outpoint.clone())
746 }
747 }
748 }
749
750 pub fn timestamp(&self) -> Option<u64> {
752 match self {
753 BroadcastMessage::NodeAnnouncement(node_announcement) => {
754 Some(node_announcement.timestamp)
755 }
756 BroadcastMessage::ChannelAnnouncement(_) => None,
757 BroadcastMessage::ChannelUpdate(channel_update) => Some(channel_update.timestamp),
758 }
759 }
760}
761
762#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
767pub struct NodeAnnouncement {
768 pub signature: Option<EcdsaSignature>,
770 pub features: FeatureVector,
772 pub timestamp: u64,
774 pub node_id: Pubkey,
776 pub version: String,
778 pub node_name: AnnouncedNodeName,
780 pub addresses: Vec<tentacle_multiaddr::Multiaddr>,
782 pub chain_hash: Hash256,
784 pub auto_accept_min_ckb_funding_amount: u64,
786 pub udt_cfg_infos: UdtCfgInfos,
788}
789
790#[derive(Debug, Clone, Eq, PartialEq, Hash)]
792pub enum BroadcastMessageID {
793 ChannelAnnouncement(OutPoint),
794 ChannelUpdate(OutPoint),
795 NodeAnnouncement(Pubkey),
796}
797
798impl Default for BroadcastMessageID {
799 fn default() -> Self {
800 BroadcastMessageID::ChannelAnnouncement(OutPoint::default())
801 }
802}
803
804impl Ord for BroadcastMessageID {
810 fn cmp(&self, other: &Self) -> Ordering {
811 match (self, other) {
812 (
813 BroadcastMessageID::ChannelAnnouncement(outpoint1),
814 BroadcastMessageID::ChannelAnnouncement(outpoint2),
815 ) => outpoint1.cmp(outpoint2),
816 (
817 BroadcastMessageID::ChannelUpdate(outpoint1),
818 BroadcastMessageID::ChannelUpdate(outpoint2),
819 ) => outpoint1.cmp(outpoint2),
820 (
821 BroadcastMessageID::NodeAnnouncement(node1),
822 BroadcastMessageID::NodeAnnouncement(node2),
823 ) => node1.cmp(node2),
824 (BroadcastMessageID::NodeAnnouncement(_), _) => Ordering::Less,
825 (BroadcastMessageID::ChannelUpdate(_), _) => Ordering::Greater,
826 (
827 BroadcastMessageID::ChannelAnnouncement(_),
828 BroadcastMessageID::NodeAnnouncement(_),
829 ) => Ordering::Greater,
830 (BroadcastMessageID::ChannelAnnouncement(_), BroadcastMessageID::ChannelUpdate(_)) => {
831 Ordering::Less
832 }
833 }
834 }
835}
836
837impl PartialOrd for BroadcastMessageID {
838 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
839 Some(self.cmp(other))
840 }
841}
842
843const MESSAGE_ID_SIZE: usize = 1 + 36;
845
846impl BroadcastMessageID {
847 pub fn to_bytes(&self) -> [u8; MESSAGE_ID_SIZE] {
848 let mut result = [0u8; MESSAGE_ID_SIZE];
849 match self {
850 BroadcastMessageID::ChannelAnnouncement(channel_outpoint) => {
851 result[0] = 0;
852 result[1..].copy_from_slice(&channel_outpoint.as_bytes());
853 }
854 BroadcastMessageID::ChannelUpdate(channel_outpoint) => {
855 result[0] = 1;
856 result[1..].copy_from_slice(&channel_outpoint.as_bytes());
857 }
858 BroadcastMessageID::NodeAnnouncement(node_id) => {
859 result[0] = 2;
860 let node_id = node_id.serialize();
861 result[1..1 + node_id.len()].copy_from_slice(&node_id);
862 }
863 };
864 result
865 }
866
867 pub fn from_bytes(bytes: &[u8]) -> Result<Self, anyhow::Error> {
868 use molecule::prelude::Entity;
869 if bytes.len() != MESSAGE_ID_SIZE {
870 anyhow::bail!("Invalid message id size: {}", bytes.len());
871 }
872 match bytes[0] {
873 0 => Ok(BroadcastMessageID::ChannelAnnouncement(
874 OutPoint::from_slice(&bytes[1..])?,
875 )),
876 1 => Ok(BroadcastMessageID::ChannelUpdate(OutPoint::from_slice(
877 &bytes[1..],
878 )?)),
879 2 => Ok(BroadcastMessageID::NodeAnnouncement(Pubkey::from_slice(
880 &bytes[1..1 + Pubkey::serialization_len()],
881 )?)),
882 _ => anyhow::bail!("Invalid message id type: {}", bytes[0]),
883 }
884 }
885}
886
887#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
889pub struct Cursor {
890 pub timestamp: u64,
891 pub message_id: BroadcastMessageID,
892}
893
894impl Cursor {
895 pub fn new(timestamp: u64, message_id: BroadcastMessageID) -> Self {
896 Self {
897 timestamp,
898 message_id,
899 }
900 }
901
902 pub fn go_back_for_some_time(&self, duration: Duration) -> Self {
905 let current_timestamp = self.timestamp;
906 let duration_millis = duration.as_millis() as u64;
907 if current_timestamp > duration_millis {
908 Self {
909 timestamp: current_timestamp - duration_millis,
910 message_id: self.message_id.clone(),
911 }
912 } else {
913 Default::default()
914 }
915 }
916
917 pub fn to_bytes(&self) -> [u8; 45] {
918 self.timestamp
919 .to_be_bytes()
920 .into_iter()
921 .chain(self.message_id.to_bytes())
922 .collect::<Vec<_>>()
923 .try_into()
924 .expect("Must serialize cursor to 45 bytes")
925 }
926
927 pub fn from_bytes(bytes: &[u8]) -> Result<Self, anyhow::Error> {
928 if bytes.len() != CURSOR_SIZE {
929 anyhow::bail!("Invalid cursor size: {}, want {}", bytes.len(), CURSOR_SIZE);
930 }
931 let timestamp = u64::from_be_bytes(bytes[..8].try_into().expect("Cursor timestamp to u64"));
932 let message_id = BroadcastMessageID::from_bytes(&bytes[8..])?;
933 Ok(Cursor {
934 timestamp,
935 message_id,
936 })
937 }
938
939 pub fn max() -> Self {
942 Self {
943 timestamp: u64::MAX,
944 message_id: BroadcastMessageID::ChannelAnnouncement(OutPoint::default()),
945 }
946 }
947
948 pub fn is_max(&self) -> bool {
949 self.timestamp == u64::MAX
950 }
951}
952
953impl From<NodeAnnouncement> for molecule_gossip::NodeAnnouncement {
956 fn from(node_announcement: NodeAnnouncement) -> Self {
957 let builder = molecule_gossip::NodeAnnouncement::new_builder()
958 .features(node_announcement.features.bytes().pack())
959 .timestamp(node_announcement.timestamp.pack())
960 .node_id(node_announcement.node_id.into())
961 .version(node_announcement.version.pack())
962 .node_name(u8_32_as_byte_32(&node_announcement.node_name.0))
963 .chain_hash(node_announcement.chain_hash.into())
964 .auto_accept_min_ckb_funding_amount(
965 node_announcement.auto_accept_min_ckb_funding_amount.pack(),
966 )
967 .udt_cfg_infos(node_announcement.udt_cfg_infos.into())
968 .address(
969 BytesVec::new_builder()
970 .set(
971 node_announcement
972 .addresses
973 .into_iter()
974 .map(|address| address.to_vec().pack())
975 .collect(),
976 )
977 .build(),
978 );
979
980 let builder = if let Some(signature) = node_announcement.signature {
981 builder.signature(signature.into())
982 } else {
983 builder
984 };
985
986 builder.build()
987 }
988}
989
990impl TryFrom<molecule_gossip::NodeAnnouncement> for NodeAnnouncement {
991 type Error = anyhow::Error;
992
993 fn try_from(node_announcement: molecule_gossip::NodeAnnouncement) -> Result<Self, Self::Error> {
994 use ckb_types::prelude::Unpack;
995 Ok(NodeAnnouncement {
996 signature: Some(
997 node_announcement
998 .signature()
999 .try_into()
1000 .map_err(|e: secp256k1::Error| anyhow::anyhow!(e))?,
1001 ),
1002 features: FeatureVector::from(node_announcement.features().unpack()),
1003 timestamp: node_announcement.timestamp().unpack(),
1004 node_id: node_announcement
1005 .node_id()
1006 .try_into()
1007 .map_err(|e: secp256k1::Error| anyhow::anyhow!(e))?,
1008 version: String::from_utf8(node_announcement.version().unpack()).unwrap_or_default(),
1009 chain_hash: node_announcement.chain_hash().into(),
1010 auto_accept_min_ckb_funding_amount: node_announcement
1011 .auto_accept_min_ckb_funding_amount()
1012 .unpack(),
1013 node_name: AnnouncedNodeName::from_slice(node_announcement.node_name().as_slice())
1014 .map_err(|e| anyhow::anyhow!("Invalid node_name: {}", e))?,
1015 udt_cfg_infos: node_announcement.udt_cfg_infos().try_into()?,
1016 addresses: node_announcement
1017 .address()
1018 .into_iter()
1019 .map(|bytes| {
1020 tentacle_multiaddr::Multiaddr::try_from(bytes.raw_data().to_vec())
1021 .map_err(Into::into)
1022 })
1023 .collect::<Result<Vec<_>, anyhow::Error>>()?,
1024 })
1025 }
1026}
1027
1028impl From<ChannelAnnouncement> for molecule_gossip::ChannelAnnouncement {
1029 fn from(channel_announcement: ChannelAnnouncement) -> Self {
1030 let builder = molecule_gossip::ChannelAnnouncement::new_builder()
1031 .features(channel_announcement.features.pack())
1032 .chain_hash(channel_announcement.chain_hash.into())
1033 .channel_outpoint(channel_announcement.channel_outpoint)
1034 .node1_id(channel_announcement.node1_id.into())
1035 .node2_id(channel_announcement.node2_id.into())
1036 .capacity(channel_announcement.capacity.pack())
1037 .udt_type_script(channel_announcement.udt_type_script.pack())
1038 .ckb_key(channel_announcement.ckb_key.into());
1039
1040 let builder = if let Some(signature) = channel_announcement.node1_signature {
1041 builder.node1_signature(signature.into())
1042 } else {
1043 builder
1044 };
1045
1046 let builder = if let Some(signature) = channel_announcement.node2_signature {
1047 builder.node2_signature(signature.into())
1048 } else {
1049 builder
1050 };
1051
1052 let builder = if let Some(signature) = channel_announcement.ckb_signature {
1053 builder.ckb_signature(signature.into())
1054 } else {
1055 builder
1056 };
1057
1058 builder.build()
1059 }
1060}
1061
1062impl TryFrom<molecule_gossip::ChannelAnnouncement> for ChannelAnnouncement {
1063 type Error = anyhow::Error;
1064
1065 fn try_from(
1066 channel_announcement: molecule_gossip::ChannelAnnouncement,
1067 ) -> Result<Self, Self::Error> {
1068 use ckb_types::prelude::Unpack;
1069 Ok(ChannelAnnouncement {
1070 node1_signature: Some(channel_announcement.node1_signature().try_into()?),
1071 node2_signature: Some(channel_announcement.node2_signature().try_into()?),
1072 ckb_signature: Some(channel_announcement.ckb_signature().try_into()?),
1073 features: channel_announcement.features().unpack(),
1074 capacity: channel_announcement.capacity().unpack(),
1075 chain_hash: channel_announcement.chain_hash().into(),
1076 channel_outpoint: channel_announcement.channel_outpoint(),
1077 udt_type_script: channel_announcement.udt_type_script().to_opt(),
1078 node1_id: channel_announcement.node1_id().try_into()?,
1079 node2_id: channel_announcement.node2_id().try_into()?,
1080 ckb_key: channel_announcement.ckb_key().try_into()?,
1081 })
1082 }
1083}
1084
1085impl From<ChannelUpdate> for molecule_fiber::ChannelUpdate {
1086 fn from(channel_update: ChannelUpdate) -> Self {
1087 let builder = molecule_fiber::ChannelUpdate::new_builder()
1088 .chain_hash(channel_update.chain_hash.into())
1089 .channel_outpoint(channel_update.channel_outpoint)
1090 .timestamp(channel_update.timestamp.pack())
1091 .message_flags(channel_update.message_flags.bits().pack())
1092 .channel_flags(channel_update.channel_flags.bits().pack())
1093 .tlc_expiry_delta(channel_update.tlc_expiry_delta.pack())
1094 .tlc_minimum_value(channel_update.tlc_minimum_value.pack())
1095 .tlc_fee_proportional_millionths(channel_update.tlc_fee_proportional_millionths.pack());
1096
1097 let builder = if let Some(signature) = channel_update.signature {
1098 builder.signature(signature.into())
1099 } else {
1100 builder
1101 };
1102
1103 builder.build()
1104 }
1105}
1106
1107impl TryFrom<molecule_fiber::ChannelUpdate> for ChannelUpdate {
1108 type Error = anyhow::Error;
1109
1110 fn try_from(channel_update: molecule_fiber::ChannelUpdate) -> Result<Self, Self::Error> {
1111 use ckb_types::prelude::Unpack;
1112 Ok(ChannelUpdate {
1113 signature: Some(channel_update.signature().try_into()?),
1114 chain_hash: channel_update.chain_hash().into(),
1115 channel_outpoint: channel_update.channel_outpoint(),
1116 timestamp: channel_update.timestamp().unpack(),
1117 message_flags: ChannelUpdateMessageFlags::from_bits_truncate(
1118 channel_update.message_flags().unpack(),
1119 ),
1120 channel_flags: ChannelUpdateChannelFlags::from_bits_truncate(
1121 channel_update.channel_flags().unpack(),
1122 ),
1123 tlc_expiry_delta: channel_update.tlc_expiry_delta().unpack(),
1124 tlc_minimum_value: channel_update.tlc_minimum_value().unpack(),
1125 tlc_fee_proportional_millionths: channel_update
1126 .tlc_fee_proportional_millionths()
1127 .unpack(),
1128 })
1129 }
1130}
1131
1132impl Ord for BroadcastMessage {
1133 fn cmp(&self, other: &Self) -> Ordering {
1134 self.message_id()
1135 .cmp(&other.message_id())
1136 .then(self.timestamp().cmp(&other.timestamp()))
1137 }
1138}
1139
1140impl PartialOrd for BroadcastMessage {
1141 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1142 Some(self.cmp(other))
1143 }
1144}
1145
1146impl From<BroadcastMessage> for molecule_gossip::BroadcastMessageUnion {
1147 fn from(fiber_broadcast_message: BroadcastMessage) -> Self {
1148 match fiber_broadcast_message {
1149 BroadcastMessage::NodeAnnouncement(node_announcement) => {
1150 molecule_gossip::BroadcastMessageUnion::NodeAnnouncement(node_announcement.into())
1151 }
1152 BroadcastMessage::ChannelAnnouncement(channel_announcement) => {
1153 molecule_gossip::BroadcastMessageUnion::ChannelAnnouncement(
1154 channel_announcement.into(),
1155 )
1156 }
1157 BroadcastMessage::ChannelUpdate(channel_update) => {
1158 molecule_gossip::BroadcastMessageUnion::ChannelUpdate(channel_update.into())
1159 }
1160 }
1161 }
1162}
1163
1164impl TryFrom<molecule_gossip::BroadcastMessageUnion> for BroadcastMessage {
1165 type Error = anyhow::Error;
1166
1167 fn try_from(
1168 fiber_broadcast_message: molecule_gossip::BroadcastMessageUnion,
1169 ) -> Result<Self, Self::Error> {
1170 match fiber_broadcast_message {
1171 molecule_gossip::BroadcastMessageUnion::NodeAnnouncement(node_announcement) => Ok(
1172 BroadcastMessage::NodeAnnouncement(node_announcement.try_into()?),
1173 ),
1174 molecule_gossip::BroadcastMessageUnion::ChannelAnnouncement(channel_announcement) => {
1175 Ok(BroadcastMessage::ChannelAnnouncement(
1176 channel_announcement.try_into()?,
1177 ))
1178 }
1179 molecule_gossip::BroadcastMessageUnion::ChannelUpdate(channel_update) => {
1180 Ok(BroadcastMessage::ChannelUpdate(channel_update.try_into()?))
1181 }
1182 }
1183 }
1184}
1185
1186impl From<BroadcastMessage> for molecule_gossip::BroadcastMessage {
1187 fn from(fiber_broadcast_message: BroadcastMessage) -> Self {
1188 molecule_gossip::BroadcastMessage::new_builder()
1189 .set(fiber_broadcast_message)
1190 .build()
1191 }
1192}
1193
1194impl TryFrom<molecule_gossip::BroadcastMessage> for BroadcastMessage {
1195 type Error = anyhow::Error;
1196
1197 fn try_from(
1198 fiber_broadcast_message: molecule_gossip::BroadcastMessage,
1199 ) -> Result<Self, Self::Error> {
1200 fiber_broadcast_message.to_enum().try_into()
1201 }
1202}
1203
1204impl Ord for Cursor {
1205 fn cmp(&self, other: &Self) -> Ordering {
1206 self.to_bytes().cmp(&other.to_bytes())
1207 }
1208}
1209
1210impl PartialOrd for Cursor {
1211 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1212 Some(self.cmp(other))
1213 }
1214}
1215
1216impl From<Cursor> for molecule_gossip::Cursor {
1217 fn from(cursor: Cursor) -> Self {
1218 use molecule::prelude::{Builder, Byte};
1219 let serialized = cursor
1220 .timestamp
1221 .to_be_bytes()
1222 .into_iter()
1223 .chain(cursor.message_id.to_bytes())
1224 .map(Byte::new)
1225 .collect::<Vec<_>>()
1226 .try_into()
1227 .expect("Must serialize cursor to 45 bytes");
1228
1229 molecule_gossip::Cursor::new_builder()
1230 .set(serialized)
1231 .build()
1232 }
1233}
1234
1235impl TryFrom<molecule_gossip::Cursor> for Cursor {
1236 type Error = anyhow::Error;
1237
1238 fn try_from(cursor: molecule_gossip::Cursor) -> Result<Self, Self::Error> {
1239 use molecule::prelude::Entity;
1240 let slice = cursor.as_slice();
1241 if slice.len() != CURSOR_SIZE {
1242 anyhow::bail!("Invalid cursor size: {}, want {}", slice.len(), CURSOR_SIZE);
1243 }
1244 let timestamp = u64::from_be_bytes(slice[..8].try_into().expect("Cursor timestamp to u64"));
1245 let message_id = BroadcastMessageID::from_bytes(&slice[8..])?;
1246 Ok(Cursor {
1247 timestamp,
1248 message_id,
1249 })
1250 }
1251}
1252
1253#[cfg(test)]
1254mod tests {
1255 use super::*;
1256
1257 fn node_announcement_with_raw_name(raw_name: [u8; 32]) -> molecule_gossip::NodeAnnouncement {
1258 let private_key = Privkey::from_slice(&[42u8; 32]);
1259 let announcement = NodeAnnouncement::new_signed(
1260 AnnouncedNodeName::from_string("valid-node").expect("valid node name"),
1261 FeatureVector::default(),
1262 vec![],
1263 &private_key,
1264 Hash256::default(),
1265 1,
1266 0,
1267 UdtCfgInfos::default(),
1268 "test".to_string(),
1269 );
1270 let molecule_announcement = molecule_gossip::NodeAnnouncement::from(announcement);
1271
1272 molecule_gossip::NodeAnnouncement::new_builder()
1273 .signature(molecule_announcement.signature())
1274 .features(molecule_announcement.features())
1275 .timestamp(molecule_announcement.timestamp())
1276 .node_id(molecule_announcement.node_id())
1277 .version(molecule_announcement.version())
1278 .node_name(u8_32_as_byte_32(&raw_name))
1279 .address(molecule_announcement.address())
1280 .chain_hash(molecule_announcement.chain_hash())
1281 .auto_accept_min_ckb_funding_amount(
1282 molecule_announcement.auto_accept_min_ckb_funding_amount(),
1283 )
1284 .udt_cfg_infos(molecule_announcement.udt_cfg_infos())
1285 .build()
1286 }
1287
1288 fn raw_node_name(name: &[u8]) -> [u8; 32] {
1289 let mut raw_name = [0u8; 32];
1290 raw_name[..name.len()].copy_from_slice(name);
1291 raw_name
1292 }
1293
1294 #[test]
1295 fn node_announcement_from_molecule_rejects_non_utf8_node_name() {
1296 let mut raw_name = [0u8; 32];
1297 raw_name[0] = b'f';
1298 raw_name[1] = 0xff;
1299
1300 let err = NodeAnnouncement::try_from(node_announcement_with_raw_name(raw_name))
1301 .expect_err("invalid UTF-8 node_name must be rejected");
1302 assert!(err.to_string().contains("Invalid node_name"));
1303 }
1304
1305 #[test]
1306 fn node_announcement_from_molecule_rejects_control_chars_in_node_name() {
1307 for raw_name in [
1308 raw_node_name(b"\x1bc"),
1309 raw_node_name(b"bad\x07name"),
1310 raw_node_name("bad\u{85}name".as_bytes()),
1311 ] {
1312 let err = NodeAnnouncement::try_from(node_announcement_with_raw_name(raw_name))
1313 .expect_err("control chars in node_name must be rejected");
1314 assert!(err.to_string().contains("Invalid node_name"));
1315 }
1316 }
1317
1318 #[test]
1319 fn announced_node_name_allows_printable_utf8() {
1320 let name = "节点-café";
1321 let announced_name =
1322 AnnouncedNodeName::from_string(name).expect("printable UTF-8 node name is valid");
1323 assert_eq!(announced_name.as_str(), name);
1324
1325 let announcement = NodeAnnouncement::try_from(node_announcement_with_raw_name(
1326 raw_node_name(name.as_bytes()),
1327 ))
1328 .expect("printable UTF-8 node_name from molecule is valid");
1329 assert_eq!(announcement.node_name.as_str(), name);
1330 }
1331
1332 #[test]
1333 fn malformed_announced_node_name_debug_and_serialize_do_not_panic() {
1334 let mut raw_name = [0u8; 32];
1335 raw_name[0] = b'f';
1336 raw_name[1] = 0xff;
1337 let node_name = AnnouncedNodeName(raw_name);
1338
1339 let debug_result = std::panic::catch_unwind(|| format!("{node_name:?}"));
1340 assert!(debug_result.is_ok());
1341
1342 let serialize_result = std::panic::catch_unwind(|| serde_json::to_string(&node_name));
1343 assert!(serialize_result.is_ok());
1344 assert!(serialize_result.expect("panic checked").is_err());
1345 }
1346}