Skip to content

Commit 3f2d51d

Browse files
feat(rpc): derive proposal scan head from head L1 origin (#100)
* Revert "feat(consensus): add Shasta EOP flag and remove batch-to-last-block DB mapping (#99)" This reverts commit cf52f4c. * docs(plans): add proposal last block uncertain design * fix(rpc): derive proposal scan head from head L1 origin * feat: update eth.rs
1 parent cf52f4c commit 3f2d51d

File tree

10 files changed

+472
-136
lines changed

10 files changed

+472
-136
lines changed

Cargo.lock

Lines changed: 150 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/consensus/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ default = []
1414
[dependencies]
1515
alethia-reth-chainspec = { path = "../chainspec", default-features = false }
1616
alethia-reth-evm = { path = "../evm" }
17-
alethia-reth-primitives = { path = "../primitives" }
1817
alloy-consensus = { workspace = true }
1918
alloy-hardforks = { workspace = true }
2019
alloy-primitives = { workspace = true }

crates/consensus/src/validation.rs

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use reth_primitives_traits::{
2121
use crate::eip4396::{SHASTA_INITIAL_BASE_FEE, calculate_next_block_eip4396_base_fee};
2222
use alethia_reth_chainspec::{hardfork::TaikoHardforks, spec::TaikoChainSpec};
2323
use alethia_reth_evm::alloy::TAIKO_GOLDEN_TOUCH_ADDRESS;
24-
use alethia_reth_primitives::SHASTA_EXTRA_DATA_LEN;
2524

2625
sol! {
2726
function anchor(bytes32, bytes32, uint64, uint32) external;
@@ -145,15 +144,6 @@ where
145144
}
146145

147146
validate_header_extra_data(header, MAXIMUM_EXTRA_DATA_SIZE)?;
148-
if self.chain_spec.is_shasta_active(header.timestamp()) &&
149-
header.extra_data().len() != SHASTA_EXTRA_DATA_LEN
150-
{
151-
return Err(ConsensusError::Other(format!(
152-
"Shasta extra-data length invalid: {} != {}",
153-
header.extra_data().len(),
154-
SHASTA_EXTRA_DATA_LEN
155-
)));
156-
}
157147
validate_header_gas(header)?;
158148
validate_header_base_fee(header, &self.chain_spec)
159149
}
@@ -355,11 +345,8 @@ fn validate_input_selector(
355345

356346
#[cfg(test)]
357347
mod test {
358-
use alethia_reth_chainspec::{TAIKO_DEVNET, spec::TaikoDevnetConfigExt};
359-
use alethia_reth_primitives::SHASTA_EXTRA_DATA_LEN;
360348
use alloy_consensus::Header;
361-
use alloy_primitives::{B256, Bytes};
362-
use std::sync::Arc;
349+
use alloy_primitives::U64;
363350

364351
use super::validate_input_selector;
365352

@@ -371,7 +358,7 @@ mod test {
371358

372359
assert!(validate_against_parent_eip4396_base_fee(&header).is_err());
373360

374-
header.base_fee_per_gas = Some(1);
361+
header.base_fee_per_gas = Some(U64::random().to::<u64>());
375362
assert!(validate_against_parent_eip4396_base_fee(&header).is_ok());
376363
}
377364

@@ -428,26 +415,4 @@ mod test {
428415
let base_fee = calculate_next_block_eip4396_base_fee(&parent, BLOCK_TIME_TARGET);
429416
assert!(base_fee < 1_000_000_000, "Base fee should decrease when below target");
430417
}
431-
432-
#[test]
433-
fn rejects_invalid_shasta_extra_data_len() {
434-
#[derive(Debug)]
435-
struct NoopReader;
436-
impl TaikoBlockReader for NoopReader {
437-
fn block_timestamp_by_hash(&self, _: B256) -> Option<u64> {
438-
None
439-
}
440-
}
441-
442-
let spec = (*TAIKO_DEVNET).clone().as_ref().clone_with_devnet_shasta_timestamp(0).unwrap();
443-
let consensus = TaikoBeaconConsensus::new(Arc::new(spec), Arc::new(NoopReader));
444-
445-
let mut header = Header::default();
446-
header.timestamp = 1;
447-
header.base_fee_per_gas = Some(1);
448-
header.extra_data = Bytes::copy_from_slice(&[0u8; SHASTA_EXTRA_DATA_LEN - 1]);
449-
450-
let sealed = SealedHeader::seal_slow(header);
451-
assert!(consensus.validate_header(&sealed).is_err());
452-
}
453418
}

crates/db/src/model.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ tables! {
7575
type Key = BlockNumber;
7676
type Value = BlockNumber;
7777
}
78+
79+
table BatchToLastBlock {
80+
type Key = BlockNumber;
81+
type Value = BlockNumber;
82+
}
7883
}
7984

8085
#[cfg(test)]
Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,20 @@
11
//! Helpers for decoding Taiko-specific block `extraData` fields.
22
3-
use std::{error::Error, fmt::Display};
4-
5-
/// Index of the end-of-proposal flag in Shasta extra data.
6-
pub const SHASTA_EXTRA_DATA_END_OF_PROPOSAL_INDEX: usize = 7;
7-
8-
/// Exact number of bytes required for Shasta extra data.
9-
pub const SHASTA_EXTRA_DATA_LEN: usize = 8;
10-
11-
/// Error indicating that the Shasta extra data has an invalid length.
12-
#[derive(Debug, Clone, PartialEq, Eq)]
13-
pub struct ShastaExtraDataError {
14-
/// The actual length of the provided extra data.
15-
pub got: usize,
16-
/// The expected length of the Shasta extra data.
17-
pub expected: usize,
18-
}
19-
20-
impl Display for ShastaExtraDataError {
21-
/// Formats the error message indicating the invalid length of Shasta extra data.
22-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23-
write!(f, "invalid Shasta extra data length: {} != {}", self.got, self.expected)
24-
}
25-
}
26-
27-
/// Implements the standard Error trait for ShastaExtraDataError.
28-
impl Error for ShastaExtraDataError {}
3+
/// Minimum number of bytes required for Shasta extra data.
4+
pub const SHASTA_EXTRA_DATA_LEN: usize = 7;
295

306
/// Returns the base fee sharing percentage encoded in Shasta extra data.
317
pub fn decode_shasta_basefee_sharing_pctg(extra: &[u8]) -> u8 {
328
extra.first().copied().unwrap_or_default()
339
}
3410

35-
/// Returns the proposal ID and end-of-proposal flag encoded in Shasta extra data.
36-
pub fn decode_shasta_proposal_id(extra: &[u8]) -> Result<(u64, bool), ShastaExtraDataError> {
37-
if extra.len() != SHASTA_EXTRA_DATA_LEN {
38-
return Err(ShastaExtraDataError { got: extra.len(), expected: SHASTA_EXTRA_DATA_LEN });
11+
/// Returns the proposal ID encoded in Shasta extra data (bytes 1..6, big-endian).
12+
pub fn decode_shasta_proposal_id(extra: &[u8]) -> Option<u64> {
13+
if extra.len() < SHASTA_EXTRA_DATA_LEN {
14+
return None;
3915
}
4016

4117
let mut buf = [0u8; 8];
4218
buf[2..].copy_from_slice(&extra[1..7]);
43-
let proposal_id = u64::from_be_bytes(buf);
44-
let end_of_proposal = extra[SHASTA_EXTRA_DATA_END_OF_PROPOSAL_INDEX] != 0;
45-
Ok((proposal_id, end_of_proposal))
46-
}
47-
48-
#[cfg(test)]
49-
mod tests {
50-
use super::*;
51-
52-
#[test]
53-
fn decodes_shasta_proposal_id_and_end_of_proposal() {
54-
let extra = [0x2a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x01];
55-
let (proposal_id, end_of_proposal) = decode_shasta_proposal_id(&extra).unwrap();
56-
assert_eq!(proposal_id, 0x010203040506);
57-
assert!(end_of_proposal);
58-
}
59-
60-
#[test]
61-
fn rejects_invalid_shasta_extra_data_len() {
62-
let err = decode_shasta_proposal_id(&[0x01, 0x02, 0x03]).unwrap_err();
63-
assert_eq!(err.expected, SHASTA_EXTRA_DATA_LEN);
64-
assert_eq!(err.got, 3);
65-
}
19+
Some(u64::from_be_bytes(buf))
6620
}

crates/primitives/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ pub mod extra_data;
44
pub mod payload;
55

66
pub use extra_data::{
7-
SHASTA_EXTRA_DATA_END_OF_PROPOSAL_INDEX, SHASTA_EXTRA_DATA_LEN, ShastaExtraDataError,
8-
decode_shasta_basefee_sharing_pctg, decode_shasta_proposal_id,
7+
SHASTA_EXTRA_DATA_LEN, decode_shasta_basefee_sharing_pctg, decode_shasta_proposal_id,
98
};

crates/rpc/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,6 @@ serde_json = { workspace = true }
5959
thiserror = { workspace = true }
6060
tokio = { workspace = true }
6161
tracing = { workspace = true }
62+
63+
[dev-dependencies]
64+
reth-provider = { workspace = true, features = ["test-utils"] }

crates/rpc/src/eth/auth.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use alethia_reth_block::{
3333
};
3434
use alethia_reth_chainspec::spec::TaikoChainSpec;
3535
use alethia_reth_db::model::{
36-
STORED_L1_HEAD_ORIGIN_KEY, StoredL1HeadOriginTable, StoredL1OriginTable,
36+
BatchToLastBlock, STORED_L1_HEAD_ORIGIN_KEY, StoredL1HeadOriginTable, StoredL1OriginTable,
3737
};
3838
use alethia_reth_evm::factory::TaikoEvmFactory;
3939
use alethia_reth_primitives::{
@@ -67,6 +67,8 @@ pub trait TaikoAuthExtApi<T: RpcObject> {
6767
async fn update_l1_origin(&self, l1_origin: RpcL1Origin) -> RpcResult<Option<RpcL1Origin>>;
6868
#[method(name = "setL1OriginSignature")]
6969
async fn set_l1_origin_signature(&self, id: U256, signature: Bytes) -> RpcResult<RpcL1Origin>;
70+
#[method(name = "setBatchToLastBlock")]
71+
async fn set_batch_to_last_block(&self, batch_id: U256, block_number: U256) -> RpcResult<u64>;
7072
#[method(name = "txPoolContentWithMinTip")]
7173
async fn tx_pool_content_with_min_tip(
7274
&self,
@@ -171,6 +173,19 @@ where
171173
Ok(l1_origin.into_rpc())
172174
}
173175

176+
/// Sets the mapping from batch ID to its last block number in the database.
177+
async fn set_batch_to_last_block(&self, batch_id: U256, block_number: U256) -> RpcResult<u64> {
178+
let tx = self
179+
.provider
180+
.database_provider_rw()
181+
.map_err(|_| EthApiError::InternalEthError)?
182+
.into_tx();
183+
tx.put::<BatchToLastBlock>(batch_id.to(), block_number.to())
184+
.map_err(|_| EthApiError::InternalEthError)?;
185+
tx.commit().map_err(|_| EthApiError::InternalEthError)?;
186+
Ok(batch_id.to())
187+
}
188+
174189
/// Updates the L1 origin in the database.
175190
async fn update_l1_origin(&self, l1_origin: RpcL1Origin) -> RpcResult<Option<RpcL1Origin>> {
176191
let tx = self

crates/rpc/src/eth/error.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ use jsonrpsee_types::error::{ErrorCode, ErrorObjectOwned};
55
pub enum TaikoApiError {
66
#[error("not found")]
77
GethNotFound,
8+
#[error(
9+
"proposal last block uncertain: BatchToLastBlockID missing and no newer proposal observed"
10+
)]
11+
ProposalLastBlockUncertain,
812
}
913

1014
impl From<TaikoApiError> for ErrorObjectOwned {
@@ -16,6 +20,11 @@ impl From<TaikoApiError> for ErrorObjectOwned {
1620
"not found",
1721
None::<()>,
1822
),
23+
TaikoApiError::ProposalLastBlockUncertain => ErrorObjectOwned::owned(
24+
ErrorCode::ServerError(-32005).code(),
25+
"proposal last block uncertain: BatchToLastBlockID missing and no newer proposal observed",
26+
None::<()>,
27+
),
1928
}
2029
}
2130
}

0 commit comments

Comments
 (0)