Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 43cd1d0

Browse files
andresilvabkchr
authored andcommitted
grandpa: always create and send justification if there are any subscribers (#6935)
* grandpa: use bytes type for justification rpc notification * grandpa: always create justification if there are rpc subscribers * grandpa: wording * grandpa: replace notify_justification macro with function * grandpa: prefer Option<&T> over &Option<T>
1 parent 508dfcd commit 43cd1d0

File tree

7 files changed

+72
-42
lines changed

7 files changed

+72
-42
lines changed

client/finality-grandpa/rpc/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ edition = "2018"
88
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
99

1010
[dependencies]
11+
sc-finality-grandpa = { version = "0.8.0-rc6", path = "../" }
1112
sc-rpc = { version = "2.0.0-rc6", path = "../../rpc" }
13+
sp-core = { version = "2.0.0-rc6", path = "../../../primitives/core" }
1214
sp-runtime = { version = "2.0.0-rc6", path = "../../../primitives/runtime" }
13-
sc-finality-grandpa = { version = "0.8.0-rc6", path = "../" }
1415
finality-grandpa = { version = "0.12.3", features = ["derive-codec"] }
1516
jsonrpc-core = "14.2.0"
1617
jsonrpc-core-client = "14.2.0"

client/finality-grandpa/rpc/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ mod tests {
406406

407407
// Notify with a header and justification
408408
let justification = create_justification();
409-
let _ = justification_sender.notify(justification.clone()).unwrap();
409+
justification_sender.notify(|| Ok(justification.clone())).unwrap();
410410

411411
// Inspect what we received
412412
let recv = receiver.take(1).wait().flatten().collect::<Vec<_>>();
@@ -418,7 +418,7 @@ mod tests {
418418

419419
let recv_sub_id: String =
420420
serde_json::from_value(json_map["subscription"].take()).unwrap();
421-
let recv_justification: Vec<u8> =
421+
let recv_justification: sp_core::Bytes =
422422
serde_json::from_value(json_map["result"].take()).unwrap();
423423
let recv_justification: GrandpaJustification<Block> =
424424
Decode::decode(&mut &recv_justification[..]).unwrap();

client/finality-grandpa/rpc/src/notification.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ use sc_finality_grandpa::GrandpaJustification;
2323

2424
/// An encoded justification proving that the given header has been finalized
2525
#[derive(Clone, Serialize, Deserialize)]
26-
pub struct JustificationNotification(Vec<u8>);
26+
pub struct JustificationNotification(sp_core::Bytes);
2727

2828
impl<Block: BlockT> From<GrandpaJustification<Block>> for JustificationNotification {
2929
fn from(notification: GrandpaJustification<Block>) -> Self {
30-
JustificationNotification(notification.encode())
30+
JustificationNotification(notification.encode().into())
3131
}
3232
}

client/finality-grandpa/src/environment.rs

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,8 @@ pub(crate) fn ancestry<Block: BlockT, Client>(
645645
client: &Arc<Client>,
646646
base: Block::Hash,
647647
block: Block::Hash,
648-
) -> Result<Vec<Block::Hash>, GrandpaError> where
648+
) -> Result<Vec<Block::Hash>, GrandpaError>
649+
where
649650
Client: HeaderMetadata<Block, Error = sp_blockchain::Error>,
650651
{
651652
if base == block { return Err(GrandpaError::NotDescendent) }
@@ -671,15 +672,14 @@ pub(crate) fn ancestry<Block: BlockT, Client>(
671672
Ok(tree_route.retracted().iter().skip(1).map(|e| e.hash).collect())
672673
}
673674

674-
impl<B, Block: BlockT, C, N, SC, VR>
675-
voter::Environment<Block::Hash, NumberFor<Block>>
676-
for Environment<B, Block, C, N, SC, VR>
675+
impl<B, Block: BlockT, C, N, SC, VR> voter::Environment<Block::Hash, NumberFor<Block>>
676+
for Environment<B, Block, C, N, SC, VR>
677677
where
678678
Block: 'static,
679679
B: Backend<Block>,
680680
C: crate::ClientForGrandpa<Block, B> + 'static,
681681
C::Api: GrandpaApi<Block, Error = sp_blockchain::Error>,
682-
N: NetworkT<Block> + 'static + Send + Sync,
682+
N: NetworkT<Block> + 'static + Send + Sync,
683683
SC: SelectChain<Block> + 'static,
684684
VR: VotingRule<Block, C>,
685685
NumberFor<Block>: BlockNumberOps,
@@ -1023,7 +1023,7 @@ where
10231023
number,
10241024
(round, commit).into(),
10251025
false,
1026-
&self.justification_sender,
1026+
self.justification_sender.as_ref(),
10271027
)
10281028
}
10291029

@@ -1088,9 +1088,10 @@ pub(crate) fn finalize_block<BE, Block, Client>(
10881088
number: NumberFor<Block>,
10891089
justification_or_commit: JustificationOrCommit<Block>,
10901090
initial_sync: bool,
1091-
justification_sender: &Option<GrandpaJustificationSender<Block>>,
1092-
) -> Result<(), CommandOrError<Block::Hash, NumberFor<Block>>> where
1093-
Block: BlockT,
1091+
justification_sender: Option<&GrandpaJustificationSender<Block>>,
1092+
) -> Result<(), CommandOrError<Block::Hash, NumberFor<Block>>>
1093+
where
1094+
Block: BlockT,
10941095
BE: Backend<Block>,
10951096
Client: crate::ClientForGrandpa<Block, BE>,
10961097
{
@@ -1154,14 +1155,29 @@ pub(crate) fn finalize_block<BE, Block, Client>(
11541155
}
11551156
}
11561157

1158+
// send a justification notification if a sender exists and in case of error log it.
1159+
fn notify_justification<Block: BlockT>(
1160+
justification_sender: Option<&GrandpaJustificationSender<Block>>,
1161+
justification: impl FnOnce() -> Result<GrandpaJustification<Block>, Error>,
1162+
) {
1163+
if let Some(sender) = justification_sender {
1164+
if let Err(err) = sender.notify(justification) {
1165+
warn!(target: "afg", "Error creating justification for subscriber: {:?}", err);
1166+
}
1167+
}
1168+
}
1169+
11571170
// NOTE: this code assumes that honest voters will never vote past a
11581171
// transition block, thus we don't have to worry about the case where
11591172
// we have a transition with `effective_block = N`, but we finalize
11601173
// `N+1`. this assumption is required to make sure we store
11611174
// justifications for transition blocks which will be requested by
11621175
// syncing clients.
11631176
let justification = match justification_or_commit {
1164-
JustificationOrCommit::Justification(justification) => Some(justification),
1177+
JustificationOrCommit::Justification(justification) => {
1178+
notify_justification(justification_sender, || Ok(justification.clone()));
1179+
Some(justification.encode())
1180+
},
11651181
JustificationOrCommit::Commit((round_number, commit)) => {
11661182
let mut justification_required =
11671183
// justification is always required when block that enacts new authorities
@@ -1181,29 +1197,31 @@ pub(crate) fn finalize_block<BE, Block, Client>(
11811197
}
11821198
}
11831199

1200+
// NOTE: the code below is a bit more verbose because we
1201+
// really want to avoid creating a justification if it isn't
1202+
// needed (e.g. if there's no subscribers), and also to avoid
1203+
// creating it twice. depending on the vote tree for the round,
1204+
// creating a justification might require multiple fetches of
1205+
// headers from the database.
1206+
let justification = || GrandpaJustification::from_commit(
1207+
&client,
1208+
round_number,
1209+
commit,
1210+
);
1211+
11841212
if justification_required {
1185-
let justification = GrandpaJustification::from_commit(
1186-
&client,
1187-
round_number,
1188-
commit,
1189-
)?;
1213+
let justification = justification()?;
1214+
notify_justification(justification_sender, || Ok(justification.clone()));
11901215

1191-
Some(justification)
1216+
Some(justification.encode())
11921217
} else {
1218+
notify_justification(justification_sender, justification);
1219+
11931220
None
11941221
}
11951222
},
11961223
};
11971224

1198-
// Notify any registered listeners in case we have a justification
1199-
if let Some(sender) = justification_sender {
1200-
if let Some(ref justification) = justification {
1201-
let _ = sender.notify(justification.clone());
1202-
}
1203-
}
1204-
1205-
let justification = justification.map(|j| j.encode());
1206-
12071225
debug!(target: "afg", "Finalizing blocks up to ({:?}, {})", number, hash);
12081226

12091227
// ideally some handle to a synchronization oracle would be used

client/finality-grandpa/src/import.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,6 @@ where
619619
Client: crate::ClientForGrandpa<Block, BE>,
620620
NumberFor<Block>: finality_grandpa::BlockNumberOps,
621621
{
622-
623622
/// Import a block justification and finalize the block.
624623
///
625624
/// If `enacts_change` is set to true, then finalizing this block *must*
@@ -653,7 +652,7 @@ where
653652
number,
654653
justification.into(),
655654
initial_sync,
656-
&Some(self.justification_sender.clone()),
655+
Some(&self.justification_sender),
657656
);
658657

659658
match result {

client/finality-grandpa/src/notification.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ use std::sync::Arc;
2020
use parking_lot::Mutex;
2121

2222
use sp_runtime::traits::Block as BlockT;
23-
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender, TracingUnboundedReceiver};
23+
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
2424

2525
use crate::justification::GrandpaJustification;
26+
use crate::Error;
2627

2728
// Stream of justifications returned when subscribing.
2829
type JustificationStream<Block> = TracingUnboundedReceiver<GrandpaJustification<Block>>;
@@ -54,10 +55,22 @@ impl<Block: BlockT> GrandpaJustificationSender<Block> {
5455

5556
/// Send out a notification to all subscribers that a new justification
5657
/// is available for a block.
57-
pub fn notify(&self, notification: GrandpaJustification<Block>) -> Result<(), ()> {
58-
self.subscribers.lock().retain(|n| {
59-
!n.is_closed() && n.unbounded_send(notification.clone()).is_ok()
60-
});
58+
pub fn notify(
59+
&self,
60+
justification: impl FnOnce() -> Result<GrandpaJustification<Block>, Error>,
61+
) -> Result<(), Error> {
62+
let mut subscribers = self.subscribers.lock();
63+
64+
// do an initial prune on closed subscriptions
65+
subscribers.retain(|n| !n.is_closed());
66+
67+
// if there's no subscribers we avoid creating
68+
// the justification which is a costly operation
69+
if !subscribers.is_empty() {
70+
let justification = justification()?;
71+
subscribers.retain(|n| n.unbounded_send(justification.clone()).is_ok());
72+
}
73+
6174
Ok(())
6275
}
6376
}

client/finality-grandpa/src/observer.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,10 @@ fn grandpa_observer<BE, Block: BlockT, Client, S, F>(
7474
last_finalized_number: NumberFor<Block>,
7575
commits: S,
7676
note_round: F,
77-
) -> impl Future<Output=Result<(), CommandOrError<Block::Hash, NumberFor<Block>>>> where
77+
) -> impl Future<Output = Result<(), CommandOrError<Block::Hash, NumberFor<Block>>>>
78+
where
7879
NumberFor<Block>: BlockNumberOps,
79-
S: Stream<
80-
Item = Result<CommunicationIn<Block>, CommandOrError<Block::Hash, NumberFor<Block>>>,
81-
>,
80+
S: Stream<Item = Result<CommunicationIn<Block>, CommandOrError<Block::Hash, NumberFor<Block>>>>,
8281
F: Fn(u64),
8382
BE: Backend<Block>,
8483
Client: crate::ClientForGrandpa<Block, BE>,
@@ -130,7 +129,7 @@ fn grandpa_observer<BE, Block: BlockT, Client, S, F>(
130129
finalized_number,
131130
(round, commit).into(),
132131
false,
133-
&justification_sender,
132+
justification_sender.as_ref(),
134133
) {
135134
Ok(_) => {},
136135
Err(e) => return future::err(e),

0 commit comments

Comments
 (0)