Files
pezkuwi-subxt/substrate/client/finality-grandpa/rpc/src/lib.rs
T
David 29c0c6a4a8 jsonrpsee integration (#8783)
* Add tokio

* No need to map CallError to CallError

* jsonrpsee proc macros (#9673)

* port error types to `JsonRpseeError`

* migrate chain module to proc macro api

* make it compile with proc macros

* update branch

* update branch

* update to jsonrpsee master

* port system rpc

* port state rpc

* port childstate & offchain

* frame system rpc

* frame transaction payment

* bring back CORS hack to work with polkadot UI

* port babe rpc

* port manual seal rpc

* port frame mmr rpc

* port frame contracts rpc

* port finality grandpa rpc

* port sync state rpc

* resolve a few TODO + no jsonrpc deps

* Update bin/node/rpc-client/src/main.rs

* Update bin/node/rpc-client/src/main.rs

* Update bin/node/rpc-client/src/main.rs

* Update bin/node/rpc-client/src/main.rs

* Port over system_ rpc tests

* Make it compile

* Use prost 0.8

* Use prost 0.8

* Make it compile

* Ignore more failing tests

* Comment out WIP tests

* fix nit in frame system api

* Update lockfile

* No more juggling tokio versions

* No more wait_for_stop ?

* Remove browser-testing

* Arguments must be arrays

* Use same argument names

* Resolve todo: no wait_for_stop for WS server
Add todo: is parse_rpc_result used?
Cleanup imports

* fmt

* log

* One test passes

* update jsonrpsee

* update jsonrpsee

* cleanup rpc-servers crate

* jsonrpsee: add host and origin filtering (#9787)

* add access control in the jsonrpsee servers

* use master

* fix nits

* rpc runtime_version safe

* fix nits

* fix grumbles

* remove unused files

* resolve some todos

* jsonrpsee more cleanup (#9803)

* more cleanup

* resolve TODOs

* fix some unwraps

* remove type hints

* update jsonrpsee

* downgrade zeroize

* pin jsonrpsee rev

* remove unwrap nit

* Comment out more tests that aren't ported

* Comment out more tests

* Fix tests after merge

* Subscription test

* Invalid nonce test

* Pending exts

* WIP removeExtrinsic test

* Test remove_extrinsic

* Make state test: should_return_storage work

* Uncomment/fix the other non-subscription related state tests

* test: author_insertKey

* test: author_rotateKeys

* Get rest of state tests passing

* asyncify a little more

* Add todo to note #msg change

* Crashing test for has_session_keys

* Fix error conversion to avoid stack overflows
Port author_hasSessionKeys test
fmt

* test author_hasKey

* Add two missing tests
Add a check on the return type
Add todos for James's concerns

* RPC tests for state, author and system (#9859)

* Fix test runner

* Impl Default for SubscriptionTaskExecutor

* Keep the minimul amount of code needed to compile tests

* Re-instate `RpcSession` (for now)

* cleanup

* Port over RPC tests

* Add tokio

* No need to map CallError to CallError

* Port over system_ rpc tests

* Make it compile

* Use prost 0.8

* Use prost 0.8

* Make it compile

* Ignore more failing tests

* Comment out WIP tests

* Update lockfile

* No more juggling tokio versions

* No more wait_for_stop ?

* Remove browser-testing

* Arguments must be arrays

* Use same argument names

* Resolve todo: no wait_for_stop for WS server
Add todo: is parse_rpc_result used?
Cleanup imports

* fmt

* log

* One test passes

* Comment out more tests that aren't ported

* Comment out more tests

* Fix tests after merge

* Subscription test

* Invalid nonce test

* Pending exts

* WIP removeExtrinsic test

* Test remove_extrinsic

* Make state test: should_return_storage work

* Uncomment/fix the other non-subscription related state tests

* test: author_insertKey

* test: author_rotateKeys

* Get rest of state tests passing

* asyncify a little more

* Add todo to note #msg change

* Crashing test for has_session_keys

* Fix error conversion to avoid stack overflows
Port author_hasSessionKeys test
fmt

* test author_hasKey

* Add two missing tests
Add a check on the return type
Add todos for James's concerns

* offchain rpc tests

* Address todos

* fmt

Co-authored-by: James Wilson <james@jsdw.me>

* fix drop in state test

* update jsonrpsee

* fix ignored system test

* fix chain tests

* remove some boiler plate

* Port BEEFY RPC (#9883)

* Merge master

* Port beefy RPC (ty @niklas!)

* trivial changes left over from merge

* Remove unused code

* Update jsonrpsee

* fix build

* make tests compile again

* beefy update jsonrpsee

* fix: respect rpc methods policy

* update cargo.lock

* update jsonrpsee

* update jsonrpsee

* downgrade error logs

* update jsonrpsee

* Fix typo

* remove unused file

* Better name

* Port Babe RPC tests

* Put docs back

* Resolve todo

* Port tests for System RPCs

* Resolve todo

* fix build

* Updated jsonrpsee to current master

* fix: port finality grandpa rpc tests

* Move .into() outside of the match

* more review grumbles

* jsonrpsee: add `rpc handlers` back (#10245)

* add back RpcHandlers

* cargo fmt

* fix docs

* fix grumble: remove needless alloc

* resolve TODO

* fmt

* Fix typo

* grumble: Use constants based on BASE_ERROR

* grumble: DRY whitelisted listening addresses
grumble: s/JSONRPC/JSON-RPC/

* cleanup

* grumbles: Making readers aware of the possibility of gaps

* review grumbles

* grumbles

* remove notes from niklasad1

* Update `jsonrpsee`

* fix: jsonrpsee features

* jsonrpsee: fallback to random port in case the specified port failed (#10304)

* jsonrpsee: fallback to random port

* better comment

* Update client/rpc-servers/src/lib.rs

Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com>

* Update client/rpc-servers/src/lib.rs

Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com>

* address grumbles

* cargo fmt

* addrs already slice

Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com>

* Update jsonrpsee to 092081a0a2b8904c6ebd2cd99e16c7bc13ffc3ae

* lockfile

* update jsonrpsee

* fix warning

* Don't fetch jsonrpsee from crates

* make tests compile again

* fix rpc tests

* remove unused deps

* update tokio

* fix rpc tests again

* fix: test runner

`HttpServerBuilder::builder` fails unless it's called within tokio runtime

* cargo fmt

* grumbles: fix subscription aliases

* make clippy happy

* update remaining subscriptions alias

* cleanup

* cleanup

* fix chain subscription: less boiler plate (#10285)

* fix chain subscription: less boiler plate

* fix bad merge

* cargo fmt

* Switch to jsonrpsee 0.5

* fix build

* add missing features

* fix nit: remove needless Box::pin

* Integrate jsonrpsee metrics (#10395)

* draft metrics impl

* Use latest api

* Add missing file

* Http server metrics

* cleanup

* bump jsonrpsee

* Remove `ServerMetrics` and use a single middleware for both connection counting (aka sessions) and call metrics.

* fix build

* remove needless Arc::clone

* Update to jsonrpsee 0.6

* lolz

* fix metrics

* Revert "lolz"

This reverts commit eed6c6a56e78d8e307b4950f4c52a1c3a2322ba1.

* fix: in-memory rpc support subscriptions

* commit Cargo.lock

* Update tests to 0.7

* fix TODOs

* ws server: generate subscriptionIDs as Strings

Some libraries seems to expect the subscription IDs to be Strings, let's not break
this in this PR.

* Increase timeout

* Port over tests

* cleanup

* Using error codes from the spec

* fix clippy

* cargo fmt

* update jsonrpsee

* fix nits

* fix: rpc_query

* enable custom subid gen through spawn_tasks

* remove unsed deps

* unify tokio deps

* Revert "enable custom subid gen through spawn_tasks"

This reverts commit 5c5eb70328fe39d154fdb55c56e637b4548cf470.

* fix bad merge of `test-utils`

* fix more nits

* downgrade wasm-instrument to 0.1.0

* [jsonrpsee]: enable custom RPC subscription ID generatation (#10731)

* enable custom subid gen through spawn_tasks

* fix nits

* Update client/service/src/builder.rs

Co-authored-by: David <dvdplm@gmail.com>

* add Poc; needs jsonrpsee pr

* update jsonrpsee

* add re-exports

* add docs

Co-authored-by: David <dvdplm@gmail.com>

* cargo fmt

* fmt

* port RPC-API dev

* Remove unused file

* fix nit: remove async trait

* fix doc links

* fix merge nit: remove jsonrpc deps

* kill namespace on rpc apis

* companion for jsonrpsee v0.10 (#11158)

* companion for jsonrpsee v0.10

* update versions v0.10.0

* add some fixes

* spelling

* fix spaces

Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>

* send error before subs are closed

* fix unsubscribe method names: chain

* fix tests

* jsonrpc server: print binded local address

* grumbles: kill SubscriptionTaskExecutor

* Update client/sync-state-rpc/src/lib.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/rpc/src/chain/chain_full.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/rpc/src/chain/chain_full.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* sync-state-rpc: kill anyhow

* no more anyhow

* remove todo

* jsonrpsee:  fix bad params in subscriptions. (#11251)

* update jsonrpsee

* fix error responses

* revert error codes

* dont do weird stuff in drop impl

* rpc servers: remove needless clone

* Remove silly constants

* chore: update jsonrpsee v0.12

* commit Cargo.lock

* deps: downgrade git2

* feat: CLI flag max subscriptions per connection

* metrics: use old logging format

* fix: read WS address from substrate output (#11379)

Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>
Co-authored-by: James Wilson <james@jsdw.me>
Co-authored-by: Maciej Hirsz <hello@maciej.codes>
Co-authored-by: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
2022-05-10 08:52:19 +00:00

455 lines
14 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 2020-2022 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/>.
//! RPC API for GRANDPA.
#![warn(missing_docs)]
use futures::{FutureExt, StreamExt};
use log::warn;
use std::sync::Arc;
use jsonrpsee::{
core::{async_trait, RpcResult},
proc_macros::rpc,
PendingSubscription,
};
mod error;
mod finality;
mod notification;
mod report;
use sc_finality_grandpa::GrandpaJustificationStream;
use sc_rpc::SubscriptionTaskExecutor;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use finality::{EncodedFinalityProof, RpcFinalityProofProvider};
use notification::JustificationNotification;
use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates};
/// Provides RPC methods for interacting with GRANDPA.
#[rpc(client, server)]
pub trait GrandpaApi<Notification, Hash, Number> {
/// Returns the state of the current best round state as well as the
/// ongoing background rounds.
#[method(name = "grandpa_roundState")]
async fn round_state(&self) -> RpcResult<ReportedRoundStates>;
/// Returns the block most recently finalized by Grandpa, alongside
/// side its justification.
#[subscription(
name = "grandpa_subscribeJustifications" => "grandpa_justifications",
unsubscribe = "grandpa_unsubscribeJustifications",
item = Notification
)]
fn subscribe_justifications(&self);
/// Prove finality for the given block number by returning the Justification for the last block
/// in the set and all the intermediary headers to link them together.
#[method(name = "grandpa_proveFinality")]
async fn prove_finality(&self, block: Number) -> RpcResult<Option<EncodedFinalityProof>>;
}
/// Provides RPC methods for interacting with GRANDPA.
pub struct GrandpaRpc<AuthoritySet, VoterState, Block: BlockT, ProofProvider> {
executor: SubscriptionTaskExecutor,
authority_set: AuthoritySet,
voter_state: VoterState,
justification_stream: GrandpaJustificationStream<Block>,
finality_proof_provider: Arc<ProofProvider>,
}
impl<AuthoritySet, VoterState, Block: BlockT, ProofProvider>
GrandpaRpc<AuthoritySet, VoterState, Block, ProofProvider>
{
/// Prepare a new [`GrandpaRpc`]
pub fn new(
executor: SubscriptionTaskExecutor,
authority_set: AuthoritySet,
voter_state: VoterState,
justification_stream: GrandpaJustificationStream<Block>,
finality_proof_provider: Arc<ProofProvider>,
) -> Self {
Self { executor, authority_set, voter_state, justification_stream, finality_proof_provider }
}
}
#[async_trait]
impl<AuthoritySet, VoterState, Block, ProofProvider>
GrandpaApiServer<JustificationNotification, Block::Hash, NumberFor<Block>>
for GrandpaRpc<AuthoritySet, VoterState, Block, ProofProvider>
where
VoterState: ReportVoterState + Send + Sync + 'static,
AuthoritySet: ReportAuthoritySet + Send + Sync + 'static,
Block: BlockT,
ProofProvider: RpcFinalityProofProvider<Block> + Send + Sync + 'static,
{
async fn round_state(&self) -> RpcResult<ReportedRoundStates> {
ReportedRoundStates::from(&self.authority_set, &self.voter_state).map_err(Into::into)
}
fn subscribe_justifications(&self, pending: PendingSubscription) {
let stream = self.justification_stream.subscribe().map(
|x: sc_finality_grandpa::GrandpaJustification<Block>| {
JustificationNotification::from(x)
},
);
let fut = async move {
if let Some(mut sink) = pending.accept() {
sink.pipe_from_stream(stream).await;
}
}
.boxed();
self.executor
.spawn("substrate-rpc-subscription", Some("rpc"), fut.map(drop).boxed());
}
async fn prove_finality(
&self,
block: NumberFor<Block>,
) -> RpcResult<Option<EncodedFinalityProof>> {
self.finality_proof_provider
.rpc_prove_finality(block)
.map_err(|e| {
warn!("Error proving finality: {}", e);
error::Error::ProveFinalityFailed(e)
})
.map_err(Into::into)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{collections::HashSet, convert::TryInto, sync::Arc};
use jsonrpsee::{
types::{EmptyParams, SubscriptionId},
RpcModule,
};
use parity_scale_codec::{Decode, Encode};
use sc_block_builder::{BlockBuilder, RecordProof};
use sc_finality_grandpa::{
report, AuthorityId, FinalityProof, GrandpaJustification, GrandpaJustificationSender,
};
use sp_blockchain::HeaderBackend;
use sp_core::{crypto::ByteArray, testing::TaskExecutor};
use sp_keyring::Ed25519Keyring;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use substrate_test_runtime_client::{
runtime::{Block, Header, H256},
DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
struct TestAuthoritySet;
struct TestVoterState;
struct EmptyVoterState;
struct TestFinalityProofProvider {
finality_proof: Option<FinalityProof<Header>>,
}
fn voters() -> HashSet<AuthorityId> {
let voter_id_1 = AuthorityId::from_slice(&[1; 32]).unwrap();
let voter_id_2 = AuthorityId::from_slice(&[2; 32]).unwrap();
vec![voter_id_1, voter_id_2].into_iter().collect()
}
impl ReportAuthoritySet for TestAuthoritySet {
fn get(&self) -> (u64, HashSet<AuthorityId>) {
(1, voters())
}
}
impl ReportVoterState for EmptyVoterState {
fn get(&self) -> Option<report::VoterState<AuthorityId>> {
None
}
}
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,
_block: NumberFor<Block>,
) -> Result<Option<EncodedFinalityProof>, sc_finality_grandpa::FinalityProofError> {
Ok(Some(EncodedFinalityProof(
self.finality_proof
.as_ref()
.expect("Don't call rpc_prove_finality without setting the FinalityProof")
.encode()
.into(),
)))
}
}
impl ReportVoterState for TestVoterState {
fn get(&self) -> Option<report::VoterState<AuthorityId>> {
let voter_id_1 = AuthorityId::from_slice(&[1; 32]).unwrap();
let voters_best: HashSet<_> = vec![voter_id_1].into_iter().collect();
let best_round_state = sc_finality_grandpa::report::RoundState {
total_weight: 100_u64.try_into().unwrap(),
threshold_weight: 67_u64.try_into().unwrap(),
prevote_current_weight: 50.into(),
prevote_ids: voters_best,
precommit_current_weight: 0.into(),
precommit_ids: HashSet::new(),
};
let past_round_state = sc_finality_grandpa::report::RoundState {
total_weight: 100_u64.try_into().unwrap(),
threshold_weight: 67_u64.try_into().unwrap(),
prevote_current_weight: 100.into(),
prevote_ids: voters(),
precommit_current_weight: 100.into(),
precommit_ids: voters(),
};
let background_rounds = vec![(1, past_round_state)].into_iter().collect();
Some(report::VoterState { background_rounds, best_round: (2, best_round_state) })
}
}
fn setup_io_handler<VoterState>(
voter_state: VoterState,
) -> (
RpcModule<GrandpaRpc<TestAuthoritySet, VoterState, Block, TestFinalityProofProvider>>,
GrandpaJustificationSender<Block>,
)
where
VoterState: ReportVoterState + Send + Sync + 'static,
{
setup_io_handler_with_finality_proofs(voter_state, None)
}
fn setup_io_handler_with_finality_proofs<VoterState>(
voter_state: VoterState,
finality_proof: Option<FinalityProof<Header>>,
) -> (
RpcModule<GrandpaRpc<TestAuthoritySet, VoterState, Block, TestFinalityProofProvider>>,
GrandpaJustificationSender<Block>,
)
where
VoterState: ReportVoterState + Send + Sync + 'static,
{
let (justification_sender, justification_stream) = GrandpaJustificationStream::channel();
let finality_proof_provider = Arc::new(TestFinalityProofProvider { finality_proof });
let executor = Arc::new(TaskExecutor::default());
let rpc = GrandpaRpc::new(
executor,
TestAuthoritySet,
voter_state,
justification_stream,
finality_proof_provider,
)
.into_rpc();
(rpc, justification_sender)
}
#[tokio::test]
async fn uninitialized_rpc_handler() {
let (rpc, _) = setup_io_handler(EmptyVoterState);
let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":0}"#.to_string();
let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#;
let (result, _) = rpc.raw_json_request(&request).await.unwrap();
assert_eq!(expected_response, result,);
}
#[tokio::test]
async fn working_rpc_handler() {
let (rpc, _) = setup_io_handler(TestVoterState);
let expected_response = "{\"jsonrpc\":\"2.0\",\"result\":{\
\"setId\":1,\
\"best\":{\
\"round\":2,\"totalWeight\":100,\"thresholdWeight\":67,\
\"prevotes\":{\"currentWeight\":50,\"missing\":[\"5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt\"]},\
\"precommits\":{\"currentWeight\":0,\"missing\":[\"5C62Ck4UrFPiBtoCmeSrgF7x9yv9mn38446dhCpsi2mLHiFT\",\"5C7LYpP2ZH3tpKbvVvwiVe54AapxErdPBbvkYhe6y9ZBkqWt\"]}\
},\
\"background\":[{\
\"round\":1,\"totalWeight\":100,\"thresholdWeight\":67,\
\"prevotes\":{\"currentWeight\":100,\"missing\":[]},\
\"precommits\":{\"currentWeight\":100,\"missing\":[]}\
}]\
},\"id\":0}".to_string();
let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#;
let (result, _) = rpc.raw_json_request(&request).await.unwrap();
assert_eq!(expected_response, result);
}
#[tokio::test]
async fn subscribe_and_unsubscribe_to_justifications() {
let (rpc, _) = setup_io_handler(TestVoterState);
// Subscribe call.
let sub = rpc
.subscribe("grandpa_subscribeJustifications", EmptyParams::new())
.await
.unwrap();
let ser_id = serde_json::to_string(sub.subscription_id()).unwrap();
// Unsubscribe
let unsub_req = format!(
"{{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_unsubscribeJustifications\",\"params\":[{}],\"id\":1}}",
ser_id
);
let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap();
assert_eq!(response, r#"{"jsonrpc":"2.0","result":true,"id":1}"#);
// Unsubscribe again and fail
let (response, _) = rpc.raw_json_request(&unsub_req).await.unwrap();
let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
assert_eq!(response, expected);
}
#[tokio::test]
async fn subscribe_and_unsubscribe_with_wrong_id() {
let (rpc, _) = setup_io_handler(TestVoterState);
// Subscribe call.
let _sub = rpc
.subscribe("grandpa_subscribeJustifications", EmptyParams::new())
.await
.unwrap();
// Unsubscribe with wrong ID
let (response, _) = rpc
.raw_json_request(
r#"{"jsonrpc":"2.0","method":"grandpa_unsubscribeJustifications","params":["FOO"],"id":1}"#,
)
.await
.unwrap();
let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
assert_eq!(response, expected);
}
fn create_justification() -> GrandpaJustification<Block> {
let peers = &[Ed25519Keyring::Alice];
let builder = TestClientBuilder::new();
let backend = builder.backend();
let client = builder.build();
let client = Arc::new(client);
let built_block = BlockBuilder::new(
&*client,
client.info().best_hash,
client.info().best_number,
RecordProof::No,
Default::default(),
&*backend,
)
.unwrap()
.build()
.unwrap();
let block = built_block.block;
let block_hash = block.hash();
let justification = {
let round = 1;
let set_id = 0;
let precommit = finality_grandpa::Precommit {
target_hash: block_hash,
target_number: *block.header.number(),
};
let msg = finality_grandpa::Message::Precommit(precommit.clone());
let encoded = sp_finality_grandpa::localized_payload(round, set_id, &msg);
let signature = peers[0].sign(&encoded[..]).into();
let precommit = finality_grandpa::SignedPrecommit {
precommit,
signature,
id: peers[0].public().into(),
};
let commit = finality_grandpa::Commit {
target_hash: block_hash,
target_number: *block.header.number(),
precommits: vec![precommit],
};
GrandpaJustification::from_commit(&client, round, commit).unwrap()
};
justification
}
#[tokio::test]
async fn subscribe_and_listen_to_one_justification() {
let (rpc, justification_sender) = setup_io_handler(TestVoterState);
let mut sub = rpc
.subscribe("grandpa_subscribeJustifications", EmptyParams::new())
.await
.unwrap();
// Notify with a header and justification
let justification = create_justification();
justification_sender.notify(|| Ok::<_, ()>(justification.clone())).unwrap();
// Inspect what we received
let (recv_justification, recv_sub_id): (sp_core::Bytes, SubscriptionId) =
sub.next().await.unwrap().unwrap();
let recv_justification: GrandpaJustification<Block> =
Decode::decode(&mut &recv_justification[..]).unwrap();
assert_eq!(&recv_sub_id, sub.subscription_id());
assert_eq!(recv_justification, justification);
}
#[tokio::test]
async fn prove_finality_with_test_finality_proof_provider() {
let finality_proof = FinalityProof {
block: header(42).hash(),
justification: create_justification().encode(),
unknown_headers: vec![header(2)],
};
let (rpc, _) =
setup_io_handler_with_finality_proofs(TestVoterState, Some(finality_proof.clone()));
let bytes: sp_core::Bytes = rpc.call("grandpa_proveFinality", [42]).await.unwrap();
let finality_proof_rpc: FinalityProof<Header> = Decode::decode(&mut &bytes[..]).unwrap();
assert_eq!(finality_proof_rpc, finality_proof);
}
}