Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
grandpa: use shared voter state to expose RPC endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
octol committed Apr 7, 2020
1 parent e803c89 commit cdd55fe
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 19 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions bin/node-template/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ name = "node-template"
futures = "0.3.4"
log = "0.4.8"
structopt = "0.3.8"
parking_lot = "0.10.0"

sc-cli = { version = "0.8.0-alpha.5", path = "../../../client/cli" }
sp-core = { version = "2.0.0-alpha.5", path = "../../../primitives/core" }
Expand Down
5 changes: 4 additions & 1 deletion bin/node-template/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use std::sync::Arc;
use std::time::Duration;
use parking_lot::RwLock;
use sc_client::LongestChain;
use sc_client_api::ExecutorProvider;
use node_template_runtime::{self, opaque::Block, RuntimeApi};
Expand Down Expand Up @@ -76,6 +77,7 @@ pub fn new_full(config: Configuration)
let force_authoring = config.force_authoring;
let name = config.name.clone();
let disable_grandpa = config.disable_grandpa;
let shared_voter_state = Arc::new(RwLock::new(None));

// sentry nodes announce themselves as authorities to the network
// and should run the same protocols authorities do, but it should
Expand Down Expand Up @@ -160,7 +162,8 @@ pub fn new_full(config: Configuration)
inherent_data_providers: inherent_data_providers.clone(),
telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(),
prometheus_registry: service.prometheus_registry()
prometheus_registry: service.prometheus_registry(),
shared_voter_state,
};

// the GRANDPA voter task is considered infallible, i.e.
Expand Down
1 change: 1 addition & 0 deletions bin/node/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ log = "0.4.8"
rand = "0.7.2"
structopt = { version = "0.3.8", optional = true }
tracing = "0.1.10"
parking_lot = "0.10.0"

# primitives
sp-authority-discovery = { version = "2.0.0-alpha.5", path = "../../../primitives/authority-discovery" }
Expand Down
15 changes: 12 additions & 3 deletions bin/node/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ macro_rules! new_full_start {
type RpcExtension = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
let mut import_setup = None;
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
let shared_voter_state: grandpa::SharedVoterState<grandpa::AuthorityId>
= Arc::new(parking_lot::RwLock::new(None));

let builder = sc_service::ServiceBuilder::new_full::<
node_primitives::Block, node_runtime::RuntimeApi, node_executor::Executor
Expand Down Expand Up @@ -91,6 +93,9 @@ macro_rules! new_full_start {
.with_rpc_extensions(|builder| -> Result<RpcExtension, _> {
let babe_link = import_setup.as_ref().map(|s| &s.2)
.expect("BabeLink is present for full services or set up failed; qed.");
let grandpa_link = import_setup.as_ref().map(|s| &s.1)
.expect("GRANDPA LinkHalf is present for full services or set up failed; qed.");
let shared_authority_set = grandpa_link.shared_authority_set();
let deps = node_rpc::FullDeps {
client: builder.client().clone(),
pool: builder.pool(),
Expand All @@ -100,12 +105,14 @@ macro_rules! new_full_start {
keystore: builder.keystore(),
babe_config: sc_consensus_babe::BabeLink::config(babe_link).clone(),
shared_epoch_changes: sc_consensus_babe::BabeLink::epoch_changes(babe_link).clone()
}
},
shared_voter_state: Arc::clone(&shared_voter_state),
shared_authority_set: shared_authority_set.clone(),
};
Ok(node_rpc::create_full(deps))
})?;

(builder, import_setup, inherent_data_providers)
(builder, import_setup, inherent_data_providers, shared_voter_state)
}}
}

Expand Down Expand Up @@ -138,7 +145,8 @@ macro_rules! new_full {
// never actively participate in any consensus process.
let participates_in_consensus = is_authority && !$config.sentry_mode;

let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config);
let (builder, mut import_setup, inherent_data_providers, shared_voter_state)
= new_full_start!($config);

let service = builder
.with_finality_proof_provider(|client, backend| {
Expand Down Expand Up @@ -233,6 +241,7 @@ macro_rules! new_full {
telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
voting_rule: grandpa::VotingRulesBuilder::default().build(),
prometheus_registry: service.prometheus_registry(),
shared_voter_state,
};

// the GRANDPA voter task is considered infallible, i.e.
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 @@ -25,6 +25,7 @@ sc-keystore = { version = "2.0.0-alpha.5", path = "../../../client/keystore" }
sc-consensus-epochs = { version = "0.8.0-alpha.5", path = "../../../client/consensus/epochs" }
sp-consensus = { version = "0.8.0-alpha.5", path = "../../../primitives/consensus/common" }
sp-blockchain = { version = "2.0.0-alpha.5", path = "../../../primitives/blockchain" }
sc-finality-grandpa = { version = "0.8.0-alpha.5", path = "../../../client/finality-grandpa" }
sc-finality-grandpa-rpc = { version = "0.8.0-alpha.5", path = "../../../client/finality-grandpa/rpc" }

[package.metadata.docs.rs]
Expand Down
13 changes: 10 additions & 3 deletions bin/node/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

use std::{sync::Arc, fmt};

use node_primitives::{Block, BlockNumber, AccountId, Index, Balance};
use node_primitives::{Block, BlockNumber, AccountId, Index, Balance, Hash};
use node_runtime::UncheckedExtrinsic;
use sp_api::ProvideRuntimeApi;
use sp_transaction_pool::TransactionPool;
Expand All @@ -42,6 +42,7 @@ use sp_consensus_babe::BabeApi;
use sc_consensus_epochs::SharedEpochChanges;
use sc_consensus_babe::{Config, Epoch};
use sc_consensus_babe_rpc::BabeRPCHandler;
use sc_finality_grandpa::{SharedVoterState, AuthorityId, SharedAuthoritySet};
use sc_finality_grandpa_rpc::GrandpaRpcHandler;

/// Light client extra dependencies.
Expand Down Expand Up @@ -76,6 +77,10 @@ pub struct FullDeps<C, P, SC> {
pub select_chain: SC,
/// BABE specific dependencies.
pub babe: BabeDeps,
/// Used to query the voter state in GRANDPA.
pub shared_voter_state: SharedVoterState<AuthorityId>,
/// WIP: add doc
pub shared_authority_set: SharedAuthoritySet<Hash, BlockNumber>,
}

/// Instantiate all Full RPC extensions.
Expand Down Expand Up @@ -103,7 +108,9 @@ pub fn create_full<C, P, M, SC>(
client,
pool,
select_chain,
babe
babe,
shared_voter_state,
shared_authority_set,
} = deps;
let BabeDeps {
keystore,
Expand All @@ -130,7 +137,7 @@ pub fn create_full<C, P, M, SC>(
);
io.extend_with(
sc_finality_grandpa_rpc::GrandpaApi::to_delegate(
GrandpaRpcHandler {}
GrandpaRpcHandler::new(shared_voter_state, shared_authority_set)
)
);

Expand Down
4 changes: 4 additions & 0 deletions client/finality-grandpa/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ license = "GPL-3.0"

[dependencies]
sc-finality-grandpa = { version = "0.8.0-alpha.5", path = "../" }
#finality-grandpa = { version = "0.11.2", features = ["derive-codec"] }
finality-grandpa = { git = "https://github.com/paritytech/finality-grandpa", branch = "andre/expose-voter-state-v11", features = ["derive-codec"] }
jsonrpc-core = "14.0.3"
jsonrpc-core-client = "14.0.3"
jsonrpc-derive = "14.0.3"
futures = "0.3.1"
serde = { version = "1.0.105", features = ["derive"] }
serde_json = "1.0.50"

[dev-dependencies]
substrate-test-runtime-client = { version = "2.0.0-dev", path = "../../../test-utils/runtime/client" }
93 changes: 85 additions & 8 deletions client/finality-grandpa/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,101 @@

//! RPC API for GRANDPA.
use futures::{FutureExt as _, TryFutureExt as _};
use futures::{FutureExt, TryFutureExt};
use jsonrpc_derive::rpc;
use jsonrpc_core::{Error as RpcError, futures::future as rpc_future};
use jsonrpc_core::Error;
use sc_finality_grandpa::{SharedVoterState, SharedAuthoritySet, AuthorityId, voter};
use finality_grandpa::BlockNumberOps;
use serde::{Serialize, Deserialize};
use std::{collections::HashSet, fmt::Debug};

type FutureResult<T> = Box<dyn rpc_future::Future<Item = T, Error = RpcError> + Send>;
type FutureResult<T> = Box<dyn jsonrpc_core::futures::Future<Item = T, Error = Error> + Send>;

#[rpc]
pub trait GrandpaApi {
#[rpc(name = "grandpa_roundState")]
fn grandpa_roundState(&self) -> FutureResult<String>;
fn grandpa_round_state(&self) -> FutureResult<RoundState>;
}

pub struct GrandpaRpcHandler;
pub struct GrandpaRpcHandler<Hash, Block> {
// WIP: pass AuthorityId as type parameter
shared_voter_state: SharedVoterState<AuthorityId>,
shared_authority_set: SharedAuthoritySet<Hash, Block>,
}

impl<Hash, Block> GrandpaRpcHandler<Hash, Block> {
pub fn new(
shared_voter_state: SharedVoterState<AuthorityId>,
shared_authority_set: SharedAuthoritySet<Hash, Block>
) -> Self {
Self {
shared_voter_state,
shared_authority_set,
}
}
}

#[derive(Serialize, Deserialize)]
pub struct RoundState {
pub set_id: u64,
pub round: u64,
pub total_weight: u64,
pub threshold_weight: u64,

pub prevote_current_weight: u64,
pub prevote_missing: HashSet<AuthorityId>,

pub precommit_current_weight: u64,
pub precommit_missing: HashSet<AuthorityId>,
}

impl RoundState {
pub fn from<Hash, Block>(
voter_state: &SharedVoterState<AuthorityId>,
authority_set: &SharedAuthoritySet<Hash, Block>
) -> Self
where
Hash: Debug + Clone + Eq + Send + Sync + 'static,
Block: BlockNumberOps + Send + Sync + 'static,
{
let voter_state = voter_state.read().as_ref().map(|vs| vs.voter_state());
// WIP: handle unwrap of lazily instantiated VoterState
let voter_state = voter_state.unwrap();

let current_authorities = authority_set.current_authorities();

let voters = current_authorities.voters();
let voters: HashSet<AuthorityId> = voters.iter().map(|p| p.0.clone()).collect();

let prevotes = voter_state.best_round.1.prevote_ids;
let missing_prevotes = voters.difference(&prevotes).cloned().collect();

let precommits = voter_state.best_round.1.precommit_ids;
let missing_precommits = voters.difference(&precommits).cloned().collect();

Self {
set_id: authority_set.set_id(),
round: voter_state.best_round.0,
total_weight: voter_state.best_round.1.total_weight,
threshold_weight: voter_state.best_round.1.threshold_weight,

prevote_current_weight: voter_state.best_round.1.prevote_current_weight,
prevote_missing: missing_prevotes,

precommit_current_weight: voter_state.best_round.1.precommit_current_weight,
precommit_missing: missing_precommits,
}
}
}

impl GrandpaApi for GrandpaRpcHandler {
fn grandpa_roundState(&self) -> FutureResult<String> {
impl<Hash, Block: Send + Sync> GrandpaApi for GrandpaRpcHandler<Hash, Block> where
Hash: Debug + Clone + Eq + Send + Sync + 'static,
Block: BlockNumberOps + Send + Sync + 'static,
{
fn grandpa_round_state(&self) -> FutureResult<RoundState> {
let round_state = RoundState::from(&self.shared_voter_state, &self.shared_authority_set);
let future = async move {
Ok(String::from("Hello world"))
Ok(round_state)
}.boxed();
Box::new(future.compat())
}
Expand Down
6 changes: 3 additions & 3 deletions client/finality-grandpa/src/authorities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use std::ops::Add;
use std::sync::Arc;

/// A shared authority set.
pub(crate) struct SharedAuthoritySet<H, N> {
pub struct SharedAuthoritySet<H, N> {
inner: Arc<RwLock<AuthoritySet<H, N>>>,
}

Expand Down Expand Up @@ -58,12 +58,12 @@ where N: Add<Output=N> + Ord + Clone + Debug,
}

/// Get the current set ID. This is incremented every time the set changes.
pub(crate) fn set_id(&self) -> u64 {
pub fn set_id(&self) -> u64 {
self.inner.read().set_id
}

/// Get the current authorities and their weights (for the current set ID).
pub(crate) fn current_authorities(&self) -> VoterSet<AuthorityId> {
pub fn current_authorities(&self) -> VoterSet<AuthorityId> {
self.inner.read().current_authorities.iter().cloned().collect()
}
}
Expand Down
Loading

0 comments on commit cdd55fe

Please sign in to comment.