geyser-grpc-connector/src/grpcmultiplex_fastestwins.rs

75 lines
2.2 KiB
Rust
Raw Normal View History

2023-12-13 06:57:50 -08:00
use async_stream::stream;
2023-12-15 01:28:25 -08:00
use futures::Stream;
2023-12-15 01:25:21 -08:00
use log::{debug, info};
2023-12-13 06:57:50 -08:00
use solana_sdk::clock::Slot;
use solana_sdk::commitment_config::CommitmentConfig;
2023-12-15 01:25:21 -08:00
use yellowstone_grpc_proto::geyser::SubscribeUpdate;
2023-12-14 03:58:47 -08:00
pub trait FromYellowstoneMapper {
2023-12-14 04:09:43 -08:00
// Target is something like ProducedBlock
2023-12-14 03:58:47 -08:00
type Target;
2023-12-14 04:09:43 -08:00
fn map_yellowstone_update(&self, update: SubscribeUpdate) -> Option<(Slot, Self::Target)>;
}
2023-12-15 02:43:00 -08:00
/// use streams created by ``create_geyser_reconnecting_stream``
/// note: this is agnostic to the type of the stream
pub fn create_multiplex<M>(
grpc_source_streams: Vec<impl Stream<Item = Option<SubscribeUpdate>>>,
2023-12-14 01:13:48 -08:00
commitment_config: CommitmentConfig,
2023-12-15 02:43:00 -08:00
mapper: M,
) -> impl Stream<Item = M::Target>
2023-12-15 01:25:21 -08:00
where
2023-12-15 02:43:00 -08:00
M: FromYellowstoneMapper,
{
2023-12-13 06:57:50 -08:00
assert!(
2023-12-14 01:13:48 -08:00
commitment_config == CommitmentConfig::confirmed()
|| commitment_config == CommitmentConfig::finalized(),
2023-12-15 01:25:21 -08:00
"Only CONFIRMED and FINALIZED is supported"
);
2023-12-13 06:57:50 -08:00
// note: PROCESSED blocks are not sequential in presense of forks; this will break the logic
2023-12-15 02:43:00 -08:00
if grpc_source_streams.is_empty() {
2023-12-13 06:57:50 -08:00
panic!("Must have at least one source");
}
info!(
2023-12-15 02:43:00 -08:00
"Starting multiplexer with {} sources",
grpc_source_streams.len(),
);
2023-12-15 02:43:00 -08:00
// use merge
let mut futures = futures::stream::SelectAll::new();
2023-12-15 02:43:00 -08:00
for grpc_source in grpc_source_streams {
futures.push(Box::pin(grpc_source));
}
2023-12-13 06:57:50 -08:00
2023-12-15 02:43:00 -08:00
map_updates(futures, mapper)
}
2023-12-13 06:57:50 -08:00
2023-12-14 04:09:43 -08:00
fn map_updates<S, E>(geyser_stream: S, mapper: E) -> impl Stream<Item = E::Target>
2023-12-15 01:25:21 -08:00
where
S: Stream<Item = Option<SubscribeUpdate>>,
E: FromYellowstoneMapper,
{
2023-12-14 04:09:43 -08:00
let mut tip: Slot = 0;
stream! {
for await update in geyser_stream {
2023-12-14 09:39:12 -08:00
match update {
Some(update) => {
// take only the update messages we want
if let Some((proposed_slot, block)) = mapper.map_yellowstone_update(update) {
if proposed_slot > tip {
tip = proposed_slot;
yield block;
}
2023-12-14 04:09:43 -08:00
}
2023-12-13 06:57:50 -08:00
}
2023-12-14 09:39:12 -08:00
None => {
debug!("Stream sent None"); // TODO waht does that mean?
}
2023-12-13 06:57:50 -08:00
}
}
}
}