Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,10 @@ type nonceTracker struct {
}

type nonceReservation struct {
deadline time.Time
used bool
expired bool
deadline time.Time
used bool
expired bool
firstHash common.Hash
}

const reservationTTL = 30 * time.Second
Expand Down Expand Up @@ -253,14 +254,24 @@ func (b *EthAPIBackend) validateAndConsumeSequencerReservation(tx *types.Transac
if r == nil {
return nil
}
if r.used {
return fmt.Errorf("reserved nonce already used: %d", tx.Nonce())
}
// If expired or past deadline, reject to force client to rebuild with a new reservation
if r.expired || time.Now().After(r.deadline) {
return fmt.Errorf("reserved nonce expired: %d", tx.Nonce())
}
// If the reservation has already been used, allow rebroadcasts or fee-bump
// replacements to proceed. The txpool is the source of truth for
// "already known" and replacement underpricing semantics. Emit a clear log.
if r.used {
if r.firstHash == tx.Hash() {
log.Info("[SSV] Re-received tx for reserved nonce (rebroadcast)", "nonce", tx.Nonce(), "txHash", tx.Hash())
} else {
log.Info("[SSV] Re-received tx for reserved nonce (replacement)", "nonce", tx.Nonce(), "txHash", tx.Hash(), "firstHash", r.firstHash)
}
return nil
}
r.used = true
r.firstHash = tx.Hash()
log.Info("[SSV] Consuming reserved nonce for tx", "nonce", tx.Nonce(), "txHash", tx.Hash())
return nil
}

Expand Down
3 changes: 3 additions & 0 deletions eth/api_userops.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,9 @@ func (api *composeUserOpsAPI) BuildSignedUserOpsTx(
return nil, fmt.Errorf("sign tx: %w", err)
}

// Log the reserved nonce and the resulting tx hash together for traceability.
log.Info("[SSV] Reserved sequencer nonce for tx", "nonce", nonce, "txHash", signedTx.Hash())

log.Info("[SSV] Signed user transaction with sequencer key",
"txHash", signedTx.Hash().Hex(),
"chainID", api.b.ChainConfig().ChainID,
Expand Down