Skip to content

Commit 8248499

Browse files
authored
refactor(stf): consolidate block validation into compute_asm_transition (#11)
* refactor(stf): consolidate block validation into compute_asm_transition * chore(asm-proof-impl): remove unused dep
1 parent 5970a7b commit 8248499

File tree

5 files changed

+52
-86
lines changed

5 files changed

+52
-86
lines changed

crates/proof/statements/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ strata-asm-spec.workspace = true
1818
strata-asm-stf.workspace = true
1919
strata-btc-types = { workspace = true, optional = true }
2020
strata-btc-verification = { workspace = true, optional = true }
21-
strata-identifiers.workspace = true
21+
strata-identifiers = { workspace = true, optional = true }
2222
strata-l1-txfmt = { workspace = true, optional = true }
2323
strata-predicate.workspace = true
2424
strata-test-utils-btc = { workspace = true, optional = true }
@@ -40,6 +40,7 @@ test-utils = [
4040
"dep:strata-btc-verification",
4141
"dep:strata-l1-txfmt",
4242
"dep:strata-test-utils-btc",
43+
"dep:strata-identifiers",
4344
]
4445

4546
[dev-dependencies]

crates/proof/statements/src/moho_program/program.rs

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
//! [`MohoProgram`] implementation for the ASM STF.
22
//!
33
//! This module contains the [`AsmStfProgram`] type that implements [`MohoProgram`], wiring the
4-
//! ASM state transition function into the Moho runtime. It handles block validation, state
5-
//! commitment via SHA-256, transition execution, and extraction of post-transition artifacts
6-
//! such as predicate updates and export state entries.
7-
use bitcoin::hashes::Hash;
4+
//! ASM state transition function into the Moho runtime. It handles state commitment via SHA-256,
5+
//! transition execution, and extraction of post-transition artifacts such as predicate updates
6+
//! and export state entries.
87
use moho_runtime_interface::MohoProgram;
98
use moho_types::{ExportState, InnerStateCommitment, StateReference};
109
use sha2::{Digest, Sha256};
11-
use strata_asm_common::{AnchorState, AsmSpec};
10+
use strata_asm_common::AnchorState;
1211
use strata_asm_logs::{AsmStfUpdate, NewExportEntry};
1312
use strata_asm_spec::StrataAsmSpec;
14-
use strata_asm_stf::{compute_asm_transition, group_txs_by_subprotocol, AsmStfInput, AsmStfOutput};
15-
use strata_identifiers::Buf32;
13+
use strata_asm_stf::{compute_asm_transition, AsmStfOutput};
1614
use strata_predicate::PredicateKey;
1715

1816
use crate::moho_program::input::AsmStepInput;
@@ -53,41 +51,8 @@ impl MohoProgram for AsmStfProgram {
5351
spec: &StrataAsmSpec,
5452
input: &AsmStepInput,
5553
) -> AsmStfOutput {
56-
// TODO: (@prajworlg) Consolidate block validation logic in a single place
57-
// https://alpenlabs.atlassian.net/browse/STR-2619
58-
59-
// 1. Validate the input
60-
assert!(input.validate_block());
61-
62-
// For blocks without witness data (pre-SegWit or legacy-only transactions),
63-
// the witness merkle root equals the transaction merkle root per Bitcoin protocol.
64-
let wtxids_root: Buf32 = input
65-
.block
66-
.0
67-
.witness_root()
68-
.map(|root| root.as_raw_hash().to_byte_array())
69-
.unwrap_or_else(|| {
70-
input
71-
.block
72-
.0
73-
.header
74-
.merkle_root
75-
.as_raw_hash()
76-
.to_byte_array()
77-
})
78-
.into();
79-
80-
// 2. Restructure the raw input to be formatted according to what we want.
81-
let protocol_txs = group_txs_by_subprotocol(spec.magic_bytes(), &input.block.0.txdata);
82-
let stf_input = AsmStfInput {
83-
protocol_txs,
84-
header: &input.block.0.header,
85-
aux_data: input.aux_data.clone(),
86-
wtxids_root,
87-
};
88-
89-
// 3. Actually invoke the ASM state transition function.
90-
compute_asm_transition(spec, pre_state, stf_input).expect("asm: compute transition")
54+
compute_asm_transition(spec, pre_state, &input.block.0, &input.aux_data)
55+
.expect("asm: compute transition")
9156
}
9257

9358
fn extract_post_state(output: &Self::StepOutput) -> &Self::State {

crates/stf/src/stf.rs

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,79 +3,95 @@
33
//! view into a single deterministic state transition.
44
// TODO rename this module to `transition`
55

6+
use bitcoin::{Block, hashes::Hash};
67
use strata_asm_common::{
7-
AnchorState, AsmError, AsmManifest, AsmResult, AsmSpec, ChainViewState, VerifiedAuxData,
8+
AnchorState, AsmError, AsmManifest, AsmResult, AsmSpec, AuxData, ChainViewState,
9+
VerifiedAuxData,
810
};
11+
use strata_identifiers::Buf32;
912

1013
use crate::{
14+
group_txs_by_subprotocol,
1115
manager::{AnchorStateLoader, SubprotoManager},
1216
stage::{FinishStage, ProcessStage},
13-
types::{AsmStfInput, AsmStfOutput},
17+
types::AsmStfOutput,
1418
};
1519

1620
/// Computes the next AnchorState by applying the Anchor State Machine (ASM) state transition
1721
/// function (STF) to the given previous state and new L1 block.
1822
///
19-
/// This function performs the main ASM state transition by validating the block header continuity,
20-
/// loading subprotocols with auxiliary input data, processing protocol-specific transactions,
21-
/// handling inter-protocol communication, and constructing the final state with logs.
22-
pub fn compute_asm_transition<'i, S: AsmSpec>(
23+
/// This function performs the main ASM state transition by validating block integrity (merkle root,
24+
/// witness commitment) and header continuity, loading subprotocols with auxiliary input data,
25+
/// processing protocol-specific transactions, handling inter-protocol communication, and
26+
/// constructing the final state with logs.
27+
pub fn compute_asm_transition<S: AsmSpec>(
2328
spec: &S,
2429
pre_state: &AnchorState,
25-
input: AsmStfInput<'i>,
30+
block: &Block,
31+
aux_data: &AuxData,
2632
) -> AsmResult<AsmStfOutput> {
27-
// 1. Validate and update PoW header continuity for the new block.
33+
// 1. Validate that the block body merkle is consistent with the header.
34+
assert!(block.check_merkle_root() && block.check_witness_commitment());
35+
36+
// 2. Validate and update PoW header continuity for the new block.
2837
// This ensures the block header follows proper Bitcoin consensus rules and chain continuity.
2938
let (mut pow_state, mut history_accumulator) = pre_state.chain_view.clone().into_parts();
3039
pow_state
31-
.check_and_update(input.header)
40+
.check_and_update(&block.header)
3241
.map_err(AsmError::InvalidL1Header)?;
3342

3443
let verified_aux_data =
35-
VerifiedAuxData::try_new(&input.aux_data, &pre_state.chain_view.history_accumulator)?;
44+
VerifiedAuxData::try_new(aux_data, &pre_state.chain_view.history_accumulator)?;
3645

3746
// After `check_and_update`, `last_verified_block` points to the block we
3847
// just validated — i.e. the L1 block whose transactions we are about to
3948
// feed into subprotocols.
4049
let current_l1ref = &pow_state.last_verified_block;
4150

51+
// 3. Restructure the raw input to be formatted according to what we want.
52+
let protocol_txs = group_txs_by_subprotocol(spec.magic_bytes(), &block.txdata);
53+
4254
let mut manager = SubprotoManager::new();
4355

44-
// 2. LOAD: Initialize each subprotocol in the subproto manager with aux input data.
56+
// 4. LOAD: Initialize each subprotocol in the subproto manager with aux input data.
4557
let mut loader = AnchorStateLoader::new(pre_state, &mut manager);
4658
spec.load_subprotocols(&mut loader);
4759

48-
// 3. PROCESS: Feed each subprotocol its filtered transactions for execution.
60+
// 5. PROCESS: Feed each subprotocol its filtered transactions for execution.
4961
// This stage performs the actual state transitions for each subprotocol.
50-
let mut process_stage = ProcessStage::new(
51-
&mut manager,
52-
current_l1ref,
53-
input.protocol_txs,
54-
verified_aux_data,
55-
);
62+
let mut process_stage =
63+
ProcessStage::new(&mut manager, current_l1ref, protocol_txs, verified_aux_data);
5664
spec.call_subprotocols(&mut process_stage);
5765

58-
// 4. FINISH: Allow each subprotocol to process buffered inter-protocol messages.
66+
// 6. FINISH: Allow each subprotocol to process buffered inter-protocol messages.
5967
// This stage handles cross-protocol communication and finalizes state changes.
6068
// TODO probably will have change this to repeat the interproto message
6169
// processing phase until we have no more messages to deliver, or some
6270
// bounded number of times
6371
let mut finish_stage = FinishStage::new(&mut manager, &pow_state.last_verified_block);
6472
spec.call_subprotocols(&mut finish_stage);
6573

66-
// 5. Construct the manifest with the logs.
74+
// For blocks without witness data (pre-SegWit or legacy-only transactions),
75+
// the witness merkle root equals the transaction merkle root per Bitcoin protocol.
76+
let wtxids_root: Buf32 = block
77+
.witness_root()
78+
.map(|root| root.as_raw_hash().to_byte_array())
79+
.unwrap_or_else(|| block.header.merkle_root.as_raw_hash().to_byte_array())
80+
.into();
81+
82+
// 7. Construct the manifest with the logs.
6783
let (sections, logs) = manager.export_sections_and_logs();
6884
let manifest = AsmManifest::new(
6985
current_l1ref.height(),
7086
*current_l1ref.blkid(),
71-
input.wtxids_root.into(),
87+
wtxids_root.into(),
7288
logs,
7389
);
7490

75-
// 6. Append the manifest to the history accumulator
91+
// 8. Append the manifest to the history accumulator
7692
history_accumulator.add_manifest(&manifest)?;
7793

78-
// 7. Construct the final `AnchorState` and output.
94+
// 9. Construct the final `AnchorState` and output.
7995
let chain_view = ChainViewState {
8096
pow_state,
8197
history_accumulator,

crates/worker/src/state.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::sync::Arc;
22

3-
use bitcoin::{Block, hashes::Hash};
3+
use bitcoin::Block;
44
use strata_asm_common::{AnchorState, AsmHistoryAccumulatorState, AuxData, ChainViewState};
55
use strata_asm_params::AsmParams;
66
use strata_asm_spec::StrataAsmSpec;
7-
use strata_asm_stf::{AsmStfInput, AsmStfOutput};
7+
use strata_asm_stf::AsmStfOutput;
88
use strata_btc_verification::HeaderVerificationState;
9-
use strata_primitives::{Buf32, l1::L1BlockCommitment};
9+
use strata_primitives::l1::L1BlockCommitment;
1010
use strata_service::ServiceState;
1111
use strata_state::asm_state::AsmState;
1212
use tracing::field::Empty;
@@ -118,26 +118,11 @@ impl<W: WorkerContext + Send + Sync + 'static> AsmWorkerServiceState<W> {
118118
resolver.resolve(&pre_process.aux_requests)?
119119
};
120120

121-
// For blocks without witness data (pre-SegWit or legacy-only transactions),
122-
// the witness merkle root equals the transaction merkle root per Bitcoin protocol.
123-
let wtxids_root: Buf32 = block
124-
.witness_root()
125-
.map(|root| root.as_raw_hash().to_byte_array())
126-
.unwrap_or_else(|| block.header.merkle_root.as_raw_hash().to_byte_array())
127-
.into();
128-
129-
let stf_input = AsmStfInput {
130-
protocol_txs: pre_process.txs,
131-
header: &block.header,
132-
wtxids_root,
133-
aux_data: aux_data.clone(),
134-
};
135-
136121
// Asm transition.
137122
let stf_span = tracing::debug_span!("asm.stf.process");
138123
let _stf_guard = stf_span.enter();
139124

140-
strata_asm_stf::compute_asm_transition(&self.asm_spec, cur_state.state(), stf_input)
125+
strata_asm_stf::compute_asm_transition(&self.asm_spec, cur_state.state(), block, &aux_data)
141126
.map(|output| (output, aux_data))
142127
.map_err(WorkerError::AsmError)
143128
}

guest-builder/sp1/guest-asm/Cargo.lock

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

0 commit comments

Comments
 (0)