openzeppelin_relayer/jobs/handlers/
transaction_request_handler.rs

1//! Transaction request handler for processing incoming transaction jobs.
2//!
3//! Handles the validation and preparation of transactions before they are
4//! submitted to the network
5use actix_web::web::ThinData;
6use apalis::prelude::{Attempt, Context, Data, TaskId, Worker, *};
7use apalis_redis::RedisContext;
8use eyre::Result;
9use log::info;
10
11use crate::{
12    constants::WORKER_DEFAULT_MAXIMUM_RETRIES,
13    domain::{get_relayer_transaction, get_transaction_by_id, Transaction},
14    jobs::{handle_result, Job, TransactionRequest},
15    models::DefaultAppState,
16};
17
18pub async fn transaction_request_handler(
19    job: Job<TransactionRequest>,
20    state: Data<ThinData<DefaultAppState>>,
21    attempt: Attempt,
22    worker: Worker<Context>,
23    task_id: TaskId,
24    ctx: RedisContext,
25) -> Result<(), Error> {
26    info!("Handling transaction request: {:?}", job.data);
27    info!("Attempt: {:?}", attempt);
28    info!("Worker: {:?}", worker);
29    info!("Task ID: {:?}", task_id);
30    info!("Context: {:?}", ctx);
31
32    let result = handle_request(job.data, state).await;
33
34    handle_result(
35        result,
36        attempt,
37        "Transaction Request",
38        WORKER_DEFAULT_MAXIMUM_RETRIES,
39    )
40}
41
42async fn handle_request(
43    request: TransactionRequest,
44    state: Data<ThinData<DefaultAppState>>,
45) -> Result<()> {
46    let relayer_transaction = get_relayer_transaction(request.relayer_id, &state).await?;
47
48    let transaction = get_transaction_by_id(request.transaction_id, &state).await?;
49
50    relayer_transaction.prepare_transaction(transaction).await?;
51
52    info!("Transaction request handled successfully");
53
54    Ok(())
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use apalis::prelude::Attempt;
61
62    #[tokio::test]
63    async fn test_handler_result_processing() {
64        // This test focuses only on the interaction with handle_result
65        // which we can test without mocking the entire state
66
67        // Create a minimal job
68        let request = TransactionRequest::new("tx123", "relayer-1");
69        let job = Job::new(crate::jobs::JobType::TransactionRequest, request);
70
71        // Create a test attempt
72        let attempt = Attempt::default();
73
74        // We cannot fully test the transaction_request_handler without extensive mocking
75        // of the domain layer, but we can verify our test setup is correct
76        assert_eq!(job.data.transaction_id, "tx123");
77        assert_eq!(job.data.relayer_id, "relayer-1");
78        assert_eq!(attempt.current(), 0);
79    }
80
81    // Note: Fully testing the functionality would require either:
82    // 1. Dependency injection for all external dependencies
83    // 2. Feature flags to enable mock implementations
84    // 3. Integration tests with a real or test database
85
86    // For now, these tests serve as placeholders to be expanded
87    // when the appropriate testing infrastructure is in place.
88}