@@ -36,8 +36,10 @@ mod finality;
3636mod notification;
3737mod report;
3838
39- use sc_finality_grandpa:: GrandpaJustificationStream ;
40- use sp_runtime:: traits:: Block as BlockT ;
39+ use sc_finality_grandpa:: { GrandpaJustificationStream , VoterCommand } ;
40+ use sc_rpc_api:: DenyUnsafe ;
41+ use sp_runtime:: traits:: { Block as BlockT , NumberFor } ;
42+ use sp_utils:: mpsc:: TracingUnboundedSender ;
4143
4244use finality:: { EncodedFinalityProofs , RpcFinalityProofProvider } ;
4345use report:: { ReportAuthoritySet , ReportVoterState , ReportedRoundStates } ;
@@ -57,6 +59,10 @@ pub trait GrandpaApi<Notification, Hash> {
5759 #[ rpc( name = "grandpa_roundState" ) ]
5860 fn round_state ( & self ) -> FutureResult < ReportedRoundStates > ;
5961
62+ /// Restarts the grandpa voter future
63+ #[ rpc( name = "grandpa_restartVoter" ) ]
64+ fn restart_voter ( & self ) -> Result < ( ) , jsonrpc_core:: Error > ;
65+
6066 /// Returns the block most recently finalized by Grandpa, alongside
6167 /// side its justification.
6268 #[ pubsub(
@@ -95,11 +101,15 @@ pub trait GrandpaApi<Notification, Hash> {
95101
96102/// Implements the GrandpaApi RPC trait for interacting with GRANDPA.
97103pub struct GrandpaRpcHandler < AuthoritySet , VoterState , Block : BlockT , ProofProvider > {
104+ /// Handle to the local grandpa voter future
105+ voter_worker_send_handle : TracingUnboundedSender < VoterCommand < Block :: Hash , NumberFor < Block > > > ,
98106 authority_set : AuthoritySet ,
99107 voter_state : VoterState ,
100108 justification_stream : GrandpaJustificationStream < Block > ,
101109 manager : SubscriptionManager ,
102110 finality_proof_provider : Arc < ProofProvider > ,
111+ /// Whether to deny unsafe calls
112+ deny_unsafe : DenyUnsafe ,
103113}
104114
105115impl < AuthoritySet , VoterState , Block : BlockT , ProofProvider >
@@ -108,21 +118,25 @@ impl<AuthoritySet, VoterState, Block: BlockT, ProofProvider>
108118 /// Creates a new GrandpaRpcHandler instance.
109119 pub fn new < E > (
110120 authority_set : AuthoritySet ,
121+ voter_worker_send_handle : TracingUnboundedSender < VoterCommand < Block :: Hash , NumberFor < Block > > > ,
111122 voter_state : VoterState ,
112123 justification_stream : GrandpaJustificationStream < Block > ,
113124 executor : E ,
114125 finality_proof_provider : Arc < ProofProvider > ,
126+ deny_unsafe : DenyUnsafe ,
115127 ) -> Self
116128 where
117129 E : Executor01 < Box < dyn Future01 < Item = ( ) , Error = ( ) > + Send > > + Send + Sync + ' static ,
118130 {
119131 let manager = SubscriptionManager :: new ( Arc :: new ( executor) ) ;
120132 Self {
121133 authority_set,
134+ voter_worker_send_handle,
122135 voter_state,
123136 justification_stream,
124137 manager,
125138 finality_proof_provider,
139+ deny_unsafe,
126140 }
127141 }
128142}
@@ -137,6 +151,12 @@ where
137151{
138152 type Metadata = sc_rpc:: Metadata ;
139153
154+ fn restart_voter ( & self ) -> Result < ( ) , jsonrpc_core:: Error > {
155+ self . deny_unsafe . check_if_safe ( ) ?;
156+ let _ = self . voter_worker_send_handle . unbounded_send ( VoterCommand :: Restart ) ;
157+ Ok ( ( ) )
158+ }
159+
140160 fn round_state ( & self ) -> FutureResult < ReportedRoundStates > {
141161 let round_states = ReportedRoundStates :: from ( & self . authority_set , & self . voter_state ) ;
142162 let future = async move { round_states } . boxed ( ) ;
@@ -211,6 +231,7 @@ mod tests {
211231 use sp_core:: crypto:: Public ;
212232 use sp_keyring:: Ed25519Keyring ;
213233 use sp_runtime:: traits:: { Block as BlockT , Header as HeaderT } ;
234+ use sp_utils:: mpsc:: tracing_unbounded;
214235 use substrate_test_runtime_client:: {
215236 runtime:: { Block , Header , H256 } ,
216237 DefaultTestClientBuilderExt ,
@@ -302,18 +323,19 @@ mod tests {
302323 }
303324 }
304325
305- fn setup_io_handler < VoterState > ( voter_state : VoterState ) -> (
326+ fn setup_io_handler < VoterState > ( voter_state : VoterState , deny_unsafe : DenyUnsafe ) -> (
306327 jsonrpc_core:: MetaIoHandler < sc_rpc:: Metadata > ,
307328 GrandpaJustificationSender < Block > ,
308329 ) where
309330 VoterState : ReportVoterState + Send + Sync + ' static ,
310331 {
311- setup_io_handler_with_finality_proofs ( voter_state, Default :: default ( ) )
332+ setup_io_handler_with_finality_proofs ( voter_state, Default :: default ( ) , deny_unsafe )
312333 }
313334
314335 fn setup_io_handler_with_finality_proofs < VoterState > (
315336 voter_state : VoterState ,
316337 finality_proofs : Vec < FinalityProofFragment < Header > > ,
338+ deny_unsafe : DenyUnsafe ,
317339 ) -> (
318340 jsonrpc_core:: MetaIoHandler < sc_rpc:: Metadata > ,
319341 GrandpaJustificationSender < Block > ,
@@ -322,13 +344,15 @@ mod tests {
322344 {
323345 let ( justification_sender, justification_stream) = GrandpaJustificationStream :: channel ( ) ;
324346 let finality_proof_provider = Arc :: new ( TestFinalityProofProvider { finality_proofs } ) ;
325-
347+ let ( voter_worker_send_handle , _ ) = tracing_unbounded ( "test_grandpa_voter_command" ) ;
326348 let handler = GrandpaRpcHandler :: new (
327349 TestAuthoritySet ,
350+ voter_worker_send_handle,
328351 voter_state,
329352 justification_stream,
330353 sc_rpc:: testing:: TaskExecutor ,
331354 finality_proof_provider,
355+ deny_unsafe,
332356 ) ;
333357
334358 let mut io = jsonrpc_core:: MetaIoHandler :: default ( ) ;
@@ -339,7 +363,7 @@ mod tests {
339363
340364 #[ test]
341365 fn uninitialized_rpc_handler ( ) {
342- let ( io, _) = setup_io_handler ( EmptyVoterState ) ;
366+ let ( io, _) = setup_io_handler ( EmptyVoterState , DenyUnsafe :: No ) ;
343367
344368 let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":1}"# ;
345369 let response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":1}"# ;
@@ -348,9 +372,31 @@ mod tests {
348372 assert_eq ! ( Some ( response. into( ) ) , io. handle_request_sync( request, meta) ) ;
349373 }
350374
375+ #[ test]
376+ fn restart_grandpa_voter ( ) {
377+ let ( io, _) = setup_io_handler ( TestVoterState , DenyUnsafe :: No ) ;
378+
379+ let request = r#"{"jsonrpc":"2.0","method":"grandpa_restartVoter","params":[],"id":1}"# ;
380+ let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"# ;
381+
382+ let meta = sc_rpc:: Metadata :: default ( ) ;
383+ assert_eq ! ( Some ( response. into( ) ) , io. handle_request_sync( request, meta) ) ;
384+ }
385+
386+ #[ test]
387+ fn restart_grandpa_voter_denied ( ) {
388+ let ( io, _) = setup_io_handler ( TestVoterState , DenyUnsafe :: Yes ) ;
389+
390+ let request = r#"{"jsonrpc":"2.0","method":"grandpa_restartVoter","params":[],"id":1}"# ;
391+ let response = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found"},"id":1}"# ;
392+
393+ let meta = sc_rpc:: Metadata :: default ( ) ;
394+ assert_eq ! ( Some ( response. into( ) ) , io. handle_request_sync( request, meta) ) ;
395+ }
396+
351397 #[ test]
352398 fn working_rpc_handler ( ) {
353- let ( io, _) = setup_io_handler ( TestVoterState ) ;
399+ let ( io, _) = setup_io_handler ( TestVoterState , DenyUnsafe :: No ) ;
354400
355401 let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":1}"# ;
356402 let response = "{\" jsonrpc\" :\" 2.0\" ,\" result\" :{\
@@ -379,7 +425,7 @@ mod tests {
379425
380426 #[ test]
381427 fn subscribe_and_unsubscribe_to_justifications ( ) {
382- let ( io, _) = setup_io_handler ( TestVoterState ) ;
428+ let ( io, _) = setup_io_handler ( TestVoterState , DenyUnsafe :: No ) ;
383429 let ( meta, _) = setup_session ( ) ;
384430
385431 // Subscribe
@@ -411,7 +457,7 @@ mod tests {
411457
412458 #[ test]
413459 fn subscribe_and_unsubscribe_with_wrong_id ( ) {
414- let ( io, _) = setup_io_handler ( TestVoterState ) ;
460+ let ( io, _) = setup_io_handler ( TestVoterState , DenyUnsafe :: No ) ;
415461 let ( meta, _) = setup_session ( ) ;
416462
417463 // Subscribe
@@ -483,7 +529,7 @@ mod tests {
483529
484530 #[ test]
485531 fn subscribe_and_listen_to_one_justification ( ) {
486- let ( io, justification_sender) = setup_io_handler ( TestVoterState ) ;
532+ let ( io, justification_sender) = setup_io_handler ( TestVoterState , DenyUnsafe :: No ) ;
487533 let ( meta, receiver) = setup_session ( ) ;
488534
489535 // Subscribe
@@ -529,6 +575,7 @@ mod tests {
529575 let ( io, _) = setup_io_handler_with_finality_proofs (
530576 TestVoterState ,
531577 finality_proofs. clone ( ) ,
578+ DenyUnsafe :: No ,
532579 ) ;
533580
534581 let request = "{\" jsonrpc\" :\" 2.0\" ,\" method\" :\" grandpa_proveFinality\" ,\" params\" :[\
0 commit comments