Skip to content

Race condition in in registration causes "ReplacementNotAllowed" under concurrent requests #121

@konradkonrad

Description

@konradkonrad

When stress testing multiple time based identity registrations, I hit 500 server errors when registering the identities concurrently:

[GIN] 2026/06/11 - 11:34:22 | 200 |   25.774833ms |     83.135.3.18 | POST     "/api/time/register_identity"
[GIN] 2026/06/11 - 11:34:22 | 500 |   25.398819ms |     83.135.3.18 | POST     "/api/time/register_identity"
Error #01: description: failed to register identity,  metadata: 
{"level":"error","error":"ReplacementNotAllowed","time":"2026-06-11T11:34:22Z","message":"failed to send transaction"}

The error seems to be triggered by getSigner() creating a TransactOpts with Nonce: nil. The go-ethereum bind package resolves this by calling PendingNonceAt. PendingNonceAt includes pending (mempool) transactions in its count, so sequential requests are safe - by the time request N+1 fetches the nonce, request N's transaction is already in the mempool and the pending nonce has advanced.

The failure only occurs when two requests are received and processed concurrently on the server and both execute PendingNonceAt before either transaction has been submitted to the mempool. There is a small window during which both calls observe the same pending nonce N, both sign and submit a transaction with nonce N, and the one submission is then rejected with ReplacementNotAllowed.

Potential fixes:

  • Mutex around nonce fetch + submit to serialize all tx submissions
  • Disable concurrency at the registration endpoints
  • In-memory nonce counter - read nonce once at startup, increment atomically, reset on nonce too low error
  • Transaction queue - single goroutine owns submission

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions