Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/proof/statements/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ strata-asm-spec.workspace = true
strata-asm-stf.workspace = true
strata-btc-types = { workspace = true, optional = true }
strata-btc-verification = { workspace = true, optional = true }
strata-identifiers.workspace = true
strata-identifiers = { workspace = true, optional = true }
strata-l1-txfmt = { workspace = true, optional = true }
strata-predicate.workspace = true
strata-test-utils-btc = { workspace = true, optional = true }
Expand All @@ -40,6 +40,7 @@ test-utils = [
"dep:strata-btc-verification",
"dep:strata-l1-txfmt",
"dep:strata-test-utils-btc",
"dep:strata-identifiers",
]

[dev-dependencies]
Expand Down
49 changes: 7 additions & 42 deletions crates/proof/statements/src/moho_program/program.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
//! [`MohoProgram`] implementation for the ASM STF.
//!
//! This module contains the [`AsmStfProgram`] type that implements [`MohoProgram`], wiring the
//! ASM state transition function into the Moho runtime. It handles block validation, state
//! commitment via SHA-256, transition execution, and extraction of post-transition artifacts
//! such as predicate updates and export state entries.
use bitcoin::hashes::Hash;
//! ASM state transition function into the Moho runtime. It handles state commitment via SHA-256,
//! transition execution, and extraction of post-transition artifacts such as predicate updates
//! and export state entries.
use moho_runtime_interface::MohoProgram;
use moho_types::{ExportState, InnerStateCommitment, StateReference};
use sha2::{Digest, Sha256};
use strata_asm_common::{AnchorState, AsmSpec};
use strata_asm_common::AnchorState;
use strata_asm_logs::{AsmStfUpdate, NewExportEntry};
use strata_asm_spec::StrataAsmSpec;
use strata_asm_stf::{compute_asm_transition, group_txs_by_subprotocol, AsmStfInput, AsmStfOutput};
use strata_identifiers::Buf32;
use strata_asm_stf::{compute_asm_transition, AsmStfOutput};
use strata_predicate::PredicateKey;

use crate::moho_program::input::AsmStepInput;
Expand Down Expand Up @@ -53,41 +51,8 @@ impl MohoProgram for AsmStfProgram {
spec: &StrataAsmSpec,
input: &AsmStepInput,
) -> AsmStfOutput {
// TODO: (@prajworlg) Consolidate block validation logic in a single place
// https://alpenlabs.atlassian.net/browse/STR-2619

// 1. Validate the input
assert!(input.validate_block());

// For blocks without witness data (pre-SegWit or legacy-only transactions),
// the witness merkle root equals the transaction merkle root per Bitcoin protocol.
let wtxids_root: Buf32 = input
.block
.0
.witness_root()
.map(|root| root.as_raw_hash().to_byte_array())
.unwrap_or_else(|| {
input
.block
.0
.header
.merkle_root
.as_raw_hash()
.to_byte_array()
})
.into();

// 2. Restructure the raw input to be formatted according to what we want.
let protocol_txs = group_txs_by_subprotocol(spec.magic_bytes(), &input.block.0.txdata);
let stf_input = AsmStfInput {
protocol_txs,
header: &input.block.0.header,
aux_data: input.aux_data.clone(),
wtxids_root,
};

// 3. Actually invoke the ASM state transition function.
compute_asm_transition(spec, pre_state, stf_input).expect("asm: compute transition")
compute_asm_transition(spec, pre_state, &input.block.0, &input.aux_data)
.expect("asm: compute transition")
}

fn extract_post_state(output: &Self::StepOutput) -> &Self::State {
Expand Down
62 changes: 39 additions & 23 deletions crates/stf/src/stf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,79 +3,95 @@
//! view into a single deterministic state transition.
// TODO rename this module to `transition`

use bitcoin::{Block, hashes::Hash};
use strata_asm_common::{
AnchorState, AsmError, AsmManifest, AsmResult, AsmSpec, ChainViewState, VerifiedAuxData,
AnchorState, AsmError, AsmManifest, AsmResult, AsmSpec, AuxData, ChainViewState,
VerifiedAuxData,
};
use strata_identifiers::Buf32;

use crate::{
group_txs_by_subprotocol,
manager::{AnchorStateLoader, SubprotoManager},
stage::{FinishStage, ProcessStage},
types::{AsmStfInput, AsmStfOutput},
types::AsmStfOutput,
};

/// Computes the next AnchorState by applying the Anchor State Machine (ASM) state transition
/// function (STF) to the given previous state and new L1 block.
///
/// This function performs the main ASM state transition by validating the block header continuity,
/// loading subprotocols with auxiliary input data, processing protocol-specific transactions,
/// handling inter-protocol communication, and constructing the final state with logs.
pub fn compute_asm_transition<'i, S: AsmSpec>(
/// This function performs the main ASM state transition by validating block integrity (merkle root,
/// witness commitment) and header continuity, loading subprotocols with auxiliary input data,
/// processing protocol-specific transactions, handling inter-protocol communication, and
/// constructing the final state with logs.
pub fn compute_asm_transition<S: AsmSpec>(
spec: &S,
pre_state: &AnchorState,
input: AsmStfInput<'i>,
block: &Block,
aux_data: &AuxData,
) -> AsmResult<AsmStfOutput> {
// 1. Validate and update PoW header continuity for the new block.
// 1. Validate that the block body merkle is consistent with the header.
assert!(block.check_merkle_root() && block.check_witness_commitment());

// 2. Validate and update PoW header continuity for the new block.
// This ensures the block header follows proper Bitcoin consensus rules and chain continuity.
let (mut pow_state, mut history_accumulator) = pre_state.chain_view.clone().into_parts();
pow_state
.check_and_update(input.header)
.check_and_update(&block.header)
.map_err(AsmError::InvalidL1Header)?;

let verified_aux_data =
VerifiedAuxData::try_new(&input.aux_data, &pre_state.chain_view.history_accumulator)?;
VerifiedAuxData::try_new(aux_data, &pre_state.chain_view.history_accumulator)?;

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

// 3. Restructure the raw input to be formatted according to what we want.
let protocol_txs = group_txs_by_subprotocol(spec.magic_bytes(), &block.txdata);

let mut manager = SubprotoManager::new();

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

// 3. PROCESS: Feed each subprotocol its filtered transactions for execution.
// 5. PROCESS: Feed each subprotocol its filtered transactions for execution.
// This stage performs the actual state transitions for each subprotocol.
let mut process_stage = ProcessStage::new(
&mut manager,
current_l1ref,
input.protocol_txs,
verified_aux_data,
);
let mut process_stage =
ProcessStage::new(&mut manager, current_l1ref, protocol_txs, verified_aux_data);
spec.call_subprotocols(&mut process_stage);

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

// 5. Construct the manifest with the logs.
// For blocks without witness data (pre-SegWit or legacy-only transactions),
// the witness merkle root equals the transaction merkle root per Bitcoin protocol.
let wtxids_root: Buf32 = block
.witness_root()
.map(|root| root.as_raw_hash().to_byte_array())
.unwrap_or_else(|| block.header.merkle_root.as_raw_hash().to_byte_array())
.into();

// 7. Construct the manifest with the logs.
let (sections, logs) = manager.export_sections_and_logs();
let manifest = AsmManifest::new(
current_l1ref.height(),
*current_l1ref.blkid(),
input.wtxids_root.into(),
wtxids_root.into(),
logs,
);

// 6. Append the manifest to the history accumulator
// 8. Append the manifest to the history accumulator
history_accumulator.add_manifest(&manifest)?;

// 7. Construct the final `AnchorState` and output.
// 9. Construct the final `AnchorState` and output.
let chain_view = ChainViewState {
pow_state,
history_accumulator,
Expand Down
23 changes: 4 additions & 19 deletions crates/worker/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::sync::Arc;

use bitcoin::{Block, hashes::Hash};
use bitcoin::Block;
use strata_asm_common::{AnchorState, AsmHistoryAccumulatorState, AuxData, ChainViewState};
use strata_asm_params::AsmParams;
use strata_asm_spec::StrataAsmSpec;
use strata_asm_stf::{AsmStfInput, AsmStfOutput};
use strata_asm_stf::AsmStfOutput;
use strata_btc_verification::HeaderVerificationState;
use strata_primitives::{Buf32, l1::L1BlockCommitment};
use strata_primitives::l1::L1BlockCommitment;
use strata_service::ServiceState;
use strata_state::asm_state::AsmState;
use tracing::field::Empty;
Expand Down Expand Up @@ -118,26 +118,11 @@ impl<W: WorkerContext + Send + Sync + 'static> AsmWorkerServiceState<W> {
resolver.resolve(&pre_process.aux_requests)?
};

// For blocks without witness data (pre-SegWit or legacy-only transactions),
// the witness merkle root equals the transaction merkle root per Bitcoin protocol.
let wtxids_root: Buf32 = block
.witness_root()
.map(|root| root.as_raw_hash().to_byte_array())
.unwrap_or_else(|| block.header.merkle_root.as_raw_hash().to_byte_array())
.into();

let stf_input = AsmStfInput {
protocol_txs: pre_process.txs,
header: &block.header,
wtxids_root,
aux_data: aux_data.clone(),
};

// Asm transition.
let stf_span = tracing::debug_span!("asm.stf.process");
let _stf_guard = stf_span.enter();

strata_asm_stf::compute_asm_transition(&self.asm_spec, cur_state.state(), stf_input)
strata_asm_stf::compute_asm_transition(&self.asm_spec, cur_state.state(), block, &aux_data)
.map(|output| (output, aux_data))
.map_err(WorkerError::AsmError)
}
Expand Down
1 change: 0 additions & 1 deletion guest-builder/sp1/guest-asm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading