diff --git a/substrate/node/src/service.rs b/substrate/node/src/service.rs index fcf863ff..c3d570db 100644 --- a/substrate/node/src/service.rs +++ b/substrate/node/src/service.rs @@ -1,11 +1,9 @@ use std::{boxed::Box, sync::Arc, error::Error}; -use sp_keystore::SyncCryptoStore; use sp_runtime::traits::{Block as BlockTrait}; use sp_inherents::CreateInherentDataProviders; use sp_consensus::DisableProofRecording; -use sp_api::{BlockId, ProvideRuntimeApi}; -use sp_tendermint::TendermintApi; +use sp_api::ProvideRuntimeApi; use sc_executor::{NativeVersion, NativeExecutionDispatch, NativeElseWasmExecutor}; use sc_transaction_pool::FullPool; @@ -231,44 +229,23 @@ pub async fn new_full(mut config: Configuration) -> Result { number: Arc>, - signature_scheme: Arc>, + signature_scheme: TendermintValidators, } impl TendermintGossip { - pub(crate) fn new( - number: Arc>, - signature_scheme: Arc>, - ) -> Self { + pub(crate) fn new(number: Arc>, signature_scheme: TendermintValidators) -> Self { TendermintGossip { number, signature_scheme } } diff --git a/substrate/tendermint/client/src/authority/mod.rs b/substrate/tendermint/client/src/authority/mod.rs index c87c8394..7d910158 100644 --- a/substrate/tendermint/client/src/authority/mod.rs +++ b/substrate/tendermint/client/src/authority/mod.rs @@ -34,7 +34,8 @@ use tendermint_machine::{ }; use crate::{ - CONSENSUS_ID, PROTOCOL_NAME, TendermintValidator, validators::TendermintValidators, + CONSENSUS_ID, PROTOCOL_NAME, TendermintValidator, + validators::{TendermintSigner, TendermintValidators}, tendermint::TendermintImport, }; @@ -49,6 +50,8 @@ use import_future::ImportFuture; // as it's only Authority which implements tendermint_machine::ext::Network. Network has // verify_commit provided, and even non-authorities have to verify commits struct ActiveAuthority { + signer: TendermintSigner, + // Block whose gossip is being tracked number: Arc>, // Outgoing message queue, placed here as the GossipEngine itself can't be @@ -138,7 +141,7 @@ impl TendermintAuthority { /// as it will not return until the P2P stack shuts down. pub async fn authority( mut self, - validator: (u16, Arc), + keys: Arc, providers: T::CIDP, env: T::Environment, network: T::Network, @@ -165,21 +168,21 @@ impl TendermintAuthority { // Set this struct as active *self.import.providers.write().await = Some(providers); self.active = Some(ActiveAuthority { + signer: TendermintSigner(keys, self.import.validators.clone()), + number: number.clone(), gossip_queue: gossip_queue.clone(), env, announce: network, }); - let (validator, keys) = validator; - self.import.validators.set_keys(keys).await; let proposal = self .get_proposal(&self.import.client.header(BlockId::Hash(best_hash)).unwrap().unwrap()) .await; // We no longer need self, so let TendermintMachine become its owner - TendermintMachine::new(self, validator, last, proposal) + TendermintMachine::new(self, last, proposal) }; // Start receiving messages about the Tendermint process for this block @@ -248,11 +251,15 @@ impl Network for TendermintAuthority { const BLOCK_TIME: u32 = T::BLOCK_TIME_IN_SECONDS; - fn signature_scheme(&self) -> Arc> { + fn signer(&self) -> TendermintSigner { + self.active.as_ref().unwrap().signer.clone() + } + + fn signature_scheme(&self) -> TendermintValidators { self.import.validators.clone() } - fn weights(&self) -> Arc> { + fn weights(&self) -> TendermintValidators { self.import.validators.clone() } diff --git a/substrate/tendermint/client/src/tendermint.rs b/substrate/tendermint/client/src/tendermint.rs index 901c591e..042a6902 100644 --- a/substrate/tendermint/client/src/tendermint.rs +++ b/substrate/tendermint/client/src/tendermint.rs @@ -27,7 +27,7 @@ use crate::{ /// Tendermint import handler. pub struct TendermintImport { - pub(crate) validators: Arc>, + pub(crate) validators: TendermintValidators, pub(crate) providers: Arc>>, pub(crate) importing_block: Arc::Hash>>>, @@ -54,7 +54,7 @@ impl Clone for TendermintImport { impl TendermintImport { pub(crate) fn new(client: Arc) -> TendermintImport { TendermintImport { - validators: Arc::new(TendermintValidators::new(client.clone())), + validators: TendermintValidators::new(client.clone()), providers: Arc::new(AsyncRwLock::new(None)), importing_block: Arc::new(RwLock::new(None)), diff --git a/substrate/tendermint/client/src/validators.rs b/substrate/tendermint/client/src/validators.rs index c3299506..409733c7 100644 --- a/substrate/tendermint/client/src/validators.rs +++ b/substrate/tendermint/client/src/validators.rs @@ -3,8 +3,6 @@ use std::sync::{Arc, RwLock}; use async_trait::async_trait; -use tokio::sync::RwLock as AsyncRwLock; - use sp_core::Decode; use sp_application_crypto::{ RuntimePublic as PublicTrait, @@ -17,7 +15,7 @@ use sp_api::{BlockId, ProvideRuntimeApi}; use sc_client_api::HeaderBackend; -use tendermint_machine::ext::{BlockNumber, Round, Weights, SignatureScheme}; +use tendermint_machine::ext::{BlockNumber, Round, Weights, Signer, SignatureScheme}; use sp_tendermint::TendermintApi; @@ -82,49 +80,81 @@ impl Deref for Refresh { } /// Tendermint validators observer, providing data on the active validators. -pub struct TendermintValidators( - Refresh, - Arc>>>, -); +pub struct TendermintValidators(Refresh); +impl Clone for TendermintValidators { + fn clone(&self) -> Self { + Self(Refresh { _refresh: self.0._refresh.clone(), client: self.0.client.clone() }) + } +} impl TendermintValidators { pub(crate) fn new(client: Arc) -> TendermintValidators { - TendermintValidators( - Refresh { - _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module::(&client))), - client, - }, - Arc::new(AsyncRwLock::new(None)), - ) + TendermintValidators(Refresh { + _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module::(&client))), + client, + }) } +} - pub(crate) async fn set_keys(&self, keys: Arc) { - *self.1.write().await = Some(keys); +pub struct TendermintSigner( + pub(crate) Arc, + pub(crate) TendermintValidators, +); + +impl Clone for TendermintSigner { + fn clone(&self) -> Self { + Self(self.0.clone(), self.1.clone()) + } +} + +impl TendermintSigner { + async fn get_public_key(&self) -> Public { + let pubs = self.0.sr25519_public_keys(KEY_TYPE_ID).await; + if pubs.is_empty() { + self.0.sr25519_generate_new(KEY_TYPE_ID, None).await.unwrap() + } else { + pubs[0] + } } } #[async_trait] +impl Signer for TendermintSigner { + type ValidatorId = u16; + type Signature = Signature; + + async fn validator_id(&self) -> u16 { + let key = self.get_public_key().await; + for (i, k) in (*self.1 .0).read().unwrap().lookup.iter().enumerate() { + if k == &key { + return u16::try_from(i).unwrap(); + } + } + // TODO: Enable switching between being a validator and not being one, likely be returning + // Option here. Non-validators should be able to simply not broadcast when they think + // they have messages. + panic!("not a validator"); + } + + async fn sign(&self, msg: &[u8]) -> Signature { + Signature::decode( + &mut self + .0 + .sign_with(KEY_TYPE_ID, &self.get_public_key().await.into(), msg) + .await + .unwrap() + .unwrap() + .as_ref(), + ) + .unwrap() + } +} + impl SignatureScheme for TendermintValidators { type ValidatorId = u16; type Signature = Signature; type AggregateSignature = Vec; - - async fn sign(&self, msg: &[u8]) -> Signature { - let read = self.1.read().await; - let keys = read.as_ref().unwrap(); - let key = { - let pubs = keys.sr25519_public_keys(KEY_TYPE_ID).await; - if pubs.is_empty() { - keys.sr25519_generate_new(KEY_TYPE_ID, None).await.unwrap() - } else { - pubs[0] - } - }; - Signature::decode( - &mut keys.sign_with(KEY_TYPE_ID, &key.into(), msg).await.unwrap().unwrap().as_ref(), - ) - .unwrap() - } + type Signer = TendermintSigner; fn verify(&self, validator: u16, msg: &[u8], sig: &Signature) -> bool { self.0.read().unwrap().lookup[usize::try_from(validator).unwrap()].verify(&msg, sig)