Skip to content

Commit e1cb212

Browse files
committed
impl SubprotocolManager trait to pass to each stage
1 parent e252e90 commit e1cb212

File tree

6 files changed

+150
-109
lines changed

6 files changed

+150
-109
lines changed

crates/asm/common/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ mod state;
88
mod subprotocol;
99
mod tx;
1010

11-
pub use error::AsmError;
12-
pub use msg::{InterprotoMsg, Log, NullMsg};
13-
pub use spec::{AsmSpec, Stage};
14-
pub use state::{AnchorState, ChainViewState, SectionState};
15-
pub use subprotocol::{MsgRelayer, Subprotocol, SubprotocolId};
16-
pub use tx::{TagPayload, TxInput};
11+
pub use error::*;
12+
pub use msg::*;
13+
pub use spec::*;
14+
pub use state::*;
15+
pub use subprotocol::*;
16+
pub use tx::*;

crates/asm/common/src/spec.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::Subprotocol;
1+
use crate::{Subprotocol, SubprotocolManager};
22

33
/// Specification for a concrete ASM instantiation describing the subprotocols we
44
/// want to invoke and in what order.
@@ -8,11 +8,11 @@ use crate::Subprotocol;
88
pub trait AsmSpec {
99
/// Function that calls the loader with each subprotocol we intend to
1010
/// process, in the order we intend to process them.
11-
fn call_subprotocols(stage: &mut impl Stage);
11+
fn call_subprotocols(stage: &mut impl Stage, manager: &mut impl SubprotocolManager);
1212
}
1313

1414
/// Implementation of a subprotocol handling stage.
1515
pub trait Stage {
1616
/// Invoked by the ASM spec to perform logic relating to a specific subprotocol.
17-
fn process_subprotocol<S: Subprotocol>(&mut self);
17+
fn process_subprotocol<S: Subprotocol>(&mut self, manager: &mut impl SubprotocolManager);
1818
}

crates/asm/common/src/subprotocol.rs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::any::Any;
88

99
use borsh::{BorshDeserialize, BorshSerialize};
1010

11-
use crate::{Log, TxInput, msg::InterprotoMsg};
11+
use crate::{AsmError, Log, SectionState, TxInput, msg::InterprotoMsg};
1212

1313
/// Identifier for a subprotocol.
1414
pub type SubprotocolId = u8;
@@ -57,3 +57,93 @@ pub trait MsgRelayer: Any {
5757
/// Gets this msg relayer as a `&dyn Any`.
5858
fn as_mut_any(&mut self) -> &mut dyn Any;
5959
}
60+
61+
/// Subprotocol handler trait for a loaded subprotocol.
62+
pub trait SubprotoHandler {
63+
/// Processes transactions that were previously collected.
64+
fn process_txs(&mut self, txs: &[TxInput<'_>], relayer: &mut dyn MsgRelayer);
65+
66+
/// Accepts a message. This is called while processing other subprotocols.
67+
/// These should not be processed until we do the finalization.
68+
///
69+
/// This MUST NOT act on any messages that were accepted before this was
70+
/// called.
71+
///
72+
/// # Panics
73+
///
74+
/// If an mismatched message type (behind the `dyn`) is provided.
75+
fn accept_msg(&mut self, msg: &dyn InterprotoMsg);
76+
77+
/// Processes the messages received.
78+
fn process_msgs(&mut self);
79+
80+
/// Repacks the state into a [`SectionState`] instance.
81+
fn to_section(&self) -> SectionState;
82+
}
83+
84+
/// Manages the lifecycle and execution of subprotocol handlers in the Anchor State Machine (ASM).
85+
///
86+
/// Implementors of this trait maintain a collection of subprotocol handlers and
87+
/// provide methods to insert, remove, lookup, and drive execution (transactions and messages),
88+
/// as well as extract the final `SectionState`.
89+
pub trait SubprotocolManager: MsgRelayer + Sized {
90+
/// Inserts a new subprotocol by consuming its initial state and creating its handler.
91+
fn insert_subproto<S: Subprotocol>(&mut self, state: S::State);
92+
93+
/// Inserts a boxed handler directly.
94+
fn insert_handler<S: Subprotocol>(&mut self, handler: Box<dyn SubprotoHandler>);
95+
96+
/// Removes and returns the handler for the given `id`.
97+
///
98+
/// # Errors
99+
///
100+
/// Returns `AsmError::InvalidSubprotocol(id)` if no handler with that ID is present.
101+
fn remove_handler(&mut self, id: SubprotocolId) -> Result<Box<dyn SubprotoHandler>, AsmError>;
102+
103+
/// Retrieves an immutable reference to the handler for the given `id`.
104+
///
105+
/// # Errors
106+
///
107+
/// Returns `AsmError::InvalidSubprotocol(id)` if no handler with that ID is present.
108+
fn get_handler(&self, id: SubprotocolId) -> Result<&dyn SubprotoHandler, AsmError>;
109+
110+
/// Retrieves a mutable reference to the handler for the given `id`.
111+
///
112+
/// # Errors
113+
///
114+
/// Returns `AsmError::InvalidSubprotocol(id)` if no handler with that ID is present.
115+
fn get_handler_mut(
116+
&mut self,
117+
id: SubprotocolId,
118+
) -> Result<&mut Box<dyn SubprotoHandler>, AsmError>;
119+
120+
/// Dispatches transaction processing to the appropriate handler.
121+
///
122+
/// This default implementation temporarily removes the handler to satisfy
123+
/// borrow-checker constraints, invokes `process_txs` with `self` as the relayer,
124+
/// and then reinserts the handler.
125+
fn invoke_process_txs<S: Subprotocol>(&mut self, txs: &[TxInput<'_>]) {
126+
// We temporarily take the handler out of the map so we can call
127+
// `process_txs` with `self` as the relayer without violating the
128+
// borrow checker.
129+
let mut h = self
130+
.remove_handler(S::ID)
131+
.expect("asm: unloaded subprotocol");
132+
h.process_txs(txs, self);
133+
self.insert_handler::<S>(h);
134+
}
135+
136+
/// Dispatches buffered inter-protocol message processing to the handler.
137+
fn invoke_process_msgs<S: Subprotocol>(&mut self) {
138+
let h = self
139+
.get_handler_mut(S::ID)
140+
.expect("asm: unloaded subprotocol");
141+
h.process_msgs()
142+
}
143+
144+
/// Extracts the finalized `SectionState` from the handler.
145+
fn to_section_state<S: Subprotocol>(&self) -> SectionState {
146+
let h = self.get_handler(S::ID).expect("asm: unloaded subprotocol");
147+
h.to_section()
148+
}
149+
}

crates/asm/stf/src/handler.rs

Lines changed: 23 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,10 @@
33
use std::{any::Any, collections::BTreeMap};
44

55
use strata_asm_common::{
6-
AsmError, InterprotoMsg, Log, MsgRelayer, SectionState, Subprotocol, SubprotocolId, TxInput,
6+
AsmError, InterprotoMsg, Log, MsgRelayer, SectionState, SubprotoHandler, Subprotocol,
7+
SubprotocolId, SubprotocolManager, TxInput,
78
};
89

9-
/// Subprotocol handler trait for a loaded subprotocol.
10-
pub(crate) trait SubprotoHandler {
11-
/// Processes transactions that were previously collected.
12-
fn process_txs(&mut self, txs: &[TxInput<'_>], relayer: &mut dyn MsgRelayer);
13-
14-
/// Accepts a message. This is called while processing other subprotocols.
15-
/// These should not be processed until we do the finalization.
16-
///
17-
/// This MUST NOT act on any messages that were accepted before this was
18-
/// called.
19-
///
20-
/// # Panics
21-
///
22-
/// If an mismatched message type (behind the `dyn`) is provided.
23-
fn accept_msg(&mut self, msg: &dyn InterprotoMsg);
24-
25-
/// Processes the messages received.
26-
fn process_msgs(&mut self);
27-
28-
/// Repacks the state into a [`SectionState`] instance.
29-
fn to_section(&self) -> SectionState;
30-
}
31-
3210
/// Wrapper around the common subprotocol interface that handles the common
3311
/// buffering logic for interproto messages.
3412
pub(crate) struct HandlerImpl<S: Subprotocol, R> {
@@ -84,60 +62,48 @@ pub(crate) struct HandlerRelayer {
8462
logs: Vec<Log>,
8563
}
8664

87-
impl HandlerRelayer {
88-
pub(crate) fn new() -> Self {
89-
Self {
90-
handlers: BTreeMap::new(),
91-
logs: Vec::new(),
92-
}
93-
}
94-
65+
impl SubprotocolManager for HandlerRelayer {
9566
/// Inserts a subproto by creating a handler for it.
96-
pub(crate) fn insert_subproto<S: Subprotocol>(&mut self, state: S::State) {
67+
fn insert_subproto<S: Subprotocol>(&mut self, state: S::State) {
9768
let handler = HandlerImpl::<S, Self>::from_state(state);
9869
if self.handlers.insert(S::ID, Box::new(handler)).is_some() {
9970
panic!("asm: loaded state twice");
10071
}
10172
}
10273

103-
pub(crate) fn get_handler(&self, id: SubprotocolId) -> Result<&dyn SubprotoHandler, AsmError> {
74+
fn insert_handler<S: Subprotocol>(&mut self, handler: Box<dyn SubprotoHandler>) {
75+
self.handlers.insert(S::ID, handler);
76+
}
77+
78+
fn remove_handler(&mut self, id: SubprotocolId) -> Result<Box<dyn SubprotoHandler>, AsmError> {
79+
self.handlers
80+
.remove(&id)
81+
.ok_or(AsmError::InvalidSubprotocol(id))
82+
}
83+
84+
fn get_handler(&self, id: SubprotocolId) -> Result<&dyn SubprotoHandler, AsmError> {
10485
self.handlers
10586
.get(&id)
10687
.map(Box::as_ref)
10788
.ok_or(AsmError::InvalidSubprotocol(id))
10889
}
10990

110-
pub(crate) fn get_handler_mut(
91+
fn get_handler_mut(
11192
&mut self,
11293
id: SubprotocolId,
11394
) -> Result<&mut Box<dyn SubprotoHandler>, AsmError> {
11495
self.handlers
11596
.get_mut(&id)
11697
.ok_or(AsmError::InvalidSubprotocol(id))
11798
}
99+
}
118100

119-
pub(crate) fn invoke_process_txs<S: Subprotocol>(&mut self, txs: &[TxInput<'_>]) {
120-
// We temporarily take the handler out of the map so we can call
121-
// `process_txs` with `self` as the relayer without violating the
122-
// borrow checker.
123-
let mut h = self
124-
.handlers
125-
.remove(&S::ID)
126-
.expect("asm: unloaded subprotocol");
127-
h.process_txs(txs, self);
128-
self.handlers.insert(S::ID, h);
129-
}
130-
131-
pub(crate) fn invoke_process_msgs<S: Subprotocol>(&mut self) {
132-
let h = self
133-
.get_handler_mut(S::ID)
134-
.expect("asm: unloaded subprotocol");
135-
h.process_msgs()
136-
}
137-
138-
pub(crate) fn to_section_state<S: Subprotocol>(&self) -> SectionState {
139-
let h = self.get_handler(S::ID).expect("asm: unloaded subprotocol");
140-
h.to_section()
101+
impl HandlerRelayer {
102+
pub(crate) fn new() -> Self {
103+
Self {
104+
handlers: BTreeMap::new(),
105+
logs: Vec::new(),
106+
}
141107
}
142108
}
143109

crates/asm/stf/src/stage.rs

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,23 @@
33

44
use std::collections::BTreeMap;
55

6-
use strata_asm_common::{AnchorState, SectionState, Stage, Subprotocol, SubprotocolId, TxInput};
7-
8-
use crate::handler::HandlerRelayer;
6+
use strata_asm_common::{
7+
AnchorState, SectionState, Stage, Subprotocol, SubprotocolId, SubprotocolManager, TxInput,
8+
};
99

1010
/// Stage that loads each subprotocol from the anchor state we're basing off of.
1111
pub(crate) struct SubprotoLoaderStage<'a> {
1212
anchor_state: &'a AnchorState,
13-
handler: HandlerRelayer,
1413
}
1514

1615
impl<'a> SubprotoLoaderStage<'a> {
1716
pub(crate) fn new(anchor_state: &'a AnchorState) -> Self {
18-
Self {
19-
anchor_state,
20-
handler: HandlerRelayer::new(),
21-
}
22-
}
23-
24-
pub(crate) fn into_handler(self) -> HandlerRelayer {
25-
self.handler
17+
Self { anchor_state }
2618
}
2719
}
2820

2921
impl Stage for SubprotoLoaderStage<'_> {
30-
fn process_subprotocol<S: Subprotocol>(&mut self) {
22+
fn process_subprotocol<S: Subprotocol>(&mut self, manager: &mut impl SubprotocolManager) {
3123
// Load or create the subprotocol state.
3224
// OPTIMIZE: Linear scan is done every time to find the section
3325
let state = match self.anchor_state.find_section(S::ID) {
@@ -37,50 +29,41 @@ impl Stage for SubprotoLoaderStage<'_> {
3729
None => S::init(),
3830
};
3931

40-
self.handler.insert_subproto::<S>(state);
32+
manager.insert_subproto::<S>(state);
4133
}
4234
}
4335

4436
/// Stage to process txs pre-extracted from the block for each subprotocol.
4537
pub(crate) struct ProcessStage<'b> {
4638
tx_bufs: BTreeMap<SubprotocolId, Vec<TxInput<'b>>>,
47-
handler: HandlerRelayer,
4839
}
4940

5041
impl<'b> ProcessStage<'b> {
51-
pub(crate) fn new(
52-
tx_bufs: BTreeMap<SubprotocolId, Vec<TxInput<'b>>>,
53-
handler: HandlerRelayer,
54-
) -> Self {
55-
Self { tx_bufs, handler }
56-
}
57-
58-
pub(crate) fn into_handler(self) -> HandlerRelayer {
59-
self.handler
42+
pub(crate) fn new(tx_bufs: BTreeMap<SubprotocolId, Vec<TxInput<'b>>>) -> Self {
43+
Self { tx_bufs }
6044
}
6145
}
6246

6347
impl Stage for ProcessStage<'_> {
64-
fn process_subprotocol<S: Subprotocol>(&mut self) {
48+
fn process_subprotocol<S: Subprotocol>(&mut self, manager: &mut impl SubprotocolManager) {
6549
let txs = self
6650
.tx_bufs
6751
.get(&S::ID)
6852
.map(|v| v.as_slice())
6953
.unwrap_or(&[]);
70-
self.handler.invoke_process_txs::<S>(txs);
54+
manager.invoke_process_txs::<S>(txs);
7155
}
7256
}
7357

7458
/// Stage to handle messages exchanged between subprotocols in execution.
7559
pub(crate) struct FinishStage {
76-
handler: HandlerRelayer,
7760
sections: Vec<SectionState>,
7861
}
7962

8063
impl FinishStage {
81-
pub(crate) fn new(handler: HandlerRelayer) -> Self {
64+
pub(crate) fn new() -> Self {
8265
let sections = Vec::new();
83-
Self { handler, sections }
66+
Self { sections }
8467
}
8568

8669
pub(crate) fn into_sections(self) -> Vec<SectionState> {
@@ -89,9 +72,9 @@ impl FinishStage {
8972
}
9073

9174
impl Stage for FinishStage {
92-
fn process_subprotocol<S: Subprotocol>(&mut self) {
93-
self.handler.invoke_process_msgs::<S>();
94-
let section = self.handler.to_section_state::<S>();
75+
fn process_subprotocol<S: Subprotocol>(&mut self, manager: &mut impl SubprotocolManager) {
76+
manager.invoke_process_msgs::<S>();
77+
let section = manager.to_section_state::<S>();
9578
self.sections.push(section);
9679
}
9780
}

0 commit comments

Comments
 (0)