1use core::convert::{TryFrom, TryInto};
6use core::str::FromStr;
7use core::fmt;
8
9#[cfg(feature = "alloc")]
10use alloc::{boxed::Box, string::String, vec::Vec};
11
12#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
31pub struct NodeId([u8; 33]);
32
33impl NodeId {
34 #[inline]
36 pub fn from_raw_bytes(bytes: [u8; 33]) -> Result<Self, InvalidNodeId> {
37 if bytes[0] == 0x02 || bytes[0] == 0x03 {
38 Ok(NodeId(bytes))
39 } else {
40 Err(InvalidNodeId { bad_byte: bytes[0], })
41 }
42 }
43
44 #[cfg(feature = "alloc")]
49 pub fn to_vec(self) -> Vec<u8> {
50 self.0.to_vec()
51 }
52
53 pub fn to_array(self) -> [u8; 33] {
57 self.0
58 }
59
60 pub(crate) fn parse_raw(s: &str) -> Result<Self, ParseErrorInner> {
64 fn decode_digit(digit: u8, pos: usize, s: &str) -> Result<u8, ParseErrorInner> {
65 match digit {
66 b'0'..=b'9' => Ok(digit - b'0'),
67 b'a'..=b'f' => Ok(digit - b'a' + 10),
68 b'A'..=b'F' => Ok(digit - b'A' + 10),
69 _ => Err(ParseErrorInner::Char { pos, c: s.chars().nth(pos).unwrap(), }),
70 }
71 }
72
73 let mut result = [0; 33];
74
75 if s.len() != 66 {
76 return Err(ParseErrorInner::Length)
77 }
78
79 for ((i, pair), dst) in s.as_bytes().chunks_exact(2).enumerate().zip(&mut result) {
80 *dst = decode_digit(pair[0], i * 2, s)? * 16 + decode_digit(pair[1], i * 2 + 1, s)?;
81 }
82
83 Self::from_raw_bytes(result).map_err(Into::into)
84 }
85
86 #[cfg(feature = "alloc")]
88 #[inline]
89 fn internal_parse<S: AsRef<str> + Into<String>>(s: S) -> Result<Self, ParseError> {
90 Self::parse_raw(s.as_ref()).map_err(|error| ParseError {
91 input: s.into(),
92 reason: error,
93 })
94 }
95
96 #[cfg(not(feature = "alloc"))]
97 #[inline]
98 fn internal_parse<S: AsRef<str>>(s: S) -> Result<Self, ParseError> {
99 Self::parse_raw(s.as_ref()).map_err(|error| ParseError {
100 reason: error,
101 })
102 }
103 #[cfg(not(feature = "hex-conservative"))]
105 fn prefill(&self, f: &mut fmt::Formatter) -> fmt::Result {
106 use fmt::Write;
107
108 if let Some(width) = f.width() {
109 for _ in 0..width.saturating_sub(66) {
110 f.write_char(f.fill())?;
111 }
112 }
113 Ok(())
114 }
115}
116
117impl fmt::Display for NodeId {
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 fmt::LowerHex::fmt(self, f)
121 }
122}
123
124impl fmt::Debug for NodeId {
126 #[inline]
127 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128 fmt::Display::fmt(self, f)
129 }
130}
131
132impl fmt::LowerHex for NodeId {
134 #[inline]
135 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136 #[cfg(feature = "hex-conservative")]
137 {
138 hex_conservative::fmt_hex_exact!(f, 33, &self.0, hex_conservative::Case::Lower)
139 }
140
141 #[cfg(not(feature = "hex-conservative"))]
142 {
143 self.prefill(f)?;
144 for byte in &self.0 {
145 write!(f, "{:02x}", byte)?;
146 }
147 Ok(())
148 }
149 }
150}
151
152impl fmt::UpperHex for NodeId {
154 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155 #[cfg(feature = "hex-conservative")]
156 {
157 hex_conservative::fmt_hex_exact!(f, 33, &self.0, hex_conservative::Case::Upper)
158 }
159
160 #[cfg(not(feature = "hex-conservative"))]
161 {
162 self.prefill(f)?;
163 for byte in &self.0 {
164 write!(f, "{:02X}", byte)?;
165 }
166 Ok(())
167 }
168 }
169}
170
171impl FromStr for NodeId {
173 type Err = ParseError;
174
175 #[inline]
176 fn from_str(s: &str) -> Result<Self, Self::Err> {
177 Self::internal_parse(s)
178 }
179}
180
181impl<'a> TryFrom<&'a str> for NodeId {
183 type Error = ParseError;
184
185 #[inline]
186 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
187 Self::internal_parse(s)
188 }
189}
190
191#[cfg(feature = "alloc")]
193impl TryFrom<String> for NodeId {
194 type Error = ParseError;
195
196 #[inline]
197 fn try_from(s: String) -> Result<Self, Self::Error> {
198 Self::internal_parse(s)
199 }
200}
201
202#[cfg(feature = "alloc")]
204impl TryFrom<Box<str>> for NodeId {
205 type Error = ParseError;
206
207 #[inline]
208 fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
209 Self::internal_parse(s)
210 }
211}
212
213impl<'a> TryFrom<&'a [u8]> for NodeId {
214 type Error = DecodeError;
215
216 #[inline]
217 fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
218 let bytes = slice.try_into()
219 .map_err(|_| DecodeError { error: DecodeErrorInner::InvalidLen(slice.len()) })?;
220
221 NodeId::from_raw_bytes(bytes).map_err(Into::into)
222 }
223}
224
225#[cfg(feature = "alloc")]
226impl TryFrom<Vec<u8>> for NodeId {
227 type Error = DecodeError;
228
229 #[inline]
230 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
231 (*vec).try_into()
232 }
233}
234
235#[cfg(feature = "alloc")]
236impl TryFrom<Box<[u8]>> for NodeId {
237 type Error = DecodeError;
238
239 #[inline]
240 fn try_from(slice: Box<[u8]>) -> Result<Self, Self::Error> {
241 (*slice).try_into()
242 }
243}
244
245impl From<NodeId> for [u8; 33] {
246 fn from(value: NodeId) -> Self {
247 value.0
248 }
249}
250
251impl AsRef<[u8; 33]> for NodeId {
252 fn as_ref(&self) -> &[u8; 33] {
253 &self.0
254 }
255}
256
257impl AsRef<[u8]> for NodeId {
258 fn as_ref(&self) -> &[u8] {
259 &self.0
260 }
261}
262
263impl core::borrow::Borrow<[u8; 33]> for NodeId {
264 fn borrow(&self) -> &[u8; 33] {
265 &self.0
266 }
267}
268
269impl core::borrow::Borrow<[u8]> for NodeId {
270 fn borrow(&self) -> &[u8] {
271 &self.0
272 }
273}
274
275#[derive(Debug, Clone)]
279pub struct DecodeError {
280 error: DecodeErrorInner,
281}
282
283#[derive(Debug, Clone)]
284enum DecodeErrorInner {
285 InvalidLen(usize),
286 InvalidNodeId(InvalidNodeId),
287}
288
289impl From<InvalidNodeId> for DecodeError {
290 fn from(value: InvalidNodeId) -> Self {
291 DecodeError {
292 error: DecodeErrorInner::InvalidNodeId(value),
293 }
294 }
295}
296
297
298impl fmt::Display for DecodeError {
299 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300 match &self.error {
301 DecodeErrorInner::InvalidLen(len) => write!(f, "invalid length {} bytes, the lenght must be 33 bytes", len),
302 DecodeErrorInner::InvalidNodeId(error) => write_err!(f, "invalid node ID"; error),
303 }
304 }
305}
306
307#[cfg(feature = "std")]
308impl std::error::Error for DecodeError {
309 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
310 match &self.error {
311 DecodeErrorInner::InvalidLen(_) => None,
312 DecodeErrorInner::InvalidNodeId(error) => Some(error),
313 }
314 }
315}
316
317#[derive(Debug, Clone)]
321pub struct ParseError {
322 #[cfg(feature = "alloc")]
324 input: String,
325 reason: ParseErrorInner,
327}
328
329impl fmt::Display for ParseError {
330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331 write_err!(f, "failed to parse{} Lightning Network node ID", opt_fmt!("alloc", format_args!(" '{}' as", &self.input)); &self.reason)
332 }
333}
334
335#[cfg(feature = "std")]
336impl std::error::Error for ParseError {
337 #[inline]
338 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
339 Some(&self.reason)
340 }
341}
342
343#[derive(Debug, Clone)]
347pub(crate) enum ParseErrorInner {
348 Length,
350 Char { pos: usize, c: char, },
351 NodeId(InvalidNodeId),
352}
353
354impl fmt::Display for ParseErrorInner {
355 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
356 match self {
357 ParseErrorInner::Length => f.write_str("invalid length (must be 66 chars)"),
358 ParseErrorInner::Char { c, pos, } => write!(f, "invalid character '{}' at position {} (must be hex digit)", c, pos),
359 ParseErrorInner::NodeId(error) => write_err!(f, "invalid node ID"; error),
360 }
361 }
362}
363
364#[cfg(feature = "std")]
365impl std::error::Error for ParseErrorInner {
366 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
367 match self {
368 ParseErrorInner::Length | ParseErrorInner::Char { .. } => None,
369 ParseErrorInner::NodeId(error) => Some(error),
370 }
371 }
372}
373
374impl From<InvalidNodeId> for ParseErrorInner {
375 fn from(value: InvalidNodeId) -> Self {
376 ParseErrorInner::NodeId(value)
377 }
378}
379
380#[derive(Debug, Clone)]
387pub struct InvalidNodeId {
388 bad_byte: u8,
389}
390
391impl fmt::Display for InvalidNodeId {
392 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
393 write!(f, "invalid zeroth byte 0x{:02x}", self.bad_byte)?;
395 Ok(())
396 }
397}
398
399#[cfg(feature = "std")]
400impl std::error::Error for InvalidNodeId {}
401
402#[cfg(feature = "parse_arg")]
404mod parse_arg_impl {
405 use core::fmt;
406 use super::NodeId;
407
408 impl parse_arg::ParseArgFromStr for NodeId {
409 fn describe_type<W: fmt::Write>(mut writer: W) -> fmt::Result {
410 writer.write_str("a hex-encoded LN node ID (66 hex digits/33 bytes)")
411 }
412 }
413}
414
415#[cfg(feature = "serde")]
417mod serde_impl {
418 use core::fmt;
419 use super::NodeId;
420 use serde::{Serialize, Deserialize, Serializer, Deserializer, de::{Visitor, Error}};
421 use core::convert::TryFrom;
422
423 struct HRVisitor;
425
426 impl<'de> Visitor<'de> for HRVisitor {
427 type Value = NodeId;
428
429 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
430 formatter.write_str("a 66 digits long hex string")
431 }
432
433 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: Error {
434 use super::ParseErrorInner;
435
436 NodeId::parse_raw(v).map_err(|error| {
437 match error {
438 ParseErrorInner::Length => E::invalid_length(v.len(), &"66 hex digits beginning with 02 or 03"),
439 ParseErrorInner::Char { c, pos: _, } => E::invalid_value(serde::de::Unexpected::Char(c), &"a hex digit"),
440 ParseErrorInner::NodeId(error) => E::invalid_value(serde::de::Unexpected::Bytes(&[error.bad_byte]), &"02 or 03"),
441 }
442 })
443 }
444 }
445
446 struct BytesVisitor;
448
449 impl<'de> Visitor<'de> for BytesVisitor {
450 type Value = NodeId;
451
452 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
453 formatter.write_str("33 bytes")
454 }
455
456 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> where E: Error {
457 use super::DecodeErrorInner;
458
459 NodeId::try_from(v).map_err(|error| {
460 match error.error {
461 DecodeErrorInner::InvalidLen(len) => E::invalid_length(len, &"33 bytes"),
462 DecodeErrorInner::InvalidNodeId(error) => E::invalid_value(serde::de::Unexpected::Bytes(&[error.bad_byte]), &"02 or 03"),
463 }
464 })
465 }
466 }
467
468 impl Serialize for NodeId {
470 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
471 if serializer.is_human_readable() {
472 serializer.collect_str(self)
473 } else {
474 serializer.serialize_bytes(&self.0)
475 }
476 }
477 }
478
479 impl<'de> Deserialize<'de> for NodeId {
481 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
482 if deserializer.is_human_readable() {
483 deserializer.deserialize_str(HRVisitor)
484 } else {
485 deserializer.deserialize_bytes(BytesVisitor)
486 }
487 }
488 }
489}
490
491#[cfg(feature = "postgres-types")]
493mod postgres_impl {
494 use alloc::boxed::Box;
495 use super::NodeId;
496 use postgres_types::{ToSql, FromSql, IsNull, Type};
497 use bytes::BytesMut;
498 use std::error::Error;
499 use core::convert::TryInto;
500
501 impl ToSql for NodeId {
505 fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Send + Sync + 'static>> {
506 use core::fmt::Write;
507
508 match *ty {
509 Type::BYTEA => (&self.0 as &[_]).to_sql(ty, out),
510 _ => write!(out, "{}", self).map(|_| IsNull::No).map_err(|error| Box::new(error) as _)
511 }
512 }
513
514 fn accepts(ty: &Type) -> bool {
515 match *ty {
516 Type::BYTEA => true,
517 Type::TEXT => true,
518 Type::VARCHAR => true,
519 _ => false,
520 }
521 }
522
523 postgres_types::to_sql_checked!();
524 }
525
526 impl<'a> FromSql<'a> for NodeId {
530 fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> {
531 match *ty {
532 Type::BYTEA => <&[u8]>::from_sql(ty, raw)?.try_into().map_err(|error| Box::new(error) as _),
533 _ => <&str>::from_sql(ty, raw)?.parse().map_err(|error| Box::new(error) as _),
534 }
535 }
536
537 fn accepts(ty: &Type) -> bool {
538 match *ty {
539 Type::BYTEA => true,
540 Type::TEXT => true,
541 Type::VARCHAR => true,
542 _ => false,
543 }
544 }
545 }
546}
547
548#[cfg(feature = "slog")]
550mod slog_impl {
551 use super::NodeId;
552 use slog::{Key, Value, Record, Serializer};
553
554 impl Value for NodeId {
556 fn serialize(&self, _rec: &Record, key: Key, serializer: &mut dyn Serializer) -> slog::Result {
557 serializer.emit_arguments(key, &format_args!("{}", self))
558 }
559 }
560
561 impl_error_value!(super::ParseError, super::DecodeError);
562}
563
564#[cfg(test)]
565mod tests {
566 use super::NodeId;
567
568 #[test]
569 fn empty() {
570 assert!("".parse::<NodeId>().is_err());
571 }
572
573 #[test]
574 fn one_less() {
575 assert!("02234567890123456789012345678901234567890123456789012345678901234".parse::<NodeId>().is_err());
576 }
577
578 #[test]
579 fn one_more() {
580 assert!("0223456789012345678901234567890123456789012345678901234567890123456".parse::<NodeId>().is_err());
581 }
582
583 #[test]
584 fn invalid_node_id() {
585 assert!("012345678901234567890123456789012345678901234567890123456789abcdef".parse::<NodeId>().is_err());
586 }
587
588 #[test]
589 fn correct_02() {
590 let parsed = "022345678901234567890123456789012345678901234567890123456789abcdef".parse::<NodeId>().unwrap();
591 let expected = b"\x02\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\xab\xcd\xef";
592 assert_eq!(parsed.0, *expected);
593 }
594
595 #[test]
596 fn correct_03() {
597 let parsed = "032345678901234567890123456789012345678901234567890123456789abcdef".parse::<NodeId>().unwrap();
598 let expected = b"\x03\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\x01\x23\x45\x67\x89\xab\xcd\xef";
599 assert_eq!(parsed.0, *expected);
600 }
601
602 #[test]
603 fn invalid_digit() {
604 assert!("g12345678901234567890123456789012345678901234567890123456789012345".parse::<NodeId>().is_err());
605 }
606
607 chk_err_impl! {
608 parse_node_id_error_empty, "", NodeId, [
609 "failed to parse '' as Lightning Network node ID",
610 "invalid length (must be 66 chars)",
611 ], [
612 "failed to parse Lightning Network node ID",
613 "invalid length (must be 66 chars)",
614 ];
615 }
616}