Skip to content
This repository was archived by the owner on Jul 4, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions bin/node/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
2 changes: 2 additions & 0 deletions bin/node/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
client.clone(), &(client.clone() as Arc<_>), select_chain.clone(),
)?;
let justification_import = grandpa_block_import.clone();
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)?,
Expand Down Expand Up @@ -136,6 +137,7 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen
keystore: keystore.clone(),
},
grandpa: node_rpc::GrandpaDeps {
voter_worker_send_handle: send_voter_commands.clone(),
shared_voter_state: shared_voter_state.clone(),
shared_authority_set: shared_authority_set.clone(),
justification_stream: justification_stream.clone(),
Expand Down
1 change: 1 addition & 0 deletions bin/node/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ sp-blockchain = { version = "2.0.0", path = "../../../primitives/blockchain" }
sp-consensus = { version = "0.8.0", path = "../../../primitives/consensus/common" }
sp-consensus-babe = { version = "0.8.0", path = "../../../primitives/consensus/babe" }
sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" }
sp-utils = { version = "2.0.0", path = "../../../primitives/utils" }
sp-transaction-pool = { version = "2.0.0", path = "../../../primitives/transaction-pool" }
substrate-frame-rpc-system = { version = "2.0.0", path = "../../../utils/frame/rpc/system" }
11 changes: 10 additions & 1 deletion bin/node/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ use sc_consensus_babe::{Config, Epoch};
use sc_consensus_babe_rpc::BabeRpcHandler;
use sc_consensus_epochs::SharedEpochChanges;
use sc_finality_grandpa::{
SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream
FinalityProofProvider, GrandpaJustificationStream, SharedVoterState, SharedAuthoritySet,
VoterCommand,
};
use sc_finality_grandpa_rpc::GrandpaRpcHandler;
use sc_keystore::KeyStorePtr;
Expand All @@ -48,7 +49,10 @@ use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend};
use sp_consensus::SelectChain;
use sp_consensus_babe::BabeApi;
use sc_rpc::SubscriptionTaskExecutor;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use sp_transaction_pool::TransactionPool;
use sp_utils::mpsc::TracingUnboundedSender;


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

/// Extra dependencies for GRANDPA
pub struct GrandpaDeps<B> {
/// send handle for grandpa voter worker
pub voter_worker_send_handle: TracingUnboundedSender<VoterCommand<<Block as BlockT>::Hash, NumberFor<Block>>>,
/// Voting round info.
pub shared_voter_state: SharedVoterState,
/// Authority set info.
Expand Down Expand Up @@ -142,6 +148,7 @@ pub fn create_full<C, P, SC, B>(
shared_epoch_changes,
} = babe;
let GrandpaDeps {
voter_worker_send_handle,
shared_voter_state,
shared_authority_set,
justification_stream,
Expand Down Expand Up @@ -177,10 +184,12 @@ pub fn create_full<C, P, SC, B>(
sc_finality_grandpa_rpc::GrandpaApi::to_delegate(
GrandpaRpcHandler::new(
shared_authority_set,
voter_worker_send_handle,
shared_voter_state,
justification_stream,
subscription_executor,
finality_provider,
deny_unsafe,
)
)
);
Expand Down
2 changes: 2 additions & 0 deletions client/finality-grandpa/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -26,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" }
Expand Down
67 changes: 57 additions & 10 deletions client/finality-grandpa/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ 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 sc_rpc_api::DenyUnsafe;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use sp_utils::mpsc::TracingUnboundedSender;

use finality::{EncodedFinalityProofs, RpcFinalityProofProvider};
use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates};
Expand All @@ -57,6 +59,10 @@ pub trait GrandpaApi<Notification, Hash> {
#[rpc(name = "grandpa_roundState")]
fn round_state(&self) -> FutureResult<ReportedRoundStates>;

/// Restarts the grandpa voter future
#[rpc(name = "grandpa_restartVoter")]
fn restart_voter(&self) -> Result<(), jsonrpc_core::Error>;

/// Returns the block most recently finalized by Grandpa, alongside
/// side its justification.
#[pubsub(
Expand Down Expand Up @@ -95,11 +101,15 @@ pub trait GrandpaApi<Notification, Hash> {

/// Implements the GrandpaApi RPC trait for interacting with GRANDPA.
pub struct GrandpaRpcHandler<AuthoritySet, VoterState, Block: BlockT, ProofProvider> {
/// Handle to the local grandpa voter future
voter_worker_send_handle: TracingUnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>>,
authority_set: AuthoritySet,
voter_state: VoterState,
justification_stream: GrandpaJustificationStream<Block>,
manager: SubscriptionManager,
finality_proof_provider: Arc<ProofProvider>,
/// Whether to deny unsafe calls
deny_unsafe: DenyUnsafe,
}

impl<AuthoritySet, VoterState, Block: BlockT, ProofProvider>
Expand All @@ -108,21 +118,25 @@ impl<AuthoritySet, VoterState, Block: BlockT, ProofProvider>
/// Creates a new GrandpaRpcHandler instance.
pub fn new<E>(
authority_set: AuthoritySet,
voter_worker_send_handle: TracingUnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>>,
voter_state: VoterState,
justification_stream: GrandpaJustificationStream<Block>,
executor: E,
finality_proof_provider: Arc<ProofProvider>,
deny_unsafe: DenyUnsafe,
) -> Self
where
E: Executor01<Box<dyn Future01<Item = (), Error = ()> + Send>> + Send + Sync + 'static,
{
let manager = SubscriptionManager::new(Arc::new(executor));
Self {
authority_set,
voter_worker_send_handle,
voter_state,
justification_stream,
manager,
finality_proof_provider,
deny_unsafe,
}
}
}
Expand All @@ -137,6 +151,12 @@ where
{
type Metadata = sc_rpc::Metadata;

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<ReportedRoundStates> {
let round_states = ReportedRoundStates::from(&self.authority_set, &self.voter_state);
let future = async move { round_states }.boxed();
Expand Down Expand Up @@ -211,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,
Expand Down Expand Up @@ -302,18 +323,19 @@ mod tests {
}
}

fn setup_io_handler<VoterState>(voter_state: VoterState) -> (
fn setup_io_handler<VoterState>(voter_state: VoterState, deny_unsafe: DenyUnsafe) -> (
jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>,
GrandpaJustificationSender<Block>,
) 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<VoterState>(
voter_state: VoterState,
finality_proofs: Vec<FinalityProofFragment<Header>>,
deny_unsafe: DenyUnsafe,
) -> (
jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>,
GrandpaJustificationSender<Block>,
Expand All @@ -322,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();
Expand All @@ -339,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}"#;
Expand All @@ -348,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\":{\
Expand Down Expand Up @@ -379,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
Expand Down Expand Up @@ -411,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
Expand Down Expand Up @@ -483,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
Expand Down Expand Up @@ -529,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\":[\
Expand Down
7 changes: 7 additions & 0 deletions client/finality-grandpa/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ pub struct GrandpaBlockImport<Backend, Block: BlockT, Client, SC> {
_phantom: PhantomData<Backend>,
}

impl<Backend, Block: BlockT, Client, SC> GrandpaBlockImport<Backend, Block, Client, SC> {
/// Get the grandpa voter future command handle
pub fn send_voter_commands(&self) -> TracingUnboundedSender<VoterCommand<Block::Hash, NumberFor<Block>>> {
self.send_voter_commands.clone()
}
}

impl<Backend, Block: BlockT, Client, SC: Clone> Clone for
GrandpaBlockImport<Backend, Block, Client, SC>
{
Expand Down
Loading