|
3 | 3 | //! view into a single deterministic state transition. |
4 | 4 | // TODO rename this module to `transition` |
5 | 5 |
|
| 6 | +use bitcoin::{Block, hashes::Hash}; |
6 | 7 | use strata_asm_common::{ |
7 | | - AnchorState, AsmError, AsmManifest, AsmResult, AsmSpec, ChainViewState, VerifiedAuxData, |
| 8 | + AnchorState, AsmError, AsmManifest, AsmResult, AsmSpec, AuxData, ChainViewState, |
| 9 | + VerifiedAuxData, |
8 | 10 | }; |
| 11 | +use strata_identifiers::Buf32; |
9 | 12 |
|
10 | 13 | use crate::{ |
| 14 | + group_txs_by_subprotocol, |
11 | 15 | manager::{AnchorStateLoader, SubprotoManager}, |
12 | 16 | stage::{FinishStage, ProcessStage}, |
13 | | - types::{AsmStfInput, AsmStfOutput}, |
| 17 | + types::AsmStfOutput, |
14 | 18 | }; |
15 | 19 |
|
16 | 20 | /// Computes the next AnchorState by applying the Anchor State Machine (ASM) state transition |
17 | 21 | /// function (STF) to the given previous state and new L1 block. |
18 | 22 | /// |
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>( |
23 | 28 | spec: &S, |
24 | 29 | pre_state: &AnchorState, |
25 | | - input: AsmStfInput<'i>, |
| 30 | + block: &Block, |
| 31 | + aux_data: &AuxData, |
26 | 32 | ) -> 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. |
28 | 37 | // This ensures the block header follows proper Bitcoin consensus rules and chain continuity. |
29 | 38 | let (mut pow_state, mut history_accumulator) = pre_state.chain_view.clone().into_parts(); |
30 | 39 | pow_state |
31 | | - .check_and_update(input.header) |
| 40 | + .check_and_update(&block.header) |
32 | 41 | .map_err(AsmError::InvalidL1Header)?; |
33 | 42 |
|
34 | 43 | 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)?; |
36 | 45 |
|
37 | 46 | // After `check_and_update`, `last_verified_block` points to the block we |
38 | 47 | // just validated — i.e. the L1 block whose transactions we are about to |
39 | 48 | // feed into subprotocols. |
40 | 49 | let current_l1ref = &pow_state.last_verified_block; |
41 | 50 |
|
| 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 | + |
42 | 54 | let mut manager = SubprotoManager::new(); |
43 | 55 |
|
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. |
45 | 57 | let mut loader = AnchorStateLoader::new(pre_state, &mut manager); |
46 | 58 | spec.load_subprotocols(&mut loader); |
47 | 59 |
|
48 | | - // 3. PROCESS: Feed each subprotocol its filtered transactions for execution. |
| 60 | + // 5. PROCESS: Feed each subprotocol its filtered transactions for execution. |
49 | 61 | // 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); |
56 | 64 | spec.call_subprotocols(&mut process_stage); |
57 | 65 |
|
58 | | - // 4. FINISH: Allow each subprotocol to process buffered inter-protocol messages. |
| 66 | + // 6. FINISH: Allow each subprotocol to process buffered inter-protocol messages. |
59 | 67 | // This stage handles cross-protocol communication and finalizes state changes. |
60 | 68 | // TODO probably will have change this to repeat the interproto message |
61 | 69 | // processing phase until we have no more messages to deliver, or some |
62 | 70 | // bounded number of times |
63 | 71 | let mut finish_stage = FinishStage::new(&mut manager, &pow_state.last_verified_block); |
64 | 72 | spec.call_subprotocols(&mut finish_stage); |
65 | 73 |
|
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. |
67 | 83 | let (sections, logs) = manager.export_sections_and_logs(); |
68 | 84 | let manifest = AsmManifest::new( |
69 | 85 | current_l1ref.height(), |
70 | 86 | *current_l1ref.blkid(), |
71 | | - input.wtxids_root.into(), |
| 87 | + wtxids_root.into(), |
72 | 88 | logs, |
73 | 89 | ); |
74 | 90 |
|
75 | | - // 6. Append the manifest to the history accumulator |
| 91 | + // 8. Append the manifest to the history accumulator |
76 | 92 | history_accumulator.add_manifest(&manifest)?; |
77 | 93 |
|
78 | | - // 7. Construct the final `AnchorState` and output. |
| 94 | + // 9. Construct the final `AnchorState` and output. |
79 | 95 | let chain_view = ChainViewState { |
80 | 96 | pow_state, |
81 | 97 | history_accumulator, |
|
0 commit comments