mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 05:07:55 +00:00
Add BEEFY latestFinalized RPC and deduplicate code between BEEFY and GRANDPA (#10568)
* beefy: add dummy latest_finalized() RPC * beefy: rpc latest_best_beefy() using shared mem * beefy: rpc populate latest_best_beefy() * beefy: rpc handle readiness * beefy: best block over channel - wip Not working because channel can't be simply opened and receiver passed to `rpc_extensions_builder` because `rpc_extensions_builder` has to be `Fn` and not `FnOnce`... and and Receiver side of mpsc can't be cloned yay!.. * beefy: make notification channels payload-agnostic * beefy: use notification mechanism instead of custom channel * beefy: add tracing key to notif channels * sc-utils: add notification channel - wip * beefy: use sc-utils generic notification channel * grandpa: use sc-utils generic notification channel * fix grumbles * beefy-rpc: get best block header instead of number * beefy-rpc: rename to `beefy_getFinalizedHead` * fix nitpicks * client-rpc-notifications: move generic Error from struct to fn * beefy: use header from notification instead of getting from database * beefy-rpc: get best block hash instead of header * beefy-rpc: fix and improve latestHead test * beefy-rpc: bubble up errors from rpc-handler instantiation * update lockfile * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * fix errors and warnings * fix nit Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
@@ -31,6 +31,8 @@ use sp_runtime::traits::Block;
|
||||
|
||||
use beefy_primitives::BeefyApi;
|
||||
|
||||
use crate::notification::{BeefyBestBlockSender, BeefySignedCommitmentSender};
|
||||
|
||||
mod error;
|
||||
mod gossip;
|
||||
mod keystore;
|
||||
@@ -121,7 +123,9 @@ where
|
||||
/// Gossip network
|
||||
pub network: N,
|
||||
/// BEEFY signed commitment sender
|
||||
pub signed_commitment_sender: notification::BeefySignedCommitmentSender<B>,
|
||||
pub signed_commitment_sender: BeefySignedCommitmentSender<B>,
|
||||
/// BEEFY best block sender
|
||||
pub beefy_best_block_sender: BeefyBestBlockSender<B>,
|
||||
/// Minimal delta between blocks, BEEFY should vote for
|
||||
pub min_block_delta: u32,
|
||||
/// Prometheus metric registry
|
||||
@@ -147,6 +151,7 @@ where
|
||||
key_store,
|
||||
network,
|
||||
signed_commitment_sender,
|
||||
beefy_best_block_sender,
|
||||
min_block_delta,
|
||||
prometheus_registry,
|
||||
protocol_name,
|
||||
@@ -174,6 +179,7 @@ where
|
||||
backend,
|
||||
key_store: key_store.into(),
|
||||
signed_commitment_sender,
|
||||
beefy_best_block_sender,
|
||||
gossip_engine,
|
||||
gossip_validator,
|
||||
min_block_delta,
|
||||
|
||||
@@ -16,98 +16,41 @@
|
||||
// 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::sync::Arc;
|
||||
use sc_utils::notification::{NotificationSender, NotificationStream, TracingKeyStr};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
||||
|
||||
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
|
||||
use sp_runtime::traits::{Block, NumberFor};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
/// Stream of signed commitments returned when subscribing.
|
||||
pub type SignedCommitment<Block> =
|
||||
/// A commitment with matching BEEFY authorities' signatures.
|
||||
pub type BeefySignedCommitment<Block> =
|
||||
beefy_primitives::SignedCommitment<NumberFor<Block>, beefy_primitives::crypto::Signature>;
|
||||
|
||||
/// Stream of signed commitments returned when subscribing.
|
||||
type SignedCommitmentStream<Block> = TracingUnboundedReceiver<SignedCommitment<Block>>;
|
||||
/// The sending half of the notifications channel(s) used to send
|
||||
/// notifications about best BEEFY block from the gadget side.
|
||||
pub type BeefyBestBlockSender<Block> = NotificationSender<<Block as BlockT>::Hash>;
|
||||
|
||||
/// Sending endpoint for notifying about signed commitments.
|
||||
type SignedCommitmentSender<Block> = TracingUnboundedSender<SignedCommitment<Block>>;
|
||||
/// The receiving half of a notifications channel used to receive
|
||||
/// notifications about best BEEFY blocks determined on the gadget side.
|
||||
pub type BeefyBestBlockStream<Block> =
|
||||
NotificationStream<<Block as BlockT>::Hash, BeefyBestBlockTracingKey>;
|
||||
|
||||
/// Collection of channel sending endpoints shared with the receiver side so they can register
|
||||
/// themselves.
|
||||
type SharedSignedCommitmentSenders<Block> = Arc<Mutex<Vec<SignedCommitmentSender<Block>>>>;
|
||||
/// The sending half of the notifications channel(s) used to send notifications
|
||||
/// about signed commitments generated at the end of a BEEFY round.
|
||||
pub type BeefySignedCommitmentSender<Block> = NotificationSender<BeefySignedCommitment<Block>>;
|
||||
|
||||
/// The sending half of the signed commitment channel(s).
|
||||
///
|
||||
/// Used to send notifications about signed commitments generated at the end of a BEEFY round.
|
||||
/// The receiving half of a notifications channel used to receive notifications
|
||||
/// about signed commitments generated at the end of a BEEFY round.
|
||||
pub type BeefySignedCommitmentStream<Block> =
|
||||
NotificationStream<BeefySignedCommitment<Block>, BeefySignedCommitmentTracingKey>;
|
||||
|
||||
/// Provides tracing key for BEEFY best block stream.
|
||||
#[derive(Clone)]
|
||||
pub struct BeefySignedCommitmentSender<B>
|
||||
where
|
||||
B: Block,
|
||||
{
|
||||
subscribers: SharedSignedCommitmentSenders<B>,
|
||||
pub struct BeefyBestBlockTracingKey;
|
||||
impl TracingKeyStr for BeefyBestBlockTracingKey {
|
||||
const TRACING_KEY: &'static str = "mpsc_beefy_best_block_notification_stream";
|
||||
}
|
||||
|
||||
impl<B> BeefySignedCommitmentSender<B>
|
||||
where
|
||||
B: Block,
|
||||
{
|
||||
/// The `subscribers` should be shared with a corresponding `SignedCommitmentSender`.
|
||||
fn new(subscribers: SharedSignedCommitmentSenders<B>) -> Self {
|
||||
Self { subscribers }
|
||||
}
|
||||
|
||||
/// Send out a notification to all subscribers that a new signed commitment is available for a
|
||||
/// block.
|
||||
pub fn notify(&self, signed_commitment: SignedCommitment<B>) {
|
||||
let mut subscribers = self.subscribers.lock();
|
||||
|
||||
// do an initial prune on closed subscriptions
|
||||
subscribers.retain(|n| !n.is_closed());
|
||||
|
||||
if !subscribers.is_empty() {
|
||||
subscribers.retain(|n| n.unbounded_send(signed_commitment.clone()).is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The receiving half of the signed commitments channel.
|
||||
///
|
||||
/// Used to receive notifications about signed commitments generated at the end of a BEEFY round.
|
||||
/// The `BeefySignedCommitmentStream` entity stores the `SharedSignedCommitmentSenders` so it can be
|
||||
/// used to add more subscriptions.
|
||||
/// Provides tracing key for BEEFY signed commitments stream.
|
||||
#[derive(Clone)]
|
||||
pub struct BeefySignedCommitmentStream<B>
|
||||
where
|
||||
B: Block,
|
||||
{
|
||||
subscribers: SharedSignedCommitmentSenders<B>,
|
||||
}
|
||||
|
||||
impl<B> BeefySignedCommitmentStream<B>
|
||||
where
|
||||
B: Block,
|
||||
{
|
||||
/// Creates a new pair of receiver and sender of signed commitment notifications.
|
||||
pub fn channel() -> (BeefySignedCommitmentSender<B>, Self) {
|
||||
let subscribers = Arc::new(Mutex::new(vec![]));
|
||||
let receiver = BeefySignedCommitmentStream::new(subscribers.clone());
|
||||
let sender = BeefySignedCommitmentSender::new(subscribers);
|
||||
(sender, receiver)
|
||||
}
|
||||
|
||||
/// Create a new receiver of signed commitment notifications.
|
||||
///
|
||||
/// The `subscribers` should be shared with a corresponding `BeefySignedCommitmentSender`.
|
||||
fn new(subscribers: SharedSignedCommitmentSenders<B>) -> Self {
|
||||
Self { subscribers }
|
||||
}
|
||||
|
||||
/// Subscribe to a channel through which signed commitments are sent at the end of each BEEFY
|
||||
/// voting round.
|
||||
pub fn subscribe(&self) -> SignedCommitmentStream<B> {
|
||||
let (sender, receiver) = tracing_unbounded("mpsc_signed_commitments_notification_stream");
|
||||
self.subscribers.lock().push(sender);
|
||||
receiver
|
||||
}
|
||||
pub struct BeefySignedCommitmentTracingKey;
|
||||
impl TracingKeyStr for BeefySignedCommitmentTracingKey {
|
||||
const TRACING_KEY: &'static str = "mpsc_beefy_signed_commitments_notification_stream";
|
||||
}
|
||||
|
||||
@@ -46,7 +46,8 @@ use crate::{
|
||||
keystore::BeefyKeystore,
|
||||
metric_inc, metric_set,
|
||||
metrics::Metrics,
|
||||
notification, round, Client,
|
||||
notification::{BeefyBestBlockSender, BeefySignedCommitmentSender},
|
||||
round, Client,
|
||||
};
|
||||
|
||||
pub(crate) struct WorkerParams<B, BE, C>
|
||||
@@ -56,7 +57,8 @@ where
|
||||
pub client: Arc<C>,
|
||||
pub backend: Arc<BE>,
|
||||
pub key_store: BeefyKeystore,
|
||||
pub signed_commitment_sender: notification::BeefySignedCommitmentSender<B>,
|
||||
pub signed_commitment_sender: BeefySignedCommitmentSender<B>,
|
||||
pub beefy_best_block_sender: BeefyBestBlockSender<B>,
|
||||
pub gossip_engine: GossipEngine<B>,
|
||||
pub gossip_validator: Arc<GossipValidator<B>>,
|
||||
pub min_block_delta: u32,
|
||||
@@ -73,7 +75,7 @@ where
|
||||
client: Arc<C>,
|
||||
backend: Arc<BE>,
|
||||
key_store: BeefyKeystore,
|
||||
signed_commitment_sender: notification::BeefySignedCommitmentSender<B>,
|
||||
signed_commitment_sender: BeefySignedCommitmentSender<B>,
|
||||
gossip_engine: Arc<Mutex<GossipEngine<B>>>,
|
||||
gossip_validator: Arc<GossipValidator<B>>,
|
||||
/// Min delta in block numbers between two blocks, BEEFY should vote on
|
||||
@@ -85,6 +87,8 @@ where
|
||||
best_grandpa_block: NumberFor<B>,
|
||||
/// Best block a BEEFY voting round has been concluded for
|
||||
best_beefy_block: Option<NumberFor<B>>,
|
||||
/// Used to keep RPC worker up to date on latest/best beefy
|
||||
beefy_best_block_sender: BeefyBestBlockSender<B>,
|
||||
/// Validator set id for the last signed commitment
|
||||
last_signed_id: u64,
|
||||
// keep rustc happy
|
||||
@@ -110,6 +114,7 @@ where
|
||||
backend,
|
||||
key_store,
|
||||
signed_commitment_sender,
|
||||
beefy_best_block_sender,
|
||||
gossip_engine,
|
||||
gossip_validator,
|
||||
min_block_delta,
|
||||
@@ -130,6 +135,7 @@ where
|
||||
best_grandpa_block: client.info().finalized_number,
|
||||
best_beefy_block: None,
|
||||
last_signed_id: 0,
|
||||
beefy_best_block_sender,
|
||||
_backend: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -242,6 +248,9 @@ where
|
||||
debug!(target: "beefy", "🥩 New Rounds for id: {:?}", id);
|
||||
|
||||
self.best_beefy_block = Some(*notification.header.number());
|
||||
self.beefy_best_block_sender
|
||||
.notify(|| Ok::<_, ()>(notification.hash.clone()))
|
||||
.expect("forwards closure result; the closure always returns Ok; qed.");
|
||||
|
||||
// this metric is kind of 'fake'. Best BEEFY block should only be updated once we
|
||||
// have a signed commitment for the block. Remove once the above TODO is done.
|
||||
@@ -329,22 +338,23 @@ where
|
||||
// id is stored for skipped session metric calculation
|
||||
self.last_signed_id = rounds.validator_set_id();
|
||||
|
||||
let block_num = round.1;
|
||||
let commitment = Commitment {
|
||||
payload: round.0,
|
||||
block_number: round.1,
|
||||
block_number: block_num,
|
||||
validator_set_id: self.last_signed_id,
|
||||
};
|
||||
|
||||
let signed_commitment = SignedCommitment { commitment, signatures };
|
||||
|
||||
metric_set!(self, beefy_round_concluded, round.1);
|
||||
metric_set!(self, beefy_round_concluded, block_num);
|
||||
|
||||
info!(target: "beefy", "🥩 Round #{} concluded, committed: {:?}.", round.1, signed_commitment);
|
||||
|
||||
if self
|
||||
.backend
|
||||
.append_justification(
|
||||
BlockId::Number(round.1),
|
||||
BlockId::Number(block_num),
|
||||
(
|
||||
BEEFY_ENGINE_ID,
|
||||
VersionedFinalityProof::V1(signed_commitment.clone()).encode(),
|
||||
@@ -356,11 +366,23 @@ where
|
||||
// conclude certain rounds multiple times.
|
||||
trace!(target: "beefy", "🥩 Failed to append justification: {:?}", signed_commitment);
|
||||
}
|
||||
self.signed_commitment_sender
|
||||
.notify(|| Ok::<_, ()>(signed_commitment))
|
||||
.expect("forwards closure result; the closure always returns Ok; qed.");
|
||||
|
||||
self.signed_commitment_sender.notify(signed_commitment);
|
||||
self.best_beefy_block = Some(round.1);
|
||||
self.best_beefy_block = Some(block_num);
|
||||
if let Err(err) = self.client.hash(block_num).map(|h| {
|
||||
if let Some(hash) = h {
|
||||
self.beefy_best_block_sender
|
||||
.notify(|| Ok::<_, ()>(hash))
|
||||
.expect("forwards closure result; the closure always returns Ok; qed.");
|
||||
}
|
||||
}) {
|
||||
error!(target: "beefy", "🥩 Failed to get hash for block number {}; err: {:?}",
|
||||
block_num, err);
|
||||
}
|
||||
|
||||
metric_set!(self, beefy_best_block, round.1);
|
||||
metric_set!(self, beefy_best_block, block_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user