Skip to content
27 changes: 23 additions & 4 deletions crates/rpc/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use ethereum_rust_core::{
types::{ExecutionPayloadV3, PayloadStatus, PayloadValidationStatus},
H256,
};
use ethereum_rust_storage::Store;
use serde_json::{json, Value};
use tracing::info;

Expand All @@ -15,6 +16,20 @@ pub struct NewPayloadV3Request {
pub parent_beacon_block_root: H256,
}

impl NewPayloadV3Request {
pub fn parse(params: &Option<Vec<Value>>) -> Option<NewPayloadV3Request> {
let params = params.as_ref()?;
if params.len() != 3 {
return None;
}
Some(NewPayloadV3Request {
payload: serde_json::from_value(params[0].clone()).ok()?,
expected_blob_versioned_hashes: serde_json::from_value(params[1].clone()).ok()?,
parent_beacon_block_root: serde_json::from_value(params[2].clone()).ok()?,
})
}
}

pub fn exchange_capabilities(capabilities: &ExchangeCapabilitiesRequest) -> Result<Value, RpcErr> {
Ok(json!(capabilities))
}
Expand All @@ -30,7 +45,10 @@ pub fn forkchoice_updated_v3() -> Result<Value, RpcErr> {
}))
}

pub fn new_payload_v3(request: NewPayloadV3Request) -> Result<PayloadStatus, RpcErr> {
pub fn new_payload_v3(
request: NewPayloadV3Request,
storage: Store,
) -> Result<PayloadStatus, RpcErr> {
let block_hash = request.payload.block_hash;

info!("Received new payload with block hash: {}", block_hash);
Expand All @@ -50,10 +68,11 @@ pub fn new_payload_v3(request: NewPayloadV3Request) -> Result<PayloadStatus, Rpc
// Payload Validation

// Check timestamp does not fall within the time frame of the Cancun fork
let cancun_time = 0; // Placeholder -> we should fetch this from genesis?
if block_header.timestamp <= cancun_time {
return Err(RpcErr::UnsuportedFork);
match storage.get_cancun_time().map_err(|_| RpcErr::Internal)? {
Some(cancun_time) if block_header.timestamp > cancun_time => {}
_ => return Err(RpcErr::UnsuportedFork),
}

// Check that block_hash is valid
let actual_block_hash = block_header.compute_block_hash();
if block_hash != actual_block_hash {
Expand Down
21 changes: 2 additions & 19 deletions crates/rpc/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,8 @@ pub fn map_requests(req: &RpcRequest, storage: Store) -> Result<Value, RpcErr> {
"eth_blockNumber" => block::block_number(storage),
"engine_forkchoiceUpdatedV3" => engine::forkchoice_updated_v3(),
"engine_newPayloadV3" => {
let request =
parse_new_payload_v3_request(req.params.as_ref().ok_or(RpcErr::BadParams)?)?;
Ok(serde_json::to_value(engine::new_payload_v3(request)?).unwrap())
let request = NewPayloadV3Request::parse(&req.params).ok_or(RpcErr::BadParams)?;
Ok(serde_json::to_value(engine::new_payload_v3(request, storage)?).unwrap())
}
"admin_nodeInfo" => admin::node_info(),
_ => Err(RpcErr::MethodNotFound),
Expand Down Expand Up @@ -180,22 +179,6 @@ where
}
}

fn parse_new_payload_v3_request(params: &[Value]) -> Result<NewPayloadV3Request, RpcErr> {
if params.len() != 3 {
return Err(RpcErr::BadParams);
}
let payload = serde_json::from_value(params[0].clone()).map_err(|_| RpcErr::BadParams)?;
let expected_blob_versioned_hashes =
serde_json::from_value(params[1].clone()).map_err(|_| RpcErr::BadParams)?;
let parent_beacon_block_root =
serde_json::from_value(params[2].clone()).map_err(|_| RpcErr::BadParams)?;
Ok(NewPayloadV3Request {
payload,
expected_blob_versioned_hashes,
parent_beacon_block_root,
})
}

#[cfg(test)]
mod tests {
use ethereum_rust_core::{
Expand Down
13 changes: 9 additions & 4 deletions crates/storage/engines/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use bytes::Bytes;
use ethereum_types::{Address, H256, U256};

use ethereum_rust_core::types::{
Account, AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, Index, Receipt,
Transaction,
Account, AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index,
Receipt, Transaction,
};

use crate::error::StoreError;
Expand Down Expand Up @@ -169,12 +169,17 @@ pub trait StoreEngine: Debug + Send {
}
Ok(())
}
/// Updates the value of the chain id
fn update_chain_id(&mut self, chain_id: U256) -> Result<(), StoreError>;

/// Stores the chain configuration values, should only be called once after reading the genesis file
/// Ignores previously stored values if present
fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError>;

/// Obtain the current chain id
fn get_chain_id(&self) -> Result<Option<U256>, StoreError>;

/// Obtain the timestamp at which the cancun fork was activated
fn get_cancun_time(&self) -> Result<Option<u64>, StoreError>;

// Update earliest block number
fn update_earliest_block_number(&mut self, block_number: BlockNumber)
-> Result<(), StoreError>;
Expand Down
14 changes: 11 additions & 3 deletions crates/storage/engines/in_memory.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::StoreError;
use bytes::Bytes;
use ethereum_rust_core::types::{
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, Index, Receipt,
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index, Receipt,
};
use ethereum_types::{Address, H256, U256};
use std::{collections::HashMap, fmt::Debug};
Expand Down Expand Up @@ -31,6 +31,7 @@ struct ChainData {
safe_block_number: Option<BlockNumber>,
latest_block_number: Option<BlockNumber>,
pending_block_number: Option<BlockNumber>,
cancun_time: Option<u64>,
}

impl Store {
Expand Down Expand Up @@ -174,15 +175,22 @@ impl StoreEngine for Store {
Ok(())
}

fn update_chain_id(&mut self, chain_id: U256) -> Result<(), StoreError> {
self.chain_data.chain_id.replace(chain_id);
fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError> {
// Store cancun timestamp
self.chain_data.cancun_time = chain_config.cancun_time;
// Store chain id
self.chain_data.chain_id.replace(chain_config.chain_id);
Ok(())
}

fn get_chain_id(&self) -> Result<Option<U256>, StoreError> {
Ok(self.chain_data.chain_id)
}

fn get_cancun_time(&self) -> Result<Option<u64>, StoreError> {
Ok(self.chain_data.cancun_time)
}

fn update_earliest_block_number(
&mut self,
block_number: BlockNumber,
Expand Down
24 changes: 21 additions & 3 deletions crates/storage/engines/libmdbx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bytes::Bytes;
use ethereum_rust_core::rlp::decode::RLPDecode;
use ethereum_rust_core::rlp::encode::RLPEncode;
use ethereum_rust_core::types::{
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, Index, Receipt,
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index, Receipt,
};
use ethereum_types::{Address, H256, U256};
use libmdbx::orm::{Decodable, Encodable};
Expand Down Expand Up @@ -199,8 +199,16 @@ impl StoreEngine for Store {
self.remove::<AccountStorages>(address.into())
}

fn update_chain_id(&mut self, chain_id: U256) -> Result<(), StoreError> {
self.write::<ChainData>(ChainDataIndex::ChainId, chain_id.encode_to_vec())
fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError> {
// Store cancun timestamp
if let Some(cancun_time) = chain_config.cancun_time {
self.write::<ChainData>(ChainDataIndex::CancunTime, cancun_time.encode_to_vec())?;
};
// Store chain id
self.write::<ChainData>(
ChainDataIndex::ChainId,
chain_config.chain_id.encode_to_vec(),
)
}

fn get_chain_id(&self) -> Result<Option<U256>, StoreError> {
Expand All @@ -212,6 +220,15 @@ impl StoreEngine for Store {
}
}

fn get_cancun_time(&self) -> Result<Option<u64>, StoreError> {
match self.read::<ChainData>(ChainDataIndex::CancunTime)? {
None => Ok(None),
Some(ref rlp) => RLPDecode::decode(rlp)
.map(Some)
.map_err(|_| StoreError::DecodeError),
}
}

fn update_earliest_block_number(
&mut self,
block_number: BlockNumber,
Expand Down Expand Up @@ -408,6 +425,7 @@ pub enum ChainDataIndex {
SafeBlockNumber = 3,
LatestBlockNumber = 4,
PendingBlockNumber = 5,
CancunTime = 6,
}

impl Encodable for ChainDataIndex {
Expand Down
40 changes: 29 additions & 11 deletions crates/storage/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use self::error::StoreError;
use bytes::Bytes;
use engines::api::StoreEngine;
use ethereum_rust_core::types::{
Account, AccountInfo, Block, BlockBody, BlockHash, BlockHeader, BlockNumber, Genesis, Index,
Receipt, Transaction,
Account, AccountInfo, Block, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig,
Genesis, Index, Receipt, Transaction,
};
use ethereum_types::{Address, H256, U256};
use std::fmt::Debug;
Expand Down Expand Up @@ -246,8 +246,8 @@ impl Store {
self.add_account(address, account.into())?;
}

// Store chain info
self.update_chain_id(genesis.config.chain_id)
// Set chain config
self.set_chain_config(&genesis.config)
}

pub fn get_transaction_by_hash(
Expand Down Expand Up @@ -298,14 +298,18 @@ impl Store {
.increment_balance(address, amount)
}

pub fn update_chain_id(&self, chain_id: U256) -> Result<(), StoreError> {
self.engine.lock().unwrap().update_chain_id(chain_id)
pub fn set_chain_config(&self, chain_config: &ChainConfig) -> Result<(), StoreError> {
self.engine.lock().unwrap().set_chain_config(chain_config)
}

pub fn get_chain_id(&self) -> Result<Option<U256>, StoreError> {
self.engine.lock().unwrap().get_chain_id()
}

pub fn get_cancun_time(&self) -> Result<Option<u64>, StoreError> {
self.engine.lock().unwrap().get_cancun_time()
}

pub fn update_earliest_block_number(
&self,
block_number: BlockNumber,
Expand Down Expand Up @@ -409,7 +413,8 @@ mod tests {
test_store_account_storage(store.clone());
test_remove_account_storage(store.clone());
test_increment_balance(store.clone());
test_store_chain_data(store.clone());
test_store_chain_config(store.clone());
test_store_block_tags(store.clone());
}

fn test_store_account(store: Store) {
Expand Down Expand Up @@ -661,15 +666,30 @@ mod tests {
assert_eq!(stored_account_info.balance, 75.into());
}

fn test_store_chain_data(store: Store) {
fn test_store_chain_config(store: Store) {
let chain_id = U256::from_dec_str("46").unwrap();
let cancun_time = 12;
let chain_config = ChainConfig {
chain_id,
cancun_time: Some(cancun_time),
..Default::default()
};

store.set_chain_config(&chain_config).unwrap();

let stored_chain_id = store.get_chain_id().unwrap().unwrap();
let stored_cancun_time = store.get_cancun_time().unwrap().unwrap();

assert_eq!(chain_id, stored_chain_id);
assert_eq!(cancun_time, stored_cancun_time);
}
fn test_store_block_tags(store: Store) {
let earliest_block_number = 0;
let finalized_block_number = 7;
let safe_block_number = 6;
let latest_block_number = 8;
let pending_block_number = 9;

store.update_chain_id(chain_id).unwrap();
store
.update_earliest_block_number(earliest_block_number)
.unwrap();
Expand All @@ -684,14 +704,12 @@ mod tests {
.update_pending_block_number(pending_block_number)
.unwrap();

let stored_chain_id = store.get_chain_id().unwrap().unwrap();
let stored_earliest_block_number = store.get_earliest_block_number().unwrap().unwrap();
let stored_finalized_block_number = store.get_finalized_block_number().unwrap().unwrap();
let stored_safe_block_number = store.get_safe_block_number().unwrap().unwrap();
let stored_latest_block_number = store.get_latest_block_number().unwrap().unwrap();
let stored_pending_block_number = store.get_pending_block_number().unwrap().unwrap();

assert_eq!(chain_id, stored_chain_id);
assert_eq!(earliest_block_number, stored_earliest_block_number);
assert_eq!(finalized_block_number, stored_finalized_block_number);
assert_eq!(safe_block_number, stored_safe_block_number);
Expand Down