Skip to content

Commit 6a725cc

Browse files
authored
feat: update block data hint (#253)
* feat: update BlockDataHint struct Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * fix: lints Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: skip book tests (issue 250) Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: bump revm Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: add gas limit to ScrollPayloadAttributes Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: validate state root using consensus Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: log attributes on validation error Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * chore: clean Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> * feat: using `HeaderValidator::validate_state_root` where possible Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com> --------- Signed-off-by: Gregory Edison <gregory.edison1993@gmail.com>
1 parent b2377df commit 6a725cc

9 files changed

Lines changed: 61 additions & 11 deletions

File tree

Cargo.lock

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

crates/engine/local/src/payload.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ where
7676
transactions: None,
7777
no_tx_pool: false,
7878
block_data_hint: None,
79+
gas_limit: None,
7980
}
8081
}
8182
}

crates/engine/tree/src/tree/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,7 +2287,7 @@ where
22872287
let elapsed = execution_finish.elapsed();
22882288
info!(target: "engine::tree", ?state_root, ?elapsed, "State root task finished");
22892289
// we double check the state root here for good measure
2290-
if state_root == block.header().state_root() {
2290+
if self.consensus.validate_state_root(block.header(), state_root).is_ok() {
22912291
maybe_state_root = Some((state_root, trie_updates, elapsed))
22922292
} else {
22932293
warn!(
@@ -2347,7 +2347,7 @@ where
23472347
debug!(target: "engine::tree", ?root_elapsed, block=?block_num_hash, "Calculated state root");
23482348

23492349
// ensure state root matches
2350-
if state_root != block.header().state_root() {
2350+
if self.consensus.validate_state_root(block.header(), state_root).is_err() {
23512351
// call post-block hook
23522352
self.on_invalid_block(&parent_block, &block, &output, Some((&trie_output, state_root)));
23532353
return Err((

crates/rpc/rpc/src/validation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use core::fmt;
1515
use jsonrpsee::core::RpcResult;
1616
use jsonrpsee_types::error::ErrorObject;
1717
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
18-
use reth_consensus::{Consensus, FullConsensus};
18+
use reth_consensus::{Consensus, FullConsensus, HeaderValidator};
1919
use reth_engine_primitives::PayloadValidator;
2020
use reth_errors::{BlockExecutionError, ConsensusError, ProviderError};
2121
use reth_evm::{execute::Executor, ConfigureEvm};
@@ -207,7 +207,7 @@ where
207207
let state_root =
208208
state_provider.state_root(state_provider.hashed_post_state(&output.state))?;
209209

210-
if state_root != block.header().state_root() {
210+
if self.consensus.validate_state_root(block.header(), state_root).is_err() {
211211
return Err(ConsensusError::BodyStateRootDiff(
212212
GotExpected { got: state_root, expected: block.header().state_root() }.into(),
213213
)

crates/scroll/alloy/rpc-types-engine/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ serde = { workspace = true, optional = true }
2323
arbitrary = { workspace = true, optional = true }
2424

2525
[dev-dependencies]
26+
alloy-primitives = { workspace = true, features = ["getrandom"] }
2627
serde_json.workspace = true
2728

2829
[features]

crates/scroll/alloy/rpc-types-engine/src/attributes.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Scroll-specific payload attributes.
22
33
use alloc::vec::Vec;
4-
use alloy_primitives::{Bytes, U256};
4+
use alloy_primitives::{Address, Bytes, B256, U256};
55
use alloy_rpc_types_engine::PayloadAttributes;
66

77
/// The payload attributes for block building tailored for Scroll.
@@ -18,6 +18,8 @@ pub struct ScrollPayloadAttributes {
1818
/// The pre-Euclid block data hint, necessary for the block builder to derive the correct block
1919
/// hash.
2020
pub block_data_hint: Option<BlockDataHint>,
21+
/// The gas limit for the block building task.
22+
pub gas_limit: Option<u64>,
2123
}
2224

2325
/// Block data provided as a hint to the payload attributes.
@@ -27,14 +29,26 @@ pub struct ScrollPayloadAttributes {
2729
pub struct BlockDataHint {
2830
/// The extra data for the block.
2931
pub extra_data: Bytes,
32+
/// The state root for the block.
33+
pub state_root: B256,
34+
/// The optional coinbase for the block.
35+
pub coinbase: Option<Address>,
36+
/// The optional nonce for the block.
37+
pub nonce: Option<u64>,
3038
/// The difficulty for the block.
3139
pub difficulty: U256,
3240
}
3341

3442
#[cfg(feature = "arbitrary")]
3543
impl<'a> arbitrary::Arbitrary<'a> for BlockDataHint {
3644
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
37-
Ok(Self { extra_data: Bytes::arbitrary(u)?, difficulty: U256::arbitrary(u)? })
45+
Ok(Self {
46+
extra_data: Bytes::arbitrary(u)?,
47+
state_root: B256::arbitrary(u)?,
48+
coinbase: Some(Address::arbitrary(u)?),
49+
nonce: Some(u64::arbitrary(u)?),
50+
difficulty: U256::arbitrary(u)?,
51+
})
3852
}
3953
}
4054

@@ -52,6 +66,7 @@ impl<'a> arbitrary::Arbitrary<'a> for ScrollPayloadAttributes {
5266
transactions: Some(Vec::arbitrary(u)?),
5367
no_tx_pool: bool::arbitrary(u)?,
5468
block_data_hint: Some(BlockDataHint::arbitrary(u)?),
69+
gas_limit: Some(u64::arbitrary(u)?),
5570
})
5671
}
5772
}
@@ -76,8 +91,12 @@ mod test {
7691
no_tx_pool: true,
7792
block_data_hint: Some(BlockDataHint {
7893
extra_data: b"world".into(),
94+
state_root: B256::random(),
95+
coinbase: Some(Address::random()),
96+
nonce: Some(0x12345),
7997
difficulty: U256::from(10),
8098
}),
99+
gas_limit: Some(10_000_000),
81100
};
82101

83102
let ser = serde_json::to_string(&attributes).unwrap();

crates/scroll/engine-primitives/src/payload/attributes.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub struct ScrollPayloadBuilderAttributes {
2626
/// The pre-Euclid block data hint, necessary for the block builder to derive the correct block
2727
/// hash.
2828
pub block_data_hint: Option<BlockDataHint>,
29+
/// The gas limit for the generated payload.
30+
pub gas_limit: Option<u64>,
2931
}
3032

3133
impl PayloadBuilderAttributes for ScrollPayloadBuilderAttributes {
@@ -70,6 +72,7 @@ impl PayloadBuilderAttributes for ScrollPayloadBuilderAttributes {
7072
no_tx_pool: attributes.no_tx_pool,
7173
transactions,
7274
block_data_hint: attributes.block_data_hint,
75+
gas_limit: attributes.gas_limit,
7376
})
7477
}
7578

@@ -144,9 +147,20 @@ pub(crate) fn payload_id_scroll(
144147

145148
if let Some(block_data) = &attributes.block_data_hint {
146149
hasher.update(&block_data.extra_data);
150+
hasher.update(block_data.state_root.0);
151+
if let Some(coinbase) = block_data.coinbase {
152+
hasher.update(coinbase);
153+
}
154+
if let Some(nonce) = block_data.nonce {
155+
hasher.update(nonce.to_be_bytes());
156+
}
147157
hasher.update(block_data.difficulty.to_be_bytes::<32>());
148158
}
149159

160+
if let Some(gas_limit) = attributes.gas_limit {
161+
hasher.update(gas_limit.to_be_bytes());
162+
}
163+
150164
let mut out = hasher.finalize();
151165
out[0] = payload_version;
152166
PayloadId::new(out.as_slice()[..8].try_into().expect("sufficient length"))
@@ -169,7 +183,7 @@ mod tests {
169183
#[test]
170184
fn test_payload_id() {
171185
let expected =
172-
PayloadId::new(FixedBytes::<8>::from_str("0x0322b5f17cf26e85").unwrap().into());
186+
PayloadId::new(FixedBytes::<8>::from_str("0x036369370c155d4c").unwrap().into());
173187
let attrs = ScrollPayloadAttributes {
174188
payload_attributes: PayloadAttributes {
175189
timestamp: 1728933301,
@@ -180,7 +194,14 @@ mod tests {
180194
},
181195
transactions: Some([bytes!("7ef8f8a0dc19cfa777d90980e4875d0a548a881baaa3f83f14d1bc0d3038bc329350e54194deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e20000f424000000000000000000000000300000000670d6d890000000000000125000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000014bf9181db6e381d4384bbf69c48b0ee0eed23c6ca26143c6d2544f9d39997a590000000000000000000000007f83d659683caf2767fd3c720981d51f5bc365bc")].into()),
182196
no_tx_pool: false,
183-
block_data_hint: Some(BlockDataHint{ extra_data: bytes!("476574682f76312e302e302f6c696e75782f676f312e342e32"), difficulty: U256::from(10) } ),
197+
block_data_hint: Some(BlockDataHint{
198+
extra_data: bytes!("476574682f76312e302e302f6c696e75782f676f312e342e32"),
199+
state_root: b256!("0x000000000000000000000000000000000000000000000000000000000000dead"),
200+
coinbase: Some(address!("0x000000000000000000000000000000000000dead")),
201+
nonce: Some(u64::MAX),
202+
difficulty: U256::from(10)
203+
}),
204+
gas_limit: Some(10_000_000),
184205
};
185206

186207
assert_eq!(

crates/scroll/node/src/test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,6 @@ pub fn scroll_payload_attributes(timestamp: u64) -> ScrollPayloadBuilderAttribut
7979
transactions: vec![],
8080
no_tx_pool: false,
8181
block_data_hint: None,
82+
gas_limit: None,
8283
}
8384
}

crates/scroll/payload/src/builder.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,19 @@ impl<Txs> ScrollBuilder<'_, Txs> {
262262
let BlockBuilderOutcome { execution_result, hashed_state, trie_updates, mut block } =
263263
builder.finish(state_provider)?;
264264

265-
// set the block extra data and difficulty fields using the payload attributes.
265+
// set the block fields using the hints from the payload attributes.
266266
if let Some(block_data) = &ctx.config.attributes.block_data_hint {
267267
let (mut scroll_block, senders) = block.split();
268268
scroll_block = scroll_block.map_header(|mut header| {
269269
header.extra_data = block_data.extra_data.clone();
270+
header.state_root = block_data.state_root;
270271
header.difficulty = block_data.difficulty;
272+
if let Some(coinbase) = block_data.coinbase {
273+
header.beneficiary = coinbase;
274+
}
275+
if let Some(nonce) = block_data.nonce {
276+
header.nonce = nonce.into();
277+
}
271278
header
272279
});
273280
block = RecoveredBlock::new_unhashed(scroll_block, senders)
@@ -387,7 +394,7 @@ where
387394
ScrollNextBlockEnvAttributes {
388395
timestamp: self.attributes().timestamp(),
389396
suggested_fee_recipient: self.attributes().suggested_fee_recipient(),
390-
gas_limit: builder_config.gas_limit,
397+
gas_limit: self.attributes().gas_limit.unwrap_or(builder_config.gas_limit),
391398
base_fee,
392399
},
393400
)

0 commit comments

Comments
 (0)