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<TaskManager, ServiceE })?; if is_authority { - let keys = keystore_container.sync_keystore(); - let key = SyncCryptoStore::sr25519_public_keys(&*keys, sc_tendermint::KEY_TYPE_ID) - .get(0) - .cloned() - .unwrap_or_else(|| { - SyncCryptoStore::sr25519_generate_new(&*keys, sc_tendermint::KEY_TYPE_ID, None).unwrap() - }); - - let mut spawned = false; - let mut validators = - client.runtime_api().validators(&BlockId::Hash(client.chain_info().finalized_hash)).unwrap(); - for (i, validator) in validators.drain(..).enumerate() { - if validator == key { - task_manager.spawn_essential_handle().spawn( - "tendermint", - None, - TendermintAuthority::new(authority).authority( - (u16::try_from(i).unwrap(), keystore_container.keystore()), - Cidp, - sc_basic_authorship::ProposerFactory::new( - task_manager.spawn_handle(), - client, - transaction_pool, - registry.as_ref(), - telemetry.map(|telemtry| telemtry.handle()), - ), - network, - None, - ), - ); - spawned = true; - break; - } - } - - if !spawned { - log::warn!("authority role yet not a validator"); - } + task_manager.spawn_essential_handle().spawn( + "tendermint", + None, + TendermintAuthority::new(authority).authority( + keystore_container.keystore(), + Cidp, + sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client, + transaction_pool, + registry.as_ref(), + telemetry.map(|telemtry| telemtry.handle()), + ), + network, + None, + ), + ); } network_starter.start_network(); diff --git a/substrate/tendermint/client/src/authority/gossip.rs b/substrate/tendermint/client/src/authority/gossip.rs index 9e1b54ef..fec5c8be 100644 --- a/substrate/tendermint/client/src/authority/gossip.rs +++ b/substrate/tendermint/client/src/authority/gossip.rs @@ -13,14 +13,11 @@ use crate::{TendermintValidator, validators::TendermintValidators}; #[derive(Clone)] pub(crate) struct TendermintGossip<T: TendermintValidator> { number: Arc<RwLock<u64>>, - signature_scheme: Arc<TendermintValidators<T>>, + signature_scheme: TendermintValidators<T>, } impl<T: TendermintValidator> TendermintGossip<T> { - pub(crate) fn new( - number: Arc<RwLock<u64>>, - signature_scheme: Arc<TendermintValidators<T>>, - ) -> Self { + pub(crate) fn new(number: Arc<RwLock<u64>>, signature_scheme: TendermintValidators<T>) -> 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<T: TendermintValidator> { + signer: TendermintSigner<T>, + // Block whose gossip is being tracked number: Arc<RwLock<u64>>, // Outgoing message queue, placed here as the GossipEngine itself can't be @@ -138,7 +141,7 @@ impl<T: TendermintValidator> TendermintAuthority<T> { /// as it will not return until the P2P stack shuts down. pub async fn authority( mut self, - validator: (u16, Arc<dyn CryptoStore>), + keys: Arc<dyn CryptoStore>, providers: T::CIDP, env: T::Environment, network: T::Network, @@ -165,21 +168,21 @@ impl<T: TendermintValidator> TendermintAuthority<T> { // 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<T: TendermintValidator> Network for TendermintAuthority<T> { const BLOCK_TIME: u32 = T::BLOCK_TIME_IN_SECONDS; - fn signature_scheme(&self) -> Arc<TendermintValidators<T>> { + fn signer(&self) -> TendermintSigner<T> { + self.active.as_ref().unwrap().signer.clone() + } + + fn signature_scheme(&self) -> TendermintValidators<T> { self.import.validators.clone() } - fn weights(&self) -> Arc<TendermintValidators<T>> { + fn weights(&self) -> TendermintValidators<T> { 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<T: TendermintValidator> { - pub(crate) validators: Arc<TendermintValidators<T>>, + pub(crate) validators: TendermintValidators<T>, pub(crate) providers: Arc<AsyncRwLock<Option<T::CIDP>>>, pub(crate) importing_block: Arc<RwLock<Option<<T::Block as Block>::Hash>>>, @@ -54,7 +54,7 @@ impl<T: TendermintValidator> Clone for TendermintImport<T> { impl<T: TendermintValidator> TendermintImport<T> { pub(crate) fn new(client: Arc<T::Client>) -> TendermintImport<T> { 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<T: TendermintClient> Deref for Refresh<T> { } /// Tendermint validators observer, providing data on the active validators. -pub struct TendermintValidators<T: TendermintClient>( - Refresh<T>, - Arc<AsyncRwLock<Option<Arc<dyn CryptoStore>>>>, -); +pub struct TendermintValidators<T: TendermintClient>(Refresh<T>); +impl<T: TendermintClient> Clone for TendermintValidators<T> { + fn clone(&self) -> Self { + Self(Refresh { _refresh: self.0._refresh.clone(), client: self.0.client.clone() }) + } +} impl<T: TendermintClient> TendermintValidators<T> { pub(crate) fn new(client: Arc<T::Client>) -> TendermintValidators<T> { - TendermintValidators( - Refresh { - _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module::<T>(&client))), - client, - }, - Arc::new(AsyncRwLock::new(None)), - ) + TendermintValidators(Refresh { + _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module::<T>(&client))), + client, + }) } +} - pub(crate) async fn set_keys(&self, keys: Arc<dyn CryptoStore>) { - *self.1.write().await = Some(keys); +pub struct TendermintSigner<T: TendermintClient>( + pub(crate) Arc<dyn CryptoStore>, + pub(crate) TendermintValidators<T>, +); + +impl<T: TendermintClient> Clone for TendermintSigner<T> { + fn clone(&self) -> Self { + Self(self.0.clone(), self.1.clone()) + } +} + +impl<T: TendermintClient> TendermintSigner<T> { + 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<T: TendermintClient> Signer for TendermintSigner<T> { + 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<u16> 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<T: TendermintClient> SignatureScheme for TendermintValidators<T> { type ValidatorId = u16; type Signature = Signature; type AggregateSignature = Vec<Signature>; - - 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<T>; fn verify(&self, validator: u16, msg: &[u8], sig: &Signature) -> bool { self.0.read().unwrap().lookup[usize::try_from(validator).unwrap()].verify(&msg, sig)