Skip to content

Commit cb72a3f

Browse files
authored
feat: eth_newPayloadV3: fetch cancun time from db for timestamp validation (#220)
**Motivation** Fetch cancun time from DB when validating payload v3 timestamp <!-- Why does this pull request exist? What are its goals? --> **Description** * Store cancun_time in db * Use the stored cancun_time when validating payload timestamp in `eth_newPayloadV3` * Replace update methods for chain data in `Store` with `set_chain_config` Bonus: * Move `NewPayloadV3Request` to its corresponding module and update is parsing to match the rest of the codebase <!-- A clear and concise general description of the changes this PR introduces --> <!-- Link to issues: Resolves #111, Resolves #222 --> Closes None, but is part of #51
1 parent 0c9170a commit cb72a3f

File tree

6 files changed

+95
-44
lines changed

6 files changed

+95
-44
lines changed

crates/rpc/engine/mod.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use ethereum_rust_core::{
22
types::{ExecutionPayloadV3, PayloadStatus, PayloadValidationStatus},
33
H256,
44
};
5+
use ethereum_rust_storage::Store;
56
use serde_json::{json, Value};
67
use tracing::info;
78

@@ -15,6 +16,20 @@ pub struct NewPayloadV3Request {
1516
pub parent_beacon_block_root: H256,
1617
}
1718

19+
impl NewPayloadV3Request {
20+
pub fn parse(params: &Option<Vec<Value>>) -> Option<NewPayloadV3Request> {
21+
let params = params.as_ref()?;
22+
if params.len() != 3 {
23+
return None;
24+
}
25+
Some(NewPayloadV3Request {
26+
payload: serde_json::from_value(params[0].clone()).ok()?,
27+
expected_blob_versioned_hashes: serde_json::from_value(params[1].clone()).ok()?,
28+
parent_beacon_block_root: serde_json::from_value(params[2].clone()).ok()?,
29+
})
30+
}
31+
}
32+
1833
pub fn exchange_capabilities(capabilities: &ExchangeCapabilitiesRequest) -> Result<Value, RpcErr> {
1934
Ok(json!(capabilities))
2035
}
@@ -30,7 +45,10 @@ pub fn forkchoice_updated_v3() -> Result<Value, RpcErr> {
3045
}))
3146
}
3247

33-
pub fn new_payload_v3(request: NewPayloadV3Request) -> Result<PayloadStatus, RpcErr> {
48+
pub fn new_payload_v3(
49+
request: NewPayloadV3Request,
50+
storage: Store,
51+
) -> Result<PayloadStatus, RpcErr> {
3452
let block_hash = request.payload.block_hash;
3553

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

5270
// Check timestamp does not fall within the time frame of the Cancun fork
53-
let cancun_time = 0; // Placeholder -> we should fetch this from genesis?
54-
if block_header.timestamp <= cancun_time {
55-
return Err(RpcErr::UnsuportedFork);
71+
match storage.get_cancun_time().map_err(|_| RpcErr::Internal)? {
72+
Some(cancun_time) if block_header.timestamp > cancun_time => {}
73+
_ => return Err(RpcErr::UnsuportedFork),
5674
}
75+
5776
// Check that block_hash is valid
5877
let actual_block_hash = block_header.compute_block_hash();
5978
if block_hash != actual_block_hash {

crates/rpc/rpc.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,8 @@ pub fn map_requests(req: &RpcRequest, storage: Store) -> Result<Value, RpcErr> {
142142
"eth_blockNumber" => block::block_number(storage),
143143
"engine_forkchoiceUpdatedV3" => engine::forkchoice_updated_v3(),
144144
"engine_newPayloadV3" => {
145-
let request =
146-
parse_new_payload_v3_request(req.params.as_ref().ok_or(RpcErr::BadParams)?)?;
147-
Ok(serde_json::to_value(engine::new_payload_v3(request)?).unwrap())
145+
let request = NewPayloadV3Request::parse(&req.params).ok_or(RpcErr::BadParams)?;
146+
Ok(serde_json::to_value(engine::new_payload_v3(request, storage)?).unwrap())
148147
}
149148
"admin_nodeInfo" => admin::node_info(),
150149
_ => Err(RpcErr::MethodNotFound),
@@ -180,22 +179,6 @@ where
180179
}
181180
}
182181

183-
fn parse_new_payload_v3_request(params: &[Value]) -> Result<NewPayloadV3Request, RpcErr> {
184-
if params.len() != 3 {
185-
return Err(RpcErr::BadParams);
186-
}
187-
let payload = serde_json::from_value(params[0].clone()).map_err(|_| RpcErr::BadParams)?;
188-
let expected_blob_versioned_hashes =
189-
serde_json::from_value(params[1].clone()).map_err(|_| RpcErr::BadParams)?;
190-
let parent_beacon_block_root =
191-
serde_json::from_value(params[2].clone()).map_err(|_| RpcErr::BadParams)?;
192-
Ok(NewPayloadV3Request {
193-
payload,
194-
expected_blob_versioned_hashes,
195-
parent_beacon_block_root,
196-
})
197-
}
198-
199182
#[cfg(test)]
200183
mod tests {
201184
use ethereum_rust_core::{

crates/storage/engines/api.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use bytes::Bytes;
44
use ethereum_types::{Address, H256, U256};
55

66
use ethereum_rust_core::types::{
7-
Account, AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, Index, Receipt,
8-
Transaction,
7+
Account, AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index,
8+
Receipt, Transaction,
99
};
1010

1111
use crate::error::StoreError;
@@ -169,12 +169,17 @@ pub trait StoreEngine: Debug + Send {
169169
}
170170
Ok(())
171171
}
172-
/// Updates the value of the chain id
173-
fn update_chain_id(&mut self, chain_id: U256) -> Result<(), StoreError>;
172+
173+
/// Stores the chain configuration values, should only be called once after reading the genesis file
174+
/// Ignores previously stored values if present
175+
fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError>;
174176

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

180+
/// Obtain the timestamp at which the cancun fork was activated
181+
fn get_cancun_time(&self) -> Result<Option<u64>, StoreError>;
182+
178183
// Update earliest block number
179184
fn update_earliest_block_number(&mut self, block_number: BlockNumber)
180185
-> Result<(), StoreError>;

crates/storage/engines/in_memory.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::error::StoreError;
22
use bytes::Bytes;
33
use ethereum_rust_core::types::{
4-
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, Index, Receipt,
4+
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index, Receipt,
55
};
66
use ethereum_types::{Address, H256, U256};
77
use std::{collections::HashMap, fmt::Debug};
@@ -31,6 +31,7 @@ struct ChainData {
3131
safe_block_number: Option<BlockNumber>,
3232
latest_block_number: Option<BlockNumber>,
3333
pending_block_number: Option<BlockNumber>,
34+
cancun_time: Option<u64>,
3435
}
3536

3637
impl Store {
@@ -174,15 +175,22 @@ impl StoreEngine for Store {
174175
Ok(())
175176
}
176177

177-
fn update_chain_id(&mut self, chain_id: U256) -> Result<(), StoreError> {
178-
self.chain_data.chain_id.replace(chain_id);
178+
fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError> {
179+
// Store cancun timestamp
180+
self.chain_data.cancun_time = chain_config.cancun_time;
181+
// Store chain id
182+
self.chain_data.chain_id.replace(chain_config.chain_id);
179183
Ok(())
180184
}
181185

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

190+
fn get_cancun_time(&self) -> Result<Option<u64>, StoreError> {
191+
Ok(self.chain_data.cancun_time)
192+
}
193+
186194
fn update_earliest_block_number(
187195
&mut self,
188196
block_number: BlockNumber,

crates/storage/engines/libmdbx.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use bytes::Bytes;
99
use ethereum_rust_core::rlp::decode::RLPDecode;
1010
use ethereum_rust_core::rlp::encode::RLPEncode;
1111
use ethereum_rust_core::types::{
12-
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, Index, Receipt,
12+
AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index, Receipt,
1313
};
1414
use ethereum_types::{Address, H256, U256};
1515
use libmdbx::orm::{Decodable, Encodable};
@@ -199,8 +199,16 @@ impl StoreEngine for Store {
199199
self.remove::<AccountStorages>(address.into())
200200
}
201201

202-
fn update_chain_id(&mut self, chain_id: U256) -> Result<(), StoreError> {
203-
self.write::<ChainData>(ChainDataIndex::ChainId, chain_id.encode_to_vec())
202+
fn set_chain_config(&mut self, chain_config: &ChainConfig) -> Result<(), StoreError> {
203+
// Store cancun timestamp
204+
if let Some(cancun_time) = chain_config.cancun_time {
205+
self.write::<ChainData>(ChainDataIndex::CancunTime, cancun_time.encode_to_vec())?;
206+
};
207+
// Store chain id
208+
self.write::<ChainData>(
209+
ChainDataIndex::ChainId,
210+
chain_config.chain_id.encode_to_vec(),
211+
)
204212
}
205213

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

223+
fn get_cancun_time(&self) -> Result<Option<u64>, StoreError> {
224+
match self.read::<ChainData>(ChainDataIndex::CancunTime)? {
225+
None => Ok(None),
226+
Some(ref rlp) => RLPDecode::decode(rlp)
227+
.map(Some)
228+
.map_err(|_| StoreError::DecodeError),
229+
}
230+
}
231+
215232
fn update_earliest_block_number(
216233
&mut self,
217234
block_number: BlockNumber,
@@ -408,6 +425,7 @@ pub enum ChainDataIndex {
408425
SafeBlockNumber = 3,
409426
LatestBlockNumber = 4,
410427
PendingBlockNumber = 5,
428+
CancunTime = 6,
411429
}
412430

413431
impl Encodable for ChainDataIndex {

crates/storage/storage.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use self::error::StoreError;
66
use bytes::Bytes;
77
use engines::api::StoreEngine;
88
use ethereum_rust_core::types::{
9-
Account, AccountInfo, Block, BlockBody, BlockHash, BlockHeader, BlockNumber, Genesis, Index,
10-
Receipt, Transaction,
9+
Account, AccountInfo, Block, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig,
10+
Genesis, Index, Receipt, Transaction,
1111
};
1212
use ethereum_types::{Address, H256, U256};
1313
use std::fmt::Debug;
@@ -246,8 +246,8 @@ impl Store {
246246
self.add_account(address, account.into())?;
247247
}
248248

249-
// Store chain info
250-
self.update_chain_id(genesis.config.chain_id)
249+
// Set chain config
250+
self.set_chain_config(&genesis.config)
251251
}
252252

253253
pub fn get_transaction_by_hash(
@@ -298,14 +298,18 @@ impl Store {
298298
.increment_balance(address, amount)
299299
}
300300

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

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

309+
pub fn get_cancun_time(&self) -> Result<Option<u64>, StoreError> {
310+
self.engine.lock().unwrap().get_cancun_time()
311+
}
312+
309313
pub fn update_earliest_block_number(
310314
&self,
311315
block_number: BlockNumber,
@@ -409,7 +413,8 @@ mod tests {
409413
test_store_account_storage(store.clone());
410414
test_remove_account_storage(store.clone());
411415
test_increment_balance(store.clone());
412-
test_store_chain_data(store.clone());
416+
test_store_chain_config(store.clone());
417+
test_store_block_tags(store.clone());
413418
}
414419

415420
fn test_store_account(store: Store) {
@@ -661,15 +666,30 @@ mod tests {
661666
assert_eq!(stored_account_info.balance, 75.into());
662667
}
663668

664-
fn test_store_chain_data(store: Store) {
669+
fn test_store_chain_config(store: Store) {
665670
let chain_id = U256::from_dec_str("46").unwrap();
671+
let cancun_time = 12;
672+
let chain_config = ChainConfig {
673+
chain_id,
674+
cancun_time: Some(cancun_time),
675+
..Default::default()
676+
};
677+
678+
store.set_chain_config(&chain_config).unwrap();
679+
680+
let stored_chain_id = store.get_chain_id().unwrap().unwrap();
681+
let stored_cancun_time = store.get_cancun_time().unwrap().unwrap();
682+
683+
assert_eq!(chain_id, stored_chain_id);
684+
assert_eq!(cancun_time, stored_cancun_time);
685+
}
686+
fn test_store_block_tags(store: Store) {
666687
let earliest_block_number = 0;
667688
let finalized_block_number = 7;
668689
let safe_block_number = 6;
669690
let latest_block_number = 8;
670691
let pending_block_number = 9;
671692

672-
store.update_chain_id(chain_id).unwrap();
673693
store
674694
.update_earliest_block_number(earliest_block_number)
675695
.unwrap();
@@ -684,14 +704,12 @@ mod tests {
684704
.update_pending_block_number(pending_block_number)
685705
.unwrap();
686706

687-
let stored_chain_id = store.get_chain_id().unwrap().unwrap();
688707
let stored_earliest_block_number = store.get_earliest_block_number().unwrap().unwrap();
689708
let stored_finalized_block_number = store.get_finalized_block_number().unwrap().unwrap();
690709
let stored_safe_block_number = store.get_safe_block_number().unwrap().unwrap();
691710
let stored_latest_block_number = store.get_latest_block_number().unwrap().unwrap();
692711
let stored_pending_block_number = store.get_pending_block_number().unwrap().unwrap();
693712

694-
assert_eq!(chain_id, stored_chain_id);
695713
assert_eq!(earliest_block_number, stored_earliest_block_number);
696714
assert_eq!(finalized_block_number, stored_finalized_block_number);
697715
assert_eq!(safe_block_number, stored_safe_block_number);

0 commit comments

Comments
 (0)