feat: add metamask support (#2)
* add eth_getBlockByNumber and net_version * fmt
This commit is contained in:
parent
374dd1f38f
commit
92e30c3d50
|
@ -1,18 +1,22 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ethers::prelude::{Address, U256};
|
use ethers::prelude::{Address, U256};
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use consensus::types::Header;
|
use consensus::types::{ExecutionPayload, Header};
|
||||||
use consensus::ConsensusClient;
|
use consensus::ConsensusClient;
|
||||||
use execution::evm::Evm;
|
use execution::evm::Evm;
|
||||||
|
use execution::types::ExecutionBlock;
|
||||||
use execution::ExecutionClient;
|
use execution::ExecutionClient;
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
consensus: ConsensusClient,
|
consensus: ConsensusClient,
|
||||||
execution: ExecutionClient,
|
execution: ExecutionClient,
|
||||||
config: Arc<Config>,
|
config: Arc<Config>,
|
||||||
|
payloads: HashMap<u64, ExecutionPayload>,
|
||||||
|
block_head: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
|
@ -25,52 +29,82 @@ impl Client {
|
||||||
ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone()).await?;
|
ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone()).await?;
|
||||||
let execution = ExecutionClient::new(execution_rpc);
|
let execution = ExecutionClient::new(execution_rpc);
|
||||||
|
|
||||||
|
let payloads = HashMap::new();
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
consensus,
|
consensus,
|
||||||
execution,
|
execution,
|
||||||
config,
|
config,
|
||||||
|
payloads,
|
||||||
|
block_head: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sync(&mut self) -> Result<()> {
|
pub async fn sync(&mut self) -> Result<()> {
|
||||||
self.consensus.sync().await
|
self.consensus.sync().await?;
|
||||||
|
|
||||||
|
let head = self.consensus.get_head();
|
||||||
|
let payload = self
|
||||||
|
.consensus
|
||||||
|
.get_execution_payload(&Some(head.slot))
|
||||||
|
.await?;
|
||||||
|
self.block_head = payload.block_number;
|
||||||
|
self.payloads.insert(payload.block_number, payload);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn advance(&mut self) -> Result<()> {
|
pub async fn advance(&mut self) -> Result<()> {
|
||||||
self.consensus.advance().await
|
self.consensus.advance().await?;
|
||||||
|
|
||||||
|
let head = self.consensus.get_head();
|
||||||
|
let payload = self
|
||||||
|
.consensus
|
||||||
|
.get_execution_payload(&Some(head.slot))
|
||||||
|
.await?;
|
||||||
|
self.block_head = payload.block_number;
|
||||||
|
self.payloads.insert(payload.block_number, payload);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn call(&self, to: &Address, calldata: &Vec<u8>, value: U256) -> Result<Vec<u8>> {
|
pub fn call(
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
&self,
|
||||||
|
to: &Address,
|
||||||
|
calldata: &Vec<u8>,
|
||||||
|
value: U256,
|
||||||
|
block: &Option<u64>,
|
||||||
|
) -> Result<Vec<u8>> {
|
||||||
|
let payload = self.get_payload(block)?;
|
||||||
let mut evm = Evm::new(self.execution.clone(), payload);
|
let mut evm = Evm::new(self.execution.clone(), payload);
|
||||||
evm.call(to, calldata, value)
|
evm.call(to, calldata, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn estimate_gas(&self, to: &Address, calldata: &Vec<u8>, value: U256) -> Result<u64> {
|
pub fn estimate_gas(&self, to: &Address, calldata: &Vec<u8>, value: U256) -> Result<u64> {
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
let payload = self.get_payload(&None)?;
|
||||||
let mut evm = Evm::new(self.execution.clone(), payload);
|
let mut evm = Evm::new(self.execution.clone(), payload);
|
||||||
evm.estimate_gas(to, calldata, value)
|
evm.estimate_gas(to, calldata, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_balance(&self, address: &Address) -> Result<U256> {
|
pub async fn get_balance(&self, address: &Address, block: &Option<u64>) -> Result<U256> {
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
let payload = self.get_payload(block)?;
|
||||||
let account = self.execution.get_account(&address, None, &payload).await?;
|
let account = self.execution.get_account(&address, None, &payload).await?;
|
||||||
Ok(account.balance)
|
Ok(account.balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_nonce(&self, address: &Address) -> Result<U256> {
|
pub async fn get_nonce(&self, address: &Address, block: &Option<u64>) -> Result<U256> {
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
let payload = self.get_payload(block)?;
|
||||||
let account = self.execution.get_account(&address, None, &payload).await?;
|
let account = self.execution.get_account(&address, None, &payload).await?;
|
||||||
Ok(account.nonce)
|
Ok(account.nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_code(&self, address: &Address) -> Result<Vec<u8>> {
|
pub async fn get_code(&self, address: &Address, block: &Option<u64>) -> Result<Vec<u8>> {
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
let payload = self.get_payload(block)?;
|
||||||
self.execution.get_code(&address, &payload).await
|
self.execution.get_code(&address, &payload).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_storage_at(&self, address: &Address, slot: U256) -> Result<U256> {
|
pub async fn get_storage_at(&self, address: &Address, slot: U256) -> Result<U256> {
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
let payload = self.get_payload(&None)?;
|
||||||
let account = self
|
let account = self
|
||||||
.execution
|
.execution
|
||||||
.get_account(address, Some(&[slot]), &payload)
|
.get_account(address, Some(&[slot]), &payload)
|
||||||
|
@ -82,23 +116,28 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_gas_price(&self) -> Result<U256> {
|
pub fn get_gas_price(&self) -> Result<U256> {
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
let payload = self.get_payload(&None)?;
|
||||||
let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le());
|
let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le());
|
||||||
let tip = U256::from(10_u64.pow(9));
|
let tip = U256::from(10_u64.pow(9));
|
||||||
Ok(base_fee + tip)
|
Ok(base_fee + tip)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_priority_fee(&self) -> Result<U256> {
|
pub fn get_priority_fee(&self) -> Result<U256> {
|
||||||
let tip = U256::from(10_u64.pow(9));
|
let tip = U256::from(10_u64.pow(9));
|
||||||
Ok(tip)
|
Ok(tip)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_block_number(&self) -> Result<u64> {
|
pub fn get_block_number(&self) -> Result<u64> {
|
||||||
let payload = self.consensus.get_execution_payload().await?;
|
let payload = self.get_payload(&None)?;
|
||||||
Ok(payload.block_number)
|
Ok(payload.block_number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_block_by_number(&self, block: &Option<u64>) -> Result<ExecutionBlock> {
|
||||||
|
let payload = self.get_payload(block)?;
|
||||||
|
self.execution.get_block(&payload)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn chain_id(&self) -> u64 {
|
pub fn chain_id(&self) -> u64 {
|
||||||
self.config.general.chain_id
|
self.config.general.chain_id
|
||||||
}
|
}
|
||||||
|
@ -106,4 +145,23 @@ impl Client {
|
||||||
pub fn get_header(&self) -> &Header {
|
pub fn get_header(&self) -> &Header {
|
||||||
self.consensus.get_head()
|
self.consensus.get_head()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_payload(&self, block: &Option<u64>) -> Result<ExecutionPayload> {
|
||||||
|
match block {
|
||||||
|
Some(block) => {
|
||||||
|
let payload = self.payloads.get(block);
|
||||||
|
match payload {
|
||||||
|
Some(payload) => Ok(payload.clone()),
|
||||||
|
None => Err(eyre::eyre!("Block Not Found")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let payload = self.payloads.get(&self.block_head);
|
||||||
|
match payload {
|
||||||
|
Some(payload) => Ok(payload.clone()),
|
||||||
|
None => Err(eyre::eyre!("Block Not Found")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,14 @@ use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use jsonrpsee::{
|
use jsonrpsee::{
|
||||||
core::{async_trait, Error},
|
core::{async_trait, server::rpc_module::Methods, Error},
|
||||||
http_server::{HttpServerBuilder, HttpServerHandle},
|
http_server::{HttpServerBuilder, HttpServerHandle},
|
||||||
proc_macros::rpc,
|
proc_macros::rpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use common::utils::{hex_str_to_bytes, u64_to_hex_string};
|
|
||||||
|
|
||||||
use super::Client;
|
use super::Client;
|
||||||
|
use common::utils::{hex_str_to_bytes, u64_to_hex_string};
|
||||||
|
use execution::types::ExecutionBlock;
|
||||||
|
|
||||||
pub struct Rpc {
|
pub struct Rpc {
|
||||||
client: Arc<Mutex<Client>>,
|
client: Arc<Mutex<Client>>,
|
||||||
|
@ -63,8 +63,17 @@ trait EthRpc {
|
||||||
async fn max_priority_fee_per_gas(&self) -> Result<String, Error>;
|
async fn max_priority_fee_per_gas(&self) -> Result<String, Error>;
|
||||||
#[method(name = "blockNumber")]
|
#[method(name = "blockNumber")]
|
||||||
async fn block_number(&self) -> Result<String, Error>;
|
async fn block_number(&self) -> Result<String, Error>;
|
||||||
|
#[method(name = "getBlockByNumber")]
|
||||||
|
async fn get_block_by_number(&self, num: &str, full_tx: bool) -> Result<ExecutionBlock, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rpc(client, server, namespace = "net")]
|
||||||
|
trait NetRpc {
|
||||||
|
#[method(name = "version")]
|
||||||
|
async fn version(&self) -> Result<String, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct RpcInner {
|
struct RpcInner {
|
||||||
client: Arc<Mutex<Client>>,
|
client: Arc<Mutex<Client>>,
|
||||||
port: u16,
|
port: u16,
|
||||||
|
@ -73,60 +82,45 @@ 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: &str) -> Result<String, Error> {
|
||||||
match block {
|
let block = convert_err(decode_block(block))?;
|
||||||
"latest" => {
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let client = self.client.lock().await;
|
||||||
let client = self.client.lock().await;
|
let balance = convert_err(client.get_balance(&address, &block).await)?;
|
||||||
let balance = convert_err(client.get_balance(&address).await)?;
|
|
||||||
|
|
||||||
Ok(balance.encode_hex())
|
Ok(balance.encode_hex())
|
||||||
}
|
|
||||||
_ => Err(Error::Custom("Invalid Block Number".to_string())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_transaction_count(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_transaction_count(&self, address: &str, block: &str) -> Result<String, Error> {
|
||||||
match block {
|
let block = convert_err(decode_block(block))?;
|
||||||
"latest" => {
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let client = self.client.lock().await;
|
||||||
let client = self.client.lock().await;
|
let nonce = convert_err(client.get_nonce(&address, &block).await)?;
|
||||||
let nonce = convert_err(client.get_nonce(&address).await)?;
|
|
||||||
|
|
||||||
Ok(nonce.encode_hex())
|
Ok(nonce.encode_hex())
|
||||||
}
|
|
||||||
_ => Err(Error::Custom("Invalid Block Number".to_string())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_code(&self, address: &str, block: &str) -> Result<String, Error> {
|
async fn get_code(&self, address: &str, block: &str) -> Result<String, Error> {
|
||||||
match block {
|
let block = convert_err(decode_block(block))?;
|
||||||
"latest" => {
|
let address = convert_err(Address::from_str(address))?;
|
||||||
let address = convert_err(Address::from_str(address))?;
|
let client = self.client.lock().await;
|
||||||
let client = self.client.lock().await;
|
let code = convert_err(client.get_code(&address, &block).await)?;
|
||||||
let code = convert_err(client.get_code(&address).await)?;
|
|
||||||
|
|
||||||
Ok(hex::encode(code))
|
Ok(hex::encode(code))
|
||||||
}
|
|
||||||
_ => Err(Error::Custom("Invalid Block Number".to_string())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error> {
|
async fn call(&self, opts: CallOpts, block: &str) -> Result<String, Error> {
|
||||||
match block {
|
let block = convert_err(decode_block(block))?;
|
||||||
"latest" => {
|
let to = convert_err(Address::from_str(&opts.to))?;
|
||||||
let to = convert_err(Address::from_str(&opts.to))?;
|
let data = convert_err(hex_str_to_bytes(&opts.data.unwrap_or("0x".to_string())))?;
|
||||||
let data = convert_err(hex_str_to_bytes(&opts.data.unwrap_or("0x".to_string())))?;
|
let value = convert_err(U256::from_str_radix(
|
||||||
let value = convert_err(U256::from_str_radix(
|
&opts.value.unwrap_or("0x0".to_string()),
|
||||||
&opts.value.unwrap_or("0x0".to_string()),
|
16,
|
||||||
16,
|
))?;
|
||||||
))?;
|
|
||||||
|
|
||||||
let client = self.client.lock().await;
|
let client = self.client.lock().await;
|
||||||
let res = convert_err(client.call(&to, &data, value).await)?;
|
let res = convert_err(client.call(&to, &data, value, &block))?;
|
||||||
Ok(hex::encode(res))
|
|
||||||
}
|
Ok(hex::encode(res))
|
||||||
_ => Err(Error::Custom("Invalid Block Number".to_string())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn estimate_gas(&self, opts: CallOpts) -> Result<String, Error> {
|
async fn estimate_gas(&self, opts: CallOpts) -> Result<String, Error> {
|
||||||
|
@ -138,7 +132,7 @@ impl EthRpcServer for RpcInner {
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let client = self.client.lock().await;
|
let client = self.client.lock().await;
|
||||||
let gas = convert_err(client.estimate_gas(&to, &data, value).await)?;
|
let gas = convert_err(client.estimate_gas(&to, &data, value))?;
|
||||||
Ok(u64_to_hex_string(gas))
|
Ok(u64_to_hex_string(gas))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,21 +144,41 @@ impl EthRpcServer for RpcInner {
|
||||||
|
|
||||||
async fn gas_price(&self) -> Result<String, Error> {
|
async fn gas_price(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let client = self.client.lock().await;
|
||||||
let gas_price = convert_err(client.get_gas_price().await)?;
|
let gas_price = convert_err(client.get_gas_price())?;
|
||||||
Ok(gas_price.encode_hex())
|
Ok(gas_price.encode_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn max_priority_fee_per_gas(&self) -> Result<String, Error> {
|
async fn max_priority_fee_per_gas(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let client = self.client.lock().await;
|
||||||
let tip = convert_err(client.get_priority_fee().await)?;
|
let tip = convert_err(client.get_priority_fee())?;
|
||||||
Ok(tip.encode_hex())
|
Ok(tip.encode_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn block_number(&self) -> Result<String, Error> {
|
async fn block_number(&self) -> Result<String, Error> {
|
||||||
let client = self.client.lock().await;
|
let client = self.client.lock().await;
|
||||||
let num = convert_err(client.get_block_number().await)?;
|
let num = convert_err(client.get_block_number())?;
|
||||||
Ok(u64_to_hex_string(num))
|
Ok(u64_to_hex_string(num))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_block_by_number(
|
||||||
|
&self,
|
||||||
|
block: &str,
|
||||||
|
_full_tx: bool,
|
||||||
|
) -> Result<ExecutionBlock, Error> {
|
||||||
|
let block = convert_err(decode_block(block))?;
|
||||||
|
let client = self.client.lock().await;
|
||||||
|
let block = convert_err(client.get_block_by_number(&block))?;
|
||||||
|
|
||||||
|
Ok(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl NetRpcServer for RpcInner {
|
||||||
|
async fn version(&self) -> Result<String, Error> {
|
||||||
|
let client = self.client.lock().await;
|
||||||
|
Ok(client.chain_id().to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start(rpc: RpcInner) -> Result<(HttpServerHandle, SocketAddr)> {
|
async fn start(rpc: RpcInner) -> Result<(HttpServerHandle, SocketAddr)> {
|
||||||
|
@ -172,13 +186,40 @@ async fn start(rpc: RpcInner) -> Result<(HttpServerHandle, SocketAddr)> {
|
||||||
let server = HttpServerBuilder::default().build(addr).await?;
|
let server = HttpServerBuilder::default().build(addr).await?;
|
||||||
|
|
||||||
let addr = server.local_addr()?;
|
let addr = server.local_addr()?;
|
||||||
let handle = server.start(rpc.into_rpc())?;
|
|
||||||
|
let mut methods = Methods::new();
|
||||||
|
let eth_methods: Methods = EthRpcServer::into_rpc(rpc.clone()).into();
|
||||||
|
let net_methods: Methods = NetRpcServer::into_rpc(rpc).into();
|
||||||
|
|
||||||
|
methods.merge(eth_methods)?;
|
||||||
|
methods.merge(net_methods)?;
|
||||||
|
|
||||||
|
let handle = server.start(methods)?;
|
||||||
|
|
||||||
Ok((handle, addr))
|
Ok((handle, addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_err<T, E: Display>(res: Result<T, E>) -> Result<T, Error> {
|
fn convert_err<T, E: Display>(res: Result<T, E>) -> Result<T, Error> {
|
||||||
res.map_err(|err| Error::Custom(err.to_string()))
|
res.map_err(|err| {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
Error::Custom(err.to_string())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_block(block: &str) -> Result<Option<u64>> {
|
||||||
|
match block {
|
||||||
|
"latest" => Ok(None),
|
||||||
|
_ => {
|
||||||
|
if block.starts_with("0x") {
|
||||||
|
Ok(Some(u64::from_str_radix(
|
||||||
|
block.strip_prefix("0x").unwrap(),
|
||||||
|
16,
|
||||||
|
)?))
|
||||||
|
} else {
|
||||||
|
Ok(Some(block.parse()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl ConsensusClient {
|
||||||
finalized_header: bootstrap.header.clone(),
|
finalized_header: bootstrap.header.clone(),
|
||||||
current_sync_committee: bootstrap.current_sync_committee,
|
current_sync_committee: bootstrap.current_sync_committee,
|
||||||
next_sync_committee: None,
|
next_sync_committee: None,
|
||||||
optimistic_header: bootstrap.header,
|
optimistic_header: bootstrap.header.clone(),
|
||||||
previous_max_active_participants: 0,
|
previous_max_active_participants: 0,
|
||||||
current_max_active_participants: 0,
|
current_max_active_participants: 0,
|
||||||
};
|
};
|
||||||
|
@ -65,8 +65,8 @@ impl ConsensusClient {
|
||||||
Ok(ConsensusClient { rpc, store, config })
|
Ok(ConsensusClient { rpc, store, config })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_execution_payload(&self) -> Result<ExecutionPayload> {
|
pub async fn get_execution_payload(&self, slot: &Option<u64>) -> Result<ExecutionPayload> {
|
||||||
let slot = self.store.optimistic_header.slot;
|
let slot = slot.unwrap_or(self.store.optimistic_header.slot);
|
||||||
let mut block = self.rpc.get_block(slot).await?.clone();
|
let mut block = self.rpc.get_block(slot).await?.clone();
|
||||||
let block_hash = block.hash_tree_root()?;
|
let block_hash = block.hash_tree_root()?;
|
||||||
let verified_block_hash = self.store.optimistic_header.clone().hash_tree_root()?;
|
let verified_block_hash = self.store.optimistic_header.clone().hash_tree_root()?;
|
||||||
|
@ -319,6 +319,7 @@ impl ConsensusClient {
|
||||||
&& update.attested_header.slot > self.store.optimistic_header.slot
|
&& update.attested_header.slot > self.store.optimistic_header.slot
|
||||||
{
|
{
|
||||||
self.store.optimistic_header = update.attested_header.clone();
|
self.store.optimistic_header = update.attested_header.clone();
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"applying optimistic update for slot: {}",
|
"applying optimistic update for slot: {}",
|
||||||
self.store.optimistic_header.slot
|
self.store.optimistic_header.slot
|
||||||
|
|
|
@ -36,8 +36,7 @@ pub struct BeaconBlockBody {
|
||||||
// TODO: handle
|
// TODO: handle
|
||||||
attester_slashings: List<Dummy, 2>,
|
attester_slashings: List<Dummy, 2>,
|
||||||
attestations: List<Attestation, 128>,
|
attestations: List<Attestation, 128>,
|
||||||
// TODO: handle
|
deposits: List<Deposit, 16>,
|
||||||
deposits: List<Dummy, 16>,
|
|
||||||
// TODO: handle
|
// TODO: handle
|
||||||
voluntary_exits: List<Dummy, 16>,
|
voluntary_exits: List<Dummy, 16>,
|
||||||
sync_aggregate: SyncAggregate,
|
sync_aggregate: SyncAggregate,
|
||||||
|
@ -47,33 +46,33 @@ pub struct BeaconBlockBody {
|
||||||
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
|
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
|
||||||
pub struct ExecutionPayload {
|
pub struct ExecutionPayload {
|
||||||
#[serde(deserialize_with = "bytes32_deserialize")]
|
#[serde(deserialize_with = "bytes32_deserialize")]
|
||||||
parent_hash: Bytes32,
|
pub parent_hash: Bytes32,
|
||||||
#[serde(deserialize_with = "address_deserialize")]
|
#[serde(deserialize_with = "address_deserialize")]
|
||||||
fee_recipient: Address,
|
pub fee_recipient: Address,
|
||||||
#[serde(deserialize_with = "bytes32_deserialize")]
|
#[serde(deserialize_with = "bytes32_deserialize")]
|
||||||
pub state_root: Bytes32,
|
pub state_root: Bytes32,
|
||||||
#[serde(deserialize_with = "bytes32_deserialize")]
|
#[serde(deserialize_with = "bytes32_deserialize")]
|
||||||
pub receipts_root: Bytes32,
|
pub receipts_root: Bytes32,
|
||||||
#[serde(deserialize_with = "logs_bloom_deserialize")]
|
#[serde(deserialize_with = "logs_bloom_deserialize")]
|
||||||
logs_bloom: Vector<u8, 256>,
|
pub logs_bloom: Vector<u8, 256>,
|
||||||
#[serde(deserialize_with = "bytes32_deserialize")]
|
#[serde(deserialize_with = "bytes32_deserialize")]
|
||||||
prev_randao: Bytes32,
|
pub prev_randao: Bytes32,
|
||||||
#[serde(deserialize_with = "u64_deserialize")]
|
#[serde(deserialize_with = "u64_deserialize")]
|
||||||
pub block_number: u64,
|
pub block_number: u64,
|
||||||
#[serde(deserialize_with = "u64_deserialize")]
|
#[serde(deserialize_with = "u64_deserialize")]
|
||||||
gas_limit: u64,
|
pub gas_limit: u64,
|
||||||
#[serde(deserialize_with = "u64_deserialize")]
|
#[serde(deserialize_with = "u64_deserialize")]
|
||||||
gas_used: u64,
|
pub gas_used: u64,
|
||||||
#[serde(deserialize_with = "u64_deserialize")]
|
#[serde(deserialize_with = "u64_deserialize")]
|
||||||
timestamp: u64,
|
pub timestamp: u64,
|
||||||
#[serde(deserialize_with = "extra_data_deserialize")]
|
#[serde(deserialize_with = "extra_data_deserialize")]
|
||||||
extra_data: List<u8, 32>,
|
pub extra_data: List<u8, 32>,
|
||||||
#[serde(deserialize_with = "u256_deserialize")]
|
#[serde(deserialize_with = "u256_deserialize")]
|
||||||
pub base_fee_per_gas: U256,
|
pub base_fee_per_gas: U256,
|
||||||
#[serde(deserialize_with = "bytes32_deserialize")]
|
#[serde(deserialize_with = "bytes32_deserialize")]
|
||||||
pub block_hash: Bytes32,
|
pub block_hash: Bytes32,
|
||||||
#[serde(deserialize_with = "transactions_deserialize")]
|
#[serde(deserialize_with = "transactions_deserialize")]
|
||||||
transactions: List<Transaction, 1048576>,
|
pub transactions: List<Transaction, 1048576>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
|
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
|
||||||
|
@ -109,6 +108,25 @@ struct Dummy {
|
||||||
t: u64,
|
t: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
|
||||||
|
struct Deposit {
|
||||||
|
#[serde(deserialize_with = "bytes_vector_deserialize")]
|
||||||
|
proof: Vector<Bytes32, 33>,
|
||||||
|
data: DepositData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, Default, Debug, SimpleSerialize, Clone)]
|
||||||
|
struct DepositData {
|
||||||
|
#[serde(deserialize_with = "pubkey_deserialize")]
|
||||||
|
pubkey: BLSPubKey,
|
||||||
|
#[serde(deserialize_with = "bytes32_deserialize")]
|
||||||
|
withdrawal_credentials: Bytes32,
|
||||||
|
#[serde(deserialize_with = "u64_deserialize")]
|
||||||
|
amount: u64,
|
||||||
|
#[serde(deserialize_with = "signature_deserialize")]
|
||||||
|
signature: SignatureBytes,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
|
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
|
||||||
pub struct Eth1Data {
|
pub struct Eth1Data {
|
||||||
#[serde(deserialize_with = "bytes32_deserialize")]
|
#[serde(deserialize_with = "bytes32_deserialize")]
|
||||||
|
@ -213,6 +231,21 @@ where
|
||||||
.map_err(D::Error::custom)?)
|
.map_err(D::Error::custom)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bytes_vector_deserialize<'de, D>(deserializer: D) -> Result<Vector<Bytes32, 33>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let elems: Vec<String> = serde::Deserialize::deserialize(deserializer)?;
|
||||||
|
Ok(elems
|
||||||
|
.iter()
|
||||||
|
.map(|elem| {
|
||||||
|
let elem_bytes = hex_str_to_bytes(elem)?;
|
||||||
|
Ok(Vector::from_iter(elem_bytes))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vector<Bytes32, 33>>>()
|
||||||
|
.map_err(D::Error::custom)?)
|
||||||
|
}
|
||||||
|
|
||||||
fn signature_deserialize<'de, D>(deserializer: D) -> Result<SignatureBytes, D::Error>
|
fn signature_deserialize<'de, D>(deserializer: D) -> Result<SignatureBytes, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use ethers::abi::AbiEncode;
|
use ethers::abi::AbiEncode;
|
||||||
use ethers::prelude::{Address, U256};
|
use ethers::prelude::{Address, U256};
|
||||||
|
use ethers::types::H256;
|
||||||
use ethers::utils::keccak256;
|
use ethers::utils::keccak256;
|
||||||
use ethers::utils::rlp::encode;
|
use ethers::utils::rlp::encode;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
@ -11,7 +13,7 @@ use consensus::types::ExecutionPayload;
|
||||||
|
|
||||||
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;
|
use super::types::{Account, ExecutionBlock};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ExecutionClient {
|
pub struct ExecutionClient {
|
||||||
|
@ -94,4 +96,39 @@ impl ExecutionClient {
|
||||||
|
|
||||||
Ok(code)
|
Ok(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_block(&self, payload: &ExecutionPayload) -> Result<ExecutionBlock> {
|
||||||
|
let empty_nonce = "0x0000000000000000".to_string();
|
||||||
|
let empty_uncle_hash = "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347";
|
||||||
|
|
||||||
|
let txs = payload
|
||||||
|
.transactions
|
||||||
|
.iter()
|
||||||
|
.map(|tx| H256::from_slice(&keccak256(tx.to_vec())))
|
||||||
|
.collect::<Vec<H256>>();
|
||||||
|
|
||||||
|
Ok(ExecutionBlock {
|
||||||
|
number: payload.block_number,
|
||||||
|
base_fee_per_gas: U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le()),
|
||||||
|
difficulty: U256::from(0),
|
||||||
|
extra_data: payload.extra_data.to_vec(),
|
||||||
|
gas_limit: payload.gas_limit,
|
||||||
|
gas_used: payload.gas_used,
|
||||||
|
hash: H256::from_slice(&payload.block_hash),
|
||||||
|
logs_bloom: payload.logs_bloom.to_vec(),
|
||||||
|
miner: Address::from_slice(&payload.fee_recipient),
|
||||||
|
parent_hash: H256::from_slice(&payload.parent_hash),
|
||||||
|
receipts_root: H256::from_slice(&payload.receipts_root),
|
||||||
|
state_root: H256::from_slice(&payload.state_root),
|
||||||
|
timestamp: payload.timestamp,
|
||||||
|
total_difficulty: 0,
|
||||||
|
transactions: txs,
|
||||||
|
mix_hash: H256::from_slice(&payload.prev_randao),
|
||||||
|
nonce: empty_nonce,
|
||||||
|
sha3_uncles: H256::from_str(empty_uncle_hash)?,
|
||||||
|
size: 0,
|
||||||
|
transactions_root: H256::default(),
|
||||||
|
uncles: vec![],
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::collections::HashMap;
|
||||||
use ethers::prelude::{Address, H256, U256};
|
use ethers::prelude::{Address, H256, U256};
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use serde::de::Error;
|
use serde::de::Error;
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use common::utils::hex_str_to_bytes;
|
use common::utils::{hex_str_to_bytes, u64_to_hex_string};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -38,6 +38,56 @@ pub struct Account {
|
||||||
pub slots: HashMap<U256, U256>,
|
pub slots: HashMap<U256, U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ExecutionBlock {
|
||||||
|
#[serde(serialize_with = "serialize_u64_string")]
|
||||||
|
pub number: u64,
|
||||||
|
pub base_fee_per_gas: U256,
|
||||||
|
pub difficulty: U256,
|
||||||
|
#[serde(serialize_with = "serialize_bytes")]
|
||||||
|
pub extra_data: Vec<u8>,
|
||||||
|
#[serde(serialize_with = "serialize_u64_string")]
|
||||||
|
pub gas_limit: u64,
|
||||||
|
#[serde(serialize_with = "serialize_u64_string")]
|
||||||
|
pub gas_used: u64,
|
||||||
|
pub hash: H256,
|
||||||
|
#[serde(serialize_with = "serialize_bytes")]
|
||||||
|
pub logs_bloom: Vec<u8>,
|
||||||
|
pub miner: Address,
|
||||||
|
pub mix_hash: H256,
|
||||||
|
pub nonce: String,
|
||||||
|
pub parent_hash: H256,
|
||||||
|
pub receipts_root: H256,
|
||||||
|
pub sha3_uncles: H256,
|
||||||
|
#[serde(serialize_with = "serialize_u64_string")]
|
||||||
|
pub size: u64,
|
||||||
|
pub state_root: H256,
|
||||||
|
#[serde(serialize_with = "serialize_u64_string")]
|
||||||
|
pub timestamp: u64,
|
||||||
|
#[serde(serialize_with = "serialize_u64_string")]
|
||||||
|
pub total_difficulty: u64,
|
||||||
|
pub transactions: Vec<H256>,
|
||||||
|
pub transactions_root: H256,
|
||||||
|
pub uncles: Vec<H256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bytes<S>(bytes: &Vec<u8>, s: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let bytes_str = format!("0x{}", hex::encode(bytes));
|
||||||
|
s.serialize_str(&bytes_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_u64_string<S>(x: &u64, s: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let num_string = u64_to_hex_string(*x);
|
||||||
|
s.serialize_str(&num_string)
|
||||||
|
}
|
||||||
|
|
||||||
fn proof_deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
|
fn proof_deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
|
|
Loading…
Reference in New Issue