Skip to content

Commit

Permalink
txmgr: Fake sendState clock in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
trianglesphere committed Mar 30, 2023
1 parent 1d50cc9 commit 90c5955
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 12 deletions.
16 changes: 11 additions & 5 deletions op-service/txmgr/send_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
type SendState struct {
minedTxs map[common.Hash]struct{}
mu sync.RWMutex
now func() time.Time

// Config
nonceTooLowCount uint64
Expand All @@ -27,20 +28,25 @@ type SendState struct {
safeAbortNonceTooLowCount uint64 // nonce too low error
}

// NewSendState parameterizes a new SendState from the passed
// safeAbortNonceTooLowCount.
func NewSendState(safeAbortNonceTooLowCount uint64, unableToSendTimeout time.Duration) *SendState {
// NewSendStateWithNow creates a new send state with the provided clock.
func NewSendStateWithNow(safeAbortNonceTooLowCount uint64, unableToSendTimeout time.Duration, now func() time.Time) *SendState {
if safeAbortNonceTooLowCount == 0 {
panic("txmgr: safeAbortNonceTooLowCount cannot be zero")
}

return &SendState{
minedTxs: make(map[common.Hash]struct{}),
safeAbortNonceTooLowCount: safeAbortNonceTooLowCount,
txInMempoolDeadline: time.Now().Add(unableToSendTimeout),
txInMempoolDeadline: now().Add(unableToSendTimeout),
now: now,
}
}

// NewSendState creates a new send state
func NewSendState(safeAbortNonceTooLowCount uint64, unableToSendTimeout time.Duration) *SendState {
return NewSendStateWithNow(safeAbortNonceTooLowCount, unableToSendTimeout, time.Now)
}

// ProcessSendError should be invoked with the error returned for each
// publication. It is safe to call this method with nil or arbitrary errors.
func (s *SendState) ProcessSendError(err error) {
Expand Down Expand Up @@ -100,7 +106,7 @@ func (s *SendState) ShouldAbortImmediately() bool {
// If we have exceeded the nonce too low count, abort
if s.nonceTooLowCount >= s.safeAbortNonceTooLowCount ||
// If we have not published a transaction in the allotted time, abort
(s.successFullPublishCount == 0 && time.Now().After(s.txInMempoolDeadline)) {
(s.successFullPublishCount == 0 && s.now().After(s.txInMempoolDeadline)) {
return true
}

Expand Down
21 changes: 14 additions & 7 deletions op-service/txmgr/send_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ var (
const testSafeAbortNonceTooLowCount = 3

func newSendState() *txmgr.SendState {
return newSendStateWithTimeout(time.Hour)
return newSendStateWithTimeout(time.Hour, time.Now)
}

func newSendStateWithTimeout(t time.Duration) *txmgr.SendState {
return txmgr.NewSendState(testSafeAbortNonceTooLowCount, t)
func newSendStateWithTimeout(t time.Duration, now func() time.Time) *txmgr.SendState {
return txmgr.NewSendStateWithNow(testSafeAbortNonceTooLowCount, t, now)
}

func processNSendErrors(sendState *txmgr.SendState, err error, n int) {
Expand Down Expand Up @@ -166,19 +166,26 @@ func TestSendStateIsNotWaitingForConfirmationAfterTxUnmined(t *testing.T) {
require.False(t, sendState.IsWaitingForConfirmation())
}

func stepClock(step time.Duration) func() time.Time {
i := 0
return func() time.Time {
var start time.Time
i += 1
return start.Add(time.Duration(i) * step)
}
}

// TestSendStateTimeoutAbort ensure that this will abort if it passes the tx pool timeout
// when no successful transactions have been recorded
func TestSendStateTimeoutAbort(t *testing.T) {
sendState := newSendStateWithTimeout(10 * time.Millisecond)
time.Sleep(20 * time.Millisecond)
sendState := newSendStateWithTimeout(10*time.Millisecond, stepClock(20*time.Millisecond))
require.True(t, sendState.ShouldAbortImmediately(), "Should abort after timing out")
}

// TestSendStateNoTimeoutAbortIfPublishedTx ensure that this will not abort if there is
// a successful transaction send.
func TestSendStateNoTimeoutAbortIfPublishedTx(t *testing.T) {
sendState := newSendStateWithTimeout(10 * time.Millisecond)
sendState := newSendStateWithTimeout(10*time.Millisecond, stepClock(20*time.Millisecond))
sendState.ProcessSendError(nil)
time.Sleep(20 * time.Millisecond)
require.False(t, sendState.ShouldAbortImmediately(), "Should not abort if published transcation successfully")
}

0 comments on commit 90c5955

Please sign in to comment.