Skip to content
This repository was archived by the owner on Jul 4, 2022. It is now read-only.

Commit c8239c7

Browse files
authored
RPC Restart Grandpa Voter (#168)
* Add unsafe grandpa_restartVoter rpc to manually restart the grandpa voter worker on demand
1 parent 399cd5b commit c8239c7

File tree

10 files changed

+105
-18
lines changed

10 files changed

+105
-18
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/node/cli/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ sp-keyring = { version = "2.0.0", path = "../../../primitives/keyring" }
5757
sp-io = { version = "2.0.0", path = "../../../primitives/io" }
5858
sp-consensus = { version = "0.8.0", path = "../../../primitives/consensus/common" }
5959
sp-transaction-pool = { version = "2.0.0", path = "../../../primitives/transaction-pool" }
60+
sp-utils = { version = "2.0.0", path = "../../../primitives/utils" }
61+
6062

6163
# client dependencies
6264
sc-client-api = { version = "2.0.0", path = "../../../client/api" }

bin/node/cli/src/service.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
8181
client.clone(), &(client.clone() as Arc<_>), select_chain.clone(),
8282
)?;
8383
let justification_import = grandpa_block_import.clone();
84+
let send_voter_commands = grandpa_block_import.send_voter_commands();
8485

8586
let (block_import, babe_link) = sc_consensus_babe::block_import(
8687
sc_consensus_babe::Config::get_or_compute(&*client)?,
@@ -136,6 +137,7 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
136137
keystore: keystore.clone(),
137138
},
138139
grandpa: node_rpc::GrandpaDeps {
140+
voter_worker_send_handle: send_voter_commands.clone(),
139141
shared_voter_state: shared_voter_state.clone(),
140142
shared_authority_set: shared_authority_set.clone(),
141143
justification_stream: justification_stream.clone(),

bin/node/rpc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ sp-blockchain = { version = "2.0.0", path = "../../../primitives/blockchain" }
3131
sp-consensus = { version = "0.8.0", path = "../../../primitives/consensus/common" }
3232
sp-consensus-babe = { version = "0.8.0", path = "../../../primitives/consensus/babe" }
3333
sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" }
34+
sp-utils = { version = "2.0.0", path = "../../../primitives/utils" }
3435
sp-transaction-pool = { version = "2.0.0", path = "../../../primitives/transaction-pool" }
3536
substrate-frame-rpc-system = { version = "2.0.0", path = "../../../utils/frame/rpc/system" }

bin/node/rpc/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ use sc_consensus_babe::{Config, Epoch};
3737
use sc_consensus_babe_rpc::BabeRpcHandler;
3838
use sc_consensus_epochs::SharedEpochChanges;
3939
use sc_finality_grandpa::{
40-
SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream
40+
FinalityProofProvider, GrandpaJustificationStream, SharedVoterState, SharedAuthoritySet,
41+
VoterCommand,
4142
};
4243
use sc_finality_grandpa_rpc::GrandpaRpcHandler;
4344
use sc_keystore::KeyStorePtr;
@@ -48,7 +49,10 @@ use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend};
4849
use sp_consensus::SelectChain;
4950
use sp_consensus_babe::BabeApi;
5051
use sc_rpc::SubscriptionTaskExecutor;
52+
use sp_runtime::traits::{Block as BlockT, NumberFor};
5153
use sp_transaction_pool::TransactionPool;
54+
use sp_utils::mpsc::TracingUnboundedSender;
55+
5256

5357
/// Light client extra dependencies.
5458
pub struct LightDeps<C, F, P> {
@@ -74,6 +78,8 @@ pub struct BabeDeps {
7478

7579
/// Extra dependencies for GRANDPA
7680
pub struct GrandpaDeps<B> {
81+
/// send handle for grandpa voter worker
82+
pub voter_worker_send_handle: TracingUnboundedSender<VoterCommand<<Block as BlockT>::Hash, NumberFor<Block>>>,
7783
/// Voting round info.
7884
pub shared_voter_state: SharedVoterState,
7985
/// Authority set info.
@@ -142,6 +148,7 @@ pub fn create_full<C, P, SC, B>(
142148
shared_epoch_changes,
143149
} = babe;
144150
let GrandpaDeps {
151+
voter_worker_send_handle,
145152
shared_voter_state,
146153
shared_authority_set,
147154
justification_stream,
@@ -177,10 +184,12 @@ pub fn create_full<C, P, SC, B>(
177184
sc_finality_grandpa_rpc::GrandpaApi::to_delegate(
178185
GrandpaRpcHandler::new(
179186
shared_authority_set,
187+
voter_worker_send_handle,
180188
shared_voter_state,
181189
justification_stream,
182190
subscription_executor,
183191
finality_provider,
192+
deny_unsafe,
184193
)
185194
)
186195
);

client/finality-grandpa/rpc/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ sc-rpc = { version = "2.0.0", path = "../../rpc" }
1414
sp-blockchain = { version = "2.0.0", path = "../../../primitives/blockchain" }
1515
sp-core = { version = "2.0.0", path = "../../../primitives/core" }
1616
sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" }
17+
sp-utils = { version = "2.0.0", path = "../../../primitives/utils" }
1718
finality-grandpa = { version = "0.12.3", features = ["derive-codec"] }
1819
jsonrpc-core = "15.0.0"
1920
jsonrpc-core-client = "15.0.0"
@@ -26,6 +27,7 @@ log = "0.4.8"
2627
derive_more = "0.99.2"
2728
parity-scale-codec = { version = "1.3.0", features = ["derive"] }
2829
sc-client-api = { version = "2.0.0", path = "../../api" }
30+
sc-rpc-api = { version = "0.8.0", path = "../../rpc-api" }
2931

3032
[dev-dependencies]
3133
sc-block-builder = { version = "0.8.0", path = "../../block-builder" }

client/finality-grandpa/rpc/src/lib.rs

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ mod finality;
3636
mod notification;
3737
mod 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

4244
use finality::{EncodedFinalityProofs, RpcFinalityProofProvider};
4345
use 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.
97103
pub 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

105115
impl<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\":[\

client/finality-grandpa/src/import.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ pub struct GrandpaBlockImport<Backend, Block: BlockT, Client, SC> {
6767
_phantom: PhantomData<Backend>,
6868
}
6969

70+
impl<Backend, Block: BlockT, Client, SC> GrandpaBlockImport<Backend, Block, Client, SC> {
71+
/// Get the grandpa voter future command handle
72+
pub fn send_voter_commands(&self) -> TracingUnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>> {
73+
self.send_voter_commands.clone()
74+
}
75+
}
76+
7077
impl<Backend, Block: BlockT, Client, SC: Clone> Clone for
7178
GrandpaBlockImport<Backend, Block, Client, SC>
7279
{

0 commit comments

Comments
 (0)