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
9 changes: 9 additions & 0 deletions tools/bidder-bot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ var (
Value: false,
}

optionBlockInterval = &cli.Uint64Flag{
Name: "block-interval",
Usage: "Only used for full notifier. Headers that are not a multiple of this interval will be skipped",
EnvVars: []string{"BLOCK_INTERVAL"},
Value: 4,
}

optionCheckBalances = &cli.BoolFlag{
Name: "check-balances",
Usage: "whether to periodically check account balances",
Expand Down Expand Up @@ -169,6 +176,7 @@ func main() {
optionAutoDepositAmount,
optionBidAmount,
optionUseFullNotifier,
optionBlockInterval,
optionCheckBalances,
},
Action: func(c *cli.Context) error {
Expand Down Expand Up @@ -225,6 +233,7 @@ func main() {
L1WsUrls: c.StringSlice(optionL1WsUrls.Name),
BeaconApiUrls: c.StringSlice(optionBeaconApiUrls.Name),
IsFullNotifier: c.Bool(optionUseFullNotifier.Name),
BlockInterval: c.Uint64(optionBlockInterval.Name),
Signer: signer,
CheckBalances: c.Bool(optionCheckBalances.Name),
}
Expand Down
8 changes: 8 additions & 0 deletions tools/bidder-bot/notifier/full.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@ type FullNotifier struct {
l1Client L1Client
lastNotifiedBlockNum uint64
mu sync.Mutex
blockInterval uint64
}

func NewFullNotifier(
logger *slog.Logger,
l1Client L1Client,
targetBlockChan chan bidder.TargetBlock,
blockInterval uint64,
) *FullNotifier {
return &FullNotifier{
logger: logger,
l1Client: l1Client,
targetBlockChan: targetBlockChan,
blockInterval: blockInterval,
}
}

Expand Down Expand Up @@ -84,6 +87,11 @@ func (b *FullNotifier) handleHeader(ctx context.Context, header *types.Header) e
"target_block_time", targetBlock.Time,
)

if header.Number.Uint64()%b.blockInterval != 0 {
b.logger.Debug("skipping header", "header_number", header.Number.Uint64())
return nil
}

b.mu.Lock()
defer b.mu.Unlock()

Expand Down
86 changes: 86 additions & 0 deletions tools/bidder-bot/notifier/full_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"math/big"
"os"
"slices"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -52,6 +53,7 @@ func TestHandleHeader(t *testing.T) {
logger,
nil,
targetBlockChan,
1, // Setting block interval to 1 ensures no headers are skipped
)
header := &types.Header{
Number: big.NewInt(int64(71)),
Expand Down Expand Up @@ -89,6 +91,7 @@ func TestChannelTimeout(t *testing.T) {
logger,
nil,
targetBlockChan,
1, // Setting block interval to 1 ensures no headers are skipped
)

err := notifier.HandleHeader(ctx, &types.Header{Number: big.NewInt(5)})
Expand Down Expand Up @@ -147,3 +150,86 @@ func TestChannelTimeout(t *testing.T) {
default:
}
}

func TestBlockInterval(t *testing.T) {
t.Parallel()
logger := util.NewTestLogger(os.Stdout)

tests := []struct {
name string
blockInterval uint64
headers []types.Header
expectedTargetBlocks []uint64
}{
{
name: "block interval 1, should receive all headers",
blockInterval: 1,
headers: []types.Header{
{Number: big.NewInt(1)},
{Number: big.NewInt(2)},
{Number: big.NewInt(777)},
{Number: big.NewInt(778)},
},
expectedTargetBlocks: []uint64{2, 3, 778, 779}, // target = header + 1
},

{
name: "block interval 2, should receive 2nd, 4th, 444th headers",
blockInterval: 2,
headers: []types.Header{
{Number: big.NewInt(1)},
{Number: big.NewInt(2)},
{Number: big.NewInt(3)},
{Number: big.NewInt(4)},
{Number: big.NewInt(444)},
},
expectedTargetBlocks: []uint64{3, 5, 445}, // target = header + 1
},

{
name: "block interval 7, should receive 7th, 14th, 700th headers",
blockInterval: 7,
headers: []types.Header{
{Number: big.NewInt(1)},
{Number: big.NewInt(2)},
{Number: big.NewInt(3)},
{Number: big.NewInt(4)},
{Number: big.NewInt(7)},
{Number: big.NewInt(14)},
{Number: big.NewInt(700)},
{Number: big.NewInt(701)},
},
expectedTargetBlocks: []uint64{8, 15, 701}, // target = header + 1
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
targetBlockChan := make(chan bidder.TargetBlock, len(test.headers))
notifier := notifier.NewFullNotifier(
logger,
nil,
targetBlockChan,
test.blockInterval,
)
for _, header := range test.headers {
err := notifier.HandleHeader(context.Background(), &header)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
}
receivedTargetBlocks := make([]uint64, 0, len(test.expectedTargetBlocks))
for len(targetBlockChan) > 0 {
select {
case targetBlock := <-targetBlockChan:
receivedTargetBlocks = append(receivedTargetBlocks, targetBlock.Num)
case <-time.After(1 * time.Second):
t.Fatal("timeout waiting for target block")
}
}
if !slices.Equal(receivedTargetBlocks, test.expectedTargetBlocks) {
t.Fatalf("expected to receive blocks %v, but got %v", test.expectedTargetBlocks, receivedTargetBlocks)
}
})
}
}
2 changes: 2 additions & 0 deletions tools/bidder-bot/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Config struct {
GasFeeCap *big.Int
BidAmount *big.Int
IsFullNotifier bool
BlockInterval uint64
CheckBalances bool
}

Expand Down Expand Up @@ -113,6 +114,7 @@ func New(config *Config) (*Service, error) {
config.Logger.With("module", "full_notifier"),
l1WsClient,
targetBlockChan, // send-and-receive for draining capability
config.BlockInterval,
)
} else {
if len(config.BeaconApiUrls) == 0 {
Expand Down
Loading