Senior · Blockchain infrastructure

Two replicas reserve the same account nonce

Two Go processes call PendingNonceAt for one account, both receive 42 and prepare different transfers. Would a mutex in each process solve it?

Try explaining this aloud before opening the answer. State your assumptions and trace a boundary case.

EXAMPLE · FRAGMENT UNLESS A COMPLETE PROGRAM IS SHOWN

go
package main

import "fmt"

type Allocator struct {
	next     uint64
	reserved map[string]uint64
}

func (a *Allocator) Reserve(intent string) uint64 {
	if nonce, ok := a.reserved[intent]; ok {
		return nonce
	}
	nonce := a.next
	a.next++
	a.reserved[intent] = nonce
	return nonce
}
func main() {
	// Single-owner model: the durable multi-process implementation is separate.
	a := Allocator{next: 42, reserved: map[string]uint64{}}
	fmt.Println(a.Reserve("invoice-7"), a.Reserve("invoice-7"), a.Reserve("invoice-8")) // 42 42 43
}
Reveal a strong answer
  1. Two Go workers can read the same pending nonce and sign conflicting transactions. A process-local mutex helps only while one process owns the account; it does not coordinate replicas or survive a crash. Give each business intent a stable identity, persist its nonce and signed transaction identity under one ownership protocol, and reconcile unknown send outcomes before allocating new work.

  2. Distinguish prepared, submitted, pending, included, reverted and finalized states. An inclusion receipt with failed status is not a successful business effect. EIP-1559 fee cap, priority fee, gas limit and value have different meanings. A replacement may use the same nonce but a different transaction hash and policy-approved fees; keep the business intent stable and record the replacement chain. Repeating the same business intent reuses its reservation rather than consuming another nonce. The model assumes one owner and intentionally does not persist or sign transactions. A production allocator must atomically store intent and reservation, prevent concurrent owners from diverging and reconcile reservations after restart or account activity outside the service.

  3. A send timeout is not proof that the transaction was rejected. Retrying with a fresh nonce can repeat a transfer; blindly retrying the same underpriced transaction may not solve inclusion. PendingNonceAt is an observation, not a distributed reservation. Test concurrent intents, duplicate requests, external account activity, fee replacement, receipt absence, reorg and restart between signing and send.

Common trap

A fresh nonce can produce a second business transfer rather than a safe retry of the first.

Try it

Design the durable intent/reservation record, single-account ownership or fencing, replay identity and recovery after a send timeout.

Worked solution

Separate local locks do not coordinate replicas. One durable account-ownership protocol must reserve a nonce with a stable business intent and persist the signed transaction identity before recovery can reconcile it. PendingNonceAt is a provider observation, not a reservation service. Track pending, replacement, included, reverted and finalized outcomes, and do not create a new transfer merely because the first send timed out.

Change the constraint

How do external wallet activity, fee replacement and gaps after a crash affect the allocator?

How did you do?

Self-assessment, not a compiler pass or interview score. Explain the reasoning unaided before marking understood.

Not marked. Progress stays on this browser, separate from course completion.

Primary references

Checked 2026-10-28. Use documentation for your pinned runtime, driver and tool version.