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

Use sign_with for signing grandpa's outgoing message #6178

Merged
14 commits merged into from
Jun 9, 2020
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion bin/node-template/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ pub fn new_full(config: Configuration) -> Result<impl AbstractService, ServiceEr
// if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below.
let keystore = if role.is_authority() {
Some(service.keystore())
Some(service.keystore() as sp_core::traits::BareCryptoStorePtr)
} else {
None
};
Expand Down
4 changes: 2 additions & 2 deletions bin/node/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
//! Service implementation. Specialized wrapper over substrate service.

use std::sync::Arc;

use sc_consensus_babe;
use grandpa::{
self, FinalityProofProvider as GrandpaFinalityProofProvider, StorageAndProofProvider,
Expand Down Expand Up @@ -157,6 +156,7 @@ macro_rules! new_full {
use futures::prelude::*;
use sc_network::Event;
use sc_client_api::ExecutorProvider;
use sp_core::traits::BareCryptoStorePtr;

let (
role,
Expand Down Expand Up @@ -256,7 +256,7 @@ macro_rules! new_full {
// if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below.
let keystore = if role.is_authority() {
Some(service.keystore())
Some(service.keystore() as BareCryptoStorePtr)
} else {
None
};
Expand Down
1 change: 1 addition & 0 deletions client/finality-grandpa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ parking_lot = "0.10.0"
rand = "0.7.2"
assert_matches = "1.3.0"
parity-scale-codec = { version = "1.3.0", features = ["derive"] }
sp-application-crypto = { version = "2.0.0-rc3", path = "../../primitives/application-crypto" }
sp-arithmetic = { version = "2.0.0-rc3", path = "../../primitives/arithmetic" }
sp-runtime = { version = "2.0.0-rc3", path = "../../primitives/runtime" }
sp-utils = { version = "2.0.0-rc3", path = "../../primitives/utils" }
Expand Down
36 changes: 25 additions & 11 deletions client/finality-grandpa/src/communication/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ use parking_lot::Mutex;
use prometheus_endpoint::Registry;
use std::{pin::Pin, sync::Arc, task::{Context, Poll}};

use sp_core::traits::BareCryptoStorePtr;
use finality_grandpa::Message::{Prevote, Precommit, PrimaryPropose};
use finality_grandpa::{voter, voter_set::VoterSet};
use sc_network::{NetworkService, ReputationChange};
use sc_network_gossip::{GossipEngine, Network as GossipNetwork};
use parity_scale_codec::{Encode, Decode};
use sp_core::Pair;
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor};
use sc_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO};

Expand All @@ -58,7 +58,7 @@ use gossip::{
VoteMessage,
};
use sp_finality_grandpa::{
AuthorityPair, AuthorityId, AuthoritySignature, SetId as SetIdNumber, RoundNumber,
AuthorityId, AuthoritySignature, SetId as SetIdNumber, RoundNumber,
};
use sp_utils::mpsc::TracingUnboundedReceiver;

Expand Down Expand Up @@ -272,10 +272,11 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
/// network all within the current set.
pub(crate) fn round_communication(
&self,
keystore: Option<BareCryptoStorePtr>,
round: Round,
set_id: SetId,
voters: Arc<VoterSet<AuthorityId>>,
local_key: Option<AuthorityPair>,
local_key: Option<AuthorityId>,
has_voted: HasVoted<B>,
) -> (
impl Stream<Item = SignedMessage<B>> + Unpin,
Expand All @@ -287,10 +288,9 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
&*voters,
);

let locals = local_key.and_then(|pair| {
let id = pair.public();
let local_id = local_key.and_then(|id| {
if voters.contains(&id) {
Some((pair, id))
Some(id)
} else {
None
}
Expand Down Expand Up @@ -350,10 +350,11 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {

let (tx, out_rx) = mpsc::channel(0);
let outgoing = OutgoingMessages::<B> {
keystore: keystore.clone(),
round: round.0,
set_id: set_id.0,
network: self.gossip_engine.clone(),
locals,
local_id,
sender: tx,
has_voted,
};
Expand Down Expand Up @@ -628,10 +629,11 @@ pub struct SetId(pub SetIdNumber);
pub(crate) struct OutgoingMessages<Block: BlockT> {
round: RoundNumber,
set_id: SetIdNumber,
locals: Option<(AuthorityPair, AuthorityId)>,
local_id: Option<AuthorityId>,
sender: mpsc::Sender<SignedMessage<Block>>,
network: Arc<Mutex<GossipEngine<Block>>>,
has_voted: HasVoted<Block>,
keystore: Option<BareCryptoStorePtr>,
rakanalh marked this conversation as resolved.
Show resolved Hide resolved
}

impl<B: BlockT> Unpin for OutgoingMessages<B> {}
Expand Down Expand Up @@ -665,14 +667,26 @@ impl<Block: BlockT> Sink<Message<Block>> for OutgoingMessages<Block>
}

// when locals exist, sign messages on import
if let Some((ref pair, _)) = self.locals {
if let Some(ref public) = self.local_id {
let keystore = match &self.keystore {
Some(keystore) => keystore.clone(),
None => {
return Err(Error::Signing("Cannot sign without a keystore".to_string()))
andresilva marked this conversation as resolved.
Show resolved Hide resolved
}
};

let target_hash = *(msg.target().0);
let signed = sp_finality_grandpa::sign_message(
keystore,
msg,
pair,
public.clone(),
self.round,
self.set_id,
);
).ok_or(
Error::Signing(format!(
"Failed to sign GRANDPA vote for round {} targetting {:?}", self.round, target_hash
))
)?;

let message = GossipMessage::Vote(VoteMessage::<Block> {
message: signed.clone(),
Expand Down
20 changes: 10 additions & 10 deletions client/finality-grandpa/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use finality_grandpa::{
voter, voter_set::VoterSet,
};
use sp_blockchain::{HeaderBackend, HeaderMetadata, Error as ClientError};
use sp_core::Pair;
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{
Block as BlockT, Header as HeaderT, NumberFor, One, Zero,
Expand Down Expand Up @@ -704,11 +703,11 @@ where
let prevote_timer = Delay::new(self.config.gossip_duration * 2);
let precommit_timer = Delay::new(self.config.gossip_duration * 4);

let local_key = crate::is_voter(&self.voters, &self.config.keystore);
let local_key = crate::is_voter(&self.voters, self.config.keystore.as_ref());

let has_voted = match self.voter_set_state.has_voted(round) {
HasVoted::Yes(id, vote) => {
if local_key.as_ref().map(|k| k.public() == id).unwrap_or(false) {
if local_key.as_ref().map(|k| k == &id).unwrap_or(false) {
HasVoted::Yes(id, vote)
} else {
HasVoted::No
Expand All @@ -718,6 +717,7 @@ where
};

let (incoming, outgoing) = self.network.round_communication(
self.config.keystore.clone(),
crate::communication::Round(round),
crate::communication::SetId(self.set_id),
self.voters.clone(),
Expand All @@ -740,7 +740,7 @@ where
let outgoing = Box::pin(outgoing.sink_err_into());

voter::RoundData {
voter_id: local_key.map(|pair| pair.public()),
voter_id: local_key,
prevote_timer: Box::pin(prevote_timer.map(Ok)),
precommit_timer: Box::pin(precommit_timer.map(Ok)),
incoming,
Expand All @@ -749,10 +749,10 @@ where
}

fn proposed(&self, round: RoundNumber, propose: PrimaryPropose<Block>) -> Result<(), Self::Error> {
let local_id = crate::is_voter(&self.voters, &self.config.keystore);
let local_id = crate::is_voter(&self.voters, self.config.keystore.as_ref());

let local_id = match local_id {
Some(id) => id.public(),
Some(id) => id,
None => return Ok(()),
};

Expand Down Expand Up @@ -788,10 +788,10 @@ where
}

fn prevoted(&self, round: RoundNumber, prevote: Prevote<Block>) -> Result<(), Self::Error> {
let local_id = crate::is_voter(&self.voters, &self.config.keystore);
let local_id = crate::is_voter(&self.voters, self.config.keystore.as_ref());

let local_id = match local_id {
Some(id) => id.public(),
Some(id) => id,
None => return Ok(()),
};

Expand Down Expand Up @@ -829,10 +829,10 @@ where
}

fn precommitted(&self, round: RoundNumber, precommit: Precommit<Block>) -> Result<(), Self::Error> {
let local_id = crate::is_voter(&self.voters, &self.config.keystore);
let local_id = crate::is_voter(&self.voters, self.config.keystore.as_ref());

let local_id = match local_id {
Some(id) => id.public(),
Some(id) => id,
None => return Ok(()),
};

Expand Down
1 change: 1 addition & 0 deletions client/finality-grandpa/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ where
Error::Blockchain(error) => ConsensusError::ClientImport(error),
Error::Client(error) => ConsensusError::ClientImport(error.to_string()),
Error::Safety(error) => ConsensusError::ClientImport(error),
Error::Signing(error) => ConsensusError::ClientImport(error),
Error::Timer(error) => ConsensusError::ClientImport(error.to_string()),
});
},
Expand Down
51 changes: 29 additions & 22 deletions client/finality-grandpa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@

#![warn(missing_docs)]

use futures::prelude::*;
use futures::StreamExt;
use futures::{
prelude::*,
StreamExt,
};
use log::{debug, info};
use sc_client_api::{
backend::{AuxStore, Backend},
Expand All @@ -70,10 +72,13 @@ use sp_api::ProvideRuntimeApi;
use sp_blockchain::{HeaderBackend, Error as ClientError, HeaderMetadata};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{NumberFor, Block as BlockT, DigestFor, Zero};
use sc_keystore::KeyStorePtr;
use sp_inherents::InherentDataProviders;
use sp_consensus::{SelectChain, BlockImport};
use sp_core::Pair;
use sp_core::{
crypto::Public,
traits::BareCryptoStorePtr,
};
use sp_application_crypto::AppKey;
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver};
use sc_telemetry::{telemetry, CONSENSUS_INFO, CONSENSUS_DEBUG};
use parking_lot::RwLock;
Expand Down Expand Up @@ -131,10 +136,10 @@ use aux_schema::PersistentData;
use environment::{Environment, VoterSetState};
use until_imported::UntilGlobalMessageBlocksImported;
use communication::{NetworkBridge, Network as NetworkT};
use sp_finality_grandpa::{AuthorityList, AuthorityPair, AuthoritySignature, SetId};
use sp_finality_grandpa::{AuthorityList, AuthoritySignature, SetId};

// Re-export these two because it's just so damn convenient.
pub use sp_finality_grandpa::{AuthorityId, GrandpaApi, ScheduledChange};
pub use sp_finality_grandpa::{AuthorityId, AuthorityPair, GrandpaApi, ScheduledChange};
use std::marker::PhantomData;

#[cfg(test)]
Expand Down Expand Up @@ -264,7 +269,7 @@ pub struct Config {
/// Some local identifier of the voter.
pub name: Option<String>,
/// The keystore that manages the keys of this node.
pub keystore: Option<sc_keystore::KeyStorePtr>,
pub keystore: Option<BareCryptoStorePtr>,
}

impl Config {
Expand All @@ -284,6 +289,8 @@ pub enum Error {
Blockchain(String),
/// Could not complete a round on disk.
Client(ClientError),
/// Could not sign outgoing message
Signing(String),
/// An invariant has been violated (e.g. not finalizing pending change blocks in-order)
Safety(String),
/// A timer failed to fire.
Expand Down Expand Up @@ -586,7 +593,7 @@ fn global_communication<BE, Block: BlockT, C, N>(
voters: &Arc<VoterSet<AuthorityId>>,
client: Arc<C>,
network: &NetworkBridge<Block, N>,
keystore: &Option<KeyStorePtr>,
keystore: &Option<BareCryptoStorePtr>,
metrics: Option<until_imported::Metrics>,
) -> (
impl Stream<
Expand All @@ -602,7 +609,7 @@ fn global_communication<BE, Block: BlockT, C, N>(
N: NetworkT<Block>,
NumberFor<Block>: BlockNumberOps,
{
let is_voter = is_voter(voters, keystore).is_some();
let is_voter = is_voter(voters, keystore.as_ref()).is_some();

// verification stream
let (global_in, global_out) = network.global_communication(
Expand Down Expand Up @@ -729,7 +736,7 @@ pub fn run_grandpa_voter<Block: BlockT, BE: 'static, C, N, SC, VR>(
.for_each(move |_| {
let curr = authorities.current_authorities();
let mut auths = curr.iter().map(|(p, _)| p);
let maybe_authority_id = authority_id(&mut auths, &conf.keystore)
let maybe_authority_id = authority_id(&mut auths, conf.keystore.as_ref())
.unwrap_or_default();

telemetry!(CONSENSUS_INFO; "afg.authority_set";
Expand Down Expand Up @@ -865,8 +872,7 @@ where
fn rebuild_voter(&mut self) {
debug!(target: "afg", "{}: Starting new voter with set ID {}", self.env.config.name(), self.env.set_id);

let authority_id = is_voter(&self.env.voters, &self.env.config.keystore)
.map(|ap| ap.public())
let authority_id = is_voter(&self.env.voters, self.env.config.keystore.as_ref())
.unwrap_or_default();

telemetry!(CONSENSUS_DEBUG; "afg.starting_new_voter";
Expand Down Expand Up @@ -1089,32 +1095,33 @@ pub fn setup_disabled_grandpa<Block: BlockT, Client, N>(
/// Returns the key pair of the node that is being used in the current voter set or `None`.
fn is_voter(
voters: &Arc<VoterSet<AuthorityId>>,
keystore: &Option<KeyStorePtr>,
) -> Option<AuthorityPair> {
keystore: Option<&BareCryptoStorePtr>,
) -> Option<AuthorityId> {
match keystore {
Some(keystore) => voters
.iter()
.find_map(|(p, _)| keystore.read().key_pair::<AuthorityPair>(&p).ok()),
rakanalh marked this conversation as resolved.
Show resolved Hide resolved
.find(|(p, _)| {
keystore.read()
.has_keys(&[(p.to_raw_vec(), AuthorityId::ID)])
})
.map(|(p, _)| p.clone()),
None => None,
}
}

/// Returns the authority id of this node, if available.
fn authority_id<'a, I>(
authorities: &mut I,
keystore: &Option<KeyStorePtr>,
keystore: Option<&BareCryptoStorePtr>,
) -> Option<AuthorityId> where
I: Iterator<Item = &'a AuthorityId>,
{
match keystore {
Some(keystore) => {
authorities
.find_map(|p| {
keystore.read().key_pair::<AuthorityPair>(&p)
.ok()
.map(|ap| ap.public())
})
}
.find(|p| keystore.read().has_keys(&[(p.to_raw_vec(), AuthorityId::ID)]))
.cloned()
},
None => None,
}
}
Loading