@@ -3,7 +3,7 @@ use borsh_derive::{BorshDeserialize, BorshSerialize};
3
3
use company:: Company ;
4
4
use contact:: Contact ;
5
5
use serde:: { Deserialize , Serialize } ;
6
- use std:: { fmt, pin:: Pin } ;
6
+ use std:: { fmt, pin:: Pin , str :: FromStr } ;
7
7
use thiserror:: Error ;
8
8
use util:: is_blank;
9
9
@@ -20,6 +20,137 @@ pub mod notification;
20
20
mod tests;
21
21
pub mod util;
22
22
23
+ const ID_PREFIX : & str = "bitcr" ;
24
+ const NETWORK_MAINNET : char = 'm' ;
25
+ const NETWORK_TESTNET : char = 't' ;
26
+ const NETWORK_TESTNET4 : char = 'T' ;
27
+ const NETWORK_REGTEST : char = 'r' ;
28
+
29
+ fn network_char ( network : & bitcoin:: Network ) -> char {
30
+ match network {
31
+ bitcoin:: Network :: Bitcoin => NETWORK_MAINNET ,
32
+ bitcoin:: Network :: Testnet => NETWORK_TESTNET ,
33
+ bitcoin:: Network :: Testnet4 => NETWORK_TESTNET4 ,
34
+ bitcoin:: Network :: Signet => unreachable ! ( ) ,
35
+ bitcoin:: Network :: Regtest => NETWORK_REGTEST ,
36
+ _ => unreachable ! ( ) ,
37
+ }
38
+ }
39
+
40
+ /// A bitcr Node ID of the format <prefix><network><pub_key>
41
+ /// Example: bitcrt039180c169e5f6d7c579cf1cefa37bffd47a2b389c8125601f4068c87bea795943
42
+ /// The prefix is bitcr
43
+ /// The pub key is a secp256k1 public key
44
+ /// The network character can be parsed like this:
45
+ /// * m => Mainnet
46
+ /// * t => Testnet
47
+ /// * T => Testnet4
48
+ /// * r => Regtest
49
+ #[ derive( Debug , Clone , Eq , PartialEq , PartialOrd , Ord ) ]
50
+ pub struct NodeId {
51
+ pub_key : bitcoin:: secp256k1:: PublicKey ,
52
+ network : bitcoin:: Network ,
53
+ }
54
+
55
+ impl NodeId {
56
+ pub fn new ( pub_key : bitcoin:: secp256k1:: PublicKey , network : bitcoin:: Network ) -> Self {
57
+ Self { pub_key, network }
58
+ }
59
+
60
+ pub fn network ( & self ) -> bitcoin:: Network {
61
+ self . network
62
+ }
63
+
64
+ pub fn pub_key ( & self ) -> bitcoin:: secp256k1:: PublicKey {
65
+ self . pub_key
66
+ }
67
+
68
+ pub fn npub ( & self ) -> nostr:: PublicKey {
69
+ nostr:: PublicKey :: from ( self . pub_key . x_only_public_key ( ) . 0 )
70
+ }
71
+
72
+ pub fn equals_npub ( & self , npub : & nostr:: PublicKey ) -> bool {
73
+ self . npub ( ) == * npub
74
+ }
75
+ }
76
+
77
+ impl std:: fmt:: Display for NodeId {
78
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
79
+ write ! (
80
+ f,
81
+ "{}{}{}" ,
82
+ ID_PREFIX ,
83
+ network_char( & self . network) ,
84
+ self . pub_key
85
+ )
86
+ }
87
+ }
88
+
89
+ impl FromStr for NodeId {
90
+ type Err = ValidationError ;
91
+
92
+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
93
+ if !s. starts_with ( ID_PREFIX ) {
94
+ return Err ( ValidationError :: InvalidNodeId ) ;
95
+ }
96
+
97
+ let network = match s. chars ( ) . nth ( ID_PREFIX . len ( ) ) {
98
+ None => {
99
+ return Err ( ValidationError :: InvalidNodeId ) ;
100
+ }
101
+ Some ( network_str) => match network_str {
102
+ NETWORK_MAINNET => bitcoin:: Network :: Bitcoin ,
103
+ NETWORK_TESTNET => bitcoin:: Network :: Testnet ,
104
+ NETWORK_TESTNET4 => bitcoin:: Network :: Testnet4 ,
105
+ NETWORK_REGTEST => bitcoin:: Network :: Regtest ,
106
+ _ => {
107
+ return Err ( ValidationError :: InvalidNodeId ) ;
108
+ }
109
+ } ,
110
+ } ;
111
+
112
+ let pub_key_str = & s[ ID_PREFIX . len ( ) + 1 ..] ;
113
+ let pub_key = bitcoin:: secp256k1:: PublicKey :: from_str ( pub_key_str)
114
+ . map_err ( |_| ValidationError :: InvalidNodeId ) ?;
115
+
116
+ Ok ( Self { pub_key, network } )
117
+ }
118
+ }
119
+
120
+ impl serde:: Serialize for NodeId {
121
+ fn serialize < S > ( & self , s : S ) -> Result < S :: Ok , S :: Error >
122
+ where
123
+ S : serde:: Serializer ,
124
+ {
125
+ s. collect_str ( self )
126
+ }
127
+ }
128
+
129
+ impl < ' de > serde:: Deserialize < ' de > for NodeId {
130
+ fn deserialize < D > ( d : D ) -> Result < Self , D :: Error >
131
+ where
132
+ D : serde:: Deserializer < ' de > ,
133
+ {
134
+ let s = String :: deserialize ( d) ?;
135
+ NodeId :: from_str ( & s) . map_err ( serde:: de:: Error :: custom)
136
+ }
137
+ }
138
+
139
+ impl borsh:: BorshSerialize for NodeId {
140
+ fn serialize < W : std:: io:: Write > ( & self , writer : & mut W ) -> std:: io:: Result < ( ) > {
141
+ let node_id_str = self . to_string ( ) ;
142
+ borsh:: BorshSerialize :: serialize ( & node_id_str, writer)
143
+ }
144
+ }
145
+
146
+ impl borsh:: BorshDeserialize for NodeId {
147
+ fn deserialize_reader < R : std:: io:: Read > ( reader : & mut R ) -> std:: io:: Result < Self > {
148
+ let node_id_str: String = borsh:: BorshDeserialize :: deserialize_reader ( reader) ?;
149
+ NodeId :: from_str ( & node_id_str)
150
+ . map_err ( |e| std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , e) )
151
+ }
152
+ }
153
+
23
154
/// Return type of an async function. Can be used to avoid async_trait
24
155
pub type BoxedFuture < ' a , T > = Pin < Box < dyn std:: future:: Future < Output = T > + Send + ' a > > ;
25
156
@@ -258,6 +389,10 @@ pub enum ValidationError {
258
389
#[ error( "invalid bill type" ) ]
259
390
InvalidBillType ,
260
391
392
+ /// errors stemming from providing an invalid bill id
393
+ #[ error( "invalid bill id" ) ]
394
+ InvalidBillId ,
395
+
261
396
/// errors stemming from when the drawee is the payee
262
397
#[ error( "Drawee can't be Payee at the same time" ) ]
263
398
DraweeCantBePayee ,
@@ -463,6 +598,10 @@ pub enum ValidationError {
463
598
#[ error( "Invalid contact type" ) ]
464
599
InvalidContactType ,
465
600
601
+ /// error returned if the node id is not valid
602
+ #[ error( "Invalid node id" ) ]
603
+ InvalidNodeId ,
604
+
466
605
/// error returned if the identity type is not valid
467
606
#[ error( "Invalid identity type" ) ]
468
607
InvalidIdentityType ,
0 commit comments