Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix minor comments from Timeboost PR #2787

Merged
20 changes: 10 additions & 10 deletions execution/gethexec/express_lane_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,14 @@ type expressLaneControl struct {
controller common.Address
}

type transactionPublisher interface {
PublishTimeboostedTransaction(context.Context, *types.Transaction, *arbitrum_types.ConditionalOptions) error
}

type expressLaneService struct {
stopwaiter.StopWaiter
sync.RWMutex
transactionPublisher transactionPublisher
auctionContractAddr common.Address
apiBackend *arbitrum.APIBackend
initialTimestamp time.Time
Expand Down Expand Up @@ -116,14 +121,15 @@ func (a *contractAdapter) CallContract(ctx context.Context, call ethereum.CallMs
}

func newExpressLaneService(
transactionPublisher transactionPublisher,
apiBackend *arbitrum.APIBackend,
filterSystem *filters.FilterSystem,
auctionContractAddr common.Address,
bc *core.BlockChain,
) (*expressLaneService, error) {
chainConfig := bc.Config()

var contractBackend bind.ContractBackend = &contractAdapter{filters.NewFilterAPI(filterSystem, false), nil, apiBackend}
var contractBackend bind.ContractBackend = &contractAdapter{filters.NewFilterAPI(filterSystem), nil, apiBackend}

auctionContract, err := express_lane_auctiongen.NewExpressLaneAuction(auctionContractAddr, contractBackend)
if err != nil {
Expand Down Expand Up @@ -153,6 +159,7 @@ pending:
roundDuration := arbmath.SaturatingCast[time.Duration](roundTimingInfo.RoundDurationSeconds) * time.Second
auctionClosingDuration := arbmath.SaturatingCast[time.Duration](roundTimingInfo.AuctionClosingSeconds) * time.Second
return &expressLaneService{
transactionPublisher: transactionPublisher,
auctionContract: auctionContract,
apiBackend: apiBackend,
chainConfig: chainConfig,
Expand Down Expand Up @@ -305,12 +312,6 @@ func (es *expressLaneService) isWithinAuctionCloseWindow(arrivalTime time.Time)
func (es *expressLaneService) sequenceExpressLaneSubmission(
ctx context.Context,
msg *timeboost.ExpressLaneSubmission,
publishTxFn func(
parentCtx context.Context,
tx *types.Transaction,
options *arbitrum_types.ConditionalOptions,
delay bool,
) error,
) error {
es.Lock()
defer es.Unlock()
Expand All @@ -328,7 +329,7 @@ func (es *expressLaneService) sequenceExpressLaneSubmission(
}
// Log an informational warning if the message's sequence number is in the future.
if msg.SequenceNumber > control.sequence {
log.Warn("Received express lane submission with future sequence number", "SequenceNumber", msg.SequenceNumber)
log.Info("Received express lane submission with future sequence number", "SequenceNumber", msg.SequenceNumber)
}
// Put into the sequence number map.
es.messagesBySequenceNumber[msg.SequenceNumber] = msg
Expand All @@ -339,11 +340,10 @@ func (es *expressLaneService) sequenceExpressLaneSubmission(
if !exists {
break
}
if err := publishTxFn(
if err := es.transactionPublisher.PublishTimeboostedTransaction(
ctx,
nextMsg.Transaction,
msg.Options,
false, /* no delay, as it should go through express lane */
); err != nil {
// If the tx failed, clear it from the sequence map.
delete(es.messagesBySequenceNumber, msg.SequenceNumber)
Expand Down
90 changes: 51 additions & 39 deletions execution/gethexec/express_lane_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,23 +231,45 @@ func Test_expressLaneService_validateExpressLaneTx(t *testing.T) {
}
}

type stubPublisher struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not critical:
seems easier to have the stubPublisher hold array of txs and have a publishTransaction function that appends to it. Some tests could use the array, some could use just it's length and some could ignore it completley.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored it along those lines.

els *expressLaneService
publishedTxOrder []uint64
}

func makeStubPublisher(els *expressLaneService) *stubPublisher {
return &stubPublisher{
els: els,
publishedTxOrder: make([]uint64, 0),
}
}

func (s *stubPublisher) PublishTimeboostedTransaction(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions) error {
if tx == nil {
return errors.New("oops, bad tx")
}
control, _ := s.els.roundControl.Get(0)
s.publishedTxOrder = append(s.publishedTxOrder, control.sequence)
return nil

}

func Test_expressLaneService_sequenceExpressLaneSubmission_nonceTooLow(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
els := &expressLaneService{
messagesBySequenceNumber: make(map[uint64]*timeboost.ExpressLaneSubmission),
roundControl: lru.NewCache[uint64, *expressLaneControl](8),
}
stubPublisher := makeStubPublisher(els)
els.transactionPublisher = stubPublisher
els.roundControl.Add(0, &expressLaneControl{
sequence: 1,
})
msg := &timeboost.ExpressLaneSubmission{
SequenceNumber: 0,
}
publishFn := func(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions, delay bool) error {
return nil
}
err := els.sequenceExpressLaneSubmission(ctx, msg, publishFn)

err := els.sequenceExpressLaneSubmission(ctx, msg)
require.ErrorIs(t, err, timeboost.ErrSequenceNumberTooLow)
}

Expand All @@ -258,24 +280,21 @@ func Test_expressLaneService_sequenceExpressLaneSubmission_duplicateNonce(t *tes
roundControl: lru.NewCache[uint64, *expressLaneControl](8),
messagesBySequenceNumber: make(map[uint64]*timeboost.ExpressLaneSubmission),
}
stubPublisher := makeStubPublisher(els)
els.transactionPublisher = stubPublisher
els.roundControl.Add(0, &expressLaneControl{
sequence: 1,
})
msg := &timeboost.ExpressLaneSubmission{
SequenceNumber: 2,
}
numPublished := 0
publishFn := func(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions, delay bool) error {
numPublished += 1
return nil
}
err := els.sequenceExpressLaneSubmission(ctx, msg, publishFn)
err := els.sequenceExpressLaneSubmission(ctx, msg)
require.NoError(t, err)
// Because the message is for a future sequence number, it
// should get queued, but not yet published.
require.Equal(t, 0, numPublished)
require.Equal(t, 0, len(stubPublisher.publishedTxOrder))
// Sending it again should give us an error.
err = els.sequenceExpressLaneSubmission(ctx, msg, publishFn)
err = els.sequenceExpressLaneSubmission(ctx, msg)
require.ErrorIs(t, err, timeboost.ErrDuplicateSequenceNumber)
}

Expand All @@ -286,45 +305,46 @@ func Test_expressLaneService_sequenceExpressLaneSubmission_outOfOrder(t *testing
roundControl: lru.NewCache[uint64, *expressLaneControl](8),
messagesBySequenceNumber: make(map[uint64]*timeboost.ExpressLaneSubmission),
}
stubPublisher := makeStubPublisher(els)
els.transactionPublisher = stubPublisher

els.roundControl.Add(0, &expressLaneControl{
sequence: 1,
})
numPublished := 0
publishedTxOrder := make([]uint64, 0)
control, _ := els.roundControl.Get(0)
publishFn := func(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions, delay bool) error {
numPublished += 1
publishedTxOrder = append(publishedTxOrder, control.sequence)
return nil
}

messages := []*timeboost.ExpressLaneSubmission{
{
SequenceNumber: 10,
Transaction: &types.Transaction{},
},
{
SequenceNumber: 5,
Transaction: &types.Transaction{},
},
{
SequenceNumber: 1,
Transaction: &types.Transaction{},
},
{
SequenceNumber: 4,
Transaction: &types.Transaction{},
},
{
SequenceNumber: 2,
Transaction: &types.Transaction{},
},
}
for _, msg := range messages {
err := els.sequenceExpressLaneSubmission(ctx, msg, publishFn)
err := els.sequenceExpressLaneSubmission(ctx, msg)
require.NoError(t, err)
}
// We should have only published 2, as we are missing sequence number 3.
require.Equal(t, 2, numPublished)
require.Equal(t, 2, len(stubPublisher.publishedTxOrder))
require.Equal(t, len(messages), len(els.messagesBySequenceNumber))

err := els.sequenceExpressLaneSubmission(ctx, &timeboost.ExpressLaneSubmission{SequenceNumber: 3}, publishFn)
err := els.sequenceExpressLaneSubmission(ctx, &timeboost.ExpressLaneSubmission{SequenceNumber: 3, Transaction: &types.Transaction{}})
require.NoError(t, err)
require.Equal(t, 5, numPublished)
require.Equal(t, 5, len(stubPublisher.publishedTxOrder))
}

func Test_expressLaneService_sequenceExpressLaneSubmission_erroredTx(t *testing.T) {
Expand All @@ -337,17 +357,9 @@ func Test_expressLaneService_sequenceExpressLaneSubmission_erroredTx(t *testing.
els.roundControl.Add(0, &expressLaneControl{
sequence: 1,
})
numPublished := 0
publishedTxOrder := make([]uint64, 0)
control, _ := els.roundControl.Get(0)
publishFn := func(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions, delay bool) error {
if tx == nil {
return errors.New("oops, bad tx")
}
numPublished += 1
publishedTxOrder = append(publishedTxOrder, control.sequence)
return nil
}
stubPublisher := makeStubPublisher(els)
els.transactionPublisher = stubPublisher

messages := []*timeboost.ExpressLaneSubmission{
{
SequenceNumber: 1,
Expand All @@ -368,16 +380,16 @@ func Test_expressLaneService_sequenceExpressLaneSubmission_erroredTx(t *testing.
}
for _, msg := range messages {
if msg.Transaction == nil {
err := els.sequenceExpressLaneSubmission(ctx, msg, publishFn)
err := els.sequenceExpressLaneSubmission(ctx, msg)
require.ErrorContains(t, err, "oops, bad tx")
} else {
err := els.sequenceExpressLaneSubmission(ctx, msg, publishFn)
err := els.sequenceExpressLaneSubmission(ctx, msg)
require.NoError(t, err)
}
}
// One tx out of the four should have failed, so we should have only published 3.
require.Equal(t, 3, numPublished)
require.Equal(t, []uint64{1, 2, 3}, publishedTxOrder)
require.Equal(t, 3, len(stubPublisher.publishedTxOrder))
require.Equal(t, []uint64{1, 2, 3}, stubPublisher.publishedTxOrder)
}

func TestIsWithinAuctionCloseWindow(t *testing.T) {
Expand Down
13 changes: 9 additions & 4 deletions execution/gethexec/sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,10 +454,14 @@ func ctxWithTimeout(ctx context.Context, timeout time.Duration) (context.Context
}

func (s *Sequencer) PublishTransaction(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions) error {
return s.publishTransactionImpl(parentCtx, tx, options, true /* delay tx if express lane is active */)
return s.publishTransactionImpl(parentCtx, tx, options, false /* delay tx if express lane is active */)
}

func (s *Sequencer) publishTransactionImpl(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions, delay bool) error {
func (s *Sequencer) PublishTimeboostedTransaction(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions) error {
return s.publishTransactionImpl(parentCtx, tx, options, true)
}

func (s *Sequencer) publishTransactionImpl(parentCtx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions, isExpressLaneController bool) error {
config := s.config()
// Only try to acquire Rlock and check for hard threshold if l1reader is not nil
// And hard threshold was enabled, this prevents spamming of read locks when not needed
Expand Down Expand Up @@ -503,7 +507,7 @@ func (s *Sequencer) publishTransactionImpl(parentCtx context.Context, tx *types.
}

if s.config().Timeboost.Enable && s.expressLaneService != nil {
if delay && s.expressLaneService.currentRoundHasController() {
if !isExpressLaneController && s.expressLaneService.currentRoundHasController() {
time.Sleep(s.config().Timeboost.ExpressLaneAdvantage)
}
}
Expand Down Expand Up @@ -557,7 +561,7 @@ func (s *Sequencer) PublishExpressLaneTransaction(ctx context.Context, msg *time
if err := s.expressLaneService.validateExpressLaneTx(msg); err != nil {
return err
}
return s.expressLaneService.sequenceExpressLaneSubmission(ctx, msg, s.publishTransactionImpl)
return s.expressLaneService.sequenceExpressLaneSubmission(ctx, msg)
}

func (s *Sequencer) PublishAuctionResolutionTransaction(ctx context.Context, tx *types.Transaction) error {
Expand Down Expand Up @@ -1275,6 +1279,7 @@ func (s *Sequencer) StartExpressLane(ctx context.Context, apiBackend *arbitrum.A
}

els, err := newExpressLaneService(
s,
apiBackend,
filterSystem,
auctionContractAddr,
Expand Down
Loading