Around Go: blockchain infrastructure · 3 MIN READ
Nonces, fees and unknown outcomes: one durable owner per account
Coordinate transaction intent and account nonce allocation before retrying a send.
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.
blockchain · A MAP OF THE IDEA
- Stable business intent
- Reserve nonce durably
- Sign + record identity
- Send then reconcile
Useful when
- Coordinate transaction intent and account nonce allocation before retrying a send.
- Makes the owner and the failure boundary explicit.
Watch out
- A send timeout is not proof that the transaction was rejected.
- Run native service and failure tests in your own development environment.
Implementation & operation cost: Additional state and tests must be justified by the demonstrated failure; this lesson is not a requirement for every Go program.
The contract and the failure
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.
Work through the example
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.
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
}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.
Production decisions
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.
Explain it in an interview
SendTransaction timed out. Is allocating a fresh nonce and sending the transfer again safe? No. The original outcome may be unknown. Reconcile the existing signed intent, hash and nonce before choosing a policy-controlled retry or replacement. Describe the state before the operation, its owner, the failure between steps and the evidence you would test. Distinguish what this example demonstrates from the infrastructure a production service still needs.
TAKE THIS WITH YOU
Coordinate transaction intent and account nonce allocation before retrying a send. No. The original outcome may be unknown. Reconcile the existing signed intent, hash and nonce before choosing a policy-controlled retry or replacement.
Check your understanding
SendTransaction timed out. Is allocating a fresh nonce and sending the transfer again safe?
Go to the source
Progress stays in this browser. No account needed.