substreams_ethereum_core/
rpc.rs1use 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}