Skip to content

Commit 299f340

Browse files
committed
test: add missing checks to STF spec-test runner
1 parent c424116 commit 299f340

File tree

2 files changed

+98
-3
lines changed

2 files changed

+98
-3
lines changed

crates/blockchain/state_transition/tests/stf_spectests.rs

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
use std::collections::HashMap;
12
use std::path::Path;
23

34
use ethlambda_state_transition::state_transition;
4-
use ethlambda_types::{block::Block, state::State};
5+
use ethlambda_types::{
6+
block::Block,
7+
primitives::{H256, HashTreeRoot as _},
8+
state::State,
9+
};
510

611
use crate::types::PostState;
712

@@ -24,8 +29,13 @@ fn run(path: &Path) -> datatest_stable::Result<()> {
2429
let mut pre_state: State = test.pre.into();
2530
let mut result = Ok(());
2631

27-
for block in test.blocks {
32+
// Build a block registry mapping "block_N" labels to hash tree roots.
33+
// Labels are 1-indexed: "block_1" is the first block in the array.
34+
let mut block_registry: HashMap<String, H256> = HashMap::new();
35+
for (i, block) in test.blocks.into_iter().enumerate() {
2836
let block: Block = block.into();
37+
let label = format!("block_{}", i + 1);
38+
block_registry.insert(label, block.hash_tree_root());
2939
result = state_transition(&mut pre_state, &block);
3040
if result.is_err() {
3141
break;
@@ -34,7 +44,7 @@ fn run(path: &Path) -> datatest_stable::Result<()> {
3444
let post_state = pre_state;
3545
match (result, test.post) {
3646
(Ok(_), Some(expected_post)) => {
37-
compare_post_states(&post_state, &expected_post)?;
47+
compare_post_states(&post_state, &expected_post, &block_registry)?;
3848
}
3949
(Ok(_), None) => {
4050
return Err(
@@ -55,9 +65,24 @@ fn run(path: &Path) -> datatest_stable::Result<()> {
5565
Ok(())
5666
}
5767

68+
fn resolve_label(
69+
label: &str,
70+
block_registry: &HashMap<String, H256>,
71+
) -> datatest_stable::Result<H256> {
72+
block_registry.get(label).copied().ok_or_else(|| {
73+
format!(
74+
"label '{}' not found in block registry. Available: {:?}",
75+
label,
76+
block_registry.keys().collect::<Vec<_>>()
77+
)
78+
.into()
79+
})
80+
}
81+
5882
fn compare_post_states(
5983
post_state: &State,
6084
expected_post: &PostState,
85+
block_registry: &HashMap<String, H256>,
6186
) -> datatest_stable::Result<()> {
6287
let PostState {
6388
config_genesis_time,
@@ -77,6 +102,11 @@ fn compare_post_states(
77102
justifications_roots,
78103
justifications_validators,
79104
validator_count,
105+
latest_justified_root_label,
106+
latest_finalized_root_label,
107+
justifications_roots_labels,
108+
justifications_roots_count,
109+
justifications_validators_count,
80110
} = expected_post;
81111
if let Some(config_genesis_time) = config_genesis_time
82112
&& post_state.config.genesis_time != *config_genesis_time
@@ -237,6 +267,57 @@ fn compare_post_states(
237267
.into());
238268
}
239269
}
270+
if let Some(label) = latest_justified_root_label {
271+
let expected = resolve_label(label, block_registry)?;
272+
if post_state.latest_justified.root != expected {
273+
return Err(format!(
274+
"latest_justified.root mismatch (via label '{label}'): expected {expected:?}, got {:?}",
275+
post_state.latest_justified.root
276+
)
277+
.into());
278+
}
279+
}
280+
if let Some(label) = latest_finalized_root_label {
281+
let expected = resolve_label(label, block_registry)?;
282+
if post_state.latest_finalized.root != expected {
283+
return Err(format!(
284+
"latest_finalized.root mismatch (via label '{label}'): expected {expected:?}, got {:?}",
285+
post_state.latest_finalized.root
286+
)
287+
.into());
288+
}
289+
}
290+
if let Some(labels) = justifications_roots_labels {
291+
let expected_roots: Vec<H256> = labels
292+
.iter()
293+
.map(|label| resolve_label(label, block_registry))
294+
.collect::<datatest_stable::Result<Vec<_>>>()?;
295+
let post_roots: Vec<_> = post_state.justifications_roots.iter().copied().collect();
296+
if post_roots != expected_roots {
297+
return Err(format!(
298+
"justifications_roots mismatch (via labels {labels:?}): expected {expected_roots:?}, got {post_roots:?}",
299+
)
300+
.into());
301+
}
302+
}
303+
if let Some(expected_count) = justifications_roots_count {
304+
let count = post_state.justifications_roots.len() as u64;
305+
if count != *expected_count {
306+
return Err(format!(
307+
"justifications_roots count mismatch: expected {expected_count}, got {count}",
308+
)
309+
.into());
310+
}
311+
}
312+
if let Some(expected_count) = justifications_validators_count {
313+
let count = post_state.justifications_validators.len() as u64;
314+
if count != *expected_count {
315+
return Err(format!(
316+
"justifications_validators count mismatch: expected {expected_count}, got {count}",
317+
)
318+
.into());
319+
}
320+
}
240321
Ok(())
241322
}
242323

crates/blockchain/state_transition/tests/types.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,18 @@ pub struct PostState {
8181

8282
#[serde(rename = "validatorCount")]
8383
pub validator_count: Option<u64>,
84+
85+
// Label-based root checks: "block_N" labels resolved to hash_tree_root of the Nth block.
86+
#[serde(rename = "latestJustifiedRootLabel")]
87+
pub latest_justified_root_label: Option<String>,
88+
#[serde(rename = "latestFinalizedRootLabel")]
89+
pub latest_finalized_root_label: Option<String>,
90+
#[serde(rename = "justificationsRootsLabels")]
91+
pub justifications_roots_labels: Option<Vec<String>>,
92+
93+
// Count checks for variable-length collections.
94+
#[serde(rename = "justificationsRootsCount")]
95+
pub justifications_roots_count: Option<u64>,
96+
#[serde(rename = "justificationsValidatorsCount")]
97+
pub justifications_validators_count: Option<u64>,
8498
}

0 commit comments

Comments
 (0)