diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index f635807f6fbc6918267b0b91dae81f9a649d0d95..3b08f91f2a8dc8c7026856a607ef5f38e18971ed 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -3823,6 +3823,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-runtime", "sp-transaction-pool", "substrate-frame-rpc-system", ] @@ -6821,6 +6822,7 @@ dependencies = [ "log", "parity-scale-codec", "sc-block-builder", + "sc-client-api", "sc-finality-grandpa", "sc-network-test", "sc-rpc", diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 03347e455e6a3545f5d82e752a7c85f59f661dbd..b15ace6181a8fa0321f5c206fdc6abad7ecd6cbd 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -58,7 +58,10 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen grandpa::LinkHalf<Block, FullClient, FullSelectChain>, sc_consensus_babe::BabeLink<Block>, ), - grandpa::SharedVoterState, + ( + grandpa::SharedVoterState, + Arc<GrandpaFinalityProofProvider<FullBackend, Block>>, + ), ) >, ServiceError> { let (client, backend, keystore, task_manager) = @@ -108,8 +111,10 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen let justification_stream = grandpa_link.justification_stream(); let shared_authority_set = grandpa_link.shared_authority_set().clone(); let shared_voter_state = grandpa::SharedVoterState::empty(); + let finality_proof_provider = + GrandpaFinalityProofProvider::new_for_service(backend.clone(), client.clone()); - let rpc_setup = shared_voter_state.clone(); + let rpc_setup = (shared_voter_state.clone(), finality_proof_provider.clone()); let babe_config = babe_link.config().clone(); let shared_epoch_changes = babe_link.epoch_changes().clone(); @@ -135,6 +140,7 @@ pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponen shared_authority_set: shared_authority_set.clone(), justification_stream: justification_stream.clone(), subscription_executor, + finality_provider: finality_proof_provider.clone(), }, }; @@ -174,8 +180,7 @@ pub fn new_full_base( other: (rpc_extensions_builder, import_setup, rpc_setup), } = new_partial(&config)?; - let finality_proof_provider = - GrandpaFinalityProofProvider::new_for_service(backend.clone(), client.clone()); + let (shared_voter_state, finality_proof_provider) = rpc_setup; let (network, network_status_sinks, system_rpc_tx, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams { @@ -220,7 +225,6 @@ pub fn new_full_base( })?; let (block_import, grandpa_link, babe_link) = import_setup; - let shared_voter_state = rpc_setup; (with_startup_data)(&block_import, &babe_link); diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index e9abaef35f655b5ff477dc9c845eb3ffdb67cbad..020fc88a3d0f2db08056b93011f2403313de4b69 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -30,5 +30,6 @@ sp-block-builder = { version = "2.0.0-rc6", path = "../../../primitives/block-bu sp-blockchain = { version = "2.0.0-rc6", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.8.0-rc6", path = "../../../primitives/consensus/common" } sp-consensus-babe = { version = "0.8.0-rc6", path = "../../../primitives/consensus/babe" } +sp-runtime = { version = "2.0.0-rc6", path = "../../../primitives/runtime" } sp-transaction-pool = { version = "2.0.0-rc6", path = "../../../primitives/transaction-pool" } substrate-frame-rpc-system = { version = "2.0.0-rc6", path = "../../../utils/frame/rpc/system" } diff --git a/substrate/bin/node/rpc/src/lib.rs b/substrate/bin/node/rpc/src/lib.rs index 420fd0eb1475b3926455b6c0af0932a21f6b5ffb..55a7adf612119a28d727f9c62e240a9beaed965c 100644 --- a/substrate/bin/node/rpc/src/lib.rs +++ b/substrate/bin/node/rpc/src/lib.rs @@ -36,7 +36,9 @@ use node_primitives::{Block, BlockNumber, AccountId, Index, Balance, Hash}; use sc_consensus_babe::{Config, Epoch}; use sc_consensus_babe_rpc::BabeRpcHandler; use sc_consensus_epochs::SharedEpochChanges; -use sc_finality_grandpa::{SharedVoterState, SharedAuthoritySet, GrandpaJustificationStream}; +use sc_finality_grandpa::{ + SharedVoterState, SharedAuthoritySet, FinalityProofProvider, GrandpaJustificationStream +}; use sc_finality_grandpa_rpc::GrandpaRpcHandler; use sc_keystore::KeyStorePtr; pub use sc_rpc_api::DenyUnsafe; @@ -71,7 +73,7 @@ pub struct BabeDeps { } /// Extra dependencies for GRANDPA -pub struct GrandpaDeps { +pub struct GrandpaDeps<B> { /// Voting round info. pub shared_voter_state: SharedVoterState, /// Authority set info. @@ -80,10 +82,12 @@ pub struct GrandpaDeps { pub justification_stream: GrandpaJustificationStream<Block>, /// Executor to drive the subscription manager in the Grandpa RPC handler. pub subscription_executor: SubscriptionTaskExecutor, + /// Finality proof provider. + pub finality_provider: Arc<FinalityProofProvider<B, Block>>, } /// Full client dependencies. -pub struct FullDeps<C, P, SC> { +pub struct FullDeps<C, P, SC, B> { /// The client instance to use. pub client: Arc<C>, /// Transaction pool instance. @@ -95,15 +99,15 @@ pub struct FullDeps<C, P, SC> { /// BABE specific dependencies. pub babe: BabeDeps, /// GRANDPA specific dependencies. - pub grandpa: GrandpaDeps, + pub grandpa: GrandpaDeps<B>, } /// A IO handler that uses all Full RPC extensions. pub type IoHandler = jsonrpc_core::IoHandler<sc_rpc::Metadata>; /// Instantiate all Full RPC extensions. -pub fn create_full<C, P, SC>( - deps: FullDeps<C, P, SC>, +pub fn create_full<C, P, SC, B>( + deps: FullDeps<C, P, SC, B>, ) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata> where C: ProvideRuntimeApi<Block>, C: HeaderBackend<Block> + HeaderMetadata<Block, Error=BlockChainError> + 'static, @@ -115,6 +119,8 @@ pub fn create_full<C, P, SC>( C::Api: BlockBuilder<Block>, P: TransactionPool + 'static, SC: SelectChain<Block> +'static, + B: sc_client_api::Backend<Block> + Send + Sync + 'static, + B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>, { use substrate_frame_rpc_system::{FullSystem, SystemApi}; use pallet_contracts_rpc::{Contracts, ContractsApi}; @@ -140,6 +146,7 @@ pub fn create_full<C, P, SC>( shared_authority_set, justification_stream, subscription_executor, + finality_provider, } = grandpa; io.extend_with( @@ -173,6 +180,7 @@ pub fn create_full<C, P, SC>( shared_voter_state, justification_stream, subscription_executor, + finality_provider, ) ) ); diff --git a/substrate/client/finality-grandpa/rpc/Cargo.toml b/substrate/client/finality-grandpa/rpc/Cargo.toml index 6f3014644eaa44d1ade2d663df53dc448c05498d..0112ddd420c99dee5ec9a20e693992336c5f47a8 100644 --- a/substrate/client/finality-grandpa/rpc/Cargo.toml +++ b/substrate/client/finality-grandpa/rpc/Cargo.toml @@ -10,6 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] sc-finality-grandpa = { version = "0.8.0-rc6", path = "../" } sc-rpc = { version = "2.0.0-rc6", path = "../../rpc" } +sp-blockchain = { version = "2.0.0-rc6", path = "../../../primitives/blockchain" } sp-core = { version = "2.0.0-rc6", path = "../../../primitives/core" } sp-runtime = { version = "2.0.0-rc6", path = "../../../primitives/runtime" } finality-grandpa = { version = "0.12.3", features = ["derive-codec"] } @@ -23,12 +24,12 @@ serde_json = "1.0.50" log = "0.4.8" derive_more = "0.99.2" parity-scale-codec = { version = "1.3.0", features = ["derive"] } +sc-client-api = { version = "2.0.0-rc6", path = "../../api" } [dev-dependencies] sc-block-builder = { version = "0.8.0-rc6", path = "../../block-builder" } sc-network-test = { version = "0.8.0-rc6", path = "../../network/test" } sc-rpc = { version = "2.0.0-rc6", path = "../../rpc", features = ["test-helpers"] } -sp-blockchain = { version = "2.0.0-rc6", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.8.0-rc6", path = "../../../primitives/consensus/common" } sp-core = { version = "2.0.0-rc6", path = "../../../primitives/core" } sp-finality-grandpa = { version = "2.0.0-rc6", path = "../../../primitives/finality-grandpa" } diff --git a/substrate/client/finality-grandpa/rpc/src/error.rs b/substrate/client/finality-grandpa/rpc/src/error.rs index bfd0596fdf3205d3eda8003a3a0f109b83fe836f..6464acbe10ea076ed637d603fbf48692509fb8e6 100644 --- a/substrate/client/finality-grandpa/rpc/src/error.rs +++ b/substrate/client/finality-grandpa/rpc/src/error.rs @@ -16,8 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. -use crate::NOT_READY_ERROR_CODE; - #[derive(derive_more::Display, derive_more::From)] /// Top-level error type for the RPC handler pub enum Error { @@ -30,13 +28,41 @@ pub enum Error { /// GRANDPA reports voter state with round id or weights larger than 32-bits. #[display(fmt = "GRANDPA reports voter state as unreasonably large")] VoterStateReportsUnreasonablyLargeNumbers, + /// GRANDPA prove finality failed. + #[display(fmt = "GRANDPA prove finality rpc failed: {}", _0)] + ProveFinalityFailed(sp_blockchain::Error), +} + +/// The error codes returned by jsonrpc. +pub enum ErrorCode { + /// Returned when Grandpa RPC endpoint is not ready. + NotReady = 1, + /// Authority set ID is larger than 32-bits. + AuthoritySetTooLarge, + /// Voter state with round id or weights larger than 32-bits. + VoterStateTooLarge, + /// Failed to prove finality. + ProveFinality, +} + +impl From<Error> for ErrorCode { + fn from(error: Error) -> Self { + match error { + Error::EndpointNotReady => ErrorCode::NotReady, + Error::AuthoritySetIdReportedAsUnreasonablyLarge => ErrorCode::AuthoritySetTooLarge, + Error::VoterStateReportsUnreasonablyLargeNumbers => ErrorCode::VoterStateTooLarge, + Error::ProveFinalityFailed(_) => ErrorCode::ProveFinality, + } + } } impl From<Error> for jsonrpc_core::Error { fn from(error: Error) -> Self { + let message = format!("{}", error); + let code = ErrorCode::from(error); jsonrpc_core::Error { - message: format!("{}", error), - code: jsonrpc_core::ErrorCode::ServerError(NOT_READY_ERROR_CODE), + message, + code: jsonrpc_core::ErrorCode::ServerError(code as i64), data: None, } } diff --git a/substrate/client/finality-grandpa/rpc/src/finality.rs b/substrate/client/finality-grandpa/rpc/src/finality.rs new file mode 100644 index 0000000000000000000000000000000000000000..1f288b86a0e469efefcbc7b826f23c527a8344fc --- /dev/null +++ b/substrate/client/finality-grandpa/rpc/src/finality.rs @@ -0,0 +1,54 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +use serde::{Serialize, Deserialize}; + +use sc_finality_grandpa::FinalityProofProvider; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +#[derive(Serialize, Deserialize)] +pub struct EncodedFinalityProofs(pub sp_core::Bytes); + +/// Local trait mainly to allow mocking in tests. +pub trait RpcFinalityProofProvider<Block: BlockT> { + /// Return finality proofs for the given authorities set id, if it is provided, otherwise the + /// current one will be used. + fn rpc_prove_finality( + &self, + begin: Block::Hash, + end: Block::Hash, + authorities_set_id: u64, + ) -> Result<Option<EncodedFinalityProofs>, sp_blockchain::Error>; +} + +impl<B, Block> RpcFinalityProofProvider<Block> for FinalityProofProvider<B, Block> +where + Block: BlockT, + NumberFor<Block>: finality_grandpa::BlockNumberOps, + B: sc_client_api::backend::Backend<Block> + Send + Sync + 'static, +{ + fn rpc_prove_finality( + &self, + begin: Block::Hash, + end: Block::Hash, + authorities_set_id: u64, + ) -> Result<Option<EncodedFinalityProofs>, sp_blockchain::Error> { + self.prove_finality(begin, end, authorities_set_id) + .map(|x| x.map(|y| EncodedFinalityProofs(y.into()))) + } +} diff --git a/substrate/client/finality-grandpa/rpc/src/lib.rs b/substrate/client/finality-grandpa/rpc/src/lib.rs index fedd7220d3115a4b4a91eec0ce24192991b8300d..172473ad6518bc90e709f9bb24ebe98058fb89de 100644 --- a/substrate/client/finality-grandpa/rpc/src/lib.rs +++ b/substrate/client/finality-grandpa/rpc/src/lib.rs @@ -32,24 +32,23 @@ use jsonrpc_core::futures::{ }; mod error; +mod finality; mod notification; mod report; use sc_finality_grandpa::GrandpaJustificationStream; use sp_runtime::traits::Block as BlockT; +use finality::{EncodedFinalityProofs, RpcFinalityProofProvider}; use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates}; use notification::JustificationNotification; -/// Returned when Grandpa RPC endpoint is not ready. -pub const NOT_READY_ERROR_CODE: i64 = 1; - type FutureResult<T> = Box<dyn jsonrpc_core::futures::Future<Item = T, Error = jsonrpc_core::Error> + Send>; /// Provides RPC methods for interacting with GRANDPA. #[rpc] -pub trait GrandpaApi<Notification> { +pub trait GrandpaApi<Notification, Hash> { /// RPC Metadata type Metadata; @@ -82,23 +81,37 @@ pub trait GrandpaApi<Notification> { metadata: Option<Self::Metadata>, id: SubscriptionId ) -> jsonrpc_core::Result<bool>; + + /// Prove finality for the range (begin; end] hash. Returns None if there are no finalized blocks + /// unknown in the range. If no authorities set is provided, the current one will be attempted. + #[rpc(name = "grandpa_proveFinality")] + fn prove_finality( + &self, + begin: Hash, + end: Hash, + authorities_set_id: Option<u64>, + ) -> FutureResult<Option<EncodedFinalityProofs>>; } /// Implements the GrandpaApi RPC trait for interacting with GRANDPA. -pub struct GrandpaRpcHandler<AuthoritySet, VoterState, Block: BlockT> { +pub struct GrandpaRpcHandler<AuthoritySet, VoterState, Block: BlockT, ProofProvider> { authority_set: AuthoritySet, voter_state: VoterState, justification_stream: GrandpaJustificationStream<Block>, manager: SubscriptionManager, + finality_proof_provider: Arc<ProofProvider>, } -impl<AuthoritySet, VoterState, Block: BlockT> GrandpaRpcHandler<AuthoritySet, VoterState, Block> { +impl<AuthoritySet, VoterState, Block: BlockT, ProofProvider> + GrandpaRpcHandler<AuthoritySet, VoterState, Block, ProofProvider> +{ /// Creates a new GrandpaRpcHandler instance. pub fn new<E>( authority_set: AuthoritySet, voter_state: VoterState, justification_stream: GrandpaJustificationStream<Block>, executor: E, + finality_proof_provider: Arc<ProofProvider>, ) -> Self where E: Executor01<Box<dyn Future01<Item = (), Error = ()> + Send>> + Send + Sync + 'static, @@ -109,16 +122,18 @@ impl<AuthoritySet, VoterState, Block: BlockT> GrandpaRpcHandler<AuthoritySet, Vo voter_state, justification_stream, manager, + finality_proof_provider, } } } -impl<AuthoritySet, VoterState, Block> GrandpaApi<JustificationNotification> - for GrandpaRpcHandler<AuthoritySet, VoterState, Block> +impl<AuthoritySet, VoterState, Block, ProofProvider> GrandpaApi<JustificationNotification, Block::Hash> + for GrandpaRpcHandler<AuthoritySet, VoterState, Block, ProofProvider> where VoterState: ReportVoterState + Send + Sync + 'static, AuthoritySet: ReportAuthoritySet + Send + Sync + 'static, Block: BlockT, + ProofProvider: RpcFinalityProofProvider<Block> + Send + Sync + 'static, { type Metadata = sc_rpc::Metadata; @@ -153,6 +168,30 @@ where ) -> jsonrpc_core::Result<bool> { Ok(self.manager.cancel(id)) } + + fn prove_finality( + &self, + begin: Block::Hash, + end: Block::Hash, + authorities_set_id: Option<u64>, + ) -> FutureResult<Option<EncodedFinalityProofs>> { + // If we are not provided a set_id, try with the current one. + let authorities_set_id = authorities_set_id + .unwrap_or_else(|| self.authority_set.get().0); + let result = self + .finality_proof_provider + .rpc_prove_finality(begin, end, authorities_set_id); + let future = async move { result }.boxed(); + Box::new( + future + .map_err(|e| { + warn!("Error proving finality: {}", e); + error::Error::ProveFinalityFailed(e) + }) + .map_err(jsonrpc_core::Error::from) + .compat() + ) + } } #[cfg(test)] @@ -161,16 +200,19 @@ mod tests { use std::{collections::HashSet, convert::TryInto, sync::Arc}; use jsonrpc_core::{Notification, Output, types::Params}; - use parity_scale_codec::Decode; + use parity_scale_codec::{Encode, Decode}; use sc_block_builder::BlockBuilder; - use sc_finality_grandpa::{report, AuthorityId, GrandpaJustificationSender, GrandpaJustification}; + use sc_finality_grandpa::{ + report, AuthorityId, GrandpaJustificationSender, GrandpaJustification, + FinalityProofFragment, + }; use sp_blockchain::HeaderBackend; use sp_consensus::RecordProof; use sp_core::crypto::Public; use sp_keyring::Ed25519Keyring; - use sp_runtime::traits::Header as HeaderT; + use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use substrate_test_runtime_client::{ - runtime::Block, + runtime::{Block, Header, H256}, DefaultTestClientBuilderExt, TestClientBuilderExt, TestClientBuilder, @@ -180,6 +222,10 @@ mod tests { struct TestVoterState; struct EmptyVoterState; + struct TestFinalityProofProvider { + finality_proofs: Vec<FinalityProofFragment<Header>>, + } + fn voters() -> HashSet<AuthorityId> { let voter_id_1 = AuthorityId::from_slice(&[1; 32]); let voter_id_2 = AuthorityId::from_slice(&[2; 32]); @@ -199,6 +245,31 @@ mod tests { } } + fn header(number: u64) -> Header { + let parent_hash = match number { + 0 => Default::default(), + _ => header(number - 1).hash(), + }; + Header::new( + number, + H256::from_low_u64_be(0), + H256::from_low_u64_be(0), + parent_hash, + Default::default(), + ) + } + + impl<Block: BlockT> RpcFinalityProofProvider<Block> for TestFinalityProofProvider { + fn rpc_prove_finality( + &self, + _begin: Block::Hash, + _end: Block::Hash, + _authoritites_set_id: u64, + ) -> Result<Option<EncodedFinalityProofs>, sp_blockchain::Error> { + Ok(Some(EncodedFinalityProofs(self.finality_proofs.encode().into()))) + } + } + impl ReportVoterState for TestVoterState { fn get(&self) -> Option<report::VoterState<AuthorityId>> { let voter_id_1 = AuthorityId::from_slice(&[1; 32]); @@ -236,14 +307,28 @@ mod tests { GrandpaJustificationSender<Block>, ) where VoterState: ReportVoterState + Send + Sync + 'static, + { + setup_io_handler_with_finality_proofs(voter_state, Default::default()) + } + + fn setup_io_handler_with_finality_proofs<VoterState>( + voter_state: VoterState, + finality_proofs: Vec<FinalityProofFragment<Header>>, + ) -> ( + jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>, + GrandpaJustificationSender<Block>, + ) where + VoterState: ReportVoterState + Send + Sync + 'static, { let (justification_sender, justification_stream) = GrandpaJustificationStream::channel(); + let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proofs }); let handler = GrandpaRpcHandler::new( TestAuthoritySet, voter_state, justification_stream, sc_rpc::testing::TaskExecutor, + finality_proof_provider, ); let mut io = jsonrpc_core::MetaIoHandler::default(); @@ -432,4 +517,32 @@ mod tests { assert_eq!(recv_sub_id, sub_id); assert_eq!(recv_justification, justification); } + + #[test] + fn prove_finality_with_test_finality_proof_provider() { + let finality_proofs = vec![FinalityProofFragment { + block: header(42).hash(), + justification: create_justification().encode(), + unknown_headers: vec![header(2)], + authorities_proof: None, + }]; + let (io, _) = setup_io_handler_with_finality_proofs( + TestVoterState, + finality_proofs.clone(), + ); + + let request = "{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_proveFinality\",\"params\":[\ + \"0x0000000000000000000000000000000000000000000000000000000000000000\",\ + \"0x0000000000000000000000000000000000000000000000000000000000000001\",\ + 42\ + ],\"id\":1}"; + + let meta = sc_rpc::Metadata::default(); + let resp = io.handle_request_sync(request, meta); + let mut resp: serde_json::Value = serde_json::from_str(&resp.unwrap()).unwrap(); + let result: sp_core::Bytes = serde_json::from_value(resp["result"].take()).unwrap(); + let fragments: Vec<FinalityProofFragment<Header>> = + Decode::decode(&mut &result[..]).unwrap(); + assert_eq!(fragments, finality_proofs); + } } diff --git a/substrate/client/finality-grandpa/src/finality_proof.rs b/substrate/client/finality-grandpa/src/finality_proof.rs index 2ac9ec57f3df4a6d706514a18109addaabc2f9df..33dd69cc11d6e73c328b2ceb4d0f594a40ba1fae 100644 --- a/substrate/client/finality-grandpa/src/finality_proof.rs +++ b/substrate/client/finality-grandpa/src/finality_proof.rs @@ -180,7 +180,30 @@ impl<B, Block: BlockT> FinalityProofProvider<B, Block> ) -> Arc<Self> { Arc::new(Self::new(backend, storage_and_proof_provider)) } +} +impl<B, Block> FinalityProofProvider<B, Block> + where + Block: BlockT, + NumberFor<Block>: BlockNumberOps, + B: Backend<Block> + Send + Sync + 'static, +{ + /// Prove finality for the range (begin; end] hash. Returns None if there are no finalized blocks + /// unknown in the range. + pub fn prove_finality( + &self, + begin: Block::Hash, + end: Block::Hash, + authorities_set_id: u64, + ) -> Result<Option<Vec<u8>>, ClientError> { + prove_finality::<_, _, GrandpaJustification<Block>>( + &*self.backend.blockchain(), + &*self.authority_provider, + authorities_set_id, + begin, + end, + ) + } } impl<B, Block> sc_network::config::FinalityProofProvider<Block> for FinalityProofProvider<B, Block> @@ -232,8 +255,8 @@ pub struct FinalityEffects<Header: HeaderT> { /// 1) the justification for the descendant block F; /// 2) headers sub-chain (B; F] if B != F; /// 3) proof of GRANDPA::authorities() if the set changes at block F. -#[derive(Debug, PartialEq, Encode, Decode)] -pub(crate) struct FinalityProofFragment<Header: HeaderT> { +#[derive(Debug, PartialEq, Encode, Decode, Clone)] +pub struct FinalityProofFragment<Header: HeaderT> { /// The hash of block F for which justification is provided. pub block: Header::Hash, /// Justification of the block F. diff --git a/substrate/client/finality-grandpa/src/lib.rs b/substrate/client/finality-grandpa/src/lib.rs index ab84591f9cdec7ffec60a62df473d9d8a8cb935f..a15130942c30fb927093565c847e2a1e3df19778 100644 --- a/substrate/client/finality-grandpa/src/lib.rs +++ b/substrate/client/finality-grandpa/src/lib.rs @@ -125,7 +125,7 @@ mod until_imported; mod voting_rule; pub use authorities::SharedAuthoritySet; -pub use finality_proof::{FinalityProofProvider, StorageAndProofProvider}; +pub use finality_proof::{FinalityProofFragment, FinalityProofProvider, StorageAndProofProvider}; pub use notification::{GrandpaJustificationSender, GrandpaJustificationStream}; pub use import::GrandpaBlockImport; pub use justification::GrandpaJustification;