-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: move ExEx book examples #11616
Changes from all commits
f8b0030
46aa44c
60bec91
d896f93
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
[package] | ||
name = "remote-exex" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
# reth | ||
reth = { git = "https://github.com/paradigmxyz/reth.git" } | ||
reth-exex = { git = "https://github.com/paradigmxyz/reth.git", features = ["serde"] } | ||
reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth.git"} | ||
reth-node-api = { git = "https://github.com/paradigmxyz/reth.git"} | ||
reth-tracing = { git = "https://github.com/paradigmxyz/reth.git" } | ||
|
||
# async | ||
tokio = { version = "1", features = ["full"] } | ||
tokio-stream = "0.1" | ||
futures-util = "0.3" | ||
|
||
# grpc | ||
tonic = "0.11" | ||
prost = "0.12" | ||
bincode = "1" | ||
|
||
# misc | ||
eyre = "0.6" | ||
|
||
[build-dependencies] | ||
tonic-build = "0.11" | ||
|
||
[[bin]] | ||
name = "exex_1" | ||
path = "src/exex_1.rs" | ||
|
||
[[bin]] | ||
name = "exex_2" | ||
path = "src/exex_2.rs" | ||
|
||
[[bin]] | ||
name = "exex_3" | ||
path = "src/exex_3.rs" | ||
|
||
[[bin]] | ||
name = "exex_4" | ||
path = "src/exex_4.rs" | ||
|
||
[[bin]] | ||
name = "exex" | ||
path = "src/exex.rs" | ||
|
||
[[bin]] | ||
name = "consumer" | ||
path = "src/consumer.rs" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
tonic_build::compile_protos("proto/exex.proto")?; | ||
Ok(()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
syntax = "proto3"; | ||
|
||
package exex; | ||
|
||
service RemoteExEx { | ||
rpc Subscribe(SubscribeRequest) returns (stream ExExNotification) {} | ||
} | ||
|
||
message SubscribeRequest {} | ||
|
||
message ExExNotification { | ||
bytes data = 1; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
use remote_exex::proto::{remote_ex_ex_client::RemoteExExClient, SubscribeRequest}; | ||
use reth_exex::ExExNotification; | ||
use reth_tracing::{tracing::info, RethTracer, Tracer}; | ||
|
||
#[tokio::main] | ||
async fn main() -> eyre::Result<()> { | ||
let _ = RethTracer::new().init()?; | ||
|
||
let mut client = RemoteExExClient::connect("http://[::1]:10000") | ||
.await? | ||
.max_encoding_message_size(usize::MAX) | ||
.max_decoding_message_size(usize::MAX); | ||
|
||
let mut stream = client.subscribe(SubscribeRequest {}).await?.into_inner(); | ||
while let Some(notification) = stream.message().await? { | ||
let notification: ExExNotification = bincode::deserialize(¬ification.data)?; | ||
|
||
match notification { | ||
ExExNotification::ChainCommitted { new } => { | ||
info!(committed_chain = ?new.range(), "Received commit"); | ||
} | ||
ExExNotification::ChainReorged { old, new } => { | ||
info!(from_chain = ?old.range(), to_chain = ?new.range(), "Received reorg"); | ||
} | ||
ExExNotification::ChainReverted { old } => { | ||
info!(reverted_chain = ?old.range(), "Received revert"); | ||
} | ||
}; | ||
} | ||
|
||
Ok(()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
use futures_util::TryStreamExt; | ||
use remote_exex::proto::{ | ||
self, | ||
remote_ex_ex_server::{RemoteExEx, RemoteExExServer}, | ||
}; | ||
use reth_exex::{ExExContext, ExExEvent, ExExNotification}; | ||
use reth_node_api::FullNodeComponents; | ||
use reth_node_ethereum::EthereumNode; | ||
use reth_tracing::tracing::info; | ||
use std::sync::Arc; | ||
use tokio::sync::{broadcast, mpsc}; | ||
use tokio_stream::wrappers::ReceiverStream; | ||
use tonic::{transport::Server, Request, Response, Status}; | ||
|
||
struct ExExService { | ||
notifications: Arc<broadcast::Sender<ExExNotification>>, | ||
} | ||
|
||
#[tonic::async_trait] | ||
impl RemoteExEx for ExExService { | ||
type SubscribeStream = ReceiverStream<Result<proto::ExExNotification, Status>>; | ||
|
||
async fn subscribe( | ||
&self, | ||
_request: Request<proto::SubscribeRequest>, | ||
) -> Result<Response<Self::SubscribeStream>, Status> { | ||
let (tx, rx) = mpsc::channel(1); | ||
|
||
let mut notifications = self.notifications.subscribe(); | ||
tokio::spawn(async move { | ||
while let Ok(notification) = notifications.recv().await { | ||
let proto_notification = proto::ExExNotification { | ||
data: bincode::serialize(¬ification).expect("failed to serialize"), | ||
}; | ||
tx.send(Ok(proto_notification)) | ||
.await | ||
.expect("failed to send notification to client"); | ||
|
||
info!("Notification sent to the gRPC client"); | ||
} | ||
}); | ||
|
||
Ok(Response::new(ReceiverStream::new(rx))) | ||
} | ||
} | ||
|
||
async fn remote_exex<Node: FullNodeComponents>( | ||
mut ctx: ExExContext<Node>, | ||
notifications: Arc<broadcast::Sender<ExExNotification>>, | ||
) -> eyre::Result<()> { | ||
while let Some(notification) = ctx.notifications.try_next().await? { | ||
if let Some(committed_chain) = notification.committed_chain() { | ||
ctx.events.send(ExExEvent::FinishedHeight(committed_chain.tip().num_hash()))?; | ||
} | ||
|
||
info!("Notification sent to the gRPC server"); | ||
let _ = notifications.send(notification); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
// ANCHOR: snippet | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need this? and in other places too There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to show only the relevant sections of the files at the book references, and allow the reader to expand the complete file only if they want to. Another way to do this is to use line numbers of the snippets instead of using these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, i see! that's great, I think these anchors are fine |
||
fn main() -> eyre::Result<()> { | ||
reth::cli::Cli::parse_args().run(|builder, _| async move { | ||
let notifications = Arc::new(broadcast::channel(1).0); | ||
|
||
let server = Server::builder() | ||
.add_service(RemoteExExServer::new(ExExService { | ||
notifications: notifications.clone(), | ||
})) | ||
.serve("[::1]:10000".parse().unwrap()); | ||
|
||
let handle = builder | ||
.node(EthereumNode::default()) | ||
.install_exex("remote-exex", |ctx| async move { Ok(remote_exex(ctx, notifications)) }) | ||
.launch() | ||
.await?; | ||
|
||
handle.node.task_executor.spawn_critical("gRPC server", async move { | ||
server.await.expect("failed to start gRPC server") | ||
}); | ||
|
||
handle.wait_for_node_exit().await | ||
}) | ||
} | ||
// ANCHOR_END: snippet |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
use remote_exex::proto::{ | ||
self, | ||
remote_ex_ex_server::{RemoteExEx, RemoteExExServer}, | ||
}; | ||
use reth_node_ethereum::EthereumNode; | ||
use tokio::sync::mpsc; | ||
use tokio_stream::wrappers::ReceiverStream; | ||
use tonic::{transport::Server, Request, Response, Status}; | ||
|
||
struct ExExService {} | ||
|
||
#[tonic::async_trait] | ||
impl RemoteExEx for ExExService { | ||
type SubscribeStream = ReceiverStream<Result<proto::ExExNotification, Status>>; | ||
|
||
async fn subscribe( | ||
&self, | ||
_request: Request<proto::SubscribeRequest>, | ||
) -> Result<Response<Self::SubscribeStream>, Status> { | ||
let (_tx, rx) = mpsc::channel(1); | ||
|
||
Ok(Response::new(ReceiverStream::new(rx))) | ||
} | ||
} | ||
|
||
fn main() -> eyre::Result<()> { | ||
reth::cli::Cli::parse_args().run(|builder, _| async move { | ||
let server = Server::builder() | ||
.add_service(RemoteExExServer::new(ExExService {})) | ||
.serve("[::1]:10000".parse().unwrap()); | ||
|
||
let handle = builder.node(EthereumNode::default()).launch().await?; | ||
|
||
handle.node.task_executor.spawn_critical("gRPC server", async move { | ||
server.await.expect("failed to start gRPC server") | ||
}); | ||
|
||
handle.wait_for_node_exit().await | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for this to work in the CI, we also need to install
protoc
. I think it's not a big deal as it's quite lightweight, wdyt @mattsse ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactoring the job and adding protoc in #11618
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does this need to run on ci?
yeah I guess if we want to do have well maintained bindings then we're kinda forced to do this. sounds reasonable