Skip to content

Commit 623b545

Browse files
committed
wip
1 parent c3263e4 commit 623b545

File tree

5 files changed

+68
-64
lines changed

5 files changed

+68
-64
lines changed

executors/src/eoa/eoa_confirmation_worker.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ where
182182
message: format!("Failed to get cached nonce: {}", e),
183183
})
184184
.map_err_fail()?
185-
.map(|n| n.to::<u64>())
186185
.unwrap_or(0);
187186

188187
tracing::debug!(

executors/src/eoa/error_classifier.rs

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@ use twmq::job::RequeuePosition;
1111
pub enum EoaExecutionError {
1212
/// Nonce too low - transaction might already be in mempool
1313
NonceTooLow { message: String },
14-
14+
1515
/// Nonce too high - indicates nonce gap or desync
1616
NonceTooHigh { message: String },
17-
17+
1818
/// Transaction already known in mempool
1919
AlreadyKnown { message: String },
20-
20+
2121
/// Replacement transaction underpriced
2222
ReplacementUnderpriced { message: String },
23-
23+
2424
/// Insufficient funds for transaction
2525
InsufficientFunds { message: String },
26-
26+
2727
/// Gas-related error (limit, estimation, etc.)
2828
GasError { message: String },
29-
29+
3030
/// Transaction pool is full or has limits
3131
PoolLimitExceeded { message: String },
32-
32+
3333
/// Account does not exist or invalid
3434
AccountError { message: String },
35-
35+
3636
/// Network/connectivity issues - use existing handling
3737
RpcError {
3838
message: String,
@@ -65,9 +65,10 @@ impl EoaErrorMapper {
6565
chain: &C,
6666
) -> Result<EoaExecutionError, EngineError> {
6767
match error {
68-
RpcError::ErrorResp(error_payload) => {
69-
Ok(Self::map_ethereum_error(error_payload.code, &error_payload.message))
70-
}
68+
RpcError::ErrorResp(error_payload) => Ok(Self::map_ethereum_error(
69+
error_payload.code,
70+
&error_payload.message,
71+
)),
7172
_ => {
7273
// Use existing engine error handling for non-actionable errors
7374
Err(error.to_engine_error(chain))
@@ -78,7 +79,7 @@ impl EoaErrorMapper {
7879
/// Map Ethereum-specific errors that we need to act on
7980
fn map_ethereum_error(code: i64, message: &str) -> EoaExecutionError {
8081
let msg_lower = message.to_lowercase();
81-
82+
8283
match code {
8384
-32000 => {
8485
// Only handle the specific ethereum errors we care about
@@ -118,15 +119,19 @@ impl EoaErrorMapper {
118119
// Not an actionable error - let engine error handle it
119120
EoaExecutionError::RpcError {
120121
message: message.to_string(),
121-
inner_error: Some(EngineError::InternalError { message: message.to_string() }),
122+
inner_error: Some(EngineError::InternalError {
123+
message: message.to_string(),
124+
}),
122125
}
123126
}
124127
}
125128
_ => {
126129
// Not an actionable error code
127130
EoaExecutionError::RpcError {
128131
message: format!("RPC error code {}: {}", code, message),
129-
inner_error: Some(EngineError::InternalError { message: message.to_string() }),
132+
inner_error: Some(EngineError::InternalError {
133+
message: message.to_string(),
134+
}),
130135
}
131136
}
132137
}
@@ -142,63 +147,63 @@ impl EoaErrorMapper {
142147
retryable: false,
143148
retry_delay: None,
144149
},
145-
150+
146151
EoaExecutionError::NonceTooHigh { .. } => RecoveryStrategy {
147152
queue_confirmation: false,
148153
recycle_nonce: true,
149154
needs_resync: true,
150155
retryable: true,
151156
retry_delay: Some(Duration::from_secs(10)),
152157
},
153-
158+
154159
EoaExecutionError::AlreadyKnown { .. } => RecoveryStrategy {
155160
queue_confirmation: true,
156161
recycle_nonce: false,
157162
needs_resync: false,
158163
retryable: false,
159164
retry_delay: None,
160165
},
161-
166+
162167
EoaExecutionError::ReplacementUnderpriced { .. } => RecoveryStrategy {
163168
queue_confirmation: true,
164169
recycle_nonce: false,
165170
needs_resync: false,
166171
retryable: true,
167172
retry_delay: Some(Duration::from_secs(10)),
168173
},
169-
174+
170175
EoaExecutionError::InsufficientFunds { .. } => RecoveryStrategy {
171176
queue_confirmation: false,
172177
recycle_nonce: true,
173178
needs_resync: false,
174179
retryable: true,
175180
retry_delay: Some(Duration::from_secs(60)),
176181
},
177-
182+
178183
EoaExecutionError::GasError { .. } => RecoveryStrategy {
179184
queue_confirmation: false,
180185
recycle_nonce: true,
181186
needs_resync: false,
182187
retryable: true,
183188
retry_delay: Some(Duration::from_secs(30)),
184189
},
185-
190+
186191
EoaExecutionError::PoolLimitExceeded { .. } => RecoveryStrategy {
187192
queue_confirmation: false,
188193
recycle_nonce: true,
189194
needs_resync: false,
190195
retryable: true,
191196
retry_delay: Some(Duration::from_secs(30)),
192197
},
193-
198+
194199
EoaExecutionError::AccountError { .. } => RecoveryStrategy {
195200
queue_confirmation: false,
196201
recycle_nonce: true,
197202
needs_resync: false,
198203
retryable: false,
199204
retry_delay: None,
200205
},
201-
206+
202207
EoaExecutionError::RpcError { .. } => {
203208
// This should not be used - let engine error handle it
204209
RecoveryStrategy {
@@ -208,7 +213,7 @@ impl EoaErrorMapper {
208213
retryable: false,
209214
retry_delay: None,
210215
}
211-
},
216+
}
212217
}
213218
}
214219
}
@@ -229,7 +234,7 @@ impl EoaExecutionError {
229234
| EoaExecutionError::RpcError { message, .. } => message,
230235
}
231236
}
232-
237+
233238
/// Convert to appropriate job result for send operations
234239
pub fn to_send_job_result<T, E>(
235240
&self,
@@ -244,9 +249,11 @@ impl EoaExecutionError {
244249
Ok(success_factory())
245250
} else if strategy.retryable {
246251
if let Some(delay) = strategy.retry_delay {
247-
Err(error_factory(self.message().to_string()).nack(Some(delay), RequeuePosition::Last))
252+
Err(error_factory(self.message().to_string())
253+
.nack(Some(delay), RequeuePosition::Last))
248254
} else {
249-
Err(error_factory(self.message().to_string()).nack(Some(Duration::from_secs(5)), RequeuePosition::Last))
255+
Err(error_factory(self.message().to_string())
256+
.nack(Some(Duration::from_secs(5)), RequeuePosition::Last))
250257
}
251258
} else {
252259
// Permanent failure
@@ -263,26 +270,29 @@ mod tests {
263270
fn test_nonce_too_low_mapping() {
264271
let error = EoaErrorMapper::map_ethereum_error(-32000, "nonce too low");
265272
let strategy = EoaErrorMapper::get_recovery_strategy(&error);
266-
273+
267274
match error {
268275
EoaExecutionError::NonceTooLow { .. } => {}
269276
_ => panic!("Expected NonceTooLow error"),
270277
}
271-
278+
272279
assert!(strategy.queue_confirmation);
273280
assert!(!strategy.recycle_nonce);
274281
}
275282

276283
#[test]
277284
fn test_insufficient_funds_mapping() {
278-
let error = EoaErrorMapper::map_ethereum_error(-32000, "insufficient funds for gas * price + value");
285+
let error = EoaErrorMapper::map_ethereum_error(
286+
-32000,
287+
"insufficient funds for gas * price + value",
288+
);
279289
let strategy = EoaErrorMapper::get_recovery_strategy(&error);
280-
290+
281291
match error {
282292
EoaExecutionError::InsufficientFunds { .. } => {}
283293
_ => panic!("Expected InsufficientFunds error"),
284294
}
285-
295+
286296
assert!(!strategy.queue_confirmation);
287297
assert!(strategy.recycle_nonce);
288298
assert!(strategy.retryable);
@@ -292,13 +302,13 @@ mod tests {
292302
fn test_already_known_mapping() {
293303
let error = EoaErrorMapper::map_ethereum_error(-32000, "already known");
294304
let strategy = EoaErrorMapper::get_recovery_strategy(&error);
295-
305+
296306
match error {
297307
EoaExecutionError::AlreadyKnown { .. } => {}
298308
_ => panic!("Expected AlreadyKnown error"),
299309
}
300-
310+
301311
assert!(strategy.queue_confirmation);
302312
assert!(!strategy.recycle_nonce);
303313
}
304-
}
314+
}

executors/src/eoa/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ pub mod nonce_manager;
44
pub mod send;
55
pub mod transaction_store;
66

7-
pub use confirm::{
8-
EoaConfirmationError, EoaConfirmationHandler, EoaConfirmationJobData, EoaConfirmationResult,
9-
};
107
pub use eoa_confirmation_worker::{
118
EoaConfirmationWorker, EoaConfirmationWorkerError, EoaConfirmationWorkerJobData,
129
EoaConfirmationWorkerResult,

executors/src/eoa/send.rs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use twmq::{
2121
job::{BorrowedJob, DelayOptions, JobResult, RequeuePosition, ToJobError, ToJobResult},
2222
};
2323

24+
use crate::eoa::{EoaConfirmationWorker, EoaConfirmationWorkerJobData};
2425
use crate::{
2526
transaction_registry::TransactionRegistry,
2627
webhook::{
@@ -47,7 +48,6 @@ pub struct EoaSendJobData {
4748
pub webhook_options: Option<Vec<WebhookOptions>>,
4849

4950
pub assigned_nonce: Option<u64>,
50-
5151
pub gas_limit: Option<u64>,
5252

5353
pub signing_credential: SigningCredential,
@@ -83,12 +83,18 @@ pub enum EoaSendError {
8383
ChainServiceError { chain_id: u64, message: String },
8484

8585
#[error("Transaction simulation failed: {message}")]
86-
SimulationFailed {
86+
SimulationFailedWithRevert {
8787
message: String,
8888
revert_reason: Option<String>,
8989
revert_data: Option<Bytes>,
9090
},
9191

92+
#[error("Transaction simulation failed: {message}")]
93+
SimulationFailed {
94+
message: String,
95+
inner_error: EngineError,
96+
},
97+
9298
#[error("Gas estimation failed: {message}")]
9399
GasEstimationFailed { message: String },
94100

@@ -168,6 +174,7 @@ where
168174
pub transaction_registry: Arc<TransactionRegistry>,
169175
pub eoa_signer: Arc<EoaSigner>,
170176
pub max_in_flight: u32,
177+
pub confirm_queue: Arc<Queue<EoaConfirmationWorker<CS>>>,
171178
}
172179

173180
impl<CS> ExecutorStage for EoaSendHandler<CS>
@@ -247,13 +254,14 @@ where
247254
if let Some(gas_limit) = job_data.gas_limit {
248255
tx_request = tx_request.with_gas_limit(gas_limit);
249256
} else {
250-
match chain.provider().estimate_gas(tx_request).await {
251-
Ok(gas) => {
252-
let gas_with_buffer = gas * 110 / 100; // Add 10% buffer
257+
let gas_limit_result = chain.provider().estimate_gas(tx_request.clone()).await;
258+
match gas_limit_result {
259+
Ok(gas_limit) => {
260+
let gas_with_buffer = gas_limit * 110 / 100; // Add 10% buffer
253261
tx_request = tx_request.with_gas_limit(gas_with_buffer);
254262
}
255-
Err(rpc_error) => {
256-
return self.handle_simulation_error(rpc_error, &chain).await;
263+
Err(e) => {
264+
return self.handle_simulation_error(e, &chain);
257265
}
258266
}
259267
}
@@ -383,14 +391,9 @@ where
383391
let confirm_job = self
384392
.confirm_queue
385393
.clone()
386-
.job(EoaConfirmationJobData {
387-
transaction_id: job.job.data.transaction_id.clone(),
394+
.job(EoaConfirmationWorkerJobData {
388395
chain_id: job.job.data.chain_id,
389-
eoa_address: job.job.data.from,
390-
nonce: success_data.result.nonce_used,
391-
transaction_hash: success_data.result.transaction_hash,
392-
webhook_options: job.job.data.webhook_options.clone(),
393-
rpc_credentials: job.job.data.rpc_credentials.clone(),
396+
eoa: job.job.data.from,
394397
})
395398
.with_id(&job.job.data.transaction_id)
396399
.with_delay(DelayOptions {
@@ -508,21 +511,21 @@ impl<CS> EoaSendHandler<CS>
508511
where
509512
CS: ChainService + Send + Sync + 'static,
510513
{
511-
async fn handle_simulation_error(
514+
fn handle_simulation_error(
512515
&self,
513516
rpc_error: RpcError<TransportErrorKind>,
514517
chain: &impl Chain,
515518
) -> JobResult<EoaSendResult, EoaSendError> {
516519
// Check if this is a revert first
517520
if let RpcError::ErrorResp(error_payload) = &rpc_error {
518-
if error_payload.as_revert_data().is_some() {
519-
return Err(EoaSendError::SimulationFailed {
521+
if let Some(revert_data) = error_payload.as_revert_data() {
522+
return Err(EoaSendError::SimulationFailedWithRevert {
520523
message: format!(
521524
"Transaction reverted during simulation: {}",
522525
error_payload.message
523526
),
524-
revert_reason: Some(error_payload.message.clone()),
525-
revert_data: None,
527+
revert_reason: Some(error_payload.message.to_string()),
528+
revert_data: Some(revert_data),
526529
}
527530
.fail());
528531
}
@@ -539,16 +542,11 @@ where
539542
EoaSendResult {
540543
transaction_hash: B256::ZERO,
541544
nonce_used: U256::ZERO,
542-
gas_limit: U256::ZERO,
543-
max_fee_per_gas: U256::ZERO,
544-
max_priority_fee_per_gas: U256::ZERO,
545545
possibly_duplicate: None,
546546
}
547547
},
548548
|reason| EoaSendError::SimulationFailed {
549549
message: reason.clone(),
550-
revert_reason: None,
551-
revert_data: None,
552550
},
553551
)
554552
}

executors/src/eoa/transaction_store.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use alloy::consensus::Transaction;
1+
use alloy::consensus::{Receipt, Transaction};
22
use alloy::network::AnyTransactionReceipt;
33
use alloy::primitives::{Address, B256, U256};
44
use alloy::rpc::types::{TransactionReceipt, TransactionRequest};
@@ -55,7 +55,7 @@ impl ActiveAttempt {
5555
pub struct ConfirmationData {
5656
pub transaction_hash: B256,
5757
pub confirmed_at: u64,
58-
pub receipt: AnyTransactionReceipt,
58+
pub receipt: TransactionReceipt,
5959
}
6060

6161
/// Transaction store focused on transaction_id operations and nonce indexing

0 commit comments

Comments
 (0)