Skip to content

[Feature] Allow custom implementation for Provider methods #736

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

Closed
Gaon3 opened this issue May 12, 2024 · 3 comments · Fixed by #788
Closed

[Feature] Allow custom implementation for Provider methods #736

Gaon3 opened this issue May 12, 2024 · 3 comments · Fixed by #788
Assignees
Labels
enhancement New feature or request

Comments

@Gaon3
Copy link

Gaon3 commented May 12, 2024

Component

provider, pubsub, transports

Describe the feature you would like

Looking at the new eth_call implementation, it looks like Provider functions will now return RpcCall or a wrapper around it (like EthCall).
The previous implementation returned raw values, making it possible to implement the Provider trait on your own provider and override methods to execute your own logic (reading from database instead of using JSON-RPC transport in my case) because the returned values had no ties to Transport.

What I ask is to maintain the possibility of executing arbitrary code in Provider methods. This can maybe be achieved by making the Provider methods return an enum which can either hold an RpcCall or a CustomCall, the later containing a future not depending on the Transport trait.

Additional context

No response

@Gaon3 Gaon3 added the enhancement New feature or request label May 12, 2024
@prestwich
Copy link
Member

my current preferred implementation is to add an RpcCall state variant that looks like Wrapped(Box<dyn Future<Output = Resp + Send + Sync + 'static>>), and a RpcCall::wrap(inner: Box<dyn Future<...>>) -> Self to allow delegation to arbitrary futures

@prestwich
Copy link
Member

prestwich commented May 24, 2024

Sketch implementation

#[pin_project::pin_project(project = ProviderCallProj)]
pub enum ProviderCall<Conn, Params, Resp, Output = Resp, Map = fn(Resp) -> Output>
where
    Conn: Transport + Clone,
    Params: RpcParam,
    Map: Fn(Resp) -> Output,
{
    TransportCall(TransportRpc<Conn, Params, Resp, Output, Map>),
    Waiter {
        waiter: Waiter<Resp>,
        #[pin]
        map: Map,
    },
    Other(Pin<Box<dyn Future<Output = TransportResult<Output>> + Send>>),
    Ready(Option<Output>),
}

impl<Conn, Params, Resp, Output, Map> Future for ProviderCall<Conn, Params, Resp, Output, Map>
where
    Conn: Transport + Clone,
    Params: RpcParam,
    Resp: RpcReturn,
    Output: 'static,
    Map: Fn(Resp) -> Output,
{
    type Output = TransportResult<Output>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
        match self.as_mut().project() {
            ProviderCallProj::TransportCall(call) => call.poll_unpin(cx),
            ProviderCallProj::Waiter { waiter, map } => match waiter.poll_unpin(cx) {
                Ready(Ok(resp)) => Ready(Ok(map(resp))),
                Ready(Err(e)) => Ready(Err(e)),
                _ => task::Poll::Pending,
            },
            ProviderCallProj::Other(fut) => fut.poll_unpin(cx),
            ProviderCallProj::Ready(output) => {
                Ready(Ok(output.take().expect("output taken twice")))
            }
        }
    }
}

@prestwich prestwich mentioned this issue May 27, 2024
10 tasks
@prestwich
Copy link
Member

@Gaon3 check out #788. that future would meet your needs i assume?

@DaniPopes DaniPopes added this to the 0.1-rc.0 milestone Jun 5, 2024
@DaniPopes DaniPopes removed the 0.1-rc.0 label Jun 5, 2024
@prestwich prestwich removed this from the 0.1.0-rc.0 milestone Jun 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants