11mod error;
22use backoff:: Backoff ;
33pub use error:: Error ;
4+ use serde:: { Deserialize , Serialize } ;
45
56use std:: {
67 collections:: HashSet ,
@@ -11,6 +12,7 @@ use std::{
1112
1213use miniscript:: bitcoin:: { Amount , Network } ;
1314use simple_nostr_client:: nostr:: {
15+ self ,
1416 bitcoin:: { address:: NetworkUnchecked , Address } ,
1517 hashes:: { sha256, Hash , HashEngine } ,
1618 Keys , PublicKey ,
@@ -70,49 +72,66 @@ pub struct Status {
7072pub struct JoinstrInner < ' a > {
7173 role : Role ,
7274 step : Step ,
73- registered_peers : usize ,
74- registered_outputs : usize ,
75- registered_inputs : usize ,
7675 confirmations : usize ,
7776 error : Option < String > ,
7877 pub client : NostrClient ,
7978 pub pool : Option < Pool > ,
8079 pub denomination : Option < Amount > ,
81- pub peers : Option < usize > ,
80+ pub peers_count : Option < usize > ,
8281 pub timeout : Option < Timeline > ,
83- pub relays : Vec < String > ,
82+ pub relay : Option < String > ,
8483 pub fee : Option < Fee > ,
8584 pub network : Network ,
8685 pub coinjoin : Option < CoinJoin < ' a , crate :: electrum:: Client > > ,
8786 pub electrum_client : Option < crate :: electrum:: Client > ,
8887 input : Option < Coin > ,
8988 output : Option < Address > ,
9089 final_tx : Option < miniscript:: bitcoin:: Transaction > ,
90+ // requests history
91+ peers : Vec < nostr:: PublicKey > ,
92+ outputs : Vec < miniscript:: bitcoin:: Address > ,
93+ inputs : Vec < InputDataSigned > ,
94+ }
95+
96+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
97+ pub struct State {
98+ pool_secret_key : String , /* nostr::Keys*/
99+ relay : String ,
100+ electrum : Option < String > ,
101+ pool : Pool ,
102+ input : Option < Coin > ,
103+ output : Option < Address < NetworkUnchecked > > ,
104+ network : bitcoin:: Network ,
105+ final_tx : Option < bitcoin:: Transaction > ,
106+ // requests history
107+ peers : Vec < nostr:: PublicKey > ,
108+ outputs : Vec < bitcoin:: Address < NetworkUnchecked > > ,
109+ inputs : Vec < serde_json:: Value /* InputDataSigned*/ > ,
91110}
92111
93112impl Default for JoinstrInner < ' _ > {
94113 fn default ( ) -> Self {
95114 Self {
96115 role : Default :: default ( ) ,
97116 step : Default :: default ( ) ,
98- registered_peers : 0 ,
99- registered_outputs : 0 ,
100- registered_inputs : 0 ,
101117 confirmations : 0 ,
102118 error : None ,
103119 client : Default :: default ( ) ,
104120 pool : Default :: default ( ) ,
105121 denomination : Default :: default ( ) ,
106- peers : Default :: default ( ) ,
122+ peers_count : Default :: default ( ) ,
107123 timeout : Default :: default ( ) ,
108- relays : Default :: default ( ) ,
124+ relay : Default :: default ( ) ,
109125 fee : Default :: default ( ) ,
110126 network : Network :: Bitcoin ,
111127 coinjoin : None ,
112128 electrum_client : None ,
113129 input : None ,
114130 output : None ,
115131 final_tx : None ,
132+ peers : Default :: default ( ) ,
133+ outputs : Default :: default ( ) ,
134+ inputs : Default :: default ( ) ,
116135 }
117136 }
118137}
@@ -132,10 +151,10 @@ impl Joinstr<'_> {
132151 fn new ( keys : Keys , relay : String , name : & str ) -> Result < Self , Error > {
133152 let mut client = NostrClient :: new ( name) . relay ( relay. clone ( ) ) ?. keys ( keys) ?;
134153 client. connect_nostr ( ) ?;
135- let relays = vec ! [ relay] ;
154+ let relay = Some ( relay) ;
136155 let inner = Arc :: new ( Mutex :: new ( JoinstrInner {
137156 client,
138- relays ,
157+ relay ,
139158 ..Default :: default ( )
140159 } ) ) ;
141160 Ok ( Joinstr { inner } )
@@ -331,8 +350,8 @@ impl Joinstr<'_> {
331350 }
332351 let mut inner = self . inner . lock ( ) . expect ( "poisoned" ) ;
333352 inner. pool_not_exists ( ) ?;
334- if inner. peers . is_none ( ) {
335- inner. peers = Some ( peers) ;
353+ if inner. peers_count . is_none ( ) {
354+ inner. peers_count = Some ( peers) ;
336355 drop ( inner) ;
337356 Ok ( self )
338357 } else {
@@ -360,7 +379,7 @@ impl Joinstr<'_> {
360379 inner. pool_not_exists ( ) ?;
361380 // TODO: check the address is valid
362381 let url: String = url. into ( ) ;
363- inner. relays . push ( url) ;
382+ inner. relay = Some ( url) ;
364383 drop ( inner) ;
365384 Ok ( self )
366385 }
@@ -520,7 +539,7 @@ impl Joinstr<'_> {
520539 inner. client . send_pool_message ( & npub, response) ?;
521540 }
522541 peers. insert ( npub) ;
523- inner. registered_peers += 1 ;
542+ inner. peers . push ( npub ) ;
524543 log:: debug!(
525544 "Coordinator({}).register_outputs(): receive Join({}) request. \n peers: {}" ,
526545 inner. client. name,
@@ -588,10 +607,11 @@ impl Joinstr<'_> {
588607 inner. client. name,
589608 o
590609 ) ;
591- let outputs = vec ! [ o] ;
610+ let outputs = vec ! [ o. clone ( ) ] ;
592611 inner. receive_outputs ( outputs, & mut coinjoin) ?;
593612 // TODO: we must error if outputs > peers
594- inner. registered_outputs += 1 ;
613+ // TODO: check address network
614+ inner. outputs . push ( o. assume_checked ( ) ) ;
595615 }
596616 // FIXME: here it can be some cases where, because network timing, we can
597617 // receive a signed input before the output registration round ended, we should
@@ -709,14 +729,22 @@ impl Joinstr<'_> {
709729 }
710730 }
711731
712- /// Returns the current state of the [`Joinstr`] instance.
732+ /// Returns the current status of the [`Joinstr`] instance.
713733 ///
714734 /// # Returns
715- /// A [`State `] struct containing the current state information.
735+ /// A [`Status `] struct containing the current state information.
716736 pub fn status ( & self ) -> Status {
717737 self . inner . lock ( ) . expect ( "poisoned" ) . status ( )
718738 }
719739
740+ /// Returns the current serializable state of the [`Joinstr`] instance.
741+ ///
742+ /// # Returns
743+ /// A [`State`] struct containing the current state information.
744+ pub fn state ( & self ) -> Option < State > {
745+ self . inner . lock ( ) . expect ( "poisoned" ) . state ( )
746+ }
747+
720748 /// Start a coinjoin process, followings steps will be processed:
721749 /// - if no `pool` arg is passed, a new pool will be initiated.
722750 /// - if a `pool` arg is passed, it will join the pool
@@ -875,9 +903,9 @@ impl<'a> JoinstrInner<'a> {
875903 fn is_ready ( & self ) -> Result < ( ) , Error > {
876904 if self . pool . is_none ( )
877905 && self . denomination . is_some ( )
878- && self . peers . is_some ( )
906+ && self . peers_count . is_some ( )
879907 && self . timeout . is_some ( )
880- && ! self . relays . is_empty ( )
908+ && self . relay . is_some ( )
881909 && self . fee . is_some ( )
882910 {
883911 Ok ( ( ) )
@@ -888,13 +916,13 @@ impl<'a> JoinstrInner<'a> {
888916 if self . denomination . is_none ( ) {
889917 log:: error!( "Coordinator.is_ready(): denomination is missing!" )
890918 }
891- if self . peers . is_none ( ) {
919+ if self . peers_count . is_none ( ) {
892920 log:: error!( "Coordinator.is_ready(): peers is missing!" )
893921 }
894922 if self . timeout . is_none ( ) {
895923 log:: error!( "Coordinator.is_ready(): timeout is missing!" )
896924 }
897- if self . relays . is_empty ( ) {
925+ if self . relay . is_none ( ) {
898926 log:: error!( "Coordinator.is_ready(): no relay specified!" )
899927 }
900928 if self . fee . is_none ( ) {
@@ -924,14 +952,14 @@ impl<'a> JoinstrInner<'a> {
924952 } ) ,
925953 tor : Some ( Tor { enable : false } ) ,
926954 } ;
927- if self . relays . is_empty ( ) {
955+ if self . relay . is_none ( ) {
928956 return Err ( Error :: RelaysMissing ) ;
929957 } ;
930958 let payload = PoolPayload {
931959 denomination : self . denomination . ok_or ( Error :: DenominationMissing ) ?,
932- peers : self . peers . ok_or ( Error :: PeerMissing ) ?,
960+ peers : self . peers_count . ok_or ( Error :: PeerMissing ) ?,
933961 timeout : self . timeout . ok_or ( Error :: TimeoutMissing ) ?,
934- relays : self . relays . clone ( ) ,
962+ relays : self . relay . clone ( ) . map ( |r| vec ! [ r ] ) . unwrap_or_default ( ) ,
935963 fee : self . fee . clone ( ) . ok_or ( Error :: FeeMissing ) ?,
936964 transport,
937965 } ;
@@ -1020,7 +1048,7 @@ impl<'a> JoinstrInner<'a> {
10201048 self . pool_exists ( ) ?;
10211049 let npub = self . pool_as_ref ( ) ?. public_key ;
10221050 self . client . send_pool_message ( & npub, msg) ?;
1023- self . registered_outputs += 1 ;
1051+ self . outputs . push ( address . clone ( ) ) ;
10241052 // TODO: handle re-send if fails
10251053 Ok ( ( ) )
10261054 } else {
@@ -1086,11 +1114,11 @@ impl<'a> JoinstrInner<'a> {
10861114 let signed_input = signer
10871115 . sign_input ( & unsigned, input)
10881116 . map_err ( Error :: SigningFail ) ?;
1089- let msg = PoolMessage :: Input ( signed_input) ;
1117+ let msg = PoolMessage :: Input ( signed_input. clone ( ) ) ;
10901118 self . pool_exists ( ) ?;
10911119 let npub = self . pool_as_ref ( ) ?. public_key ;
10921120 self . client . send_pool_message ( & npub, msg) ?;
1093- self . registered_inputs += 1 ;
1121+ self . inputs . push ( signed_input ) ;
10941122 // TODO: handle re-send if fails
10951123 Ok ( ( ) )
10961124 } else {
@@ -1112,14 +1140,14 @@ impl<'a> JoinstrInner<'a> {
11121140 ) ;
11131141 // Register inputs
11141142 if let Some ( coinjoin) = self . coinjoin . as_mut ( ) {
1115- if let Err ( e) = coinjoin. add_input ( input) {
1143+ if let Err ( e) = coinjoin. add_input ( input. clone ( ) ) {
11161144 log:: error!(
11171145 "Coordinator({}).register_input(): fail to add input: {:?}" ,
11181146 self . client. name,
11191147 e
11201148 ) ;
11211149 } else {
1122- self . registered_inputs += 1 ;
1150+ self . inputs . push ( input ) ;
11231151 }
11241152 }
11251153 Ok ( ( ) )
@@ -1219,19 +1247,59 @@ impl<'a> JoinstrInner<'a> {
12191247 }
12201248 }
12211249
1222- /// Returns the current state of the [`JoinstrInner`] instance.
1250+ /// Returns the current status of the [`JoinstrInner`] instance.
12231251 ///
12241252 /// # Returns
1225- /// A [`State `] struct containing the current state information.
1253+ /// A [`Status `] struct containing the current status information.
12261254 pub fn status ( & self ) -> Status {
12271255 Status {
12281256 role : self . role ,
12291257 step : self . step ,
1230- registered_peers : self . registered_peers ,
1231- registered_outputs : self . registered_outputs ,
1232- registered_inputs : self . registered_inputs ,
1258+ registered_peers : self . peers . len ( ) ,
1259+ registered_outputs : self . outputs . len ( ) ,
1260+ registered_inputs : self . inputs . len ( ) ,
12331261 confirmations : self . confirmations ,
12341262 error : self . error . clone ( ) ,
12351263 }
12361264 }
1265+
1266+ /// Returns the current serializable state of the [`JoinstrInner`] instance.
1267+ ///
1268+ /// # Returns
1269+ /// A [`State`] struct containing the current state information.
1270+ pub fn state ( & self ) -> Option < State > {
1271+ let keys = if let Ok ( keys) = self . client . get_keys ( ) {
1272+ keys
1273+ } else {
1274+ return None ;
1275+ } ;
1276+ let relay = if let Some ( relay) = & self . relay {
1277+ relay. clone ( )
1278+ } else {
1279+ return None ;
1280+ } ;
1281+ let electrum = self . electrum_client . as_ref ( ) . map ( |c| c. url ( ) ) ;
1282+ let pool = if let Some ( pool) = & self . pool {
1283+ pool. clone ( )
1284+ } else {
1285+ return None ;
1286+ } ;
1287+ Some ( State {
1288+ pool_secret_key : keys. secret_key ( ) . to_secret_hex ( ) ,
1289+ relay,
1290+ electrum,
1291+ pool,
1292+ input : self . input . clone ( ) ,
1293+ output : self . output . clone ( ) . map ( |a| a. as_unchecked ( ) . clone ( ) ) ,
1294+ network : self . network ,
1295+ final_tx : self . final_tx . clone ( ) ,
1296+ peers : self . peers . clone ( ) ,
1297+ outputs : self
1298+ . outputs
1299+ . iter ( )
1300+ . map ( |a| a. as_unchecked ( ) . clone ( ) )
1301+ . collect ( ) ,
1302+ inputs : self . inputs . iter ( ) . map ( |i| i. to_json ( ) ) . collect ( ) ,
1303+ } )
1304+ }
12371305}
0 commit comments