Skip to content

Conversation

@alexcos20
Copy link
Member

@alexcos20 alexcos20 commented Feb 11, 2026

Fixes #1194

PR Description: Asynchronous Batch Payment Claiming with JobSettle Status

Summary

This PR refactors payment claiming for compute jobs from synchronous inline processing to asynchronous batch processing. It introduces a new JobSettle status, batch escrow operations, and a timer-based payment claim system to significantly improve scalability and reduce gas costs.

Key Features

1. New Job Status: JobSettle (71)

  • Added intermediate status between job completion and final settlement
  • Jobs now transition: PublishingResultsJobSettleJobFinished
  • Enables deferred payment processing without blocking job completion
  • Allows for better error recovery and retry mechanisms

2. Asynchronous Payment Claim Timer

  • New configurable paymentClaimInterval (default: 1 hour)
  • Periodic batch processing of jobs in JobSettle status
  • Initial run after 1 minute delay, then periodic based on configured interval
  • Timer properly cleaned up on engine stop

3. Batch Escrow Operations

  • claimLocks(): Batch claim multiple locks and withdraw funds in a single transaction
  • cancelExpiredLocks(): Batch cancel multiple expired locks in a single transaction
  • Reduces gas costs by processing multiple jobs per transaction
  • Maintains backward compatibility with single-lock methods

4. Optimized Payment Claiming Logic

  • Groups jobs by operation type (claim vs cancel) and chain
  • Processes all claims for a chain in one batch transaction
  • Processes all cancellations for a chain in one batch transaction
  • Automatic fallback to individual processing if batch fails
  • Expiration check: expired locks are automatically cancelled

5. Cache of token decimals in Escrow

  • Reduces blockchain calls

@alexcos20 alexcos20 self-assigned this Feb 11, 2026
@alexcos20
Copy link
Member Author

/run-security-scan

Copy link
Member Author

@alexcos20 alexcos20 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI automated code review (Gemini 3).

Overall risk: medium

Summary:
This pull request introduces a significant refactoring of the C2D payment claiming mechanism, moving from immediate settlement post-job-finish to an asynchronous, periodic payment claiming process. A new JobSettle status is added to the C2D job lifecycle. The C2DEngineDocker now includes a paymentClaimTimer that regularly calls a new claimPayments method. This method identifies jobs in JobSettle status, calculates costs, checks lock expiries, and performs batch claims or cancellations on the blockchain using new batch functions in the Escrow component.

Key changes:

  • New JobSettle Status: Jobs transition to JobSettle after results are published, instead of directly to JobFinished.
  • Asynchronous Payment Claims: A periodic timer (paymentClaimInterval) drives the claimPayments process.
  • Batch Processing: New claimLocks and cancelExpiredLocks methods in the Escrow service enable batch operations for efficiency.
  • Resilience: The claiming logic includes fallbacks to individual transactions if batch operations fail.
  • Performance: Escrow now caches token decimals to reduce blockchain calls.
  • Database Updates: getJobs method in C2DDatabase now accepts a status filter.
  • Comprehensive Testing: Extensive new integration tests have been added to validate the new payment flow, including status transitions, claim processing, expired locks, free jobs, and batch handling.

Comments:
• [INFO][other] The payee field has been removed from the EscrowLock interface. This seems intentional to align with the refactoring, where the payee (provider's address) is determined dynamically during contract calls. Could you confirm that this change doesn't break any external integrations or other parts of the system that might rely on payee being present in this interface, particularly if it's used for serialization/deserialization?
• [INFO][performance] The initial setTimeout for claimPayments is hardcoded to 60 seconds (60000ms). While this is a reasonable delay, consider making this configurable via an environment variable or deriving it from this.paymentClaimInterval for consistency and flexibility, e.g., this.paymentClaimInterval / X.
• [INFO][other] The claimPayments method has robust logic for fallbacks (batch to individual) on transaction failure, which is great for resilience. However, the current tests do not explicitly cover a scenario where a batch transaction fails (e.g., due to one invalid item) and then successfully falls back to individual claims. It would be valuable to add a test case for this specific failure-and-recovery path to ensure it behaves as expected.
• [ERROR][bug] The batch cancelExpiredLocks function (the new one taking arrays) appears to have a copy-paste error. It calls contract.cancelExpiredLock which is the single-job function, instead of contract.cancelExpiredLocks which is the expected batch function. Please correct this to use the batch contract method.
• [WARNING][bug] In the test case 'should handle expired locks by canceling them', the testJob.payment.lockTx is set to '0xexpired'. This is likely a placeholder and the test might not be fully validating the actual lock expiry logic on the blockchain. The claimPayments method checks currentTimestamp > lockExpiry.

To properly test this, consider either:

  1. Creating a real lock with a very short expiry (e.g., now - 60 or a few seconds in the past) and then waiting for the claimPayments to pick it up.
  2. Mocking the escrow.getLocks response to explicitly return a lock with an expired timestamp.

@alexcos20
Copy link
Member Author

alexcos20 commented Feb 11, 2026

[ERROR][bug] The batch cancelExpiredLocks functio

fixed in 10f37ff

@alexcos20 alexcos20 marked this pull request as ready for review February 11, 2026 10:41
@AdriGeorge
Copy link
Collaborator

LGTM, i've tested a full flow of c2d and it works as expected

Copy link
Contributor

@giurgiur99 giurgiur99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@alexcos20 alexcos20 merged commit 7253868 into main Feb 11, 2026
51 of 56 checks passed
@alexcos20 alexcos20 deleted the feature/refactor_c2d_claims branch February 11, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C2D Escrow claim fails from time to time

3 participants