From cb5e33d53ced0544119c900161cc22362c8ba85f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 24 Sep 2021 09:20:51 +1000 Subject: [PATCH] Start adding json rpc wrapper --- beacon_node/execution_layer/src/engine_api.rs | 3 + .../execution_layer/src/engine_api/http.rs | 75 ++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 95f6f8aa5c..1cc926c1a6 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -15,6 +15,9 @@ pub enum Error { RequestFailed(String), JsonRpc(RpcError), Json(serde_json::Error), + ServerMessage(String), + Eip155Error, + NoResultField, } impl From for Error { diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index 804d9fb0c2..2d9a106bdb 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -1,9 +1,10 @@ use super::*; use async_trait::async_trait; -use eth1::http::{response_result_or_error, send_rpc_request}; +use eth1::http::{response_result_or_error, send_rpc_request, EIP155_ERROR_STR}; pub use reqwest::Client; +use reqwest::{header::CONTENT_TYPE, ClientBuilder, StatusCode}; use sensitive_url::SensitiveUrl; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::json; use std::time::Duration; use types::{execution_payload::serde_logs_bloom, EthSpec, FixedVector, Transaction, VariableList}; @@ -35,6 +36,67 @@ impl HttpJsonRpc { url, }) } + + pub async fn rpc_request( + &self, + method: &str, + params: serde_json::Value, + timeout: Duration, + ) -> Result { + let body = JsonBody { + jsonrpc: "2.0", + method: method, + params, + id: 1, + }; + + let url: &str = self.url.as_ref(); + + let body: serde_json::Value = self + .client + .post(url) + .timeout(timeout) + .header(CONTENT_TYPE, "application/json") + .json(&body) + .send() + .await? + .error_for_status()? + .json() + .await?; + + if let Some(error) = body.get("error").map(|e| e.get("message")).flatten() { + let error = error.to_string(); + if error.contains(EIP155_ERROR_STR) { + Err(Error::Eip155Error) + } else { + Err(Error::ServerMessage(error)) + } + } else { + body.get("result").cloned().ok_or(Error::NoResultField) + } + + /* + let encoding = response + .headers() + .get(CONTENT_TYPE) + .ok_or("No content-type header in response")? + .to_str() + .map(|s| s.to_string()) + .map_err(|e| format!("Failed to parse content-type header: {}", e))?; + + response + .bytes() + .map_err(|e| format!("Failed to receive body: {:?}", e)) + .await + .and_then(move |bytes| match encoding.as_str() { + "application/json" => Ok(bytes), + "application/json; charset=utf-8" => Ok(bytes), + other => Err(format!("Unsupported encoding: {}", other)), + }) + .map(|bytes| String::from_utf8_lossy(&bytes).into_owned()) + .map_err(|e| format!("Failed to receive body: {:?}", e)) + */ + } } #[async_trait] @@ -160,6 +222,15 @@ impl EngineApi for HttpJsonRpc { } } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename = "camelCase")] +struct JsonBody<'a> { + jsonrpc: &'a str, + method: &'a str, + params: serde_json::Value, + id: u32, +} + #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename = "camelCase")] struct JsonPreparePayloadRequest {