-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
wip: enable propagation of custom rpc builder stack layers #7976
wip: enable propagation of custom rpc builder stack layers #7976
Conversation
crates/rpc/rpc-builder/src/lib.rs
Outdated
http_server_config: Option<ServerBuilder<Identity, Identity>>, | ||
/// Allowed CORS Domains for http | ||
http_cors_domains: Option<String>, | ||
/// Address where to bind the http server to | ||
http_addr: Option<SocketAddr>, | ||
/// Configs for WS server | ||
ws_server_config: Option<ServerBuilder<Identity, Identity>>, | ||
/// Allowed CORS Domains for ws. | ||
ws_cors_domains: Option<String>, | ||
/// Address where to bind the ws server to | ||
ws_addr: Option<SocketAddr>, | ||
/// Configs for JSON-RPC IPC server | ||
ipc_server_config: Option<IpcServerBuilder<Identity, Identity>>, |
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.
we should keep all of those and instead use the additional HTTP and rpc fields for all ServerBuilders that were installed, this makes it to configure these layers for all servers
need to require Http: Clone, Rpc:Clone
on start
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.
would that be in launch_rpc_servers
?
i added some kind of sketch of using it with an .option_layer(config.rpc.clone())
but that was a little bit of a stab in the dark, i'm trying to pick back up the thread of this pr rn
crates/rpc/rpc-builder/src/lib.rs
Outdated
@@ -1497,50 +1497,60 @@ where | |||
/// Once the [RpcModule] is built via [RpcModuleBuilder] the servers can be started, See also | |||
/// [ServerBuilder::build] and [Server::start](jsonrpsee::server::Server::start). | |||
#[derive(Default, Debug)] | |||
pub struct RpcServerConfig { | |||
pub struct RpcServerConfig<Http = Identity, Rpc = Identity, Endpoint = String> |
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.
@mattsse i think this is closer to what you had in mind, is that right?
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.
yeah but we need a simpler way to configure this for server configs at the same time, so we don't support configuring different layers for different server types, because this would be too complex.
we can either store the layers as separate fields and keep identity for all servers or add helper functions that apply the layer for all the servers.
crates/rpc/rpc-builder/src/lib.rs
Outdated
@@ -1497,50 +1497,60 @@ where | |||
/// Once the [RpcModule] is built via [RpcModuleBuilder] the servers can be started, See also | |||
/// [ServerBuilder::build] and [Server::start](jsonrpsee::server::Server::start). | |||
#[derive(Default, Debug)] | |||
pub struct RpcServerConfig { | |||
pub struct RpcServerConfig<Http = Identity, Rpc = Identity, Endpoint = String> |
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.
yeah but we need a simpler way to configure this for server configs at the same time, so we don't support configuring different layers for different server types, because this would be too complex.
we can either store the layers as separate fields and keep identity for all servers or add helper functions that apply the layer for all the servers.
crates/rpc/rpc-builder/src/lib.rs
Outdated
@@ -1497,50 +1497,60 @@ where | |||
/// Once the [RpcModule] is built via [RpcModuleBuilder] the servers can be started, See also | |||
/// [ServerBuilder::build] and [Server::start](jsonrpsee::server::Server::start). | |||
#[derive(Default, Debug)] | |||
pub struct RpcServerConfig { | |||
pub struct RpcServerConfig<Http = Identity, Rpc = Identity, Endpoint = String> |
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.
endpoint is not needed here
@mattsse are you saying that you want to have a more simplified/streamlined config struct like this
and that we'd change up the helper methods like |
this is how the what I think we want is a way to I think option a) is more intuitive |
@mattsse right now it looks like this
i think i get what you're talking about, it's kinda building on the work i did in the last pr of making the rpc start up/building process more generalizable, thanks for sticking with me as i figure this out, i'm trying my best to understand what you're looking for 😅 so putting it all together, this is what i'm thinking about... high level objective is working towards integrating additional layers in the rpc server. goal should be that it's possible to plug in an additional Layer here, in this code:
^which i guess means that we have a more generic method for getting the server build, that isn't tightly coupled to http, ws and ipc - is that right? you mentioned that "the way we currently use this, bypasses this intermediary step that uses the RpcServer type entirely are we trying to eliminate the you mentioned that the way the config is setup is basically with empty serverbuilders (Identity), and that we could something like
i think thats why my comment earlier was in the direction of making things maximally generic, in my interpretation, is that directionally correct but too far for right now? one of the things thats confusing me a little i think is the options you outlined. could you maybe help me zero in on option a) 😅 |
1abacb4
to
59b95d0
Compare
e250544
to
302f7c3
Compare
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.
additional args are out of scope for this pr
crates/rpc/rpc-builder/src/lib.rs
Outdated
/// Additional middleware layer. | ||
additional_middleware: Option<L>, |
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.
this is the right approach to configure the service for all servers
if we look at the ServerBuilder::set_http_middleware
function then this accepts a http_middleware: tower::ServiceBuilder<T>,
so we can do the same here, starting with tower::ServiceBuilder<L>,
then we also don't need to restrict the L
generic above
crates/rpc/rpc-builder/src/lib.rs
Outdated
/// | ||
/// - `M`: The type of the middleware layer, which must implement `tower::Layer<L> + Send + Sync | ||
/// + `static`. | ||
pub fn with_additional_middleware<M>(self, layer: M) -> RpcServerConfig<M> |
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.
this should accept tower::ServiceBuilder<T>,
and replace the current one
builder: RpcServerConfig<L>, | ||
) -> Result<RpcServerHandle, RpcError> | ||
where | ||
L: tower::Layer<Identity> + Send + Sync + 'static, |
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.
this generic will be a bit wilder, because of the restriction jsonrpsee has, see for jsonrpsee::Server::start
I assume there will be some complications for ipc vs http/ws, so lets only focus on HTTP and ws first.
we could also support configuring the middleware for each transport individually but with 2 generics per transport this would be a bit of a mess I assume
perhaps it would be simpler to tackle the RpcMiddlerware type first which is the same for all
RpcMiddleware: tower::Layer<RpcService> + Clone + Send + 'static,
and installed via set_rpc_middleware<T>(self, rpc_middleware: RpcServiceBuilder<T>)
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.
that sounds like a great plan! I'll take a crack at it 💪
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.
so I got it to build as it is now - but i'm running into problems when i try to add additional layers like this
// Initialize the ServiceBuilder
let mut service_builder = tower::ServiceBuilder::new();
// Conditionally add logging middleware
if self.enable_logging {
let trace_layer = tower_http::trace::TraceLayer::new_for_http();
service_builder = service_builder.layer(trace_layer);
}
// Conditionally add authentication middleware
if self.enable_auth {
let auth_layer = tower_http::auth::AddAuthorizationLayer::basic("username", "password");
service_builder = service_builder.layer(auth_layer);
}
or even this
if self.enable_logging {
let trace_layer = tower_http::trace::TraceLayer::new_for_http();
let service_builder = tower::ServiceBuilder::new().layer(trace_layer);
config = config.with_additional_middleware(service_builder);
}
// Conditionally add authentication middleware
if self.enable_auth {
let auth_layer = tower_http::auth::AddAuthorizationLayer::basic("username", "password");
let service_builder = tower::ServiceBuilder::new().layer(auth_layer);
config = config.with_additional_middleware(service_builder);
}
'cause the compiler is expecting a certain ServiceBuilder/middleware configuration - and then it's getting changed
what do you think is the best way to resolve that issue?
maybe to create a more generalized abstraction for it? Like a middleware struct or something?
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.
ok yeah, i'm finally looking at this jsonrpsee
code
/// Ipc Server implementation
///
/// This is an adapted `jsonrpsee` Server, but for `Ipc` connections.
pub struct IpcServer<HttpMiddleware = Identity, RpcMiddleware = Identity> {
/// The endpoint we listen for incoming transactions
endpoint: String,
id_provider: Arc<dyn IdProvider>,
cfg: Settings,
rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
http_middleware: tower::ServiceBuilder<HttpMiddleware>,
}
impl<HttpMiddleware, RpcMiddleware> IpcServer<HttpMiddleware, RpcMiddleware> {
/// Returns the configured endpoint
pub fn endpoint(&self) -> String {
self.endpoint.clone()
}
}
impl<HttpMiddleware, RpcMiddleware> IpcServer<HttpMiddleware, RpcMiddleware>
where
RpcMiddleware: for<'a> Layer<RpcService, Service: RpcServiceT<'a>> + Clone + Send + 'static,
HttpMiddleware: Layer<
TowerServiceNoHttp<RpcMiddleware>,
Service: Service<
String,
Response = Option<String>,
Error = Box<dyn std::error::Error + Send + Sync + 'static>,
Future: Send + Unpin,
> + Send,
> + Send
+ 'static,
{
i'll think this over. starting with RpcMiddlerware
sounds reasonable to me, i might make a new branch for that so i can think about it freshly
here's all the info i've collected about this task...
if you want to continue, then we can continue with flattening it even more or support configuring additional middleware layers
the endgoal for this is that we can propgate custom Layers through the rpc-builder stack
if you look at how the node-builder api currently works, it would be great to plug in a layer.
reth/examples/cli-extension-event-hooks/src/main.rs
Ok yeah, that makes sense to me. We’d parse the arguments out into an option layer.
Is it that there would be a set of possible layers we could intake that would be specified with different flags, or more like they would be generic and we’d figure out once they’re injested how to handle them
what I'm looking for is something similar to the
tower::ServiceBuilder<T>
so we can install additional layers when we build the rpc serverfor example here is where we launch the thing
reth/crates/node-builder/src/rpc.rs
so perhaps we can extend
RpcServerConfig
with<M = Identity>
so we can configure additional middlewares?goal should be that it's possible to plug in an additional Layer here:
reth/crates/node-builder/src/rpc.rs
the way we currently use this, bypasses this intermediary step that uses the
RpcServer
type entirelyreth/crates/rpc/rpc-builder/src/lib.rs
the way the config is setup is basically with empty serverbuilders (Identity)
I think what we could do is something like
Support the installation additional layers when building the RPC server, with the intention of enabling the propagation of custom layers thru the RPC builder stack.
Analogous to
tower::ServiceBuilder<T>
.Ultimately will involve an update to
rpc_server_config
functions.The resulting code should incorporate the intermediary RpcServer type for setup.
This code is an initial attempt at a simplification of
RpcServerConfig
with the intention of generalizing associated operations.