Skip to content

Commit 631ca8a

Browse files
committed
basic grpc-based subscription re-implementation
1 parent 5cb6430 commit 631ca8a

File tree

10 files changed

+369
-13
lines changed

10 files changed

+369
-13
lines changed

Cargo.lock

+11-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jormungandr/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ chain-time = { git = "https://github.com/input-output-hk/chain-libs.git", b
2222
chain-vote = { git = "https://github.com/input-output-hk/chain-libs.git", branch = "master" }
2323
cardano-legacy-address = { git = "https://github.com/input-output-hk/chain-libs.git", branch = "master" }
2424
imhamt = { git = "https://github.com/input-output-hk/chain-libs.git", branch = "master" }
25-
25+
chain-watch = { git = "https://github.com/input-output-hk/chain-libs.git", branch = "heterogeneous-client-api" }
2626
arc-swap = "^1.1.0"
2727
async-trait = "0.1.50"
2828
async-graphql = "2.5.1"

jormungandr/src/blockchain/process.rs

+59-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use super::{
77
use crate::{
88
blockcfg::{Block, FragmentId, Header, HeaderHash},
99
blockchain::Checkpoints,
10-
intercom::{self, BlockMsg, ExplorerMsg, NetworkMsg, PropagateMsg, TransactionMsg},
10+
intercom::{
11+
self, BlockMsg, ExplorerMsg, NetworkMsg, NotifierMsg, PropagateMsg, TransactionMsg,
12+
},
1113
metrics::{Metrics, MetricsBackend},
1214
network::p2p::Address,
1315
utils::{
@@ -58,6 +60,7 @@ pub struct Process {
5860
pub network_msgbox: MessageBox<NetworkMsg>,
5961
pub fragment_msgbox: MessageBox<TransactionMsg>,
6062
pub explorer_msgbox: Option<MessageBox<ExplorerMsg>>,
63+
pub notifier_msgbox: MessageBox<NotifierMsg>,
6164
pub garbage_collection_interval: Duration,
6265
}
6366

@@ -92,6 +95,7 @@ impl Process {
9295
let blockchain_tip = self.blockchain_tip.clone();
9396
let network_msg_box = self.network_msgbox.clone();
9497
let explorer_msg_box = self.explorer_msgbox.clone();
98+
let event_notifier_msg_box = self.notifier_msgbox.clone();
9599
let tx_msg_box = self.fragment_msgbox.clone();
96100
let stats_counter = self.stats_counter.clone();
97101

@@ -117,6 +121,7 @@ impl Process {
117121
tx_msg_box,
118122
network_msg_box,
119123
explorer_msg_box,
124+
event_notifier_msg_box,
120125
leadership_block,
121126
stats_counter,
122127
)
@@ -163,6 +168,7 @@ impl Process {
163168
tx_msg_box,
164169
network_msg_box,
165170
explorer_msg_box,
171+
event_notifier_msg_box,
166172
get_next_block_scheduler,
167173
handle,
168174
stats_counter,
@@ -195,6 +201,8 @@ impl Process {
195201
let explorer = self.explorer_msgbox.clone();
196202
let tx_msg_box = self.fragment_msgbox.clone();
197203

204+
let notifier = self.notifier_msgbox.clone();
205+
198206
info.run_periodic_fallible(
199207
"branch reprocessing",
200208
BRANCH_REPROCESSING_INTERVAL,
@@ -204,6 +212,7 @@ impl Process {
204212
tip.clone(),
205213
explorer.clone(),
206214
tx_msg_box.clone(),
215+
notifier.clone(),
207216
)
208217
},
209218
)
@@ -294,6 +303,7 @@ async fn reprocess_tip(
294303
tip: Tip,
295304
explorer_msg_box: Option<MessageBox<ExplorerMsg>>,
296305
tx_msg_box: MessageBox<TransactionMsg>,
306+
notifier_msg_box: MessageBox<NotifierMsg>,
297307
) -> Result<(), Error> {
298308
let branches: Vec<Arc<Ref>> = blockchain.branches().branches().await;
299309

@@ -311,6 +321,7 @@ async fn reprocess_tip(
311321
Arc::clone(other),
312322
explorer_msg_box.clone(),
313323
Some(tx_msg_box.clone()),
324+
Some(notifier_msg_box.clone()),
314325
)
315326
.await?
316327
}
@@ -333,6 +344,7 @@ pub async fn process_new_ref(
333344
candidate: Arc<Ref>,
334345
explorer_msg_box: Option<MessageBox<ExplorerMsg>>,
335346
mut tx_msg_box: Option<MessageBox<TransactionMsg>>,
347+
notifier_msg_box: Option<MessageBox<NotifierMsg>>,
336348
) -> Result<(), Error> {
337349
let candidate_hash = candidate.hash();
338350
let tip_ref = tip.get_ref().await;
@@ -411,6 +423,15 @@ pub async fn process_new_ref(
411423
.await
412424
.unwrap_or_else(|err| {
413425
tracing::error!("cannot send new tip to explorer: {}", err)
426+
})
427+
}
428+
429+
if let Some(mut msg_box) = notifier_msg_box {
430+
msg_box
431+
.send(NotifierMsg::NewTip(candidate_hash))
432+
.await
433+
.unwrap_or_else(|err| {
434+
tracing::error!("cannot notify new block to subscribers: {}", err)
414435
});
415436
}
416437
}
@@ -426,15 +447,18 @@ async fn process_and_propagate_new_ref(
426447
mut network_msg_box: MessageBox<NetworkMsg>,
427448
explorer_msg_box: Option<MessageBox<ExplorerMsg>>,
428449
tx_msg_box: MessageBox<TransactionMsg>,
450+
notifier_msg_box: MessageBox<NotifierMsg>,
429451
) -> chain::Result<()> {
430452
let header = new_block_ref.header().clone();
431453
tracing::debug!("processing the new block and propagating");
454+
432455
process_new_ref(
433456
blockchain,
434457
tip,
435458
new_block_ref,
436459
explorer_msg_box,
437460
Some(tx_msg_box),
461+
Some(notifier_msg_box),
438462
)
439463
.await?;
440464

@@ -454,6 +478,7 @@ async fn process_leadership_block(
454478
tx_msg_box: MessageBox<TransactionMsg>,
455479
network_msg_box: MessageBox<NetworkMsg>,
456480
explorer_msg_box: Option<MessageBox<ExplorerMsg>>,
481+
mut notifier_msg_box: MessageBox<crate::notifier::Message>,
457482
leadership_block: LeadershipBlock,
458483
stats_counter: Metrics,
459484
) -> chain::Result<()> {
@@ -467,12 +492,23 @@ async fn process_leadership_block(
467492
network_msg_box,
468493
explorer_msg_box.clone(),
469494
tx_msg_box,
495+
notifier_msg_box.clone(),
470496
)
471497
.await?;
472498

473499
// Track block as new new tip block
474500
stats_counter.set_tip_block(&block, &new_block_ref);
475501

502+
if let Err(err) = notifier_msg_box
503+
.send(NotifierMsg::NewBlock(block.clone()))
504+
.await
505+
{
506+
tracing::error!(
507+
"Cannot propagate block to blockchain event notifier: {}",
508+
err
509+
)
510+
}
511+
476512
if let Some(mut msg_box) = explorer_msg_box {
477513
msg_box.send(ExplorerMsg::NewBlock(block)).await?;
478514
}
@@ -547,6 +583,7 @@ async fn process_network_blocks(
547583
tx_msg_box: MessageBox<TransactionMsg>,
548584
network_msg_box: MessageBox<NetworkMsg>,
549585
mut explorer_msg_box: Option<MessageBox<ExplorerMsg>>,
586+
mut notifier_msg_box: MessageBox<NotifierMsg>,
550587
mut get_next_block_scheduler: GetNextBlockScheduler,
551588
handle: intercom::RequestStreamHandle<Block, ()>,
552589
stats_counter: Metrics,
@@ -564,6 +601,7 @@ async fn process_network_blocks(
564601
&blockchain,
565602
block.clone(),
566603
explorer_msg_box.as_mut(),
604+
&mut notifier_msg_box,
567605
&mut get_next_block_scheduler,
568606
)
569607
.await;
@@ -603,6 +641,7 @@ async fn process_network_blocks(
603641
network_msg_box,
604642
explorer_msg_box,
605643
tx_msg_box,
644+
notifier_msg_box,
606645
)
607646
.await?;
608647

@@ -620,6 +659,7 @@ async fn process_network_block(
620659
blockchain: &Blockchain,
621660
block: Block,
622661
explorer_msg_box: Option<&mut MessageBox<ExplorerMsg>>,
662+
event_notifier_msg_box: &mut MessageBox<NotifierMsg>,
623663
get_next_block_scheduler: &mut GetNextBlockScheduler,
624664
) -> Result<Option<Arc<Ref>>, chain::Error> {
625665
get_next_block_scheduler
@@ -650,7 +690,14 @@ async fn process_network_block(
650690
Err(Error::MissingParentBlock(parent_hash))
651691
}
652692
PreCheckedHeader::HeaderWithCache { parent_ref, .. } => {
653-
let r = check_and_apply_block(blockchain, parent_ref, block, explorer_msg_box).await;
693+
let r = check_and_apply_block(
694+
blockchain,
695+
parent_ref,
696+
block,
697+
explorer_msg_box,
698+
event_notifier_msg_box,
699+
)
700+
.await;
654701
r
655702
}
656703
}
@@ -661,6 +708,7 @@ async fn check_and_apply_block(
661708
parent_ref: Arc<Ref>,
662709
block: Block,
663710
explorer_msg_box: Option<&mut MessageBox<ExplorerMsg>>,
711+
event_notifier_msg_box: &mut MessageBox<NotifierMsg>,
664712
) -> Result<Option<Arc<Ref>>, chain::Error> {
665713
let explorer_enabled = explorer_msg_box.is_some();
666714
let post_checked = blockchain
@@ -679,6 +727,8 @@ async fn check_and_apply_block(
679727
} else {
680728
None
681729
};
730+
let block_for_subscribers = block.clone();
731+
682732
let applied_block = blockchain
683733
.apply_and_store_block(post_checked, block)
684734
.await?;
@@ -695,6 +745,13 @@ async fn check_and_apply_block(
695745
.try_send(ExplorerMsg::NewBlock(block_for_explorer.take().unwrap()))
696746
.unwrap_or_else(|err| tracing::error!("cannot add block to explorer: {}", err));
697747
}
748+
749+
event_notifier_msg_box
750+
.try_send(NotifierMsg::NewBlock(block_for_subscribers))
751+
.unwrap_or_else(|err| {
752+
tracing::error!("cannot notify new block to subscribers: {}", err)
753+
});
754+
698755
Ok(Some(block_ref))
699756
} else {
700757
tracing::debug!(

jormungandr/src/fragment/logs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ impl Logs {
3333
pub fn insert_pending(&mut self, log: FragmentLog) -> bool {
3434
assert!(log.is_pending());
3535
let fragment_id = *log.fragment_id();
36+
3637
if self.entries.contains(&fragment_id) {
3738
false
3839
} else {
3940
self.entries.put(fragment_id, (log, None));
41+
4042
true
4143
}
4244
}

jormungandr/src/intercom.rs

+7
Original file line numberDiff line numberDiff line change
@@ -628,5 +628,12 @@ pub enum ExplorerMsg {
628628
NewTip(HeaderHash),
629629
}
630630

631+
/// Messages to the notifier task
632+
pub enum NotifierMsg {
633+
NewBlock(Block),
634+
NewTip(HeaderHash),
635+
FragmentLog(FragmentId, FragmentStatus),
636+
}
637+
631638
#[cfg(test)]
632639
mod tests {}

jormungandr/src/main.rs

+21
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub mod leadership;
3939
pub mod log;
4040
pub mod metrics;
4141
pub mod network;
42+
pub mod notifier;
4243
pub mod rest;
4344
pub mod secure;
4445
pub mod settings;
@@ -77,6 +78,7 @@ const NETWORK_TASK_QUEUE_LEN: usize = 64;
7778
const EXPLORER_TASK_QUEUE_LEN: usize = 32;
7879
const CLIENT_TASK_QUEUE_LEN: usize = 32;
7980
const TOPOLOGY_TASK_QUEUE_LEN: usize = 32;
81+
const NOTIFIER_TASK_QUEUE_LEN: usize = 32;
8082
const BOOTSTRAP_RETRY_WAIT: Duration = Duration::from_secs(5);
8183

8284
fn start_services(bootstrapped_node: BootstrappedNode) -> Result<(), start_up::Error> {
@@ -148,12 +150,29 @@ fn start_services(bootstrapped_node: BootstrappedNode) -> Result<(), start_up::E
148150
}
149151
};
150152

153+
let (notifier_msgbox, notifier) = {
154+
let (msgbox, queue) = async_msg::channel(NOTIFIER_TASK_QUEUE_LEN);
155+
156+
let blockchain_tip = blockchain_tip.clone();
157+
let current_tip = block_on(async { blockchain_tip.get_ref().await.header().id() });
158+
159+
let (notifier, message_processor) =
160+
notifier::Notifier::new(current_tip, blockchain.storage().clone());
161+
162+
services.spawn_future("notifier", move |info| async move {
163+
message_processor.start(info, queue).await
164+
});
165+
166+
(msgbox, notifier)
167+
};
168+
151169
{
152170
let blockchain = blockchain.clone();
153171
let blockchain_tip = blockchain_tip.clone();
154172
let network_msgbox = network_msgbox.clone();
155173
let fragment_msgbox = fragment_msgbox.clone();
156174
let explorer_msgbox = explorer.as_ref().map(|(msg_box, _context)| msg_box.clone());
175+
let notifier_msgbox = notifier_msgbox.clone();
157176
// TODO: we should get this value from the configuration
158177
let block_cache_ttl: Duration = Duration::from_secs(120);
159178
let stats_counter = stats_counter.clone();
@@ -165,6 +184,7 @@ fn start_services(bootstrapped_node: BootstrappedNode) -> Result<(), start_up::E
165184
network_msgbox,
166185
fragment_msgbox,
167186
explorer_msgbox,
187+
notifier_msgbox,
168188
garbage_collection_interval: block_cache_ttl,
169189
};
170190
process.start(info, block_queue)
@@ -206,6 +226,7 @@ fn start_services(bootstrapped_node: BootstrappedNode) -> Result<(), start_up::E
206226
global_state,
207227
input: network_queue,
208228
channels,
229+
notification_service: notifier,
209230
};
210231
network::start(params)
211232
});

jormungandr/src/network/bootstrap.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ where
272272
parent_tip.clone(),
273273
None,
274274
None,
275+
None,
275276
)
276277
.await
277278
{
@@ -284,7 +285,7 @@ where
284285
}
285286

286287
if let Some(parent_tip) = maybe_parent_tip {
287-
blockchain::process_new_ref(&mut blockchain, branch, parent_tip, None, None)
288+
blockchain::process_new_ref(&mut blockchain, branch, parent_tip, None, None, None)
288289
.await
289290
.map_err(Error::ChainSelectionFailed)
290291
} else {

jormungandr/src/network/grpc/server.rs

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub async fn run_listen_socket(
1414
listen: &Listen,
1515
state: GlobalStateR,
1616
channels: Channels,
17+
notification_service: crate::notifier::Notifier,
1718
) -> Result<(), ListenError> {
1819
let sockaddr = listen.address();
1920
let span = span!(parent: &state.span, Level::TRACE, "listen_socket", local_addr = %sockaddr.to_string());
@@ -25,6 +26,7 @@ pub async fn run_listen_socket(
2526
.concurrency_limit_per_connection(concurrency_limits::SERVER_REQUESTS)
2627
.tcp_keepalive(Some(keepalive_durations::TCP))
2728
.add_service(service)
29+
.add_service(notification_service.into_server())
2830
.serve(sockaddr)
2931
.await
3032
.map_err(|cause| ListenError { cause, sockaddr })

0 commit comments

Comments
 (0)