Skip to content

Commit a91d599

Browse files
add HOW_IT_WORKS.md
1 parent fee97d9 commit a91d599

File tree

1 file changed

+313
-0
lines changed

1 file changed

+313
-0
lines changed

HOW_IT_WORKS.md

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
# How It Works: EOA Worker Transaction Processing
2+
3+
## Overview
4+
5+
The EOA (Externally Owned Account) Worker is a single worker per EOA:chain combination that processes all transactions for that specific EOA. It manages transaction lifecycle from queuing to confirmation, with robust error handling and nonce management.
6+
7+
## Core Architecture
8+
9+
### Data Structures
10+
11+
The worker maintains several key data structures:
12+
13+
- **`pending_txns`**: Queue of transaction IDs waiting to be sent
14+
- **`success_txns`**: Sorted set mapping nonces to transaction hashes for sent transactions
15+
- **`hash_to_id`**: Hash map from transaction hash to transaction ID
16+
- **`tx_data`**: Hash map from transaction ID to full transaction JSON data
17+
- **`borrowed_txns`**: Hash map for crash recovery of prepared transactions
18+
- **`recycled_nonces`**: Sorted set of available recycled nonces
19+
- **`optimistic_nonce`**: Next nonce to use for new transactions
20+
- **`last_chain_nonce`**: Cached chain nonce for comparison
21+
- **`eoa_health`**: Health status including funding state and last check timestamp
22+
23+
### Main Worker Loop
24+
25+
The worker runs in a continuous loop with three main phases:
26+
27+
1. **Recovery Phase**: Recovers any borrowed transactions from crashes
28+
2. **Confirmation Phase**: Checks for mined transactions and handles failures
29+
3. **Send Phase**: Sends new transactions while managing nonce allocation
30+
31+
## Transaction Flow Diagram
32+
33+
```mermaid
34+
flowchart TD
35+
A["🚀 EOA Worker Start"] --> B["Main Worker Loop"]
36+
B --> C["1. Recover Borrowed State"]
37+
B --> D["2. Confirm Flow"]
38+
B --> E["3. Send Flow"]
39+
B --> F["💤 Sleep(WORKER_CYCLE_DELAY)"]
40+
F --> B
41+
42+
%% Recovery Flow
43+
C --> C1["Check borrowed_txns"]
44+
C1 --> C2{Any borrowed<br/>transactions?}
45+
C2 -->|Yes| C3["For each borrowed tx:<br/>Rebroadcast prepared_tx"]
46+
C2 -->|No| D
47+
C3 --> C4["RPC Send Transaction"]
48+
C4 --> C5{Result Type?}
49+
C5 -->|Deterministic Failure| C6["❌ Requeue to pending_txns<br/>Add nonce to recycled_nonces"]
50+
C5 -->|Success/Indeterminate| C7["✅ Add to success_txns<br/>Update hash_to_id"]
51+
C6 --> C8["Remove from borrowed_txns"]
52+
C7 --> C8
53+
C8 --> C9{More borrowed<br/>transactions?}
54+
C9 -->|Yes| C3
55+
C9 -->|No| D
56+
57+
%% Confirmation Flow
58+
D --> D1["Get current_chain_nonce"]
59+
D1 --> D2{Chain nonce<br/>changed?}
60+
D2 -->|No| E
61+
D2 -->|Yes| D3["Get pending hashes for<br/>nonces < current_chain_nonce"]
62+
D3 --> D4["For each pending hash:<br/>Get transaction receipt"]
63+
D4 --> D5{Receipt exists?}
64+
D5 -->|Yes| D6["✅ Transaction mined<br/>Add to confirmed_tx_ids<br/>Cleanup success_txns"]
65+
D5 -->|No| D7["❌ Transaction failed<br/>Add to failed_tx_ids"]
66+
D6 --> D8{More hashes<br/>to check?}
67+
D7 --> D8
68+
D8 -->|Yes| D4
69+
D8 -->|No| D9["Requeue failed transactions<br/>to pending_txns"]
70+
D9 --> D10["Update last_chain_nonce"]
71+
D10 --> E
72+
73+
%% Send Flow
74+
E --> E1["Check EOA Health"]
75+
E1 --> E2{EOA funded?}
76+
E2 -->|No| B
77+
E2 -->|Yes| E3["Process Recycled Nonces"]
78+
E3 --> E4["Check in-flight count"]
79+
E4 --> E5{Too many<br/>in-flight?}
80+
E5 -->|Yes| B
81+
E5 -->|No| E6["Process New Transactions"]
82+
E6 --> B
83+
84+
%% Process Recycled Nonces
85+
E3 --> E3A{recycled_nonces<br/>> MAX_RECYCLED?}
86+
E3A -->|Yes| E3B["🧹 Clear all recycled nonces"]
87+
E3A -->|No| E3C{recycled_nonces > 0<br/>AND pending_txns > 0?}
88+
E3B --> E4
89+
E3C -->|Yes| E3D["Pop min nonce<br/>Dequeue tx_id"]
90+
E3C -->|No| E3E{Still recycled<br/>nonces?}
91+
E3D --> E3F["Send transaction with nonce"]
92+
E3F --> E3C
93+
E3E -->|Yes| E3G["Send no-op transaction"]
94+
E3E -->|No| E4
95+
E3G --> E3E
96+
97+
%% Process New Transactions
98+
E6 --> E6A{sent_count < max_count<br/>AND pending_txns > 0?}
99+
E6A -->|Yes| E6B["Dequeue tx_id<br/>Get next nonce"]
100+
E6A -->|No| B
101+
E6B --> E6C["Send transaction with nonce"]
102+
E6C --> E6D["Increment sent_count"]
103+
E6D --> E6A
104+
105+
%% Send Transaction with Nonce
106+
E3F --> ST1["Get transaction data"]
107+
E6C --> ST1
108+
E3G --> ST1
109+
ST1 --> ST2["Prepare complete transaction"]
110+
ST2 --> ST3["Store in borrowed_txns"]
111+
ST3 --> ST4["RPC Send Transaction"]
112+
ST4 --> ST5{Result Type?}
113+
ST5 -->|Deterministic Failure| ST6["❌ Requeue tx_id<br/>Add nonce to recycled<br/>Mark EOA unfunded"]
114+
ST5 -->|Success/Indeterminate| ST7["✅ Add to success_txns<br/>Update hash_to_id"]
115+
ST6 --> ST8["Remove from borrowed_txns"]
116+
ST7 --> ST8
117+
ST8 --> ST9["Return to caller"]
118+
119+
%% Health Check
120+
E1 --> E1A{Time since last<br/>check > threshold?}
121+
E1A -->|Yes| E1B["Get EOA balance"]
122+
E1A -->|No| E2
123+
E1B --> E1C["Update eoa_health.funded<br/>Update last_check"]
124+
E1C --> E2
125+
126+
%% Styling
127+
classDef startEnd fill:#e1f5fe,stroke:#01579b,stroke-width:2px
128+
classDef process fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
129+
classDef decision fill:#fff3e0,stroke:#e65100,stroke-width:2px
130+
classDef success fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
131+
classDef failure fill:#ffebee,stroke:#c62828,stroke-width:2px
132+
classDef cleanup fill:#f1f8e9,stroke:#558b2f,stroke-width:2px
133+
134+
class A,B,F startEnd
135+
class C,D,E,E1,E3,E4,E6,C1,C3,C4,D1,D3,D4,D9,D10,E3D,E3F,E6B,E6C,E6D,ST1,ST2,ST3,ST4,E1B,E1C process
136+
class C2,C5,C9,D2,D5,D8,E2,E5,E3A,E3C,E3E,E6A,ST5,E1A decision
137+
class C7,D6,ST7 success
138+
class C6,D7,ST6 failure
139+
class C8,D9,E3B,ST8,ST9 cleanup
140+
```
141+
142+
The above diagram illustrates the complete transaction processing flow. The worker operates in a continuous loop, processing three main phases sequentially.
143+
144+
## Detailed Phase Breakdown
145+
146+
### 1. Recovery Phase (`recover_borrowed_state`)
147+
148+
**Purpose**: Recover from crashes by handling any transactions that were prepared but not fully processed.
149+
150+
**Process**:
151+
152+
- Iterates through all transactions in `borrowed_txns`
153+
- Rebroadcasts each prepared transaction to the RPC
154+
- Classifies results:
155+
- **Deterministic failures**: Requeues transaction and recycles nonce
156+
- **Success/Indeterminate**: Assumes sent and adds to success tracking
157+
- Cleans up borrowed state
158+
159+
**Key Insight**: This provides crash resilience by ensuring no prepared transactions are lost.
160+
161+
### 2. Confirmation Phase (`confirm_flow`)
162+
163+
**Purpose**: Identify completed transactions and handle failures.
164+
165+
**Process**:
166+
167+
- Compares current chain nonce with cached `last_chain_nonce`
168+
- If unchanged, skips confirmation (no progress on chain)
169+
- For progressed nonces, checks transaction receipts
170+
- Categorizes results:
171+
- **Mined transactions**: Removes from tracking, adds to confirmed set
172+
- **Failed/Dropped transactions**: Adds to failed set for requeuing
173+
- Requeues failed transactions (deduplicated against confirmed ones)
174+
- Updates cached chain nonce
175+
176+
**Key Insight**: Uses nonce progression to efficiently identify which transactions need confirmation checks.
177+
178+
### 3. Send Phase (`send_flow`)
179+
180+
**Purpose**: Send new transactions while managing nonce allocation and capacity.
181+
182+
**Components**:
183+
184+
#### A. Health Check
185+
186+
- Periodically checks EOA balance
187+
- Skips sending if insufficient funds
188+
- Prevents wasteful RPC calls when EOA is unfunded
189+
190+
#### B. Recycled Nonce Processing
191+
192+
- **Overflow Protection**: Clears all recycled nonces if too many accumulate
193+
- **Reuse Priority**: Fills recycled nonces before using fresh ones
194+
- **No-op Transactions**: Sends empty transactions for unused recycled nonces
195+
196+
#### C. New Transaction Processing
197+
198+
- **Capacity Management**: Limits in-flight transactions to `MAX_IN_FLIGHT`
199+
- **Fresh Nonce Allocation**: Uses optimistic nonce counter for new transactions
200+
- **Batch Processing**: Sends multiple transactions up to available capacity
201+
202+
## Error Classification System
203+
204+
### Deterministic Failures
205+
206+
- Invalid signature
207+
- Malformed transaction
208+
- Invalid transaction format
209+
- **Action**: Immediate requeue + nonce recycling
210+
211+
### Success Cases
212+
213+
- Explicit success response
214+
- "already known" (duplicate)
215+
- "nonce too low" (already mined)
216+
- **Action**: Add to success tracking
217+
218+
### Indeterminate Cases
219+
220+
- Network timeouts
221+
- Temporary RPC failures
222+
- Unknown errors
223+
- **Action**: Assume sent (optimistic approach)
224+
225+
## Nonce Management Strategy
226+
227+
### Optimistic Nonce Counter
228+
229+
- Maintains local counter independent of chain state
230+
- Increments immediately when sending transactions
231+
- Allows parallel transaction preparation
232+
233+
### Recycled Nonce Pool
234+
235+
- Reuses nonces from failed transactions
236+
- Prevents nonce gaps in the sequence
237+
- Bounded size to prevent memory leaks
238+
239+
### Chain Nonce Synchronization
240+
241+
- Periodically syncs with actual chain state
242+
- Used for confirmation and capacity calculations
243+
- Handles chain reorganizations gracefully
244+
245+
## Key Design Decisions
246+
247+
### 1. Single Worker Per EOA:Chain
248+
249+
- **Benefit**: Eliminates nonce conflicts between workers
250+
- **Trade-off**: Limits parallelism but ensures consistency
251+
252+
### 2. Optimistic Sending
253+
254+
- **Benefit**: Higher throughput by not waiting for confirmations
255+
- **Trade-off**: Requires robust error handling and recovery
256+
257+
### 3. Borrowed Transaction Pattern
258+
259+
- **Benefit**: Crash resilience without complex state management
260+
- **Trade-off**: Slight overhead for state tracking
261+
262+
### 4. Bounded In-Flight Transactions
263+
264+
- **Benefit**: Prevents memory leaks and excessive RPC usage
265+
- **Trade-off**: May limit throughput during high-volume periods
266+
267+
### 5. Recycled Nonce Cleanup
268+
269+
- **Benefit**: Prevents unbounded memory growth
270+
- **Trade-off**: May create temporary nonce gaps
271+
272+
## Configuration Parameters
273+
274+
- **`MAX_IN_FLIGHT`**: Maximum concurrent unconfirmed transactions
275+
- **`MAX_RECYCLED_NONCES`**: Maximum recycled nonces before cleanup
276+
- **`WORKER_CYCLE_DELAY`**: Sleep time between worker iterations
277+
- **`HEALTH_CHECK_INTERVAL`**: Frequency of EOA balance checks
278+
- **`MIN_BALANCE_THRESHOLD`**: Minimum balance to consider EOA funded
279+
280+
## Monitoring and Observability
281+
282+
The worker exposes several metrics for monitoring:
283+
284+
- **Queue Depth**: Size of `pending_txns` queue
285+
- **In-Flight Count**: `optimistic_nonce - last_chain_nonce`
286+
- **Success Rate**: Ratio of confirmed to sent transactions
287+
- **Recycled Nonce Count**: Size of recycled nonce pool
288+
- **Health Status**: EOA funding state and last check time
289+
290+
## Failure Modes and Recovery
291+
292+
### Common Failure Scenarios
293+
294+
1. **EOA Runs Out of Funds**
295+
296+
- **Detection**: Balance check during health verification
297+
- **Recovery**: Automatic retry once funds are restored
298+
299+
2. **Network Partitions**
300+
301+
- **Detection**: RPC call failures during any phase
302+
- **Recovery**: Continues processing with cached state until network restored
303+
304+
3. **Worker Crashes**
305+
306+
- **Detection**: Restart detection during recovery phase
307+
- **Recovery**: Borrowed transaction rebroadcast ensures no loss
308+
309+
4. **Chain Reorganizations**
310+
- **Detection**: Chain nonce inconsistencies
311+
- **Recovery**: Confirmation phase handles dropped transactions
312+
313+
This architecture provides a robust, scalable solution for managing EOA transactions with strong consistency guarantees and graceful failure handling.

0 commit comments

Comments
 (0)