refactor: better error handling (#63)
* add custom errors to consensus * add BlockNotFoundError * better handling of blocktag parsing * clean up * add execution errors * add rpc errors * add more fields to errors
This commit is contained in:
parent
f3b9750eff
commit
5d1f4a6344
|
@ -513,6 +513,7 @@ dependencies = [
|
||||||
"openssl",
|
"openssl",
|
||||||
"serde",
|
"serde",
|
||||||
"ssz-rs",
|
"ssz-rs",
|
||||||
|
"thiserror",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -551,6 +552,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"ssz-rs",
|
"ssz-rs",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
@ -1040,6 +1042,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"ssz-rs",
|
"ssz-rs",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
"triehash-ethereum",
|
"triehash-ethereum",
|
||||||
|
@ -3285,18 +3288,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.34"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252"
|
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.34"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487"
|
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -4,6 +4,7 @@ use ethers::prelude::{Address, U256};
|
||||||
use ethers::types::{Transaction, TransactionReceipt, H256};
|
use ethers::types::{Transaction, TransactionReceipt, H256};
|
||||||
use eyre::{eyre, Result};
|
use eyre::{eyre, Result};
|
||||||
|
|
||||||
|
use common::types::BlockTag;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use consensus::types::Header;
|
use consensus::types::Header;
|
||||||
use execution::types::{CallOpts, ExecutionBlock};
|
use execution::types::{CallOpts, ExecutionBlock};
|
||||||
|
@ -13,7 +14,7 @@ use tokio::sync::RwLock;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use crate::database::{Database, FileDB};
|
use crate::database::{Database, FileDB};
|
||||||
use crate::node::{BlockTag, Node};
|
use crate::node::Node;
|
||||||
use crate::rpc::Rpc;
|
use crate::rpc::Rpc;
|
||||||
|
|
||||||
pub struct Client<DB: Database> {
|
pub struct Client<DB: Database> {
|
||||||
|
@ -49,13 +50,13 @@ impl<DB: Database> Client<DB> {
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
let res = node.write().await.sync().await;
|
let res = node.write().await.sync().await;
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
warn!("{}", err);
|
warn!("consensus error: {}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let res = node.write().await.advance().await;
|
let res = node.write().await.advance().await;
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
warn!("{}", err);
|
warn!("consensus error: {}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_update = node.read().await.duration_until_next_update();
|
let next_update = node.read().await.duration_until_next_update();
|
||||||
|
|
|
@ -6,6 +6,8 @@ use ethers::prelude::{Address, U256};
|
||||||
use ethers::types::{Transaction, TransactionReceipt, H256};
|
use ethers::types::{Transaction, TransactionReceipt, H256};
|
||||||
use eyre::{eyre, Result};
|
use eyre::{eyre, Result};
|
||||||
|
|
||||||
|
use common::errors::BlockNotFoundError;
|
||||||
|
use common::types::BlockTag;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use consensus::rpc::nimbus_rpc::NimbusRpc;
|
use consensus::rpc::nimbus_rpc::NimbusRpc;
|
||||||
use consensus::types::{ExecutionPayload, Header};
|
use consensus::types::{ExecutionPayload, Header};
|
||||||
|
@ -147,7 +149,7 @@ impl Node {
|
||||||
let value = account.slots.get(&slot);
|
let value = account.slots.get(&slot);
|
||||||
match value {
|
match value {
|
||||||
Some(value) => Ok(*value),
|
Some(value) => Ok(*value),
|
||||||
None => Err(eyre!("Slot Not Found")),
|
None => Err(eyre!("slot not found")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,15 +232,17 @@ impl Node {
|
||||||
match block {
|
match block {
|
||||||
BlockTag::Latest => {
|
BlockTag::Latest => {
|
||||||
let payload = self.payloads.last_key_value();
|
let payload = self.payloads.last_key_value();
|
||||||
Ok(payload.ok_or(eyre!("Block Not Found"))?.1)
|
Ok(payload.ok_or(BlockNotFoundError::new(BlockTag::Latest))?.1)
|
||||||
}
|
}
|
||||||
BlockTag::Finalized => {
|
BlockTag::Finalized => {
|
||||||
let payload = self.finalized_payloads.last_key_value();
|
let payload = self.finalized_payloads.last_key_value();
|
||||||
Ok(payload.ok_or(eyre!("Block Not Found"))?.1)
|
Ok(payload
|
||||||
|
.ok_or(BlockNotFoundError::new(BlockTag::Finalized))?
|
||||||
|
.1)
|
||||||
}
|
}
|
||||||
BlockTag::Number(num) => {
|
BlockTag::Number(num) => {
|
||||||
let payload = self.payloads.get(num);
|
let payload = self.payloads.get(num);
|
||||||
payload.ok_or(eyre!("Block Not Found"))
|
payload.ok_or(BlockNotFoundError::new(BlockTag::Number(*num)).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +253,7 @@ impl Node {
|
||||||
let slot_delay = expected_slot - synced_slot;
|
let slot_delay = expected_slot - synced_slot;
|
||||||
|
|
||||||
if slot_delay > 10 {
|
if slot_delay > 10 {
|
||||||
return Err(eyre!("Out of Sync"));
|
return Err(eyre!("out of sync"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -263,9 +267,3 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BlockTag {
|
|
||||||
Latest,
|
|
||||||
Finalized,
|
|
||||||
Number(u64),
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,9 +13,12 @@ use jsonrpsee::{
|
||||||
proc_macros::rpc,
|
proc_macros::rpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::node::{BlockTag, Node};
|
use crate::node::Node;
|
||||||
|
|
||||||
use common::utils::{hex_str_to_bytes, u64_to_hex_string};
|
use common::{
|
||||||
|
types::BlockTag,
|
||||||
|
utils::{hex_str_to_bytes, u64_to_hex_string},
|
||||||
|
};
|
||||||
use execution::types::{CallOpts, ExecutionBlock};
|
use execution::types::{CallOpts, ExecutionBlock};
|
||||||
|
|
||||||
pub struct Rpc {
|
pub struct Rpc {
|
||||||
|
@ -47,16 +50,16 @@ impl Rpc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rpc(client, server, namespace = "eth")]
|
#[rpc(server, namespace = "eth")]
|
||||||
trait EthRpc {
|
trait EthRpc {
|
||||||
#[method(name = "getBalance")]
|
#[method(name = "getBalance")]
|
||||||
async fn get_balance(&self, address: &str, block: &str) -> Result<String, Error>;
|
async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error>;
|
||||||
#[method(name = "getTransactionCount")]
|
#[method(name = "getTransactionCount")]
|
||||||
async fn get_transaction_count(&self, address: &str, block: &str) -> Result<String, Error>;
|
async fn get_transaction_count(&self, address: &str, block: BlockTag) -> Result<String, Error>;
|
||||||
#[method(name = "getCode")]
|
#[method(name = "getCode")]
|
||||||
async fn get_code(&self, address: &str, block: &str) -> Result<String, Error>;
|
async fn get_code(&self, address: &str, block: BlockTag) -> Result<String, Error>;
|
||||||
#[method(name = "call")]
|
#[method(name = "call")]
|
||||||
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error>;
|
async fn call(&self, opts: CallOpts, block: BlockTag) -> Result<String, Error>;
|
||||||
#[method(name = "estimateGas")]
|
#[method(name = "estimateGas")]
|
||||||
async fn estimate_gas(&self, opts: CallOpts) -> Result<String, Error>;
|
async fn estimate_gas(&self, opts: CallOpts) -> Result<String, Error>;
|
||||||
#[method(name = "chainId")]
|
#[method(name = "chainId")]
|
||||||
|
@ -70,7 +73,7 @@ trait EthRpc {
|
||||||
#[method(name = "getBlockByNumber")]
|
#[method(name = "getBlockByNumber")]
|
||||||
async fn get_block_by_number(
|
async fn get_block_by_number(
|
||||||
&self,
|
&self,
|
||||||
num: &str,
|
block: BlockTag,
|
||||||
full_tx: bool,
|
full_tx: bool,
|
||||||
) -> Result<Option<ExecutionBlock>, Error>;
|
) -> Result<Option<ExecutionBlock>, Error>;
|
||||||
#[method(name = "getBlockByHash")]
|
#[method(name = "getBlockByHash")]
|
||||||
|
@ -104,9 +107,8 @@ struct RpcInner {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EthRpcServer for RpcInner {
|
impl EthRpcServer for RpcInner {
|
||||||
async fn get_balance(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
||||||
debug!("eth_getBalance");
|
debug!("eth_getBalance");
|
||||||
let block = convert_err(decode_block(block))?;
|
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let balance = convert_err(node.get_balance(&address, &block).await)?;
|
let balance = convert_err(node.get_balance(&address, &block).await)?;
|
||||||
|
@ -114,8 +116,7 @@ impl EthRpcServer for RpcInner {
|
||||||
Ok(balance.encode_hex())
|
Ok(balance.encode_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_transaction_count(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_transaction_count(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let nonce = convert_err(node.get_nonce(&address, &block).await)?;
|
let nonce = convert_err(node.get_nonce(&address, &block).await)?;
|
||||||
|
@ -123,8 +124,7 @@ impl EthRpcServer for RpcInner {
|
||||||
Ok(nonce.encode_hex())
|
Ok(nonce.encode_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_code(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_code(&self, address: &str, block: BlockTag) -> Result<String, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let code = convert_err(node.get_code(&address, &block).await)?;
|
let code = convert_err(node.get_code(&address, &block).await)?;
|
||||||
|
@ -132,9 +132,8 @@ impl EthRpcServer for RpcInner {
|
||||||
Ok(hex::encode(code))
|
Ok(hex::encode(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error> {
|
async fn call(&self, opts: CallOpts, block: BlockTag) -> Result<String, Error> {
|
||||||
debug!("eth_call");
|
debug!("eth_call");
|
||||||
let block = convert_err(decode_block(block))?;
|
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let res = convert_err(node.call(&opts, &block))?;
|
let res = convert_err(node.call(&opts, &block))?;
|
||||||
|
|
||||||
|
@ -175,10 +174,9 @@ impl EthRpcServer for RpcInner {
|
||||||
|
|
||||||
async fn get_block_by_number(
|
async fn get_block_by_number(
|
||||||
&self,
|
&self,
|
||||||
block: &str,
|
block: BlockTag,
|
||||||
_full_tx: bool,
|
_full_tx: bool,
|
||||||
) -> Result<Option<ExecutionBlock>, Error> {
|
) -> Result<Option<ExecutionBlock>, Error> {
|
||||||
let block = convert_err(decode_block(block))?;
|
|
||||||
let node = self.node.read().await;
|
let node = self.node.read().await;
|
||||||
let block = convert_err(node.get_block_by_number(&block))?;
|
let block = convert_err(node.get_block_by_number(&block))?;
|
||||||
Ok(block)
|
Ok(block)
|
||||||
|
@ -251,20 +249,3 @@ fn convert_err<T, E: Display>(res: Result<T, E>) -> Result<T, Error> {
|
||||||
Error::Custom(err.to_string())
|
Error::Custom(err.to_string())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_block(block: &str) -> Result<BlockTag> {
|
|
||||||
match block {
|
|
||||||
"latest" => Ok(BlockTag::Latest),
|
|
||||||
"finalized" => Ok(BlockTag::Finalized),
|
|
||||||
_ => {
|
|
||||||
if block.starts_with("0x") {
|
|
||||||
Ok(BlockTag::Number(u64::from_str_radix(
|
|
||||||
block.strip_prefix("0x").unwrap(),
|
|
||||||
16,
|
|
||||||
)?))
|
|
||||||
} else {
|
|
||||||
Ok(BlockTag::Number(block.parse()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,3 +13,4 @@ ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs" }
|
||||||
ethers = "0.17.0"
|
ethers = "0.17.0"
|
||||||
toml = "0.5.9"
|
toml = "0.5.9"
|
||||||
openssl = { version = "0.10", features = ["vendored"] }
|
openssl = { version = "0.10", features = ["vendored"] }
|
||||||
|
thiserror = "1.0.37"
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::types::BlockTag;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[error("block not available: {block}")]
|
||||||
|
pub struct BlockNotFoundError {
|
||||||
|
block: BlockTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockNotFoundError {
|
||||||
|
pub fn new(block: BlockTag) -> Self {
|
||||||
|
Self { block }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[error("rpc error: {message}")]
|
||||||
|
pub struct RpcError {
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RpcError {
|
||||||
|
pub fn new(message: String) -> Self {
|
||||||
|
Self { message }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
|
pub mod errors;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
|
@ -1,3 +1,54 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use serde::{de::Error, Deserialize};
|
||||||
use ssz_rs::Vector;
|
use ssz_rs::Vector;
|
||||||
|
|
||||||
pub type Bytes32 = Vector<u8, 32>;
|
pub type Bytes32 = Vector<u8, 32>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BlockTag {
|
||||||
|
Latest,
|
||||||
|
Finalized,
|
||||||
|
Number(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BlockTag {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let formatted = match self {
|
||||||
|
Self::Latest => "latest".to_string(),
|
||||||
|
Self::Finalized => "finalized".to_string(),
|
||||||
|
Self::Number(num) => num.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "{}", formatted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for BlockTag {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let block: String = serde::Deserialize::deserialize(deserializer)?;
|
||||||
|
let parse_error = D::Error::custom("could not parse block tag");
|
||||||
|
|
||||||
|
let block_tag = match block.as_str() {
|
||||||
|
"latest" => BlockTag::Latest,
|
||||||
|
"finalized" => BlockTag::Finalized,
|
||||||
|
_ => match block.strip_prefix("0x") {
|
||||||
|
Some(hex_block) => {
|
||||||
|
let num = u64::from_str_radix(hex_block, 16).map_err(|_| parse_error)?;
|
||||||
|
|
||||||
|
BlockTag::Number(num)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let num = block.parse().map_err(|_| parse_error)?;
|
||||||
|
|
||||||
|
BlockTag::Number(num)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(block_tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ async-trait = "0.1.57"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
chrono = "0.4.22"
|
chrono = "0.4.22"
|
||||||
openssl = { version = "0.10", features = ["vendored"] }
|
openssl = { version = "0.10", features = ["vendored"] }
|
||||||
|
thiserror = "1.0.37"
|
||||||
|
|
||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
config = { path = "../config" }
|
config = { path = "../config" }
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::time::UNIX_EPOCH;
|
||||||
use blst::min_pk::{PublicKey, Signature};
|
use blst::min_pk::{PublicKey, Signature};
|
||||||
use blst::BLST_ERROR;
|
use blst::BLST_ERROR;
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use eyre::{eyre, Result};
|
use eyre::Result;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use ssz_rs::prelude::*;
|
use ssz_rs::prelude::*;
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ use common::types::*;
|
||||||
use common::utils::*;
|
use common::utils::*;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
|
||||||
|
use crate::errors::ConsensusError;
|
||||||
|
|
||||||
use super::rpc::Rpc;
|
use super::rpc::Rpc;
|
||||||
use super::types::*;
|
use super::types::*;
|
||||||
|
|
||||||
|
@ -49,12 +51,16 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
&bootstrap.current_sync_committee_branch,
|
&bootstrap.current_sync_committee_branch,
|
||||||
);
|
);
|
||||||
|
|
||||||
let header_hash = bootstrap.header.hash_tree_root()?;
|
let header_hash = bootstrap.header.hash_tree_root()?.to_string();
|
||||||
let header_valid =
|
let expected_hash = format!("0x{}", hex::encode(checkpoint_block_root));
|
||||||
header_hash.to_string() == format!("0x{}", hex::encode(checkpoint_block_root));
|
let header_valid = header_hash == expected_hash;
|
||||||
|
|
||||||
if !(header_valid && committee_valid) {
|
if !header_valid {
|
||||||
return Err(eyre!("Invalid Bootstrap"));
|
return Err(ConsensusError::InvalidHeaderHash(expected_hash, header_hash).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if !committee_valid {
|
||||||
|
return Err(ConsensusError::InvalidCurrentSyncCommitteeProof.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let store = Store {
|
let store = Store {
|
||||||
|
@ -87,11 +93,15 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
} else if slot == finalized_slot {
|
} else if slot == finalized_slot {
|
||||||
self.store.finalized_header.clone().hash_tree_root()?
|
self.store.finalized_header.clone().hash_tree_root()?
|
||||||
} else {
|
} else {
|
||||||
return Err(eyre!("Block Not Found"));
|
return Err(ConsensusError::PayloadNotFound(slot).into());
|
||||||
};
|
};
|
||||||
|
|
||||||
if verified_block_hash != block_hash {
|
if verified_block_hash != block_hash {
|
||||||
Err(eyre!("Block Root Mismatch"))
|
Err(ConsensusError::InvalidHeaderHash(
|
||||||
|
block_hash.to_string(),
|
||||||
|
verified_block_hash.to_string(),
|
||||||
|
)
|
||||||
|
.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(block.body.execution_payload)
|
Ok(block.body.execution_payload)
|
||||||
}
|
}
|
||||||
|
@ -156,7 +166,7 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
fn verify_generic_update(&self, update: &GenericUpdate) -> Result<()> {
|
fn verify_generic_update(&self, update: &GenericUpdate) -> Result<()> {
|
||||||
let bits = get_bits(&update.sync_aggregate.sync_committee_bits);
|
let bits = get_bits(&update.sync_aggregate.sync_committee_bits);
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
return Err(eyre!("Insufficient Participation"));
|
return Err(ConsensusError::InsufficientParticipation.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let update_finalized_slot = update.finalized_header.clone().unwrap_or_default().slot;
|
let update_finalized_slot = update.finalized_header.clone().unwrap_or_default().slot;
|
||||||
|
@ -165,7 +175,7 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
&& update.attested_header.slot >= update_finalized_slot;
|
&& update.attested_header.slot >= update_finalized_slot;
|
||||||
|
|
||||||
if !valid_time {
|
if !valid_time {
|
||||||
return Err(eyre!("Invalid Timestamp"));
|
return Err(ConsensusError::InvalidTimestamp.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let store_period = calc_sync_period(self.store.finalized_header.slot);
|
let store_period = calc_sync_period(self.store.finalized_header.slot);
|
||||||
|
@ -177,7 +187,7 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !valid_period {
|
if !valid_period {
|
||||||
return Err(eyre!("Invalid Period"));
|
return Err(ConsensusError::InvalidPeriod.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let update_attested_period = calc_sync_period(update.attested_header.slot);
|
let update_attested_period = calc_sync_period(update.attested_header.slot);
|
||||||
|
@ -188,7 +198,7 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
if update.attested_header.slot <= self.store.finalized_header.slot
|
if update.attested_header.slot <= self.store.finalized_header.slot
|
||||||
&& !update_has_next_committee
|
&& !update_has_next_committee
|
||||||
{
|
{
|
||||||
return Err(eyre!("Update Not Relevent"));
|
return Err(ConsensusError::NotRelevant.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if update.finalized_header.is_some() && update.finality_branch.is_some() {
|
if update.finalized_header.is_some() && update.finality_branch.is_some() {
|
||||||
|
@ -199,7 +209,7 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
return Err(eyre!("Invalid Finality Proof"));
|
return Err(ConsensusError::InvalidFinalityProof.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +221,7 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
return Err(eyre!("Invalid Next Sync Committee Proof"));
|
return Err(ConsensusError::InvalidNextSyncCommitteeProof.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +242,7 @@ impl<R: Rpc> ConsensusClient<R> {
|
||||||
let is_valid_sig = is_aggregate_valid(sig, signing_root.as_bytes(), &pks);
|
let is_valid_sig = is_aggregate_valid(sig, signing_root.as_bytes(), &pks);
|
||||||
|
|
||||||
if !is_valid_sig {
|
if !is_valid_sig {
|
||||||
return Err(eyre!("Invalid Signature"));
|
return Err(ConsensusError::InvalidSignature.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -631,6 +641,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consensus::calc_sync_period,
|
consensus::calc_sync_period,
|
||||||
|
errors::ConsensusError,
|
||||||
rpc::{mock_rpc::MockRpc, Rpc},
|
rpc::{mock_rpc::MockRpc, Rpc},
|
||||||
types::Header,
|
types::Header,
|
||||||
ConsensusClient,
|
ConsensusClient,
|
||||||
|
@ -649,7 +660,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_verify_update() {
|
async fn test_verify_update() {
|
||||||
let mut client = get_client().await;
|
let client = get_client().await;
|
||||||
let period = calc_sync_period(client.store.finalized_header.slot);
|
let period = calc_sync_period(client.store.finalized_header.slot);
|
||||||
let updates = client.rpc.get_updates(period).await.unwrap();
|
let updates = client.rpc.get_updates(period).await.unwrap();
|
||||||
|
|
||||||
|
@ -659,41 +670,50 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_verify_update_invalid_committee() {
|
async fn test_verify_update_invalid_committee() {
|
||||||
let mut client = get_client().await;
|
let client = get_client().await;
|
||||||
let period = calc_sync_period(client.store.finalized_header.slot);
|
let period = calc_sync_period(client.store.finalized_header.slot);
|
||||||
let updates = client.rpc.get_updates(period).await.unwrap();
|
let updates = client.rpc.get_updates(period).await.unwrap();
|
||||||
|
|
||||||
let mut update = updates[0].clone();
|
let mut update = updates[0].clone();
|
||||||
update.next_sync_committee.pubkeys[0] = Vector::default();
|
update.next_sync_committee.pubkeys[0] = Vector::default();
|
||||||
|
|
||||||
let res = client.verify_update(&mut update);
|
let err = client.verify_update(&mut update).err().unwrap();
|
||||||
assert!(res.is_err());
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
ConsensusError::InvalidNextSyncCommitteeProof.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_verify_upadate_invlaid_finality() {
|
async fn test_verify_upadate_invlaid_finality() {
|
||||||
let mut client = get_client().await;
|
let client = get_client().await;
|
||||||
let period = calc_sync_period(client.store.finalized_header.slot);
|
let period = calc_sync_period(client.store.finalized_header.slot);
|
||||||
let updates = client.rpc.get_updates(period).await.unwrap();
|
let updates = client.rpc.get_updates(period).await.unwrap();
|
||||||
|
|
||||||
let mut update = updates[0].clone();
|
let mut update = updates[0].clone();
|
||||||
update.finalized_header = Header::default();
|
update.finalized_header = Header::default();
|
||||||
|
|
||||||
let res = client.verify_update(&mut update);
|
let err = client.verify_update(&mut update).err().unwrap();
|
||||||
assert!(res.is_err());
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
ConsensusError::InvalidFinalityProof.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_verify_update_invalid_sig() {
|
async fn test_verify_update_invalid_sig() {
|
||||||
let mut client = get_client().await;
|
let client = get_client().await;
|
||||||
let period = calc_sync_period(client.store.finalized_header.slot);
|
let period = calc_sync_period(client.store.finalized_header.slot);
|
||||||
let updates = client.rpc.get_updates(period).await.unwrap();
|
let updates = client.rpc.get_updates(period).await.unwrap();
|
||||||
|
|
||||||
let mut update = updates[0].clone();
|
let mut update = updates[0].clone();
|
||||||
update.sync_aggregate.sync_committee_signature = Vector::default();
|
update.sync_aggregate.sync_committee_signature = Vector::default();
|
||||||
|
|
||||||
let res = client.verify_update(&mut update);
|
let err = client.verify_update(&mut update).err().unwrap();
|
||||||
assert!(res.is_err());
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
ConsensusError::InvalidSignature.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -714,8 +734,11 @@ mod tests {
|
||||||
let mut update = client.rpc.get_finality_update().await.unwrap();
|
let mut update = client.rpc.get_finality_update().await.unwrap();
|
||||||
update.finalized_header = Header::default();
|
update.finalized_header = Header::default();
|
||||||
|
|
||||||
let res = client.verify_finality_update(&update);
|
let err = client.verify_finality_update(&update).err().unwrap();
|
||||||
assert!(res.is_err());
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
ConsensusError::InvalidFinalityProof.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -726,8 +749,11 @@ mod tests {
|
||||||
let mut update = client.rpc.get_finality_update().await.unwrap();
|
let mut update = client.rpc.get_finality_update().await.unwrap();
|
||||||
update.sync_aggregate.sync_committee_signature = Vector::default();
|
update.sync_aggregate.sync_committee_signature = Vector::default();
|
||||||
|
|
||||||
let res = client.verify_finality_update(&update);
|
let err = client.verify_finality_update(&update).err().unwrap();
|
||||||
assert!(res.is_err());
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
ConsensusError::InvalidSignature.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -747,7 +773,10 @@ mod tests {
|
||||||
let mut update = client.rpc.get_optimistic_update().await.unwrap();
|
let mut update = client.rpc.get_optimistic_update().await.unwrap();
|
||||||
update.sync_aggregate.sync_committee_signature = Vector::default();
|
update.sync_aggregate.sync_committee_signature = Vector::default();
|
||||||
|
|
||||||
let res = client.verify_optimistic_update(&update);
|
let err = client.verify_optimistic_update(&update).err().unwrap();
|
||||||
assert!(res.is_err());
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
ConsensusError::InvalidSignature.to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ConsensusError {
|
||||||
|
#[error("insufficient participation")]
|
||||||
|
InsufficientParticipation,
|
||||||
|
#[error("invalid timestamp")]
|
||||||
|
InvalidTimestamp,
|
||||||
|
#[error("invalid sync committee period")]
|
||||||
|
InvalidPeriod,
|
||||||
|
#[error("update not relevant")]
|
||||||
|
NotRelevant,
|
||||||
|
#[error("invalid finality proof")]
|
||||||
|
InvalidFinalityProof,
|
||||||
|
#[error("invalid next sync committee proof")]
|
||||||
|
InvalidNextSyncCommitteeProof,
|
||||||
|
#[error("invalid current sync committee proof")]
|
||||||
|
InvalidCurrentSyncCommitteeProof,
|
||||||
|
#[error("invalid sync committee signature")]
|
||||||
|
InvalidSignature,
|
||||||
|
#[error("invalid header hash found: {0}, expected: {1}")]
|
||||||
|
InvalidHeaderHash(String, String),
|
||||||
|
#[error("payload not found for slot: {0}")]
|
||||||
|
PayloadNotFound(u64),
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod errors;
|
||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use common::errors::RpcError;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
|
||||||
use super::Rpc;
|
use super::Rpc;
|
||||||
|
@ -22,7 +23,14 @@ impl Rpc for NimbusRpc {
|
||||||
"{}/eth/v0/beacon/light_client/bootstrap/0x{}",
|
"{}/eth/v0/beacon/light_client/bootstrap/0x{}",
|
||||||
self.rpc, root_hex
|
self.rpc, root_hex
|
||||||
);
|
);
|
||||||
let res = reqwest::get(req).await?.json::<BootstrapResponse>().await?;
|
|
||||||
|
let res = reqwest::get(req)
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?
|
||||||
|
.json::<BootstrapResponse>()
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(res.data.v)
|
Ok(res.data.v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,34 +39,50 @@ impl Rpc for NimbusRpc {
|
||||||
"{}/eth/v0/beacon/light_client/updates?start_period={}&count=1000",
|
"{}/eth/v0/beacon/light_client/updates?start_period={}&count=1000",
|
||||||
self.rpc, period
|
self.rpc, period
|
||||||
);
|
);
|
||||||
let res = reqwest::get(req).await?.json::<UpdateResponse>().await?;
|
|
||||||
|
let res = reqwest::get(req)
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?
|
||||||
|
.json::<UpdateResponse>()
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(res.data)
|
Ok(res.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_finality_update(&self) -> Result<FinalityUpdate> {
|
async fn get_finality_update(&self) -> Result<FinalityUpdate> {
|
||||||
let req = format!("{}/eth/v0/beacon/light_client/finality_update", self.rpc);
|
let req = format!("{}/eth/v0/beacon/light_client/finality_update", self.rpc);
|
||||||
let res = reqwest::get(req)
|
let res = reqwest::get(req)
|
||||||
.await?
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?
|
||||||
.json::<FinalityUpdateResponse>()
|
.json::<FinalityUpdateResponse>()
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(res.data)
|
Ok(res.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_optimistic_update(&self) -> Result<OptimisticUpdate> {
|
async fn get_optimistic_update(&self) -> Result<OptimisticUpdate> {
|
||||||
let req = format!("{}/eth/v0/beacon/light_client/optimistic_update", self.rpc);
|
let req = format!("{}/eth/v0/beacon/light_client/optimistic_update", self.rpc);
|
||||||
let res = reqwest::get(req)
|
let res = reqwest::get(req)
|
||||||
.await?
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?
|
||||||
.json::<OptimisticUpdateResponse>()
|
.json::<OptimisticUpdateResponse>()
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(res.data)
|
Ok(res.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_block(&self, slot: u64) -> Result<BeaconBlock> {
|
async fn get_block(&self, slot: u64) -> Result<BeaconBlock> {
|
||||||
let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot);
|
let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot);
|
||||||
let res = reqwest::get(req)
|
let res = reqwest::get(req)
|
||||||
.await?
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?
|
||||||
.json::<BeaconBlockResponse>()
|
.json::<BeaconBlockResponse>()
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(res.data.message)
|
Ok(res.data.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ triehash-ethereum = { git = "https://github.com/openethereum/parity-ethereum" }
|
||||||
async-trait = "0.1.57"
|
async-trait = "0.1.57"
|
||||||
openssl = { version = "0.10", features = ["vendored"] }
|
openssl = { version = "0.10", features = ["vendored"] }
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
thiserror = "1.0.37"
|
||||||
|
|
||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
consensus = { path = "../consensus" }
|
consensus = { path = "../consensus" }
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
use ethers::types::{Address, H256};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ExecutionError {
|
||||||
|
#[error("invalid account proof for address: {0}")]
|
||||||
|
InvalidAccountProof(Address),
|
||||||
|
#[error("invalid storage proof for address: {0}, slot: {1}")]
|
||||||
|
InvalidStorageProof(Address, H256),
|
||||||
|
#[error("code hash mismatch for address: {0}, found: {1}, expected: {2}")]
|
||||||
|
CodeHashMismatch(Address, String, String),
|
||||||
|
#[error("receipt root mismatch for tx: {0}")]
|
||||||
|
ReceiptRootMismatch(String),
|
||||||
|
#[error("missing transaction for tx: {0}")]
|
||||||
|
MissingTransaction(String),
|
||||||
|
}
|
|
@ -14,6 +14,8 @@ use futures::future::join_all;
|
||||||
use revm::KECCAK_EMPTY;
|
use revm::KECCAK_EMPTY;
|
||||||
use triehash_ethereum::ordered_trie_root;
|
use triehash_ethereum::ordered_trie_root;
|
||||||
|
|
||||||
|
use crate::errors::ExecutionError;
|
||||||
|
|
||||||
use super::proof::{encode_account, verify_proof};
|
use super::proof::{encode_account, verify_proof};
|
||||||
use super::rpc::Rpc;
|
use super::rpc::Rpc;
|
||||||
use super::types::{Account, ExecutionBlock};
|
use super::types::{Account, ExecutionBlock};
|
||||||
|
@ -53,7 +55,7 @@ impl<R: Rpc> ExecutionClient<R> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
eyre::bail!("Invalid Proof");
|
return Err(ExecutionError::InvalidAccountProof(*address).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut slot_map = HashMap::new();
|
let mut slot_map = HashMap::new();
|
||||||
|
@ -72,7 +74,9 @@ impl<R: Rpc> ExecutionClient<R> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
eyre::bail!("Invalid Proof");
|
return Err(
|
||||||
|
ExecutionError::InvalidStorageProof(*address, storage_proof.key).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
slot_map.insert(storage_proof.key, storage_proof.value);
|
slot_map.insert(storage_proof.key, storage_proof.value);
|
||||||
|
@ -85,7 +89,12 @@ impl<R: Rpc> ExecutionClient<R> {
|
||||||
let code_hash = keccak256(&code).into();
|
let code_hash = keccak256(&code).into();
|
||||||
|
|
||||||
if proof.code_hash != code_hash {
|
if proof.code_hash != code_hash {
|
||||||
eyre::bail!("Invalid Proof");
|
return Err(ExecutionError::CodeHashMismatch(
|
||||||
|
*address,
|
||||||
|
code_hash.to_string(),
|
||||||
|
proof.code_hash.to_string(),
|
||||||
|
)
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
code
|
code
|
||||||
|
@ -183,7 +192,7 @@ impl<R: Rpc> ExecutionClient<R> {
|
||||||
let payload_receipt_root = H256::from_slice(&payload.receipts_root);
|
let payload_receipt_root = H256::from_slice(&payload.receipts_root);
|
||||||
|
|
||||||
if expected_receipt_root != payload_receipt_root || !receipts.contains(&receipt) {
|
if expected_receipt_root != payload_receipt_root || !receipts.contains(&receipt) {
|
||||||
return Err(eyre::eyre!("Receipt Proof Invalid"));
|
return Err(ExecutionError::ReceiptRootMismatch(tx_hash.to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(receipt))
|
Ok(Some(receipt))
|
||||||
|
@ -222,7 +231,7 @@ impl<R: Rpc> ExecutionClient<R> {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !txs_encoded.contains(&tx_encoded) {
|
if !txs_encoded.contains(&tx_encoded) {
|
||||||
return Err(eyre::eyre!("Transaction Proof Invalid"));
|
return Err(ExecutionError::MissingTransaction(hash.to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(tx))
|
Ok(Some(tx))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod errors;
|
||||||
pub mod evm;
|
pub mod evm;
|
||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use common::errors::RpcError;
|
||||||
use ethers::prelude::{Address, Http};
|
use ethers::prelude::{Address, Http};
|
||||||
use ethers::providers::{HttpRateLimitRetryPolicy, Middleware, Provider, RetryClient};
|
use ethers::providers::{HttpRateLimitRetryPolicy, Middleware, Provider, RetryClient};
|
||||||
use ethers::types::transaction::eip2718::TypedTransaction;
|
use ethers::types::transaction::eip2718::TypedTransaction;
|
||||||
|
@ -51,7 +52,9 @@ impl Rpc for HttpRpc {
|
||||||
let proof_response = self
|
let proof_response = self
|
||||||
.provider
|
.provider
|
||||||
.get_proof(*address, slots.to_vec(), block)
|
.get_proof(*address, slots.to_vec(), block)
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(proof_response)
|
Ok(proof_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,24 +74,44 @@ impl Rpc for HttpRpc {
|
||||||
.map(|data| Bytes::from(data.as_slice().to_owned()));
|
.map(|data| Bytes::from(data.as_slice().to_owned()));
|
||||||
|
|
||||||
let tx = TypedTransaction::Eip1559(raw_tx);
|
let tx = TypedTransaction::Eip1559(raw_tx);
|
||||||
let list = self.provider.create_access_list(&tx, block).await?;
|
let list = self
|
||||||
|
.provider
|
||||||
|
.create_access_list(&tx, block)
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(list.access_list)
|
Ok(list.access_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_code(&self, address: &Address, block: u64) -> Result<Vec<u8>> {
|
async fn get_code(&self, address: &Address, block: u64) -> Result<Vec<u8>> {
|
||||||
let block = Some(BlockId::from(block));
|
let block = Some(BlockId::from(block));
|
||||||
let code = self.provider.get_code(*address, block).await?;
|
let code = self
|
||||||
|
.provider
|
||||||
|
.get_code(*address, block)
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(code.to_vec())
|
Ok(code.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_raw_transaction(&self, bytes: &Vec<u8>) -> Result<H256> {
|
async fn send_raw_transaction(&self, bytes: &Vec<u8>) -> Result<H256> {
|
||||||
let bytes = Bytes::from(bytes.as_slice().to_owned());
|
let bytes = Bytes::from(bytes.as_slice().to_owned());
|
||||||
Ok(self.provider.send_raw_transaction(bytes).await?.tx_hash())
|
let tx = self
|
||||||
|
.provider
|
||||||
|
.send_raw_transaction(bytes)
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(tx.tx_hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_transaction_receipt(&self, tx_hash: &H256) -> Result<Option<TransactionReceipt>> {
|
async fn get_transaction_receipt(&self, tx_hash: &H256) -> Result<Option<TransactionReceipt>> {
|
||||||
let receipt = self.provider.get_transaction_receipt(*tx_hash).await?;
|
let receipt = self
|
||||||
|
.provider
|
||||||
|
.get_transaction_receipt(*tx_hash)
|
||||||
|
.await
|
||||||
|
.map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(receipt)
|
Ok(receipt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue