diff --git a/Cargo.lock b/Cargo.lock index 7d54c17a..cc72ce40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7342,6 +7342,7 @@ dependencies = [ "sp-consensus", "sp-core", "sp-inherents", + "sp-keystore", "sp-runtime", "sp-staking", "sp-tendermint", diff --git a/substrate/tendermint/client/Cargo.toml b/substrate/tendermint/client/Cargo.toml index ab814f18..80215310 100644 --- a/substrate/tendermint/client/Cargo.toml +++ b/substrate/tendermint/client/Cargo.toml @@ -22,6 +22,7 @@ tokio = { version = "1", features = ["sync", "rt"] } sp-core = { git = "https://github.com/serai-dex/substrate" } sp-application-crypto = { git = "https://github.com/serai-dex/substrate" } +sp-keystore = { git = "https://github.com/serai-dex/substrate" } sp-inherents = { git = "https://github.com/serai-dex/substrate" } sp-staking = { git = "https://github.com/serai-dex/substrate" } sp-blockchain = { git = "https://github.com/serai-dex/substrate" } diff --git a/substrate/tendermint/client/src/authority/mod.rs b/substrate/tendermint/client/src/authority/mod.rs index 97be84ed..cdc547bf 100644 --- a/substrate/tendermint/client/src/authority/mod.rs +++ b/substrate/tendermint/client/src/authority/mod.rs @@ -135,6 +135,7 @@ impl TendermintAuthority { providers: T::CIDP, env: T::Environment, network: T::Network, + validator: (u16, T::Keystore), registry: Option<&Registry>, ) { let (best_hash, last) = self.get_last(); @@ -164,16 +165,15 @@ impl TendermintAuthority { 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; - TendermintMachine::new( - self, // We no longer need self, so let TendermintMachine become its owner - 0, // TODO: ValidatorId - last, proposal, - ) + // We no longer need self, so let TendermintMachine become its owner + TendermintMachine::new(self, validator, last, proposal) }; // Start receiving messages about the Tendermint process for this block diff --git a/substrate/tendermint/client/src/lib.rs b/substrate/tendermint/client/src/lib.rs index e40cd5ac..859bd304 100644 --- a/substrate/tendermint/client/src/lib.rs +++ b/substrate/tendermint/client/src/lib.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use sp_core::crypto::KeyTypeId; +use sp_keystore::CryptoStore; use sp_inherents::CreateInherentDataProviders; use sp_runtime::traits::{Header, Block}; use sp_blockchain::HeaderBackend; @@ -28,6 +30,7 @@ pub(crate) mod authority; pub use authority::TendermintAuthority; const CONSENSUS_ID: [u8; 4] = *b"tend"; +const KEY_TYPE_ID: KeyTypeId = KeyTypeId(CONSENSUS_ID); /// Trait consolidating all generics required by sc_tendermint for processing. pub trait TendermintClient: Send + Sync + 'static { @@ -55,6 +58,8 @@ pub trait TendermintClient: Send + Sync + 'static { + Finalizer + ProvideRuntimeApi + 'static; + + type Keystore: CryptoStore; } /// Trait implementable on firm types to automatically provide a full TendermintClient impl. @@ -72,6 +77,8 @@ pub trait TendermintClientMinimal: Send + Sync + 'static { + Finalizer + ProvideRuntimeApi + 'static; + + type Keystore: CryptoStore; } impl TendermintClient for T @@ -89,6 +96,8 @@ where type StateBackend = StateBackendFor; type Api = >::Api; type Client = T::Client; + + type Keystore = T::Keystore; } /// Trait consolidating additional generics required by sc_tendermint for authoring. diff --git a/substrate/tendermint/client/src/validators.rs b/substrate/tendermint/client/src/validators.rs index 58fdde28..210178d9 100644 --- a/substrate/tendermint/client/src/validators.rs +++ b/substrate/tendermint/client/src/validators.rs @@ -3,10 +3,14 @@ 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, Pair as PairTrait, - sr25519::{Public, Pair, Signature}, + RuntimePublic as PublicTrait, + sr25519::{Public, Signature}, }; +use sp_keystore::CryptoStore; use sp_staking::SessionIndex; use sp_api::{BlockId, ProvideRuntimeApi}; @@ -17,7 +21,7 @@ use tendermint_machine::ext::{BlockNumber, Round, Weights, SignatureScheme}; use sp_tendermint::TendermintApi; -use crate::TendermintClient; +use crate::{KEY_TYPE_ID, TendermintClient}; struct TendermintValidatorsStruct { session: SessionIndex, @@ -25,19 +29,18 @@ struct TendermintValidatorsStruct { total_weight: u64, weights: Vec, - keys: Pair, // TODO: sp_keystore lookup: Vec, } impl TendermintValidatorsStruct { - fn from_module(client: &Arc) -> TendermintValidatorsStruct { + fn from_module(client: &Arc) -> Self { let last = client.info().finalized_hash; let api = client.runtime_api(); let session = api.current_session(&BlockId::Hash(last)).unwrap(); let validators = api.validators(&BlockId::Hash(last)).unwrap(); assert_eq!(validators.len(), 1); - let keys = Pair::from_string("//Alice", None).unwrap(); - TendermintValidatorsStruct { + + Self { session, // TODO @@ -45,7 +48,6 @@ impl TendermintValidatorsStruct { weights: vec![1; validators.len()], lookup: validators, - keys, } } } @@ -82,15 +84,25 @@ impl Deref for Refresh { } /// Tendermint validators observer, providing data on the active validators. -pub struct TendermintValidators(Refresh); +pub struct TendermintValidators( + Refresh, + Arc>>, +); impl TendermintValidators { pub(crate) fn new(client: Arc) -> TendermintValidators { - TendermintValidators(Refresh { - _tc: PhantomData, - _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module::(&client))), - client, - }) + TendermintValidators( + Refresh { + _tc: PhantomData, + _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module::(&client))), + client, + }, + Arc::new(AsyncRwLock::new(None)), + ) + } + + pub(crate) async fn set_keys(&self, keys: T::Keystore) { + *self.1.write().await = Some(keys); } } @@ -101,7 +113,20 @@ impl SignatureScheme for TendermintValidators { type AggregateSignature = Vec; async fn sign(&self, msg: &[u8]) -> Signature { - self.0.read().unwrap().keys.sign(msg) + 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() } fn verify(&self, validator: u16, msg: &[u8], sig: &Signature) -> bool {