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 tracing::instrument;
7
8use crate::{
9    constants::WORKER_TRANSACTION_REQUEST_RETRIES,
10    domain::{get_relayer_transaction, get_transaction_by_id, Transaction},
11    jobs::{handle_result, Job, TransactionRequest},
12    models::DefaultAppState,
13    observability::request_id::set_request_id,
14    queues::{HandlerError, WorkerContext},
15};
16
17#[instrument(
18    level = "debug",
19    skip(job, state, ctx),
20    fields(
21        request_id = ?job.request_id,
22        job_id = %job.message_id,
23        job_type = %job.job_type.to_string(),
24        attempt = %ctx.attempt,
25        tx_id = %job.data.transaction_id,
26        relayer_id = %job.data.relayer_id,
27        task_id = %ctx.task_id,
28    )
29)]
30pub async fn transaction_request_handler(
31    job: Job<TransactionRequest>,
32    state: ThinData<DefaultAppState>,
33    ctx: WorkerContext,
34) -> Result<(), HandlerError> {
35    if let Some(request_id) = job.request_id.clone() {
36        set_request_id(request_id);
37    }
38
39    tracing::debug!(
40        tx_id = %job.data.transaction_id,
41        relayer_id = %job.data.relayer_id,
42        "handling transaction request"
43    );
44
45    let result = handle_request(job.data, &state).await;
46
47    handle_result(
48        result,
49        &ctx,
50        "Transaction Request",
51        WORKER_TRANSACTION_REQUEST_RETRIES,
52    )
53}
54
55async fn handle_request(
56    request: TransactionRequest,
57    state: &ThinData<DefaultAppState>,
58) -> eyre::Result<()> {
59    let relayer_transaction = get_relayer_transaction(request.relayer_id, state).await?;
60
61    let transaction = get_transaction_by_id(request.transaction_id.clone(), state).await?;
62
63    tracing::debug!(
64        tx_id = %transaction.id,
65        relayer_id = %transaction.relayer_id,
66        status = ?transaction.status,
67        "preparing transaction"
68    );
69
70    let prepared = relayer_transaction.prepare_transaction(transaction).await?;
71
72    tracing::debug!(
73        tx_id = %prepared.id,
74        relayer_id = %prepared.relayer_id,
75        status = ?prepared.status,
76        "transaction prepared"
77    );
78
79    Ok(())
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use crate::queues::WorkerContext;
86
87    #[tokio::test]
88    async fn test_handler_result_processing() {
89        let request = TransactionRequest::new("tx123", "relayer-1");
90        let job = Job::new(crate::jobs::JobType::TransactionRequest, request);
91        let ctx = WorkerContext::new(0, "test-task".into());
92
93        assert_eq!(job.data.transaction_id, "tx123");
94        assert_eq!(job.data.relayer_id, "relayer-1");
95        assert_eq!(ctx.attempt, 0);
96    }
97}