1
1
use std:: pin:: Pin ;
2
2
3
- use crate :: proto:: auth:: { self , Token } ;
4
3
use crate :: proto:: auth:: auth_service_server:: { AuthService , AuthServiceServer } ;
4
+ use crate :: proto:: auth:: { self , Token } ;
5
5
use crate :: proto:: bundle:: { Bundle , BundleUuid } ;
6
6
use crate :: proto:: packet:: { Packet , PacketBatch } ;
7
+ use base64:: prelude:: * ;
7
8
use chrono:: { Duration , Utc } ;
9
+ use futures:: select;
10
+ use futures:: FutureExt ;
11
+ use futures_util:: stream:: Stream ;
8
12
use log:: info;
9
13
use prost_types:: Timestamp ;
14
+ use rustyline:: { error:: ReadlineError , DefaultEditor } ;
15
+ use std:: net:: SocketAddr ;
16
+ use std:: sync:: Arc ;
17
+ use tokio:: sync:: { broadcast, mpsc} ;
10
18
use tonic:: { transport:: Server , Request , Response , Status } ;
11
- use futures_util:: stream:: Stream ;
12
- use base64:: prelude:: * ;
13
- use tokio:: sync:: mpsc;
14
19
15
- use crate :: proto:: block_engine:: block_engine_validator_server:: { BlockEngineValidator , BlockEngineValidatorServer } ;
16
- use crate :: proto:: block_engine:: { SubscribePacketsRequest , SubscribePacketsResponse , SubscribeBundlesRequest , SubscribeBundlesResponse , BlockBuilderFeeInfoRequest , BlockBuilderFeeInfoResponse } ;
20
+ use crate :: proto:: block_engine:: block_engine_validator_server:: {
21
+ BlockEngineValidator , BlockEngineValidatorServer ,
22
+ } ;
23
+ use crate :: proto:: block_engine:: {
24
+ BlockBuilderFeeInfoRequest , BlockBuilderFeeInfoResponse , SubscribeBundlesRequest ,
25
+ SubscribeBundlesResponse , SubscribePacketsRequest , SubscribePacketsResponse ,
26
+ } ;
17
27
18
- #[ derive( Debug , Default ) ]
19
- pub struct BlockEngineValidatorService ;
28
+ pub struct Service {
29
+ kill_streams : broadcast:: Receiver < ( ) > ,
30
+ }
31
+
32
+ #[ derive( Clone ) ]
33
+ pub struct ServiceHandle ( Arc < Service > ) ;
20
34
21
- type PacketResponseStream = Pin < Box < dyn Stream < Item = Result < SubscribePacketsResponse , Status > > + Send > > ;
22
- type BundleResponseStream = Pin < Box < dyn Stream < Item = Result < SubscribeBundlesResponse , Status > > + Send > > ;
35
+ type PacketResponseStream =
36
+ Pin < Box < dyn Stream < Item = Result < SubscribePacketsResponse , Status > > + Send > > ;
37
+ type BundleResponseStream =
38
+ Pin < Box < dyn Stream < Item = Result < SubscribeBundlesResponse , Status > > + Send > > ;
23
39
24
- pub mod proto {
25
- pub mod auth {
40
+ pub ( crate ) mod proto {
41
+ pub ( crate ) mod auth {
26
42
tonic:: include_proto!( "auth" ) ;
27
43
}
28
- pub mod block_engine {
44
+ pub ( crate ) mod block_engine {
29
45
tonic:: include_proto!( "block_engine" ) ;
30
46
}
31
- pub mod bundle {
47
+ pub ( crate ) mod bundle {
32
48
tonic:: include_proto!( "bundle" ) ;
33
49
}
34
- pub mod packet {
50
+ pub ( crate ) mod packet {
35
51
tonic:: include_proto!( "packet" ) ;
36
52
}
37
- pub mod relayer {
53
+ pub ( crate ) mod relayer {
38
54
tonic:: include_proto!( "relayer" ) ;
39
55
}
40
- pub mod shared {
56
+ pub ( crate ) mod shared {
41
57
tonic:: include_proto!( "shared" ) ;
42
58
}
43
59
}
44
60
45
61
#[ tonic:: async_trait]
46
- impl BlockEngineValidator for BlockEngineValidatorService {
62
+ impl BlockEngineValidator for ServiceHandle {
47
63
type SubscribePacketsStream = PacketResponseStream ;
48
64
type SubscribeBundlesStream = BundleResponseStream ;
49
65
50
66
async fn subscribe_packets (
51
67
& self ,
52
68
_request : Request < SubscribePacketsRequest > ,
53
69
) -> Result < Response < Self :: SubscribePacketsStream > , Status > {
70
+ let mut kill_streams = self . 0 . kill_streams . resubscribe ( ) ;
54
71
let ( tx, rx) = mpsc:: channel ( 16 ) ;
55
72
tokio:: spawn ( async move {
56
73
info ! ( "Packet stream start" ) ;
@@ -70,19 +87,23 @@ impl BlockEngineValidator for BlockEngineValidatorService {
70
87
} ) ,
71
88
} ;
72
89
loop {
73
- if tx . send ( Ok ( msg . clone ( ) ) ) . await . is_err ( ) {
74
- info ! ( "Packet stream stop" ) ;
75
- break ;
90
+ select ! {
91
+ _ = kill_streams . recv ( ) . fuse ( ) => break ,
92
+ res = tx . send ( Ok ( msg . clone ( ) ) ) . fuse ( ) => if res . is_err ( ) { break }
76
93
}
77
94
}
95
+ info ! ( "Packet stream stop" ) ;
78
96
} ) ;
79
- Ok ( Response :: new ( Box :: pin ( tokio_stream:: wrappers:: ReceiverStream :: new ( rx) ) ) )
97
+ Ok ( Response :: new ( Box :: pin (
98
+ tokio_stream:: wrappers:: ReceiverStream :: new ( rx) ,
99
+ ) ) )
80
100
}
81
101
82
102
async fn subscribe_bundles (
83
103
& self ,
84
104
_request : Request < SubscribeBundlesRequest > ,
85
105
) -> Result < Response < Self :: SubscribeBundlesStream > , Status > {
106
+ let mut kill_streams = self . 0 . kill_streams . resubscribe ( ) ;
86
107
let ( tx, rx) = mpsc:: channel ( 16 ) ;
87
108
tokio:: spawn ( async move {
88
109
info ! ( "Bundle stream start" ) ;
@@ -111,13 +132,16 @@ impl BlockEngineValidator for BlockEngineValidatorService {
111
132
]
112
133
} ;
113
134
loop {
114
- if tx . send ( Ok ( msg . clone ( ) ) ) . await . is_err ( ) {
115
- info ! ( "Bundle stream stop" ) ;
116
- break ;
135
+ select ! {
136
+ _ = kill_streams . recv ( ) . fuse ( ) => break ,
137
+ res = tx . send ( Ok ( msg . clone ( ) ) ) . fuse ( ) => if res . is_err ( ) { break }
117
138
}
118
139
}
140
+ info ! ( "Bundle stream stop" ) ;
119
141
} ) ;
120
- Ok ( Response :: new ( Box :: pin ( tokio_stream:: wrappers:: ReceiverStream :: new ( rx) ) ) )
142
+ Ok ( Response :: new ( Box :: pin (
143
+ tokio_stream:: wrappers:: ReceiverStream :: new ( rx) ,
144
+ ) ) )
121
145
}
122
146
123
147
async fn get_block_builder_fee_info (
@@ -133,17 +157,17 @@ impl BlockEngineValidator for BlockEngineValidatorService {
133
157
}
134
158
}
135
159
136
- #[ derive( Debug , Default ) ]
137
- pub struct Auth ;
138
-
139
160
#[ tonic:: async_trait]
140
- impl AuthService for Auth {
161
+ impl AuthService for ServiceHandle {
141
162
async fn generate_auth_challenge (
142
163
& self ,
143
164
request : Request < auth:: GenerateAuthChallengeRequest > ,
144
165
) -> Result < Response < auth:: GenerateAuthChallengeResponse > , Status > {
145
166
let req_data = request. into_inner ( ) ;
146
- info ! ( "Received auth challenge request from {}" , bs58:: encode( & req_data. pubkey) . into_string( ) ) ;
167
+ info ! (
168
+ "Received auth challenge request from {}" ,
169
+ bs58:: encode( & req_data. pubkey) . into_string( )
170
+ ) ;
147
171
Ok ( Response :: new ( auth:: GenerateAuthChallengeResponse {
148
172
challenge : "012345678" . to_string ( ) ,
149
173
} ) )
@@ -187,18 +211,100 @@ impl AuthService for Auth {
187
211
}
188
212
}
189
213
190
- #[ tokio:: main]
191
- async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
192
- env_logger:: init ( ) ;
214
+ struct Cnc {
215
+ kill_streams_tx : broadcast:: Sender < ( ) > ,
216
+ kill_server_tx : broadcast:: Sender < ( ) > ,
217
+ }
193
218
194
- let addr = "127.0.0.1:50051" . parse ( ) ?;
195
- info ! ( "Block Engine Validator Server listening on {}" , addr) ;
219
+ fn handle_line ( cnc : & mut Cnc , line : & str ) -> bool {
220
+ match line {
221
+ "" => return false ,
222
+ "help" => {
223
+ println ! ( "Available commands:" ) ;
224
+ println ! ( " help - Show this help message" ) ;
225
+ println ! ( " exit - Exit the server" ) ;
226
+ println ! ( " kill-streams - Kill all active streams" ) ;
227
+ println ! ( " kill-server - Kill and restart the server" ) ;
228
+ }
229
+ "exit" | "quit" => {
230
+ println ! ( "Exiting..." ) ;
231
+ std:: process:: exit ( 0 ) ;
232
+ }
233
+ "kill-streams" => {
234
+ let _ = cnc. kill_streams_tx . send ( ( ) ) ;
235
+ }
236
+ "kill-server" => {
237
+ let _ = cnc. kill_server_tx . send ( ( ) ) ;
238
+ }
239
+ cmd => {
240
+ println ! ( "Unknown command: {}" , cmd) ;
241
+ return false ;
242
+ }
243
+ }
244
+ true
245
+ }
196
246
197
- Server :: builder ( )
198
- . add_service ( BlockEngineValidatorServer :: new ( BlockEngineValidatorService :: default ( ) ) )
199
- . add_service ( AuthServiceServer :: new ( Auth :: default ( ) ) )
200
- . serve ( addr)
201
- . await ?;
247
+ async fn run_server (
248
+ service : ServiceHandle ,
249
+ listen_addr : SocketAddr ,
250
+ mut kill_signal : broadcast:: Receiver < ( ) > ,
251
+ ) {
252
+ loop {
253
+ let server = Server :: builder ( )
254
+ . add_service ( BlockEngineValidatorServer :: new ( service. clone ( ) ) )
255
+ . add_service ( AuthServiceServer :: new ( service. clone ( ) ) )
256
+ . serve_with_shutdown ( listen_addr. clone ( ) , kill_signal. recv ( ) . map ( |_| ( ) ) ) ;
257
+ server. await . unwrap ( ) ;
258
+ info ! ( "Restarting server" ) ;
259
+ }
260
+ }
261
+
262
+ fn main ( ) {
263
+ env_logger:: Builder :: from_env ( env_logger:: Env :: default ( ) . default_filter_or ( "info" ) ) . init ( ) ;
264
+
265
+ let ( kill_streams_tx, kill_streams_rx) = broadcast:: channel ( 2 ) ;
266
+ let ( kill_server_tx, kill_server_rx) = broadcast:: channel ( 2 ) ;
267
+
268
+ let mut cnc = Cnc {
269
+ kill_streams_tx,
270
+ kill_server_tx,
271
+ } ;
272
+
273
+ // Spawn a thread handling all gRPC I/O
274
+ let addr: SocketAddr = "127.0.0.1:50051" . parse ( ) . unwrap ( ) ;
275
+ let handle = std:: thread:: spawn ( move || {
276
+ let rt = tokio:: runtime:: Builder :: new_current_thread ( )
277
+ . enable_all ( )
278
+ . build ( )
279
+ . unwrap ( ) ;
202
280
203
- Ok ( ( ) )
281
+ let service = ServiceHandle ( Arc :: new ( Service {
282
+ kill_streams : kill_streams_rx,
283
+ } ) ) ;
284
+ rt. block_on ( run_server ( service, addr, kill_server_rx) ) ;
285
+ } ) ;
286
+
287
+ // Run a REPL on the current thread
288
+ let mut rl = match DefaultEditor :: new ( ) {
289
+ Ok ( rl) => rl,
290
+ Err ( _) => {
291
+ handle. join ( ) . unwrap ( ) ;
292
+ std:: process:: exit ( 1 ) ;
293
+ }
294
+ } ;
295
+ println ! ( "Block Engine Validator Server listening on {}" , addr) ;
296
+ loop {
297
+ let readline = rl. readline ( "" ) ;
298
+ match readline {
299
+ Ok ( line) => {
300
+ if handle_line ( & mut cnc, & line) {
301
+ let _ = rl. add_history_entry ( & line) ;
302
+ }
303
+ }
304
+ Err ( ReadlineError :: Interrupted ) | Err ( ReadlineError :: Eof ) => {
305
+ std:: process:: exit ( 0 ) ;
306
+ }
307
+ Err ( err) => panic ! ( "Unexpected error: {}" , err) ,
308
+ }
309
+ }
204
310
}
0 commit comments