From 596f4f64277aaf504a37f46b905c31c6787bf3fe Mon Sep 17 00:00:00 2001 From: holygits Date: Wed, 20 Jan 2021 18:53:18 +1300 Subject: [PATCH 1/5] Additional afg logs --- client/finality-grandpa/src/environment.rs | 3 +++ client/finality-grandpa/src/lib.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 9215dcb323..ff2681aa20 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -726,6 +726,9 @@ where let local_key = crate::is_voter(&self.voters, self.config.keystore.as_ref()); + // TODO: debug here + debug!(target: "afg", "sc_finality_grandpa::environment::round_data:local key {:?}", local_key); + let has_voted = match self.voter_set_state.has_voted(round) { HasVoted::Yes(id, vote) => { if local_key.as_ref().map(|k| k == &id).unwrap_or(false) { diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index a15130942c..27cb09d80b 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -626,6 +626,7 @@ fn global_communication( NumberFor: BlockNumberOps, { let is_voter = is_voter(voters, keystore).is_some(); + debug!(target: "afg", "global communication: is_voter {:?}", is_voter); // verification stream let (global_in, global_out) = network.global_communication( @@ -861,6 +862,7 @@ where }; let voters = persistent_data.authority_set.current_authorities(); + debug!(target: "afg", "VoterWork::new voters: {:?}", voters.clone()); let env = Arc::new(Environment { client, select_chain, @@ -938,6 +940,8 @@ where let last_completed_round = completed_rounds.last(); + // TODO: Maybe this create is not aware of the new session key availability + // https://github.com/paritytech/finality-grandpa/blob/fab75b5f12235a8758dbb112e2fed3e7014b3e86/src/voter/voting_round.rs#L127 let voter = voter::Voter::new( self.env.clone(), (*self.env.voters).clone(), From f41ec841ebe88cfbc2b034c1d37630c71805e81a Mon Sep 17 00:00:00 2001 From: holygits Date: Wed, 20 Jan 2021 21:01:32 +1300 Subject: [PATCH 2/5] proof of concept --- Cargo.lock | 3 +++ bin/node/cli/Cargo.toml | 2 ++ bin/node/cli/src/service.rs | 2 ++ bin/node/rpc/Cargo.toml | 1 + bin/node/rpc/src/lib.rs | 10 +++++++++- client/finality-grandpa/rpc/Cargo.toml | 1 + client/finality-grandpa/rpc/src/lib.rs | 21 +++++++++++++++++++-- client/finality-grandpa/src/import.rs | 2 +- client/finality-grandpa/src/lib.rs | 23 +++++++++++++++-------- client/finality-grandpa/src/observer.rs | 10 ++++++++++ 10 files changed, 63 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e935169e3c..abf8910f9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3794,6 +3794,7 @@ dependencies = [ "sp-timestamp", "sp-transaction-pool", "sp-trie", + "sp-utils", "structopt", "substrate-browser-utils", "substrate-build-script-utils", @@ -3892,6 +3893,7 @@ dependencies = [ "sp-consensus-babe", "sp-runtime", "sp-transaction-pool", + "sp-utils", "substrate-frame-rpc-system", ] @@ -6976,6 +6978,7 @@ dependencies = [ "sp-finality-grandpa", "sp-keyring", "sp-runtime", + "sp-utils", "substrate-test-runtime-client", ] diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 39df211707..71dd4e592b 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -57,6 +57,8 @@ sp-keyring = { version = "2.0.0", path = "../../../primitives/keyring" } sp-io = { version = "2.0.0", path = "../../../primitives/io" } sp-consensus = { version = "0.8.0", path = "../../../primitives/consensus/common" } sp-transaction-pool = { version = "2.0.0", path = "../../../primitives/transaction-pool" } +sp-utils = { version = "2.0.0", path = "../../../primitives/utils" } + # client dependencies sc-client-api = { version = "2.0.0", path = "../../../client/api" } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index b15ace6181..5ebd29bc8c 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -81,6 +81,7 @@ pub fn new_partial(config: &Configuration) -> Result), select_chain.clone(), )?; let justification_import = grandpa_block_import.clone(); + let send_voter_commands = grandpa_block_import.clone().send_voter_commands; let (block_import, babe_link) = sc_consensus_babe::block_import( sc_consensus_babe::Config::get_or_compute(&*client)?, @@ -136,6 +137,7 @@ pub fn new_partial(config: &Configuration) -> Result { @@ -74,6 +78,8 @@ pub struct BabeDeps { /// Extra dependencies for GRANDPA pub struct GrandpaDeps { + /// send handle for grandpa voter worker + pub voter_worker_send_handle: TracingUnboundedSender::Hash, NumberFor>>, /// Voting round info. pub shared_voter_state: SharedVoterState, /// Authority set info. @@ -142,6 +148,7 @@ pub fn create_full( shared_epoch_changes, } = babe; let GrandpaDeps { + voter_worker_send_handle, shared_voter_state, shared_authority_set, justification_stream, @@ -177,6 +184,7 @@ pub fn create_full( sc_finality_grandpa_rpc::GrandpaApi::to_delegate( GrandpaRpcHandler::new( shared_authority_set, + voter_worker_send_handle, shared_voter_state, justification_stream, subscription_executor, diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index c0c2ea8b27..d013847367 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -14,6 +14,7 @@ sc-rpc = { version = "2.0.0", path = "../../rpc" } sp-blockchain = { version = "2.0.0", path = "../../../primitives/blockchain" } sp-core = { version = "2.0.0", path = "../../../primitives/core" } sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" } +sp-utils = { version = "2.0.0", path = "../../../primitives/utils" } finality-grandpa = { version = "0.12.3", features = ["derive-codec"] } jsonrpc-core = "15.0.0" jsonrpc-core-client = "15.0.0" diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 172473ad65..55a4a6b5c6 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -36,8 +36,9 @@ mod finality; mod notification; mod report; -use sc_finality_grandpa::GrandpaJustificationStream; -use sp_runtime::traits::Block as BlockT; +use sc_finality_grandpa::{GrandpaJustificationStream, VoterCommand}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_utils::mpsc::TracingUnboundedSender; use finality::{EncodedFinalityProofs, RpcFinalityProofProvider}; use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates}; @@ -57,6 +58,11 @@ pub trait GrandpaApi { #[rpc(name = "grandpa_roundState")] fn round_state(&self) -> FutureResult; + /// Returns the state of the current best round state as well as the + /// ongoing background rounds. + #[rpc(name = "grandpa_restartVoter")] + fn restart_voter(&self) -> FutureResult; + /// Returns the block most recently finalized by Grandpa, alongside /// side its justification. #[pubsub( @@ -95,6 +101,7 @@ pub trait GrandpaApi { /// Implements the GrandpaApi RPC trait for interacting with GRANDPA. pub struct GrandpaRpcHandler { + voter_worker_send_handle: TracingUnboundedSender>>, authority_set: AuthoritySet, voter_state: VoterState, justification_stream: GrandpaJustificationStream, @@ -108,6 +115,7 @@ impl /// Creates a new GrandpaRpcHandler instance. pub fn new( authority_set: AuthoritySet, + voter_worker_send_handle: TracingUnboundedSender>>, voter_state: VoterState, justification_stream: GrandpaJustificationStream, executor: E, @@ -119,6 +127,7 @@ impl let manager = SubscriptionManager::new(Arc::new(executor)); Self { authority_set, + voter_worker_send_handle, voter_state, justification_stream, manager, @@ -137,6 +146,14 @@ where { type Metadata = sc_rpc::Metadata; + fn restart_voter(&self) -> FutureResult { + self.voter_worker_send_handle.unbounded_send(VoterCommand::Restart); + // return round state + let round_states = ReportedRoundStates::from(&self.authority_set, &self.voter_state); + let future = async move { round_states }.boxed(); + Box::new(future.map_err(jsonrpc_core::Error::from).compat()) + } + fn round_state(&self) -> FutureResult { let round_states = ReportedRoundStates::from(&self.authority_set, &self.voter_state); let future = async move { round_states }.boxed(); diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 04df95a318..88f75007a7 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -60,7 +60,7 @@ pub struct GrandpaBlockImport { inner: Arc, select_chain: SC, authority_set: SharedAuthoritySet>, - send_voter_commands: TracingUnboundedSender>>, + pub send_voter_commands: TracingUnboundedSender>>, consensus_changes: SharedConsensusChanges>, authority_set_hard_forks: HashMap>>, justification_sender: GrandpaJustificationSender, diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 27cb09d80b..aafb7ee6f8 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -375,20 +375,22 @@ impl BlockSyncRequester for NetworkBridge /// A new authority set along with the canonical block it changed at. #[derive(Debug)] -pub(crate) struct NewAuthoritySet { - pub(crate) canon_number: N, - pub(crate) canon_hash: H, - pub(crate) set_id: SetId, - pub(crate) authorities: AuthorityList, +pub struct NewAuthoritySet { + pub canon_number: N, + pub canon_hash: H, + pub set_id: SetId, + pub authorities: AuthorityList, } /// Commands issued to the voter. #[derive(Debug)] -pub(crate) enum VoterCommand { +pub enum VoterCommand { /// Pause the voter for given reason. Pause(String), /// New authorities. - ChangeAuthorities(NewAuthoritySet) + ChangeAuthorities(NewAuthoritySet), + /// Restart the local grandpa worker + Restart, } impl fmt::Display for VoterCommand { @@ -396,6 +398,7 @@ impl fmt::Display for VoterCommand { match *self { VoterCommand::Pause(ref reason) => write!(f, "Pausing voter: {}", reason), VoterCommand::ChangeAuthorities(_) => write!(f, "Changing authorities"), + VoterCommand::Restart => write!(f, "Restart the local grandpa worker"), } } } @@ -941,7 +944,6 @@ where let last_completed_round = completed_rounds.last(); // TODO: Maybe this create is not aware of the new session key availability - // https://github.com/paritytech/finality-grandpa/blob/fab75b5f12235a8758dbb112e2fed3e7014b3e86/src/voter/voting_round.rs#L127 let voter = voter::Voter::new( self.env.clone(), (*self.env.voters).clone(), @@ -1038,6 +1040,11 @@ where self.rebuild_voter(); Ok(()) } + VoterCommand::Restart => { + // This should do + self.rebuild_voter(); + Ok(()) + } } } } diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 6a9955aa86..2aa3f71872 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -332,6 +332,16 @@ where crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?; + set_state + }, + VoterCommand::Restart => { + let prev = self.persistent_data.set_state.read(); + let set_state = VoterSetState::Paused { + completed_rounds: prev.completed_rounds(), + }; + + crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?; + set_state }, }.into(); From 3d83e5a2bef9c77bda886eeccb10ebdcf8f51a52 Mon Sep 17 00:00:00 2001 From: holygits Date: Thu, 21 Jan 2021 11:47:07 +1300 Subject: [PATCH 3/5] Tidy up --- Cargo.lock | 1 + bin/node/cli/src/service.rs | 2 +- bin/node/rpc/src/lib.rs | 1 + client/finality-grandpa/rpc/Cargo.toml | 1 + client/finality-grandpa/rpc/src/lib.rs | 20 ++++++++++++-------- client/finality-grandpa/src/environment.rs | 3 --- client/finality-grandpa/src/import.rs | 9 ++++++++- client/finality-grandpa/src/lib.rs | 9 +++------ client/finality-grandpa/src/observer.rs | 11 +---------- 9 files changed, 28 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abf8910f9f..4a38a49bed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6970,6 +6970,7 @@ dependencies = [ "sc-finality-grandpa", "sc-network-test", "sc-rpc", + "sc-rpc-api", "serde", "serde_json", "sp-blockchain", diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 5ebd29bc8c..66796ba945 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -81,7 +81,7 @@ pub fn new_partial(config: &Configuration) -> Result), select_chain.clone(), )?; let justification_import = grandpa_block_import.clone(); - let send_voter_commands = grandpa_block_import.clone().send_voter_commands; + let send_voter_commands = grandpa_block_import.send_voter_commands(); let (block_import, babe_link) = sc_consensus_babe::block_import( sc_consensus_babe::Config::get_or_compute(&*client)?, diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index bfffca0258..f735dc663f 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -189,6 +189,7 @@ pub fn create_full( justification_stream, subscription_executor, finality_provider, + deny_unsafe, ) ) ); diff --git a/client/finality-grandpa/rpc/Cargo.toml b/client/finality-grandpa/rpc/Cargo.toml index d013847367..2b05c3e78c 100644 --- a/client/finality-grandpa/rpc/Cargo.toml +++ b/client/finality-grandpa/rpc/Cargo.toml @@ -27,6 +27,7 @@ log = "0.4.8" derive_more = "0.99.2" parity-scale-codec = { version = "1.3.0", features = ["derive"] } sc-client-api = { version = "2.0.0", path = "../../api" } +sc-rpc-api = { version = "0.8.0", path = "../../rpc-api" } [dev-dependencies] sc-block-builder = { version = "0.8.0", path = "../../block-builder" } diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 55a4a6b5c6..86f0aa446e 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -37,6 +37,7 @@ mod notification; mod report; use sc_finality_grandpa::{GrandpaJustificationStream, VoterCommand}; +use sc_rpc_api::DenyUnsafe; use sp_runtime::traits::{Block as BlockT, NumberFor}; use sp_utils::mpsc::TracingUnboundedSender; @@ -61,7 +62,7 @@ pub trait GrandpaApi { /// Returns the state of the current best round state as well as the /// ongoing background rounds. #[rpc(name = "grandpa_restartVoter")] - fn restart_voter(&self) -> FutureResult; + fn restart_voter(&self) -> Result<(), jsonrpc_core::Error>; /// Returns the block most recently finalized by Grandpa, alongside /// side its justification. @@ -101,12 +102,15 @@ pub trait GrandpaApi { /// Implements the GrandpaApi RPC trait for interacting with GRANDPA. pub struct GrandpaRpcHandler { - voter_worker_send_handle: TracingUnboundedSender>>, + /// Handle to the local grandpa voter future + voter_worker_send_handle: TracingUnboundedSender>>, authority_set: AuthoritySet, voter_state: VoterState, justification_stream: GrandpaJustificationStream, manager: SubscriptionManager, finality_proof_provider: Arc, + /// Whether to deny unsafe calls + deny_unsafe: DenyUnsafe, } impl @@ -120,6 +124,7 @@ impl justification_stream: GrandpaJustificationStream, executor: E, finality_proof_provider: Arc, + deny_unsafe: DenyUnsafe, ) -> Self where E: Executor01 + Send>> + Send + Sync + 'static, @@ -132,6 +137,7 @@ impl justification_stream, manager, finality_proof_provider, + deny_unsafe, } } } @@ -146,12 +152,10 @@ where { type Metadata = sc_rpc::Metadata; - fn restart_voter(&self) -> FutureResult { - self.voter_worker_send_handle.unbounded_send(VoterCommand::Restart); - // return round state - let round_states = ReportedRoundStates::from(&self.authority_set, &self.voter_state); - let future = async move { round_states }.boxed(); - Box::new(future.map_err(jsonrpc_core::Error::from).compat()) + fn restart_voter(&self) -> Result<(), jsonrpc_core::Error> { + self.deny_unsafe.check_if_safe()?; + let _ = self.voter_worker_send_handle.unbounded_send(VoterCommand::Restart); + Ok(()) } fn round_state(&self) -> FutureResult { diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index ff2681aa20..9215dcb323 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -726,9 +726,6 @@ where let local_key = crate::is_voter(&self.voters, self.config.keystore.as_ref()); - // TODO: debug here - debug!(target: "afg", "sc_finality_grandpa::environment::round_data:local key {:?}", local_key); - let has_voted = match self.voter_set_state.has_voted(round) { HasVoted::Yes(id, vote) => { if local_key.as_ref().map(|k| k == &id).unwrap_or(false) { diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 88f75007a7..ed131dc55e 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -60,13 +60,20 @@ pub struct GrandpaBlockImport { inner: Arc, select_chain: SC, authority_set: SharedAuthoritySet>, - pub send_voter_commands: TracingUnboundedSender>>, + send_voter_commands: TracingUnboundedSender>>, consensus_changes: SharedConsensusChanges>, authority_set_hard_forks: HashMap>>, justification_sender: GrandpaJustificationSender, _phantom: PhantomData, } +impl GrandpaBlockImport { + /// Get the grandpa voter future command handle + pub fn send_voter_commands(&self) -> TracingUnboundedSender>> { + self.send_voter_commands.clone() + } +} + impl Clone for GrandpaBlockImport { diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index aafb7ee6f8..f9587b5ab8 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -389,7 +389,7 @@ pub enum VoterCommand { Pause(String), /// New authorities. ChangeAuthorities(NewAuthoritySet), - /// Restart the local grandpa worker + /// Restart the local grandpa voter. Restart, } @@ -398,7 +398,7 @@ impl fmt::Display for VoterCommand { match *self { VoterCommand::Pause(ref reason) => write!(f, "Pausing voter: {}", reason), VoterCommand::ChangeAuthorities(_) => write!(f, "Changing authorities"), - VoterCommand::Restart => write!(f, "Restart the local grandpa worker"), + VoterCommand::Restart => write!(f, "Restart the local grandpa voter"), } } } @@ -629,7 +629,6 @@ fn global_communication( NumberFor: BlockNumberOps, { let is_voter = is_voter(voters, keystore).is_some(); - debug!(target: "afg", "global communication: is_voter {:?}", is_voter); // verification stream let (global_in, global_out) = network.global_communication( @@ -865,7 +864,6 @@ where }; let voters = persistent_data.authority_set.current_authorities(); - debug!(target: "afg", "VoterWork::new voters: {:?}", voters.clone()); let env = Arc::new(Environment { client, select_chain, @@ -943,7 +941,6 @@ where let last_completed_round = completed_rounds.last(); - // TODO: Maybe this create is not aware of the new session key availability let voter = voter::Voter::new( self.env.clone(), (*self.env.voters).clone(), @@ -1041,7 +1038,7 @@ where Ok(()) } VoterCommand::Restart => { - // This should do + info!(target: "afg", "Restarting grandpa voter..."); self.rebuild_voter(); Ok(()) } diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 2aa3f71872..70fee2e6df 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -334,16 +334,7 @@ where set_state }, - VoterCommand::Restart => { - let prev = self.persistent_data.set_state.read(); - let set_state = VoterSetState::Paused { - completed_rounds: prev.completed_rounds(), - }; - - crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?; - - set_state - }, + VoterCommand::Restart => return Ok(()), }.into(); self.rebuild_observer(); From 758f37195c69ce0c969ad66077b985466466d7a4 Mon Sep 17 00:00:00 2001 From: holygits Date: Thu, 21 Jan 2021 12:02:22 +1300 Subject: [PATCH 4/5] [ciskip] fix comment --- client/finality-grandpa/rpc/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 86f0aa446e..931e6e7d08 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -59,8 +59,7 @@ pub trait GrandpaApi { #[rpc(name = "grandpa_roundState")] fn round_state(&self) -> FutureResult; - /// Returns the state of the current best round state as well as the - /// ongoing background rounds. + /// Restarts the grandpa voter future #[rpc(name = "grandpa_restartVoter")] fn restart_voter(&self) -> Result<(), jsonrpc_core::Error>; From 1f3a1008f15eec539c9c62c0f88707d4b8b73432 Mon Sep 17 00:00:00 2001 From: holygits Date: Thu, 21 Jan 2021 13:42:11 +1300 Subject: [PATCH 5/5] Add RPC tests --- client/finality-grandpa/rpc/src/lib.rs | 43 +++++++++++++++++++++----- client/finality-grandpa/src/lib.rs | 6 +++- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/client/finality-grandpa/rpc/src/lib.rs b/client/finality-grandpa/rpc/src/lib.rs index 931e6e7d08..44168c4c6f 100644 --- a/client/finality-grandpa/rpc/src/lib.rs +++ b/client/finality-grandpa/rpc/src/lib.rs @@ -231,6 +231,7 @@ mod tests { use sp_core::crypto::Public; use sp_keyring::Ed25519Keyring; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; + use sp_utils::mpsc::tracing_unbounded; use substrate_test_runtime_client::{ runtime::{Block, Header, H256}, DefaultTestClientBuilderExt, @@ -322,18 +323,19 @@ mod tests { } } - fn setup_io_handler(voter_state: VoterState) -> ( + fn setup_io_handler(voter_state: VoterState, deny_unsafe: DenyUnsafe) -> ( jsonrpc_core::MetaIoHandler, GrandpaJustificationSender, ) where VoterState: ReportVoterState + Send + Sync + 'static, { - setup_io_handler_with_finality_proofs(voter_state, Default::default()) + setup_io_handler_with_finality_proofs(voter_state, Default::default(), deny_unsafe) } fn setup_io_handler_with_finality_proofs( voter_state: VoterState, finality_proofs: Vec>, + deny_unsafe: DenyUnsafe, ) -> ( jsonrpc_core::MetaIoHandler, GrandpaJustificationSender, @@ -342,13 +344,15 @@ mod tests { { let (justification_sender, justification_stream) = GrandpaJustificationStream::channel(); let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proofs }); - + let (voter_worker_send_handle, _) = tracing_unbounded("test_grandpa_voter_command"); let handler = GrandpaRpcHandler::new( TestAuthoritySet, + voter_worker_send_handle, voter_state, justification_stream, sc_rpc::testing::TaskExecutor, finality_proof_provider, + deny_unsafe, ); let mut io = jsonrpc_core::MetaIoHandler::default(); @@ -359,7 +363,7 @@ mod tests { #[test] fn uninitialized_rpc_handler() { - let (io, _) = setup_io_handler(EmptyVoterState); + let (io, _) = setup_io_handler(EmptyVoterState, DenyUnsafe::No); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":1}"#; let response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":1}"#; @@ -368,9 +372,31 @@ mod tests { assert_eq!(Some(response.into()), io.handle_request_sync(request, meta)); } + #[test] + fn restart_grandpa_voter() { + let (io, _) = setup_io_handler(TestVoterState, DenyUnsafe::No); + + let request = r#"{"jsonrpc":"2.0","method":"grandpa_restartVoter","params":[],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; + + let meta = sc_rpc::Metadata::default(); + assert_eq!(Some(response.into()), io.handle_request_sync(request, meta)); + } + + #[test] + fn restart_grandpa_voter_denied() { + let (io, _) = setup_io_handler(TestVoterState, DenyUnsafe::Yes); + + let request = r#"{"jsonrpc":"2.0","method":"grandpa_restartVoter","params":[],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found"},"id":1}"#; + + let meta = sc_rpc::Metadata::default(); + assert_eq!(Some(response.into()), io.handle_request_sync(request, meta)); + } + #[test] fn working_rpc_handler() { - let (io, _) = setup_io_handler(TestVoterState); + let (io, _) = setup_io_handler(TestVoterState, DenyUnsafe::No); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":1}"#; let response = "{\"jsonrpc\":\"2.0\",\"result\":{\ @@ -399,7 +425,7 @@ mod tests { #[test] fn subscribe_and_unsubscribe_to_justifications() { - let (io, _) = setup_io_handler(TestVoterState); + let (io, _) = setup_io_handler(TestVoterState, DenyUnsafe::No); let (meta, _) = setup_session(); // Subscribe @@ -431,7 +457,7 @@ mod tests { #[test] fn subscribe_and_unsubscribe_with_wrong_id() { - let (io, _) = setup_io_handler(TestVoterState); + let (io, _) = setup_io_handler(TestVoterState, DenyUnsafe::No); let (meta, _) = setup_session(); // Subscribe @@ -503,7 +529,7 @@ mod tests { #[test] fn subscribe_and_listen_to_one_justification() { - let (io, justification_sender) = setup_io_handler(TestVoterState); + let (io, justification_sender) = setup_io_handler(TestVoterState, DenyUnsafe::No); let (meta, receiver) = setup_session(); // Subscribe @@ -549,6 +575,7 @@ mod tests { let (io, _) = setup_io_handler_with_finality_proofs( TestVoterState, finality_proofs.clone(), + DenyUnsafe::No, ); let request = "{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_proveFinality\",\"params\":[\ diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index f9587b5ab8..3321c4eaa5 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -376,9 +376,13 @@ impl BlockSyncRequester for NetworkBridge /// A new authority set along with the canonical block it changed at. #[derive(Debug)] pub struct NewAuthoritySet { + /// Canonical block number pub canon_number: N, + /// Canonical block hash pub canon_hash: H, + /// Authority set id pub set_id: SetId, + /// The authority IDs pub authorities: AuthorityList, } @@ -1038,7 +1042,7 @@ where Ok(()) } VoterCommand::Restart => { - info!(target: "afg", "Restarting grandpa voter..."); + info!(target: "afg", "👴 restarting grandpa voter..."); self.rebuild_voter(); Ok(()) }