Files
pezkuwi-subxt/substrate/client/consensus/grandpa/rpc/src/report.rs
T
Niklas Adolfsson e16ef0861f rpc: backpressured RPC server (bump jsonrpsee 0.20) (#1313)
This is a rather big change in jsonrpsee, the major things in this bump
are:
- Server backpressure (the subscription impls are modified to deal with
that)
- Allow custom error types / return types (remove jsonrpsee::core::Error
and jsonrpee::core::CallError)
- Bug fixes (graceful shutdown in particular not used by substrate
anyway)
   - Less dependencies for the clients in particular
   - Return type requires Clone in method call responses
   - Moved to tokio channels
   - Async subscription API (not used in this PR)

Major changes in this PR:
- The subscriptions are now bounded and if subscription can't keep up
with the server it is dropped
- CLI: add parameter to configure the jsonrpc server bounded message
buffer (default is 64)
- Add our own subscription helper to deal with the unbounded streams in
substrate

The most important things in this PR to review is the added helpers
functions in `substrate/client/rpc/src/utils.rs` and the rest is pretty
much chore.

Regarding the "bounded buffer limit" it may cause the server to handle
the JSON-RPC calls
slower than before.

The message size limit is bounded by "--rpc-response-size" thus "by
default 10MB * 64 = 640MB"
but the subscription message size is not covered by this limit and could
be capped as well.

Hopefully the last release prior to 1.0, sorry in advance for a big PR

Previous attempt: https://github.com/paritytech/substrate/pull/13992

Resolves https://github.com/paritytech/polkadot-sdk/issues/748, resolves
https://github.com/paritytech/polkadot-sdk/issues/627
2024-01-23 08:55:13 +00:00

151 lines
4.2 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 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 std::{
collections::{BTreeSet, HashSet},
fmt::Debug,
ops::Add,
};
use serde::{Deserialize, Serialize};
use sc_consensus_grandpa::{report, AuthorityId, SharedAuthoritySet, SharedVoterState};
use crate::error::Error;
/// Utility trait to get reporting data for the current GRANDPA authority set.
pub trait ReportAuthoritySet {
fn get(&self) -> (u64, HashSet<AuthorityId>);
}
/// Utility trait to get reporting data for the current GRANDPA voter state.
pub trait ReportVoterState {
fn get(&self) -> Option<report::VoterState<AuthorityId>>;
}
impl<H, N> ReportAuthoritySet for SharedAuthoritySet<H, N>
where
N: Add<Output = N> + Ord + Clone + Debug,
H: Clone + Debug + Eq,
{
fn get(&self) -> (u64, HashSet<AuthorityId>) {
let current_voters: HashSet<AuthorityId> =
self.current_authorities().iter().map(|p| p.0.clone()).collect();
(self.set_id(), current_voters)
}
}
impl ReportVoterState for SharedVoterState {
fn get(&self) -> Option<report::VoterState<AuthorityId>> {
self.voter_state()
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Prevotes {
current_weight: u32,
missing: BTreeSet<AuthorityId>,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Precommits {
current_weight: u32,
missing: BTreeSet<AuthorityId>,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct RoundState {
round: u32,
total_weight: u32,
threshold_weight: u32,
prevotes: Prevotes,
precommits: Precommits,
}
impl RoundState {
fn from(
round: u64,
round_state: &report::RoundState<AuthorityId>,
voters: &HashSet<AuthorityId>,
) -> Result<Self, Error> {
let prevotes = &round_state.prevote_ids;
let missing_prevotes = voters.difference(prevotes).cloned().collect();
let precommits = &round_state.precommit_ids;
let missing_precommits = voters.difference(precommits).cloned().collect();
Ok(Self {
round: round.try_into()?,
total_weight: round_state.total_weight.get().try_into()?,
threshold_weight: round_state.threshold_weight.get().try_into()?,
prevotes: Prevotes {
current_weight: round_state.prevote_current_weight.0.try_into()?,
missing: missing_prevotes,
},
precommits: Precommits {
current_weight: round_state.precommit_current_weight.0.try_into()?,
missing: missing_precommits,
},
})
}
}
/// The state of the current best round, as well as the background rounds in a
/// form suitable for serialization.
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReportedRoundStates {
set_id: u32,
best: RoundState,
background: Vec<RoundState>,
}
impl ReportedRoundStates {
pub fn from<AuthoritySet, VoterState>(
authority_set: &AuthoritySet,
voter_state: &VoterState,
) -> Result<Self, Error>
where
AuthoritySet: ReportAuthoritySet,
VoterState: ReportVoterState,
{
let voter_state = voter_state.get().ok_or(Error::EndpointNotReady)?;
let (set_id, current_voters) = authority_set.get();
let set_id =
u32::try_from(set_id).map_err(|_| Error::AuthoritySetIdReportedAsUnreasonablyLarge)?;
let best = {
let (round, round_state) = voter_state.best_round;
RoundState::from(round, &round_state, &current_voters)?
};
let background = voter_state
.background_rounds
.iter()
.map(|(round, round_state)| RoundState::from(*round, round_state, &current_voters))
.collect::<Result<Vec<_>, Error>>()?;
Ok(Self { set_id, best, background })
}
}