From 5c08fa97017c48f5ebdeb482e3599b2f45fc43bf Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Thu, 27 Oct 2022 08:44:53 -0400 Subject: [PATCH] TendermintApi, compilation fixes --- Cargo.lock | 13 +++ substrate/node/Cargo.toml | 4 +- substrate/runtime/Cargo.toml | 6 +- substrate/runtime/src/lib.rs | 10 ++ substrate/tendermint/client/Cargo.toml | 6 +- .../tendermint/client/src/block_import.rs | 5 +- .../tendermint/client/src/import_queue.rs | 10 +- substrate/tendermint/client/src/tendermint.rs | 37 +++--- substrate/tendermint/client/src/validators.rs | 88 ++++++++++----- substrate/tendermint/client/src/verifier.rs | 5 +- substrate/tendermint/pallet/Cargo.toml | 2 + substrate/tendermint/pallet/src/lib.rs | 105 ++++++++++-------- substrate/tendermint/primitives/Cargo.toml | 9 ++ substrate/tendermint/primitives/src/lib.rs | 12 +- 14 files changed, 202 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26b922f7..edbeca40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5115,6 +5115,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-application-crypto", + "sp-core", + "sp-std", ] [[package]] @@ -7439,6 +7441,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-staking", + "sp-tendermint", "sp-timestamp", "substrate-prometheus-endpoint", "tendermint-machine", @@ -7558,6 +7561,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-std", + "sp-tendermint", "sp-transaction-pool", "sp-version", "substrate-wasm-builder", @@ -8318,6 +8322,15 @@ dependencies = [ "sp-std", ] +[[package]] +name = "sp-tendermint" +version = "0.1.0" +dependencies = [ + "sp-api", + "sp-core", + "sp-std", +] + [[package]] name = "sp-timestamp" version = "4.0.0-dev" diff --git a/substrate/node/Cargo.toml b/substrate/node/Cargo.toml index 316c458e..4dfb3700 100644 --- a/substrate/node/Cargo.toml +++ b/substrate/node/Cargo.toml @@ -47,9 +47,9 @@ sc-rpc-api = { git = "https://github.com/serai-dex/substrate" } substrate-frame-rpc-system = { git = "https://github.com/serai-dex/substrate" } pallet-transaction-payment-rpc = { git = "https://github.com/serai-dex/substrate" } -pallet-tendermint = { path = "../pallet-tendermint", default-features = false } +pallet-tendermint = { path = "../tendermint/pallet", default-features = false } serai-runtime = { path = "../runtime" } -serai-consensus = { path = "../consensus" } +serai-consensus = { path = "../tendermint/client" } [build-dependencies] substrate-build-script-utils = { git = "https://github.com/serai-dex/substrate.git" } diff --git a/substrate/runtime/Cargo.toml b/substrate/runtime/Cargo.toml index be0f08cd..39ce6bb4 100644 --- a/substrate/runtime/Cargo.toml +++ b/substrate/runtime/Cargo.toml @@ -29,6 +29,8 @@ sp-block-builder = { git = "https://github.com/serai-dex/substrate", default-fea sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } sp-api = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-tendermint = { path = "../tendermint/primitives", default-features = false } + frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-executive = { git = "https://github.com/serai-dex/substrate", default-features = false } @@ -43,7 +45,7 @@ pallet-contracts-primitives = { git = "https://github.com/serai-dex/substrate", pallet-contracts = { git = "https://github.com/serai-dex/substrate", default-features = false } pallet-session = { git = "https://github.com/serai-dex/substrate", default-features = false } -pallet-tendermint = { path = "../pallet-tendermint", default-features = false } +pallet-tendermint = { path = "../tendermint/pallet", default-features = false } frame-system-rpc-runtime-api = { git = "https://github.com/serai-dex/substrate", default-features = false } pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/serai-dex/substrate", default-features = false } @@ -68,6 +70,8 @@ std = [ "sp-runtime/std", "sp-api/std", + "sp-tendermint/std", + "frame-system/std", "frame-support/std", "frame-executive/std", diff --git a/substrate/runtime/src/lib.rs b/substrate/runtime/src/lib.rs index 3f762595..7e8b29f1 100644 --- a/substrate/runtime/src/lib.rs +++ b/substrate/runtime/src/lib.rs @@ -361,6 +361,16 @@ sp_api::impl_runtime_apis! { } } + impl sp_tendermint::TendermintApi for Runtime { + fn current_session() -> u32 { + Tendermint::session() + } + + fn validators() -> Vec { + Session::validators() + } + } + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(account: AccountId) -> Index { System::account_nonce(account) diff --git a/substrate/tendermint/client/Cargo.toml b/substrate/tendermint/client/Cargo.toml index 76cf2863..37dde6d1 100644 --- a/substrate/tendermint/client/Cargo.toml +++ b/substrate/tendermint/client/Cargo.toml @@ -30,6 +30,8 @@ sp-runtime = { git = "https://github.com/serai-dex/substrate" } sp-api = { git = "https://github.com/serai-dex/substrate" } sp-consensus = { git = "https://github.com/serai-dex/substrate" } +sp-tendermint = { path = "../primitives" } + sc-transaction-pool = { git = "https://github.com/serai-dex/substrate" } sc-basic-authorship = { git = "https://github.com/serai-dex/substrate" } sc-executor = { git = "https://github.com/serai-dex/substrate" } @@ -43,6 +45,6 @@ pallet-session = { git = "https://github.com/serai-dex/substrate" } substrate-prometheus-endpoint = { git = "https://github.com/serai-dex/substrate" } -tendermint-machine = { path = "../tendermint", features = ["substrate"] } +tendermint-machine = { path = "../machine", features = ["substrate"] } -serai-runtime = { path = "../runtime" } +serai-runtime = { path = "../../runtime" } diff --git a/substrate/tendermint/client/src/block_import.rs b/substrate/tendermint/client/src/block_import.rs index 46dac4b1..ae654351 100644 --- a/substrate/tendermint/client/src/block_import.rs +++ b/substrate/tendermint/client/src/block_import.rs @@ -2,7 +2,6 @@ use std::{sync::Arc, collections::HashMap}; use async_trait::async_trait; -use sp_core::sr25519::Public; use sp_inherents::CreateInherentDataProviders; use sp_runtime::traits::Block; use sp_api::TransactionFor; @@ -12,7 +11,7 @@ use sc_consensus::{BlockCheckParams, BlockImportParams, ImportResult, BlockImpor use sc_client_api::Backend; -use frame_support::traits::ValidatorSet; +use sp_tendermint::TendermintApi; use crate::{ tendermint::{TendermintClient, TendermintImport}, @@ -32,7 +31,7 @@ where TransactionFor: Send + Sync + 'static, Arc: BlockImport>, as BlockImport>::Error: Into, - C::Api: ValidatorSet, + C::Api: TendermintApi, { type Error = Error; type Transaction = TransactionFor; diff --git a/substrate/tendermint/client/src/import_queue.rs b/substrate/tendermint/client/src/import_queue.rs index fb31d307..cf641d6a 100644 --- a/substrate/tendermint/client/src/import_queue.rs +++ b/substrate/tendermint/client/src/import_queue.rs @@ -6,7 +6,7 @@ use std::{ time::{UNIX_EPOCH, SystemTime}, }; -use sp_core::{Decode, sr25519::Public}; +use sp_core::Decode; use sp_inherents::CreateInherentDataProviders; use sp_runtime::traits::{Header, Block}; use sp_api::{BlockId, TransactionFor}; @@ -19,13 +19,13 @@ use sc_client_api::Backend; use substrate_prometheus_endpoint::Registry; -use frame_support::traits::ValidatorSet; - use tendermint_machine::{ ext::{BlockNumber, Commit}, TendermintMachine, }; +use sp_tendermint::TendermintApi; + use crate::{ CONSENSUS_ID, validators::TendermintValidators, @@ -100,7 +100,7 @@ where TransactionFor: Send + Sync + 'static, Arc: BlockImport>, as BlockImport>::Error: Into, - C::Api: ValidatorSet, + C::Api: TendermintApi, { let import = TendermintImport::new(client, announce, providers, env); @@ -119,7 +119,7 @@ where Ok(best) => BlockNumber(best), Err(_) => panic!("BlockNumber exceeded u64"), }, - Commit::>::decode( + Commit::>::decode( &mut import_clone .client .justifications(&BlockId::Number(best)) diff --git a/substrate/tendermint/client/src/tendermint.rs b/substrate/tendermint/client/src/tendermint.rs index 089721c0..a2ab4bd8 100644 --- a/substrate/tendermint/client/src/tendermint.rs +++ b/substrate/tendermint/client/src/tendermint.rs @@ -10,10 +10,7 @@ use log::warn; use tokio::sync::RwLock as AsyncRwLock; -use sp_core::{ - Encode, Decode, - sr25519::{Public, Signature}, -}; +use sp_core::{Encode, Decode, sr25519::Signature}; use sp_inherents::{InherentData, InherentDataProvider, CreateInherentDataProviders}; use sp_runtime::{ traits::{Header, Block}, @@ -28,13 +25,13 @@ use sc_consensus::{ForkChoiceStrategy, BlockImportParams, BlockImport, import_qu use sc_service::ImportQueue; use sc_client_api::{BlockBackend, Backend, Finalizer}; -use frame_support::traits::ValidatorSet; - use tendermint_machine::{ ext::{BlockError, Commit, Network}, SignedMessage, TendermintHandle, }; +use sp_tendermint::TendermintApi; + use crate::{ CONSENSUS_ID, validators::TendermintValidators, @@ -53,7 +50,7 @@ pub trait TendermintClient + 'static>: + 'static where TransactionFor: Send + Sync + 'static, - Self::Api: ValidatorSet, + Self::Api: TendermintApi, { } impl< @@ -70,7 +67,7 @@ impl< > TendermintClient for C where TransactionFor: Send + Sync + 'static, - C::Api: ValidatorSet, + C::Api: TendermintApi, { } @@ -83,12 +80,12 @@ pub(crate) struct TendermintImport< A: Announce, > where TransactionFor: Send + Sync + 'static, - C::Api: ValidatorSet, + C::Api: TendermintApi, { _block: PhantomData, _backend: PhantomData, - validators: Arc>, + validators: Arc>, importing_block: Arc>>, pub(crate) machine: Arc>>>, @@ -111,7 +108,7 @@ impl< > Clone for TendermintImport where TransactionFor: Send + Sync + 'static, - C::Api: ValidatorSet, + C::Api: TendermintApi, { fn clone(&self) -> Self { TendermintImport { @@ -143,7 +140,7 @@ impl< > TendermintImport where TransactionFor: Send + Sync + 'static, - C::Api: ValidatorSet, + C::Api: TendermintApi, { pub(crate) fn new( client: Arc, @@ -155,7 +152,7 @@ where _block: PhantomData, _backend: PhantomData, - validators: TendermintValidators::new(client), + validators: Arc::new(TendermintValidators::new(client.clone())), importing_block: Arc::new(RwLock::new(None)), machine: Arc::new(RwLock::new(None)), @@ -215,7 +212,7 @@ where Err(Error::InvalidJustification)?; } - let commit: Commit> = + let commit: Commit> = Commit::decode(&mut justification.1.as_ref()).map_err(|_| Error::InvalidJustification)?; if !self.verify_commit(hash, &commit) { Err(Error::InvalidJustification)?; @@ -328,20 +325,20 @@ impl< > Network for TendermintImport where TransactionFor: Send + Sync + 'static, - C::Api: ValidatorSet, + C::Api: TendermintApi, { type ValidatorId = u16; - type SignatureScheme = TendermintValidators; - type Weights = TendermintValidators; + type SignatureScheme = TendermintValidators; + type Weights = TendermintValidators; type Block = B; const BLOCK_TIME: u32 = { (serai_runtime::MILLISECS_PER_BLOCK / 1000) as u32 }; - fn signature_scheme(&self) -> Arc> { + fn signature_scheme(&self) -> Arc> { self.validators.clone() } - fn weights(&self) -> Arc> { + fn weights(&self) -> Arc> { self.validators.clone() } @@ -410,7 +407,7 @@ where Ok(()) } - async fn add_block(&mut self, block: B, commit: Commit>) -> B { + async fn add_block(&mut self, block: B, commit: Commit>) -> B { let hash = block.hash(); let justification = (CONSENSUS_ID, commit.encode()); debug_assert!(self.verify_justification(hash, &justification).is_ok()); diff --git a/substrate/tendermint/client/src/validators.rs b/substrate/tendermint/client/src/validators.rs index 8ebd31ed..87e1b016 100644 --- a/substrate/tendermint/client/src/validators.rs +++ b/substrate/tendermint/client/src/validators.rs @@ -8,12 +8,16 @@ use sp_application_crypto::{ use sp_runtime::traits::Block; use sp_staking::SessionIndex; -use sp_api::ProvideRuntimeApi; +use sp_api::{BlockId, TransactionFor}; -use frame_support::traits::ValidatorSet; +use sc_client_api::Backend; use tendermint_machine::ext::{BlockNumber, Round, Weights, SignatureScheme}; +use sp_tendermint::TendermintApi; + +use crate::tendermint::TendermintClient; + struct TendermintValidatorsStruct { session: SessionIndex, @@ -25,17 +29,21 @@ struct TendermintValidatorsStruct { } impl TendermintValidatorsStruct { - fn from_module>( - client: C, + fn from_module + 'static, C: TendermintClient>( + client: &Arc, ) -> TendermintValidatorsStruct where - C::Api: ValidatorSet, + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi, { - let validators = client.runtime_api().validators(); + let last = client.info().best_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 { - session: client.runtime_api().session_index(), + session, // TODO total_weight: validators.len().try_into().unwrap(), @@ -48,27 +56,42 @@ impl TendermintValidatorsStruct { } // Wrap every access of the validators struct in something which forces calling refresh -struct Refresh> { +struct Refresh + 'static, C: TendermintClient> +where + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi, +{ _block: PhantomData, - client: C, + _backend: PhantomData, + + client: Arc, _refresh: Arc>, } -impl> Refresh + +impl + 'static, C: TendermintClient> Refresh where - C::Api: ValidatorSet, + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi, { // If the session has changed, re-create the struct with the data on it fn refresh(&self) { let session = self._refresh.read().unwrap().session; - if session != self.client.runtime_api().session_index() { - *self._refresh.write().unwrap() = TendermintValidatorsStruct::from_module(self.client); + if session != + self + .client + .runtime_api() + .current_session(&BlockId::Hash(self.client.info().best_hash)) + .unwrap() + { + *self._refresh.write().unwrap() = TendermintValidatorsStruct::from_module(&self.client); } } } -impl> Deref for Refresh +impl + 'static, C: TendermintClient> Deref for Refresh where - C::Api: ValidatorSet, + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi, { type Target = RwLock; fn deref(&self) -> &RwLock { @@ -77,25 +100,36 @@ where } } -pub(crate) struct TendermintValidators>( - Refresh, -); -impl> TendermintValidators +pub(crate) struct TendermintValidators< + B: Block, + Be: Backend + 'static, + C: TendermintClient, +>(Refresh) where - C::Api: ValidatorSet, + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi; + +impl + 'static, C: TendermintClient> TendermintValidators +where + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi, { - pub(crate) fn new(client: C) -> TendermintValidators { + pub(crate) fn new(client: Arc) -> TendermintValidators { TendermintValidators(Refresh { _block: PhantomData, + _backend: PhantomData, + + _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module(&client))), client, - _refresh: Arc::new(RwLock::new(TendermintValidatorsStruct::from_module())), }) } } -impl> SignatureScheme for TendermintValidators +impl + 'static, C: TendermintClient> SignatureScheme + for TendermintValidators where - C::Api: ValidatorSet, + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi, { type ValidatorId = u16; type Signature = Signature; @@ -126,9 +160,11 @@ where } } -impl> Weights for TendermintValidators +impl + 'static, C: TendermintClient> Weights + for TendermintValidators where - C::Api: ValidatorSet, + TransactionFor: Send + Sync + 'static, + C::Api: TendermintApi, { type ValidatorId = u16; diff --git a/substrate/tendermint/client/src/verifier.rs b/substrate/tendermint/client/src/verifier.rs index d7a2f8a4..b587a52e 100644 --- a/substrate/tendermint/client/src/verifier.rs +++ b/substrate/tendermint/client/src/verifier.rs @@ -2,7 +2,6 @@ use std::sync::Arc; use async_trait::async_trait; -use sp_core::sr25519::Public; use sp_inherents::CreateInherentDataProviders; use sp_runtime::traits::Block; use sp_api::TransactionFor; @@ -12,7 +11,7 @@ use sc_consensus::{BlockImportParams, BlockImport, Verifier}; use sc_client_api::Backend; -use frame_support::traits::ValidatorSet; +use sp_tendermint::TendermintApi; use crate::{ tendermint::{TendermintClient, TendermintImport}, @@ -32,7 +31,7 @@ where TransactionFor: Send + Sync + 'static, Arc: BlockImport>, as BlockImport>::Error: Into, - C::Api: ValidatorSet, + C::Api: TendermintApi, { async fn verify( &mut self, diff --git a/substrate/tendermint/pallet/Cargo.toml b/substrate/tendermint/pallet/Cargo.toml index 6b441230..4958dbec 100644 --- a/substrate/tendermint/pallet/Cargo.toml +++ b/substrate/tendermint/pallet/Cargo.toml @@ -15,6 +15,8 @@ rustdoc-args = ["--cfg", "docsrs"] parity-scale-codec = { version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"] } +sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false } sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } diff --git a/substrate/tendermint/pallet/src/lib.rs b/substrate/tendermint/pallet/src/lib.rs index f5a1b91c..f8b92db8 100644 --- a/substrate/tendermint/pallet/src/lib.rs +++ b/substrate/tendermint/pallet/src/lib.rs @@ -1,60 +1,73 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::OneSessionHandler; - #[frame_support::pallet] pub mod pallet { + use sp_std::vec::Vec; + use sp_core::sr25519::Public; + use frame_support::pallet_prelude::*; + use frame_support::traits::{ConstU32, OneSessionHandler}; + + type MaxValidators = ConstU32<{ u16::MAX as u32 }>; #[pallet::config] pub trait Config: frame_system::Config {} #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(PhantomData); + + #[pallet::storage] + #[pallet::getter(fn session)] + pub type Session = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn validators)] + pub type Validators = StorageValue<_, BoundedVec, ValueQuery>; + + pub mod crypto { + use sp_application_crypto::{KeyTypeId, app_crypto, sr25519}; + app_crypto!(sr25519, KeyTypeId(*b"tend")); + + impl sp_application_crypto::BoundToRuntimeAppPublic for crate::Pallet { + type Public = Public; + } + + sp_application_crypto::with_pair! { + pub type AuthorityPair = Pair; + } + pub type AuthoritySignature = Signature; + pub type AuthorityId = Public; + } + + impl OneSessionHandler for Pallet { + type Key = crypto::Public; + + fn on_genesis_session<'a, I: 'a>(_validators: I) + where + I: Iterator, + V: 'a, + { + } + + fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued: I) + where + I: Iterator, + V: 'a, + { + if !changed { + return; + } + + Session::::put(Self::session() + 1); + Validators::::put( + BoundedVec::try_from(validators.map(|(_, key)| key.into()).collect::>()) + .unwrap(), + ); + } + + fn on_disabled(_validator_index: u32) {} + } } pub use pallet::*; - -pub mod crypto { - use sp_application_crypto::{KeyTypeId, app_crypto, sr25519}; - app_crypto!(sr25519, KeyTypeId(*b"tend")); - - impl sp_application_crypto::BoundToRuntimeAppPublic for crate::Pallet { - type Public = Public; - } - - sp_application_crypto::with_pair! { - pub type AuthorityPair = Pair; - } - pub type AuthoritySignature = Signature; - pub type AuthorityId = Public; -} - -impl OneSessionHandler for Pallet { - type Key = crypto::Public; - - fn on_genesis_session<'a, I: 'a>(_validators: I) - where - I: Iterator, - V: 'a, - { - } - - fn on_new_session<'a, I: 'a>(_changed: bool, _validators: I, _queued: I) - where - I: Iterator, - V: 'a, - { - /* - if !changed { - return; - } - - for validator in validators { - ... - } - */ - } - - fn on_disabled(_validator_index: u32) {} -} diff --git a/substrate/tendermint/primitives/Cargo.toml b/substrate/tendermint/primitives/Cargo.toml index a877df51..a152fa7d 100644 --- a/substrate/tendermint/primitives/Cargo.toml +++ b/substrate/tendermint/primitives/Cargo.toml @@ -10,3 +10,12 @@ edition = "2021" [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-api = { git = "https://github.com/serai-dex/substrate", default-features = false } + +[features] +std = ["sp-core/std", "sp-std/std", "sp-api/std"] +default = ["std"] diff --git a/substrate/tendermint/primitives/src/lib.rs b/substrate/tendermint/primitives/src/lib.rs index 71e29beb..50cc78d1 100644 --- a/substrate/tendermint/primitives/src/lib.rs +++ b/substrate/tendermint/primitives/src/lib.rs @@ -1,7 +1,15 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_core::sr25519::Public; +use sp_std::vec::Vec; -trait TendermintApi { - fn validators() -> Vec; +sp_api::decl_runtime_apis! { + pub trait TendermintApi { + /// Current session number. A session is NOT a fixed length of blocks, yet rather a continuous + /// set of validators. + fn current_session() -> u32; + + /// Current validators. + fn validators() -> Vec; + } }