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

Commit cdd55fe

Browse files
committed
grandpa: use shared voter state to expose RPC endpoint
1 parent e803c89 commit cdd55fe

File tree

11 files changed

+152
-19
lines changed

11 files changed

+152
-19
lines changed

Cargo.lock

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

bin/node-template/node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ name = "node-template"
1515
futures = "0.3.4"
1616
log = "0.4.8"
1717
structopt = "0.3.8"
18+
parking_lot = "0.10.0"
1819

1920
sc-cli = { version = "0.8.0-alpha.5", path = "../../../client/cli" }
2021
sp-core = { version = "2.0.0-alpha.5", path = "../../../primitives/core" }

bin/node-template/node/src/service.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::sync::Arc;
44
use std::time::Duration;
5+
use parking_lot::RwLock;
56
use sc_client::LongestChain;
67
use sc_client_api::ExecutorProvider;
78
use node_template_runtime::{self, opaque::Block, RuntimeApi};
@@ -76,6 +77,7 @@ pub fn new_full(config: Configuration)
7677
let force_authoring = config.force_authoring;
7778
let name = config.name.clone();
7879
let disable_grandpa = config.disable_grandpa;
80+
let shared_voter_state = Arc::new(RwLock::new(None));
7981

8082
// sentry nodes announce themselves as authorities to the network
8183
// and should run the same protocols authorities do, but it should
@@ -160,7 +162,8 @@ pub fn new_full(config: Configuration)
160162
inherent_data_providers: inherent_data_providers.clone(),
161163
telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
162164
voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(),
163-
prometheus_registry: service.prometheus_registry()
165+
prometheus_registry: service.prometheus_registry(),
166+
shared_voter_state,
164167
};
165168

166169
// the GRANDPA voter task is considered infallible, i.e.

bin/node/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ log = "0.4.8"
4040
rand = "0.7.2"
4141
structopt = { version = "0.3.8", optional = true }
4242
tracing = "0.1.10"
43+
parking_lot = "0.10.0"
4344

4445
# primitives
4546
sp-authority-discovery = { version = "2.0.0-alpha.5", path = "../../../primitives/authority-discovery" }

bin/node/cli/src/service.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ macro_rules! new_full_start {
4949
type RpcExtension = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
5050
let mut import_setup = None;
5151
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
52+
let shared_voter_state: grandpa::SharedVoterState<grandpa::AuthorityId>
53+
= Arc::new(parking_lot::RwLock::new(None));
5254

5355
let builder = sc_service::ServiceBuilder::new_full::<
5456
node_primitives::Block, node_runtime::RuntimeApi, node_executor::Executor
@@ -91,6 +93,9 @@ macro_rules! new_full_start {
9193
.with_rpc_extensions(|builder| -> Result<RpcExtension, _> {
9294
let babe_link = import_setup.as_ref().map(|s| &s.2)
9395
.expect("BabeLink is present for full services or set up failed; qed.");
96+
let grandpa_link = import_setup.as_ref().map(|s| &s.1)
97+
.expect("GRANDPA LinkHalf is present for full services or set up failed; qed.");
98+
let shared_authority_set = grandpa_link.shared_authority_set();
9499
let deps = node_rpc::FullDeps {
95100
client: builder.client().clone(),
96101
pool: builder.pool(),
@@ -100,12 +105,14 @@ macro_rules! new_full_start {
100105
keystore: builder.keystore(),
101106
babe_config: sc_consensus_babe::BabeLink::config(babe_link).clone(),
102107
shared_epoch_changes: sc_consensus_babe::BabeLink::epoch_changes(babe_link).clone()
103-
}
108+
},
109+
shared_voter_state: Arc::clone(&shared_voter_state),
110+
shared_authority_set: shared_authority_set.clone(),
104111
};
105112
Ok(node_rpc::create_full(deps))
106113
})?;
107114

108-
(builder, import_setup, inherent_data_providers)
115+
(builder, import_setup, inherent_data_providers, shared_voter_state)
109116
}}
110117
}
111118

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

141-
let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config);
148+
let (builder, mut import_setup, inherent_data_providers, shared_voter_state)
149+
= new_full_start!($config);
142150

143151
let service = builder
144152
.with_finality_proof_provider(|client, backend| {
@@ -233,6 +241,7 @@ macro_rules! new_full {
233241
telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
234242
voting_rule: grandpa::VotingRulesBuilder::default().build(),
235243
prometheus_registry: service.prometheus_registry(),
244+
shared_voter_state,
236245
};
237246

238247
// the GRANDPA voter task is considered infallible, i.e.

bin/node/rpc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ sc-keystore = { version = "2.0.0-alpha.5", path = "../../../client/keystore" }
2525
sc-consensus-epochs = { version = "0.8.0-alpha.5", path = "../../../client/consensus/epochs" }
2626
sp-consensus = { version = "0.8.0-alpha.5", path = "../../../primitives/consensus/common" }
2727
sp-blockchain = { version = "2.0.0-alpha.5", path = "../../../primitives/blockchain" }
28+
sc-finality-grandpa = { version = "0.8.0-alpha.5", path = "../../../client/finality-grandpa" }
2829
sc-finality-grandpa-rpc = { version = "0.8.0-alpha.5", path = "../../../client/finality-grandpa/rpc" }
2930

3031
[package.metadata.docs.rs]

bin/node/rpc/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

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

34-
use node_primitives::{Block, BlockNumber, AccountId, Index, Balance};
34+
use node_primitives::{Block, BlockNumber, AccountId, Index, Balance, Hash};
3535
use node_runtime::UncheckedExtrinsic;
3636
use sp_api::ProvideRuntimeApi;
3737
use sp_transaction_pool::TransactionPool;
@@ -42,6 +42,7 @@ use sp_consensus_babe::BabeApi;
4242
use sc_consensus_epochs::SharedEpochChanges;
4343
use sc_consensus_babe::{Config, Epoch};
4444
use sc_consensus_babe_rpc::BabeRPCHandler;
45+
use sc_finality_grandpa::{SharedVoterState, AuthorityId, SharedAuthoritySet};
4546
use sc_finality_grandpa_rpc::GrandpaRpcHandler;
4647

4748
/// Light client extra dependencies.
@@ -76,6 +77,10 @@ pub struct FullDeps<C, P, SC> {
7677
pub select_chain: SC,
7778
/// BABE specific dependencies.
7879
pub babe: BabeDeps,
80+
/// Used to query the voter state in GRANDPA.
81+
pub shared_voter_state: SharedVoterState<AuthorityId>,
82+
/// WIP: add doc
83+
pub shared_authority_set: SharedAuthoritySet<Hash, BlockNumber>,
7984
}
8085

8186
/// Instantiate all Full RPC extensions.
@@ -103,7 +108,9 @@ pub fn create_full<C, P, M, SC>(
103108
client,
104109
pool,
105110
select_chain,
106-
babe
111+
babe,
112+
shared_voter_state,
113+
shared_authority_set,
107114
} = deps;
108115
let BabeDeps {
109116
keystore,
@@ -130,7 +137,7 @@ pub fn create_full<C, P, M, SC>(
130137
);
131138
io.extend_with(
132139
sc_finality_grandpa_rpc::GrandpaApi::to_delegate(
133-
GrandpaRpcHandler {}
140+
GrandpaRpcHandler::new(shared_voter_state, shared_authority_set)
134141
)
135142
);
136143

client/finality-grandpa/rpc/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ license = "GPL-3.0"
88

99
[dependencies]
1010
sc-finality-grandpa = { version = "0.8.0-alpha.5", path = "../" }
11+
#finality-grandpa = { version = "0.11.2", features = ["derive-codec"] }
12+
finality-grandpa = { git = "https://github.com/paritytech/finality-grandpa", branch = "andre/expose-voter-state-v11", features = ["derive-codec"] }
1113
jsonrpc-core = "14.0.3"
1214
jsonrpc-core-client = "14.0.3"
1315
jsonrpc-derive = "14.0.3"
1416
futures = "0.3.1"
17+
serde = { version = "1.0.105", features = ["derive"] }
18+
serde_json = "1.0.50"
1519

1620
[dev-dependencies]
1721
substrate-test-runtime-client = { version = "2.0.0-dev", path = "../../../test-utils/runtime/client" }

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

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,101 @@
1616

1717
//! RPC API for GRANDPA.
1818
19-
use futures::{FutureExt as _, TryFutureExt as _};
19+
use futures::{FutureExt, TryFutureExt};
2020
use jsonrpc_derive::rpc;
21-
use jsonrpc_core::{Error as RpcError, futures::future as rpc_future};
21+
use jsonrpc_core::Error;
22+
use sc_finality_grandpa::{SharedVoterState, SharedAuthoritySet, AuthorityId, voter};
23+
use finality_grandpa::BlockNumberOps;
24+
use serde::{Serialize, Deserialize};
25+
use std::{collections::HashSet, fmt::Debug};
2226

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

2529
#[rpc]
2630
pub trait GrandpaApi {
2731
#[rpc(name = "grandpa_roundState")]
28-
fn grandpa_roundState(&self) -> FutureResult<String>;
32+
fn grandpa_round_state(&self) -> FutureResult<RoundState>;
2933
}
3034

31-
pub struct GrandpaRpcHandler;
35+
pub struct GrandpaRpcHandler<Hash, Block> {
36+
// WIP: pass AuthorityId as type parameter
37+
shared_voter_state: SharedVoterState<AuthorityId>,
38+
shared_authority_set: SharedAuthoritySet<Hash, Block>,
39+
}
40+
41+
impl<Hash, Block> GrandpaRpcHandler<Hash, Block> {
42+
pub fn new(
43+
shared_voter_state: SharedVoterState<AuthorityId>,
44+
shared_authority_set: SharedAuthoritySet<Hash, Block>
45+
) -> Self {
46+
Self {
47+
shared_voter_state,
48+
shared_authority_set,
49+
}
50+
}
51+
}
52+
53+
#[derive(Serialize, Deserialize)]
54+
pub struct RoundState {
55+
pub set_id: u64,
56+
pub round: u64,
57+
pub total_weight: u64,
58+
pub threshold_weight: u64,
59+
60+
pub prevote_current_weight: u64,
61+
pub prevote_missing: HashSet<AuthorityId>,
62+
63+
pub precommit_current_weight: u64,
64+
pub precommit_missing: HashSet<AuthorityId>,
65+
}
66+
67+
impl RoundState {
68+
pub fn from<Hash, Block>(
69+
voter_state: &SharedVoterState<AuthorityId>,
70+
authority_set: &SharedAuthoritySet<Hash, Block>
71+
) -> Self
72+
where
73+
Hash: Debug + Clone + Eq + Send + Sync + 'static,
74+
Block: BlockNumberOps + Send + Sync + 'static,
75+
{
76+
let voter_state = voter_state.read().as_ref().map(|vs| vs.voter_state());
77+
// WIP: handle unwrap of lazily instantiated VoterState
78+
let voter_state = voter_state.unwrap();
79+
80+
let current_authorities = authority_set.current_authorities();
81+
82+
let voters = current_authorities.voters();
83+
let voters: HashSet<AuthorityId> = voters.iter().map(|p| p.0.clone()).collect();
84+
85+
let prevotes = voter_state.best_round.1.prevote_ids;
86+
let missing_prevotes = voters.difference(&prevotes).cloned().collect();
87+
88+
let precommits = voter_state.best_round.1.precommit_ids;
89+
let missing_precommits = voters.difference(&precommits).cloned().collect();
90+
91+
Self {
92+
set_id: authority_set.set_id(),
93+
round: voter_state.best_round.0,
94+
total_weight: voter_state.best_round.1.total_weight,
95+
threshold_weight: voter_state.best_round.1.threshold_weight,
96+
97+
prevote_current_weight: voter_state.best_round.1.prevote_current_weight,
98+
prevote_missing: missing_prevotes,
99+
100+
precommit_current_weight: voter_state.best_round.1.precommit_current_weight,
101+
precommit_missing: missing_precommits,
102+
}
103+
}
104+
}
32105

33-
impl GrandpaApi for GrandpaRpcHandler {
34-
fn grandpa_roundState(&self) -> FutureResult<String> {
106+
impl<Hash, Block: Send + Sync> GrandpaApi for GrandpaRpcHandler<Hash, Block> where
107+
Hash: Debug + Clone + Eq + Send + Sync + 'static,
108+
Block: BlockNumberOps + Send + Sync + 'static,
109+
{
110+
fn grandpa_round_state(&self) -> FutureResult<RoundState> {
111+
let round_state = RoundState::from(&self.shared_voter_state, &self.shared_authority_set);
35112
let future = async move {
36-
Ok(String::from("Hello world"))
113+
Ok(round_state)
37114
}.boxed();
38115
Box::new(future.compat())
39116
}

client/finality-grandpa/src/authorities.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use std::ops::Add;
3030
use std::sync::Arc;
3131

3232
/// A shared authority set.
33-
pub(crate) struct SharedAuthoritySet<H, N> {
33+
pub struct SharedAuthoritySet<H, N> {
3434
inner: Arc<RwLock<AuthoritySet<H, N>>>,
3535
}
3636

@@ -58,12 +58,12 @@ where N: Add<Output=N> + Ord + Clone + Debug,
5858
}
5959

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

6565
/// Get the current authorities and their weights (for the current set ID).
66-
pub(crate) fn current_authorities(&self) -> VoterSet<AuthorityId> {
66+
pub fn current_authorities(&self) -> VoterSet<AuthorityId> {
6767
self.inner.read().current_authorities.iter().cloned().collect()
6868
}
6969
}

0 commit comments

Comments
 (0)