substreams_ethereum_core/
rpc.rs

1use crate::pb::eth::rpc::{RpcCall, RpcCalls, RpcResponse, RpcResponses};
2use crate::Function;
3use substreams::proto;
4
5pub trait RPCDecodable<R> {
6    fn output(data: &[u8]) -> Result<R, String>;
7}
8
9pub struct RpcBatch {
10    store: RpcCalls,
11}
12
13pub fn batch() -> RpcBatch {
14    RpcBatch {
15        store: RpcCalls {
16            ..Default::default()
17        },
18    }
19}
20
21impl RpcBatch {
22    pub fn new() -> RpcBatch {
23        RpcBatch {
24            store: RpcCalls { calls: vec![] },
25        }
26    }
27
28    pub fn add<F: Function>(mut self, call: F, address: Vec<u8>) -> Self {
29        self.store.calls.push(RpcCall {
30            to_addr: address,
31            data: call.encode(),
32        });
33        self
34    }
35
36    pub fn execute(self) -> Result<RpcResponses, String> {
37        Ok(eth_call(&self.store))
38    }
39
40    pub fn decode<R, T: RPCDecodable<R> + Function>(response: &RpcResponse) -> Option<R> {
41        if response.failed {
42            return None;
43        }
44
45        match T::output(response.raw.as_ref()) {
46            Ok(data) => Some(data),
47            Err(err) => {
48                substreams::log::info!(
49                    "Call output for function `{}` failed to decode with error: {}",
50                    T::NAME,
51                    err
52                );
53                None
54            }
55        }
56    }
57}
58
59#[cfg_attr(not(target_arch = "wasm32"), allow(unused_variables))]
60fn eth_call_internal(input: Vec<u8>) -> Vec<u8> {
61    #[cfg(target_arch = "wasm32")]
62    unsafe {
63        use substreams::memory;
64
65        let rpc_response_ptr = memory::alloc(8);
66        crate::externs::rpc::eth_call(input.as_ptr(), input.len() as u32, rpc_response_ptr);
67        return memory::get_output_data(rpc_response_ptr);
68    }
69
70    #[cfg(not(target_arch = "wasm32"))]
71    unimplemented!("this method is not implemented outside of 'wasm32' target compilation")
72}
73
74pub fn eth_call(input: &RpcCalls) -> RpcResponses {
75    let raw_resp: Vec<u8> = eth_call_internal(proto::encode(input).unwrap());
76    let resp: RpcResponses = proto::decode(&raw_resp).unwrap();
77
78    return resp;
79}