From 69ebfbb3efec149a25309539c1f0d6cc48ef9ef5 Mon Sep 17 00:00:00 2001 From: Dimitris Grigoriou Date: Fri, 12 Apr 2024 11:58:47 +0300 Subject: [PATCH] Remove unused mocks (#12769) * Remove unused mocks * Remove unused HeadBroadcasterRegistry * Cleanup head tracker structures * Fix lint & cleanup * Move HeadSaver under headtracker package --- common/headtracker/head_broadcaster.go | 47 ++-- common/headtracker/head_listener.go | 43 ++- common/headtracker/head_saver.go | 23 ++ common/headtracker/head_tracker.go | 54 ++-- .../mocks/head_broadcaster.go | 12 +- .../mocks/head_trackable.go | 3 +- .../{ => headtracker}/mocks/head_tracker.go | 3 +- common/headtracker/types/head.go | 1 - common/headtracker/types/mocks/head.go | 254 ------------------ .../headtracker/types/mocks/subscription.go | 46 ---- common/txmgr/txmgr.go | 3 +- common/txmgr/types/tx_attempt_builder.go | 3 +- common/types/chain.go | 3 - common/types/head_tracker.go | 80 ------ common/types/subscription.go | 1 - core/chains/evm/gas/models.go | 6 +- .../evm/headtracker/head_broadcaster.go | 5 +- core/chains/evm/headtracker/head_listener.go | 7 +- core/chains/evm/headtracker/head_saver.go | 4 +- core/chains/evm/headtracker/head_tracker.go | 5 - .../evm/headtracker/head_tracker_test.go | 6 +- core/chains/evm/headtracker/types/types.go | 13 +- core/chains/legacyevm/mocks/chain.go | 20 +- core/services/keeper/upkeep_executer.go | 2 +- core/services/ocr/contract_tracker_test.go | 6 +- .../evmregistry/v20/registry_test.go | 4 +- .../evmregistry/v21/block_subscriber_test.go | 4 +- .../relay/evm/mercury/v1/data_source_test.go | 16 +- .../relay/evm/request_round_tracker_test.go | 6 +- 29 files changed, 179 insertions(+), 501 deletions(-) create mode 100644 common/headtracker/head_saver.go rename common/{ => headtracker}/mocks/head_broadcaster.go (87%) rename common/{types => headtracker}/mocks/head_trackable.go (99%) rename common/{ => headtracker}/mocks/head_tracker.go (99%) delete mode 100644 common/headtracker/types/mocks/head.go delete mode 100644 common/headtracker/types/mocks/subscription.go delete mode 100644 common/types/head_tracker.go diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index 758a7713846..b20bb1993bd 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -16,17 +16,34 @@ import ( const TrackableCallbackTimeout = 2 * time.Second -type callbackSet[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] map[int]types.HeadTrackable[H, BLOCK_HASH] +type callbackSet[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] map[int]HeadTrackable[H, BLOCK_HASH] -func (set callbackSet[H, BLOCK_HASH]) values() []types.HeadTrackable[H, BLOCK_HASH] { - var values []types.HeadTrackable[H, BLOCK_HASH] +func (set callbackSet[H, BLOCK_HASH]) values() []HeadTrackable[H, BLOCK_HASH] { + var values []HeadTrackable[H, BLOCK_HASH] for _, callback := range set { values = append(values, callback) } return values } -type HeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct { +// HeadTrackable is implemented by the core txm to be able to receive head events from any chain. +// Chain implementations should notify head events to the core txm via this interface. +// +//go:generate mockery --quiet --name HeadTrackable --output ./mocks/ --case=underscore +type HeadTrackable[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface { + // OnNewLongestChain sends a new head when it becomes available. Subscribers can recursively trace the parent + // of the head to the finalized block back. + OnNewLongestChain(ctx context.Context, head H) +} + +// HeadBroadcaster relays new Heads to all subscribers. +type HeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface { + services.Service + BroadcastNewLongestChain(H) + Subscribe(callback HeadTrackable[H, BLOCK_HASH]) (currentLongestChain H, unsubscribe func()) +} + +type headBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct { services.StateMachine logger logger.Logger callbacks callbackSet[H, BLOCK_HASH] @@ -44,8 +61,8 @@ func NewHeadBroadcaster[ BLOCK_HASH types.Hashable, ]( lggr logger.Logger, -) *HeadBroadcaster[H, BLOCK_HASH] { - return &HeadBroadcaster[H, BLOCK_HASH]{ +) HeadBroadcaster[H, BLOCK_HASH] { + return &headBroadcaster[H, BLOCK_HASH]{ logger: logger.Named(lggr, "HeadBroadcaster"), callbacks: make(callbackSet[H, BLOCK_HASH]), mailbox: mailbox.NewSingle[H](), @@ -53,7 +70,7 @@ func NewHeadBroadcaster[ } } -func (hb *HeadBroadcaster[H, BLOCK_HASH]) Start(context.Context) error { +func (hb *headBroadcaster[H, BLOCK_HASH]) Start(context.Context) error { return hb.StartOnce("HeadBroadcaster", func() error { hb.wgDone.Add(1) go hb.run() @@ -61,7 +78,7 @@ func (hb *HeadBroadcaster[H, BLOCK_HASH]) Start(context.Context) error { }) } -func (hb *HeadBroadcaster[H, BLOCK_HASH]) Close() error { +func (hb *headBroadcaster[H, BLOCK_HASH]) Close() error { return hb.StopOnce("HeadBroadcaster", func() error { hb.mutex.Lock() // clear all callbacks @@ -74,21 +91,21 @@ func (hb *HeadBroadcaster[H, BLOCK_HASH]) Close() error { }) } -func (hb *HeadBroadcaster[H, BLOCK_HASH]) Name() string { +func (hb *headBroadcaster[H, BLOCK_HASH]) Name() string { return hb.logger.Name() } -func (hb *HeadBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error { +func (hb *headBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error { return map[string]error{hb.Name(): hb.Healthy()} } -func (hb *HeadBroadcaster[H, BLOCK_HASH]) BroadcastNewLongestChain(head H) { +func (hb *headBroadcaster[H, BLOCK_HASH]) BroadcastNewLongestChain(head H) { hb.mailbox.Deliver(head) } // Subscribe subscribes to OnNewLongestChain and Connect until HeadBroadcaster is closed, // or unsubscribe callback is called explicitly -func (hb *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback types.HeadTrackable[H, BLOCK_HASH]) (currentLongestChain H, unsubscribe func()) { +func (hb *headBroadcaster[H, BLOCK_HASH]) Subscribe(callback HeadTrackable[H, BLOCK_HASH]) (currentLongestChain H, unsubscribe func()) { hb.mutex.Lock() defer hb.mutex.Unlock() @@ -106,7 +123,7 @@ func (hb *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback types.HeadTrackable return } -func (hb *HeadBroadcaster[H, BLOCK_HASH]) run() { +func (hb *headBroadcaster[H, BLOCK_HASH]) run() { defer hb.wgDone.Done() for { @@ -122,7 +139,7 @@ func (hb *HeadBroadcaster[H, BLOCK_HASH]) run() { // DEV: the head relayer makes no promises about head delivery! Subscribing // Jobs should expect to the relayer to skip heads if there is a large number of listeners // and all callbacks cannot be completed in the allotted time. -func (hb *HeadBroadcaster[H, BLOCK_HASH]) executeCallbacks() { +func (hb *headBroadcaster[H, BLOCK_HASH]) executeCallbacks() { head, exists := hb.mailbox.Retrieve() if !exists { hb.logger.Info("No head to retrieve. It might have been skipped") @@ -146,7 +163,7 @@ func (hb *HeadBroadcaster[H, BLOCK_HASH]) executeCallbacks() { defer cancel() for _, callback := range callbacks { - go func(trackable types.HeadTrackable[H, BLOCK_HASH]) { + go func(trackable HeadTrackable[H, BLOCK_HASH]) { defer wg.Done() start := time.Now() cctx, cancel := context.WithTimeout(ctx, TrackableCallbackTimeout) diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index e7ea4fb51ae..15977c4dfe4 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -29,7 +29,26 @@ var ( }, []string{"ChainID"}) ) -type HeadListener[ +// headHandler is a callback that handles incoming heads +type headHandler[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] func(ctx context.Context, header H) error + +// HeadListener is a chain agnostic interface that manages connection of Client that receives heads from the blockchain node +type HeadListener[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface { + // ListenForNewHeads kicks off the listen loop (not thread safe) + // done() must be executed upon leaving ListenForNewHeads() + ListenForNewHeads(handleNewHead headHandler[H, BLOCK_HASH], done func()) + + // ReceivingHeads returns true if the listener is receiving heads (thread safe) + ReceivingHeads() bool + + // Connected returns true if the listener is connected (thread safe) + Connected() bool + + // HealthReport returns report of errors within HeadListener + HealthReport() map[string]error +} + +type headListener[ HTH htrktypes.Head[BLOCK_HASH, ID], S types.Subscription, ID types.ID, @@ -56,8 +75,8 @@ func NewHeadListener[ client CLIENT, config htrktypes.Config, chStop chan struct{}, -) *HeadListener[HTH, S, ID, BLOCK_HASH] { - return &HeadListener[HTH, S, ID, BLOCK_HASH]{ +) HeadListener[HTH, BLOCK_HASH] { + return &headListener[HTH, S, ID, BLOCK_HASH]{ config: config, client: client, logger: logger.Named(lggr, "HeadListener"), @@ -65,11 +84,11 @@ func NewHeadListener[ } } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) Name() string { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) Name() string { return hl.logger.Name() } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(handleNewHead types.NewHeadHandler[HTH, BLOCK_HASH], done func()) { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(handleNewHead headHandler[HTH, BLOCK_HASH], done func()) { defer done() defer hl.unsubscribe() @@ -91,15 +110,15 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(handleNewHead } } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) ReceivingHeads() bool { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) ReceivingHeads() bool { return hl.receivingHeads.Load() } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) Connected() bool { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) Connected() bool { return hl.connected.Load() } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error { var err error if !hl.ReceivingHeads() { err = errors.New("Listener is not receiving heads") @@ -110,7 +129,7 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error return map[string]error{hl.Name(): err} } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Context, handleNewHead types.NewHeadHandler[HTH, BLOCK_HASH]) error { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Context, handleNewHead headHandler[HTH, BLOCK_HASH]) error { var noHeadsAlarmC <-chan time.Time var noHeadsAlarmT *time.Ticker noHeadsAlarmDuration := hl.config.BlockEmissionIdleWarningThreshold() @@ -169,7 +188,7 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Conte } } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) subscribe(ctx context.Context) bool { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) subscribe(ctx context.Context) bool { subscribeRetryBackoff := utils.NewRedialBackoff() chainId := hl.client.ConfiguredChainID() @@ -196,7 +215,7 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) subscribe(ctx context.Context) b } } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) subscribeToHead(ctx context.Context) error { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) subscribeToHead(ctx context.Context) error { hl.chHeaders = make(chan HTH) var err error @@ -211,7 +230,7 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) subscribeToHead(ctx context.Cont return nil } -func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) unsubscribe() { +func (hl *headListener[HTH, S, ID, BLOCK_HASH]) unsubscribe() { if hl.headSubscription != nil { hl.connected.Store(false) hl.headSubscription.Unsubscribe() diff --git a/common/headtracker/head_saver.go b/common/headtracker/head_saver.go new file mode 100644 index 00000000000..6f461c61225 --- /dev/null +++ b/common/headtracker/head_saver.go @@ -0,0 +1,23 @@ +package headtracker + +import ( + "context" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +// HeadSaver is an chain agnostic interface for saving and loading heads +// Different chains will instantiate generic HeadSaver type with their native Head and BlockHash types. +type HeadSaver[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface { + // Save updates the latest block number, if indeed the latest, and persists + // this number in case of reboot. + Save(ctx context.Context, head H) error + // Load loads latest heads up to latestFinalized - historyDepth, returns the latest chain. + Load(ctx context.Context, latestFinalized int64) (H, error) + // LatestChain returns the block header with the highest number that has been seen, or nil. + LatestChain() H + // Chain returns a head for the specified hash, or nil. + Chain(hash BLOCK_HASH) H + // MarkFinalized - marks matching block and all it's direct ancestors as finalized + MarkFinalized(ctx context.Context, latestFinalized H) error +} diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index eb9d72f123c..bc7a4910b39 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -34,7 +34,17 @@ var ( // HeadsBufferSize - The buffer is used when heads sampling is disabled, to ensure the callback is run for every head const HeadsBufferSize = 10 -type HeadTracker[ +// HeadTracker holds and stores the block experienced by a particular node in a thread safe manner. +// +//go:generate mockery --quiet --name HeadTracker --output ./mocks/ --case=underscore +type HeadTracker[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface { + services.Service + // Backfill given a head will fill in any missing heads up to latestFinalized + Backfill(ctx context.Context, headWithChain, latestFinalized H) (err error) + LatestChain() H +} + +type headTracker[ HTH htrktypes.Head[BLOCK_HASH, ID], S types.Subscription, ID types.ID, @@ -42,17 +52,17 @@ type HeadTracker[ ] struct { services.StateMachine log logger.SugaredLogger - headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH] - headSaver types.HeadSaver[HTH, BLOCK_HASH] + headBroadcaster HeadBroadcaster[HTH, BLOCK_HASH] + headSaver HeadSaver[HTH, BLOCK_HASH] mailMon *mailbox.Monitor client htrktypes.Client[HTH, S, ID, BLOCK_HASH] - chainID ID + chainID types.ID config htrktypes.Config htConfig htrktypes.HeadTrackerConfig backfillMB *mailbox.Mailbox[HTH] broadcastMB *mailbox.Mailbox[HTH] - headListener types.HeadListener[HTH, BLOCK_HASH] + headListener HeadListener[HTH, BLOCK_HASH] chStop services.StopChan wgDone sync.WaitGroup getNilHead func() HTH @@ -69,14 +79,14 @@ func NewHeadTracker[ client htrktypes.Client[HTH, S, ID, BLOCK_HASH], config htrktypes.Config, htConfig htrktypes.HeadTrackerConfig, - headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH], - headSaver types.HeadSaver[HTH, BLOCK_HASH], + headBroadcaster HeadBroadcaster[HTH, BLOCK_HASH], + headSaver HeadSaver[HTH, BLOCK_HASH], mailMon *mailbox.Monitor, getNilHead func() HTH, -) types.HeadTracker[HTH, BLOCK_HASH] { +) HeadTracker[HTH, BLOCK_HASH] { chStop := make(chan struct{}) lggr = logger.Named(lggr, "HeadTracker") - return &HeadTracker[HTH, S, ID, BLOCK_HASH]{ + return &headTracker[HTH, S, ID, BLOCK_HASH]{ headBroadcaster: headBroadcaster, client: client, chainID: client.ConfiguredChainID(), @@ -94,7 +104,7 @@ func NewHeadTracker[ } // Start starts HeadTracker service. -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error { return ht.StartOnce("HeadTracker", func() error { ht.log.Debugw("Starting HeadTracker", "chainID", ht.chainID) // NOTE: Always try to start the head tracker off with whatever the @@ -123,7 +133,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error }) } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleInitialHead(ctx context.Context) error { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleInitialHead(ctx context.Context) error { initialHead, err := ht.client.HeadByNumber(ctx, nil) if err != nil { return fmt.Errorf("failed to fetch initial head: %w", err) @@ -167,7 +177,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleInitialHead(ctx context.Con } // Close stops HeadTracker service. -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Close() error { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Close() error { return ht.StopOnce("HeadTracker", func() error { close(ht.chStop) ht.wgDone.Wait() @@ -175,17 +185,17 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Close() error { }) } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Name() string { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Name() string { return ht.log.Name() } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error { report := map[string]error{ht.Name(): ht.Healthy()} services.CopyHealth(report, ht.headListener.HealthReport()) return report } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain, latestFinalized HTH) (err error) { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain, latestFinalized HTH) (err error) { if !latestFinalized.IsValid() { return errors.New("can not perform backfill without a valid latestFinalized head") } @@ -201,11 +211,11 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Backfill(ctx context.Context, hea return ht.backfill(ctx, headWithChain, latestFinalized) } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) LatestChain() HTH { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) LatestChain() HTH { return ht.headSaver.LatestChain() } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context, head HTH) error { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context, head HTH) error { prevHead := ht.headSaver.LatestChain() ht.log.Debugw(fmt.Sprintf("Received new head %v", head.BlockNumber()), @@ -250,7 +260,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context return nil } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop() { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop() { defer ht.wgDone.Done() samplingInterval := ht.htConfig.SamplingInterval() @@ -289,7 +299,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop() { } } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfillLoop() { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) backfillLoop() { defer ht.wgDone.Done() ctx, cancel := ht.chStop.NewCtx() @@ -327,7 +337,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfillLoop() { // calculateLatestFinalized - returns latest finalized block. It's expected that currentHeadNumber - is the head of // canonical chain. There is no guaranties that returned block belongs to the canonical chain. Additional verification // must be performed before usage. -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) calculateLatestFinalized(ctx context.Context, currentHead HTH) (h HTH, err error) { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) calculateLatestFinalized(ctx context.Context, currentHead HTH) (h HTH, err error) { if ht.config.FinalityTagEnabled() { return ht.client.LatestFinalizedBlock(ctx) } @@ -343,7 +353,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) calculateLatestFinalized(ctx cont } // backfill fetches all missing heads up until the latestFinalizedHead -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, head, latestFinalizedHead HTH) (err error) { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, head, latestFinalizedHead HTH) (err error) { headBlockNumber := head.BlockNumber() mark := time.Now() fetched := 0 @@ -402,7 +412,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, hea return } -func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) fetchAndSaveHead(ctx context.Context, n int64, hash BLOCK_HASH) (HTH, error) { +func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) fetchAndSaveHead(ctx context.Context, n int64, hash BLOCK_HASH) (HTH, error) { ht.log.Debugw("Fetching head", "blockHeight", n, "blockHash", hash) head, err := ht.client.HeadByHash(ctx, hash) if err != nil { diff --git a/common/mocks/head_broadcaster.go b/common/headtracker/mocks/head_broadcaster.go similarity index 87% rename from common/mocks/head_broadcaster.go rename to common/headtracker/mocks/head_broadcaster.go index 265fceae91e..e30da907df5 100644 --- a/common/mocks/head_broadcaster.go +++ b/common/headtracker/mocks/head_broadcaster.go @@ -5,8 +5,10 @@ package mocks import ( context "context" - types "github.com/smartcontractkit/chainlink/v2/common/types" + headtracker "github.com/smartcontractkit/chainlink/v2/common/headtracker" mock "github.com/stretchr/testify/mock" + + types "github.com/smartcontractkit/chainlink/v2/common/types" ) // HeadBroadcaster is an autogenerated mock type for the HeadBroadcaster type @@ -112,7 +114,7 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Start(_a0 context.Context) error { } // Subscribe provides a mock function with given fields: callback -func (_m *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback types.HeadTrackable[H, BLOCK_HASH]) (H, func()) { +func (_m *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback headtracker.HeadTrackable[H, BLOCK_HASH]) (H, func()) { ret := _m.Called(callback) if len(ret) == 0 { @@ -121,16 +123,16 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback types.HeadTrackable var r0 H var r1 func() - if rf, ok := ret.Get(0).(func(types.HeadTrackable[H, BLOCK_HASH]) (H, func())); ok { + if rf, ok := ret.Get(0).(func(headtracker.HeadTrackable[H, BLOCK_HASH]) (H, func())); ok { return rf(callback) } - if rf, ok := ret.Get(0).(func(types.HeadTrackable[H, BLOCK_HASH]) H); ok { + if rf, ok := ret.Get(0).(func(headtracker.HeadTrackable[H, BLOCK_HASH]) H); ok { r0 = rf(callback) } else { r0 = ret.Get(0).(H) } - if rf, ok := ret.Get(1).(func(types.HeadTrackable[H, BLOCK_HASH]) func()); ok { + if rf, ok := ret.Get(1).(func(headtracker.HeadTrackable[H, BLOCK_HASH]) func()); ok { r1 = rf(callback) } else { if ret.Get(1) != nil { diff --git a/common/types/mocks/head_trackable.go b/common/headtracker/mocks/head_trackable.go similarity index 99% rename from common/types/mocks/head_trackable.go rename to common/headtracker/mocks/head_trackable.go index 55f0ebd288e..22bc5cb280a 100644 --- a/common/types/mocks/head_trackable.go +++ b/common/headtracker/mocks/head_trackable.go @@ -5,8 +5,9 @@ package mocks import ( context "context" - types "github.com/smartcontractkit/chainlink/v2/common/types" mock "github.com/stretchr/testify/mock" + + types "github.com/smartcontractkit/chainlink/v2/common/types" ) // HeadTrackable is an autogenerated mock type for the HeadTrackable type diff --git a/common/mocks/head_tracker.go b/common/headtracker/mocks/head_tracker.go similarity index 99% rename from common/mocks/head_tracker.go rename to common/headtracker/mocks/head_tracker.go index fea31a1d6eb..9261ef3221b 100644 --- a/common/mocks/head_tracker.go +++ b/common/headtracker/mocks/head_tracker.go @@ -5,8 +5,9 @@ package mocks import ( context "context" - types "github.com/smartcontractkit/chainlink/v2/common/types" mock "github.com/stretchr/testify/mock" + + types "github.com/smartcontractkit/chainlink/v2/common/types" ) // HeadTracker is an autogenerated mock type for the HeadTracker type diff --git a/common/headtracker/types/head.go b/common/headtracker/types/head.go index c2d7e262ac7..d1f99031bf6 100644 --- a/common/headtracker/types/head.go +++ b/common/headtracker/types/head.go @@ -4,7 +4,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/types" ) -//go:generate mockery --quiet --name Head --output ./mocks/ --case=underscore type Head[BLOCK_HASH types.Hashable, CHAIN_ID types.ID] interface { types.Head[BLOCK_HASH] // ChainID returns the chain ID that the head is for diff --git a/common/headtracker/types/mocks/head.go b/common/headtracker/types/mocks/head.go deleted file mode 100644 index f86df1d7fce..00000000000 --- a/common/headtracker/types/mocks/head.go +++ /dev/null @@ -1,254 +0,0 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. - -package mocks - -import ( - big "math/big" - - mock "github.com/stretchr/testify/mock" - - time "time" - - types "github.com/smartcontractkit/chainlink/v2/common/types" -) - -// Head is an autogenerated mock type for the Head type -type Head[BLOCK_HASH types.Hashable, CHAIN_ID types.ID] struct { - mock.Mock -} - -// BlockDifficulty provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockDifficulty() *big.Int { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for BlockDifficulty") - } - - var r0 *big.Int - if rf, ok := ret.Get(0).(func() *big.Int); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - return r0 -} - -// BlockHash provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockHash() BLOCK_HASH { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for BlockHash") - } - - var r0 BLOCK_HASH - if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(BLOCK_HASH) - } - - return r0 -} - -// BlockNumber provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockNumber() int64 { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for BlockNumber") - } - - var r0 int64 - if rf, ok := ret.Get(0).(func() int64); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(int64) - } - - return r0 -} - -// ChainID provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainID() CHAIN_ID { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ChainID") - } - - var r0 CHAIN_ID - if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(CHAIN_ID) - } - - return r0 -} - -// ChainLength provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainLength() uint32 { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ChainLength") - } - - var r0 uint32 - if rf, ok := ret.Get(0).(func() uint32); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint32) - } - - return r0 -} - -// EarliestHeadInChain provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) EarliestHeadInChain() types.Head[BLOCK_HASH] { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for EarliestHeadInChain") - } - - var r0 types.Head[BLOCK_HASH] - if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.Head[BLOCK_HASH]) - } - } - - return r0 -} - -// GetParent provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParent() types.Head[BLOCK_HASH] { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetParent") - } - - var r0 types.Head[BLOCK_HASH] - if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.Head[BLOCK_HASH]) - } - } - - return r0 -} - -// GetParentHash provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParentHash() BLOCK_HASH { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetParentHash") - } - - var r0 BLOCK_HASH - if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(BLOCK_HASH) - } - - return r0 -} - -// GetTimestamp provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetTimestamp() time.Time { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetTimestamp") - } - - var r0 time.Time - if rf, ok := ret.Get(0).(func() time.Time); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(time.Time) - } - - return r0 -} - -// HasChainID provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) HasChainID() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for HasChainID") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// HashAtHeight provides a mock function with given fields: blockNum -func (_m *Head[BLOCK_HASH, CHAIN_ID]) HashAtHeight(blockNum int64) BLOCK_HASH { - ret := _m.Called(blockNum) - - if len(ret) == 0 { - panic("no return value specified for HashAtHeight") - } - - var r0 BLOCK_HASH - if rf, ok := ret.Get(0).(func(int64) BLOCK_HASH); ok { - r0 = rf(blockNum) - } else { - r0 = ret.Get(0).(BLOCK_HASH) - } - - return r0 -} - -// IsValid provides a mock function with given fields: -func (_m *Head[BLOCK_HASH, CHAIN_ID]) IsValid() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for IsValid") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// NewHead creates a new instance of Head. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewHead[BLOCK_HASH types.Hashable, CHAIN_ID types.ID](t interface { - mock.TestingT - Cleanup(func()) -}) *Head[BLOCK_HASH, CHAIN_ID] { - mock := &Head[BLOCK_HASH, CHAIN_ID]{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/common/headtracker/types/mocks/subscription.go b/common/headtracker/types/mocks/subscription.go deleted file mode 100644 index b9cb7886d1d..00000000000 --- a/common/headtracker/types/mocks/subscription.go +++ /dev/null @@ -1,46 +0,0 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. - -package mocks - -import mock "github.com/stretchr/testify/mock" - -// Subscription is an autogenerated mock type for the Subscription type -type Subscription struct { - mock.Mock -} - -// Err provides a mock function with given fields: -func (_m *Subscription) Err() <-chan error { - ret := _m.Called() - - var r0 <-chan error - if rf, ok := ret.Get(0).(func() <-chan error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(<-chan error) - } - } - - return r0 -} - -// Unsubscribe provides a mock function with given fields: -func (_m *Subscription) Unsubscribe() { - _m.Called() -} - -type mockConstructorTestingTNewSubscription interface { - mock.TestingT - Cleanup(func()) -} - -// NewSubscription creates a new instance of Subscription. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSubscription(t mockConstructorTestingTNewSubscription) *Subscription { - mock := &Subscription{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index fcfd023ece3..d183a8c3ade 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + "github.com/smartcontractkit/chainlink/v2/common/headtracker" iutils "github.com/smartcontractkit/chainlink/v2/common/internal/utils" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" @@ -41,7 +42,7 @@ type TxManager[ SEQ types.Sequence, FEE feetypes.Fee, ] interface { - types.HeadTrackable[HEAD, BLOCK_HASH] + headtracker.HeadTrackable[HEAD, BLOCK_HASH] services.Service Trigger(addr ADDR) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) diff --git a/common/txmgr/types/tx_attempt_builder.go b/common/txmgr/types/tx_attempt_builder.go index b242f73e6fc..54184733f0a 100644 --- a/common/txmgr/types/tx_attempt_builder.go +++ b/common/txmgr/types/tx_attempt_builder.go @@ -6,6 +6,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + "github.com/smartcontractkit/chainlink/v2/common/headtracker" "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -24,7 +25,7 @@ type TxAttemptBuilder[ ] interface { // interfaces for running the underlying estimator services.Service - types.HeadTrackable[HEAD, BLOCK_HASH] + headtracker.HeadTrackable[HEAD, BLOCK_HASH] // NewTxAttempt builds a transaction using the configured transaction type and fee estimator (new estimation) NewTxAttempt(ctx context.Context, tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], lggr logger.Logger, opts ...feetypes.Opt) (attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fee FEE, feeLimit uint64, retryable bool, err error) diff --git a/common/types/chain.go b/common/types/chain.go index c2c2011d8de..800f0d9fdc0 100644 --- a/common/types/chain.go +++ b/common/types/chain.go @@ -9,9 +9,6 @@ type Sequence interface { Int64() int64 // needed for numeric sequence confirmation - to be removed with confirmation logic generalization: https://smartcontract-it.atlassian.net/browse/BCI-860 } -// Generate the next usable sequence for a transaction -type GenerateNextSequenceFunc[SEQ Sequence] func(prev SEQ) SEQ - // ID represents the base type, for any chain's ID. // It should be convertible to a string, that can uniquely identify this chain type ID fmt.Stringer diff --git a/common/types/head_tracker.go b/common/types/head_tracker.go deleted file mode 100644 index 83a2d7b8adb..00000000000 --- a/common/types/head_tracker.go +++ /dev/null @@ -1,80 +0,0 @@ -package types - -import ( - "context" - - "github.com/smartcontractkit/chainlink-common/pkg/services" -) - -// HeadTracker holds and stores the block experienced by a particular node in a thread safe manner. -// Reconstitutes the last block number on reboot. -// -//go:generate mockery --quiet --name HeadTracker --output ../mocks/ --case=underscore -type HeadTracker[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - services.Service - // Backfill given a head will fill in any missing heads up to latestFinalized - Backfill(ctx context.Context, headWithChain, latestFinalized H) (err error) - LatestChain() H -} - -// HeadTrackable is implemented by the core txm, -// to be able to receive head events from any chain. -// Chain implementations should notify head events to the core txm via this interface. -// -//go:generate mockery --quiet --name HeadTrackable --output ./mocks/ --case=underscore -type HeadTrackable[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - // OnNewLongestChain sends a new head when it becomes available. Subscribers can recursively trace the parent - // of the head to the finality depth back. If this is not possible (e.g. due to recent boot, backfill not complete - // etc), users may get a shorter linked list. If there is a re-org, older blocks won't be sent to this function again. - // But the new blocks from the re-org will be available in later blocks' parent linked list. - OnNewLongestChain(ctx context.Context, head H) -} - -// HeadSaver is an chain agnostic interface for saving and loading heads -// Different chains will instantiate generic HeadSaver type with their native Head and BlockHash types. -type HeadSaver[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - // Save updates the latest block number, if indeed the latest, and persists - // this number in case of reboot. - Save(ctx context.Context, head H) error - // Load loads latest heads up to latestFinalized - historyDepth, returns the latest chain. - Load(ctx context.Context, latestFinalized int64) (H, error) - // LatestChain returns the block header with the highest number that has been seen, or nil. - LatestChain() H - // Chain returns a head for the specified hash, or nil. - Chain(hash BLOCK_HASH) H - // MarkFinalized - marks matching block and all it's direct ancestors as finalized - MarkFinalized(ctx context.Context, latestFinalized H) error -} - -// HeadListener is a chain agnostic interface that manages connection of Client that receives heads from the blockchain node -type HeadListener[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - // ListenForNewHeads kicks off the listen loop (not thread safe) - // done() must be executed upon leaving ListenForNewHeads() - ListenForNewHeads(handleNewHead NewHeadHandler[H, BLOCK_HASH], done func()) - - // ReceivingHeads returns true if the listener is receiving heads (thread safe) - ReceivingHeads() bool - - // Connected returns true if the listener is connected (thread safe) - Connected() bool - - // HealthReport returns report of errors within HeadListener - HealthReport() map[string]error -} - -// NewHeadHandler is a callback that handles incoming heads -type NewHeadHandler[H Head[BLOCK_HASH], BLOCK_HASH Hashable] func(ctx context.Context, header H) error - -// HeadBroadcaster relays new Heads to all subscribers. -// -//go:generate mockery --quiet --name HeadBroadcaster --output ../mocks/ --case=underscore -type HeadBroadcaster[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - services.Service - BroadcastNewLongestChain(H) - HeadBroadcasterRegistry[H, BLOCK_HASH] -} - -//go:generate mockery --quiet --name HeadBroadcaster --output ../mocks/ --case=underscore -type HeadBroadcasterRegistry[H Head[BLOCK_HASH], BLOCK_HASH Hashable] interface { - Subscribe(callback HeadTrackable[H, BLOCK_HASH]) (currentLongestChain H, unsubscribe func()) -} diff --git a/common/types/subscription.go b/common/types/subscription.go index 99247107bec..36d41ce1a20 100644 --- a/common/types/subscription.go +++ b/common/types/subscription.go @@ -4,7 +4,6 @@ package types // delivered on a data channel. // This is a generic interface for Subscription to represent used by clients. -//go:generate mockery --quiet --name Subscription --output ./mocks/ --case=underscore type Subscription interface { // Unsubscribe cancels the sending of events to the data channel // and closes the error channel. diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index 17ee6f6d405..04673d5a622 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/common/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -30,7 +30,7 @@ import ( //go:generate mockery --quiet --name EvmFeeEstimator --output ./mocks/ --case=underscore type EvmFeeEstimator interface { services.Service - commontypes.HeadTrackable[*evmtypes.Head, common.Hash] + headtracker.HeadTrackable[*evmtypes.Head, common.Hash] // L1Oracle returns the L1 gas price oracle only if the chain has one, e.g. OP stack L2s and Arbitrum. L1Oracle() rollups.L1Oracle @@ -117,7 +117,7 @@ type EvmPriorAttempt struct { // //go:generate mockery --quiet --name EvmEstimator --output ./mocks/ --case=underscore type EvmEstimator interface { - commontypes.HeadTrackable[*evmtypes.Head, common.Hash] + headtracker.HeadTrackable[*evmtypes.Head, common.Hash] services.Service // GetLegacyGas Calculates initial gas fee for non-EIP1559 transaction diff --git a/core/chains/evm/headtracker/head_broadcaster.go b/core/chains/evm/headtracker/head_broadcaster.go index 9929646441a..e235df3752c 100644 --- a/core/chains/evm/headtracker/head_broadcaster.go +++ b/core/chains/evm/headtracker/head_broadcaster.go @@ -5,16 +5,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/headtracker" - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) type headBroadcaster = headtracker.HeadBroadcaster[*evmtypes.Head, common.Hash] -var _ commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] = &headBroadcaster{} - func NewHeadBroadcaster( lggr logger.Logger, -) *headBroadcaster { +) headBroadcaster { return headtracker.NewHeadBroadcaster[*evmtypes.Head, common.Hash](lggr) } diff --git a/core/chains/evm/headtracker/head_listener.go b/core/chains/evm/headtracker/head_listener.go index 242b59e9a82..964d686e803 100644 --- a/core/chains/evm/headtracker/head_listener.go +++ b/core/chains/evm/headtracker/head_listener.go @@ -8,20 +8,17 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/common/headtracker" - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) -type headListener = headtracker.HeadListener[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash] - -var _ commontypes.HeadListener[*evmtypes.Head, common.Hash] = (*headListener)(nil) +type headListener = headtracker.HeadListener[*evmtypes.Head, common.Hash] func NewHeadListener( lggr logger.Logger, ethClient evmclient.Client, config Config, chStop chan struct{}, -) *headListener { +) headListener { return headtracker.NewHeadListener[ *evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash, diff --git a/core/chains/evm/headtracker/head_saver.go b/core/chains/evm/headtracker/head_saver.go index 218f9d8366f..8913d2dec21 100644 --- a/core/chains/evm/headtracker/head_saver.go +++ b/core/chains/evm/headtracker/head_saver.go @@ -8,7 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/common/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) @@ -21,7 +21,7 @@ type headSaver struct { heads Heads } -var _ commontypes.HeadSaver[*evmtypes.Head, common.Hash] = (*headSaver)(nil) +var _ headtracker.HeadSaver[*evmtypes.Head, common.Hash] = (*headSaver)(nil) func NewHeadSaver(lggr logger.Logger, orm ORM, config Config, htConfig HeadTrackerConfig) httypes.HeadSaver { return &headSaver{ diff --git a/core/chains/evm/headtracker/head_tracker.go b/core/chains/evm/headtracker/head_tracker.go index 1fed1aa0c51..414dba23833 100644 --- a/core/chains/evm/headtracker/head_tracker.go +++ b/core/chains/evm/headtracker/head_tracker.go @@ -12,16 +12,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/headtracker" - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) -type headTracker = headtracker.HeadTracker[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash] - -var _ commontypes.HeadTracker[*evmtypes.Head, common.Hash] = (*headTracker)(nil) - func NewHeadTracker( lggr logger.Logger, ethClient evmclient.Client, diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index cb554196c87..b8bdb1f5703 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -30,7 +30,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" - commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" + htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" @@ -468,7 +468,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingEnabled(t *testing.T) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - checker := commonmocks.NewHeadTrackable[*evmtypes.Head, gethCommon.Hash](t) + checker := htmocks.NewHeadTrackable[*evmtypes.Head, gethCommon.Hash](t) orm := headtracker.NewORM(*evmtest.MustGetDefaultChainID(t, config.EVMConfigs()), db) csCfg := evmtest.NewChainScopedConfig(t, config) ht := createHeadTrackerWithChecker(t, ethClient, csCfg.EVM(), csCfg.EVM().HeadTracker(), orm, checker) @@ -597,7 +597,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingDisabled(t *testing.T ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - checker := commonmocks.NewHeadTrackable[*evmtypes.Head, gethCommon.Hash](t) + checker := htmocks.NewHeadTrackable[*evmtypes.Head, gethCommon.Hash](t) orm := headtracker.NewORM(cltest.FixtureChainID, db) evmcfg := evmtest.NewChainScopedConfig(t, config) ht := createHeadTrackerWithChecker(t, ethClient, evmcfg.EVM(), evmcfg.EVM().HeadTracker(), orm, checker) diff --git a/core/chains/evm/headtracker/types/types.go b/core/chains/evm/headtracker/types/types.go index 54918588283..1a03f3cec6f 100644 --- a/core/chains/evm/headtracker/types/types.go +++ b/core/chains/evm/headtracker/types/types.go @@ -5,22 +5,21 @@ import ( "github.com/ethereum/go-ethereum/common" - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/common/headtracker" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) // HeadSaver maintains chains persisted in DB. All methods are thread-safe. type HeadSaver interface { - commontypes.HeadSaver[*evmtypes.Head, common.Hash] + headtracker.HeadSaver[*evmtypes.Head, common.Hash] // LatestHeadFromDB returns the highest seen head from DB. LatestHeadFromDB(ctx context.Context) (*evmtypes.Head, error) } // Type Alias for EVM Head Tracker Components type ( - HeadBroadcasterRegistry = commontypes.HeadBroadcasterRegistry[*evmtypes.Head, common.Hash] - HeadTracker = commontypes.HeadTracker[*evmtypes.Head, common.Hash] - HeadTrackable = commontypes.HeadTrackable[*evmtypes.Head, common.Hash] - HeadListener = commontypes.HeadListener[*evmtypes.Head, common.Hash] - HeadBroadcaster = commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] + HeadTracker = headtracker.HeadTracker[*evmtypes.Head, common.Hash] + HeadTrackable = headtracker.HeadTrackable[*evmtypes.Head, common.Hash] + HeadListener = headtracker.HeadListener[*evmtypes.Head, common.Hash] + HeadBroadcaster = headtracker.HeadBroadcaster[*evmtypes.Head, common.Hash] ) diff --git a/core/chains/legacyevm/mocks/chain.go b/core/chains/legacyevm/mocks/chain.go index d8cc4895493..87bdccf1891 100644 --- a/core/chains/legacyevm/mocks/chain.go +++ b/core/chains/legacyevm/mocks/chain.go @@ -8,8 +8,6 @@ import ( common "github.com/ethereum/go-ethereum/common" client "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - commontypes "github.com/smartcontractkit/chainlink/v2/common/types" - config "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" context "context" @@ -18,6 +16,8 @@ import ( gas "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + headtracker "github.com/smartcontractkit/chainlink/v2/common/headtracker" + log "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logger "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -165,19 +165,19 @@ func (_m *Chain) GetChainStatus(ctx context.Context) (types.ChainStatus, error) } // HeadBroadcaster provides a mock function with given fields: -func (_m *Chain) HeadBroadcaster() commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] { +func (_m *Chain) HeadBroadcaster() headtracker.HeadBroadcaster[*evmtypes.Head, common.Hash] { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for HeadBroadcaster") } - var r0 commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] - if rf, ok := ret.Get(0).(func() commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash]); ok { + var r0 headtracker.HeadBroadcaster[*evmtypes.Head, common.Hash] + if rf, ok := ret.Get(0).(func() headtracker.HeadBroadcaster[*evmtypes.Head, common.Hash]); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash]) + r0 = ret.Get(0).(headtracker.HeadBroadcaster[*evmtypes.Head, common.Hash]) } } @@ -185,19 +185,19 @@ func (_m *Chain) HeadBroadcaster() commontypes.HeadBroadcaster[*evmtypes.Head, c } // HeadTracker provides a mock function with given fields: -func (_m *Chain) HeadTracker() commontypes.HeadTracker[*evmtypes.Head, common.Hash] { +func (_m *Chain) HeadTracker() headtracker.HeadTracker[*evmtypes.Head, common.Hash] { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for HeadTracker") } - var r0 commontypes.HeadTracker[*evmtypes.Head, common.Hash] - if rf, ok := ret.Get(0).(func() commontypes.HeadTracker[*evmtypes.Head, common.Hash]); ok { + var r0 headtracker.HeadTracker[*evmtypes.Head, common.Hash] + if rf, ok := ret.Get(0).(func() headtracker.HeadTracker[*evmtypes.Head, common.Hash]); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(commontypes.HeadTracker[*evmtypes.Head, common.Hash]) + r0 = ret.Get(0).(headtracker.HeadTracker[*evmtypes.Head, common.Hash]) } } diff --git a/core/services/keeper/upkeep_executer.go b/core/services/keeper/upkeep_executer.go index bab2f73edfc..f86859f7452 100644 --- a/core/services/keeper/upkeep_executer.go +++ b/core/services/keeper/upkeep_executer.go @@ -60,7 +60,7 @@ type UpkeepExecuter struct { ethClient evmclient.Client config UpkeepExecuterConfig executionQueue chan struct{} - headBroadcaster httypes.HeadBroadcasterRegistry + headBroadcaster httypes.HeadBroadcaster gasEstimator gas.EvmFeeEstimator job job.Job mailbox *mailbox.Mailbox[*evmtypes.Head] diff --git a/core/services/ocr/contract_tracker_test.go b/core/services/ocr/contract_tracker_test.go index 185a9cd3197..678af35fa04 100644 --- a/core/services/ocr/contract_tracker_test.go +++ b/core/services/ocr/contract_tracker_test.go @@ -18,7 +18,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" - commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" + htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -49,7 +49,7 @@ func mustNewFilterer(t *testing.T) *offchainaggregator.OffchainAggregatorFiltere type contractTrackerUni struct { db *ocrmocks.OCRContractTrackerDB lb *logmocks.Broadcaster - hb *commonmocks.HeadBroadcaster[*evmtypes.Head, common.Hash] + hb *htmocks.HeadBroadcaster[*evmtypes.Head, common.Hash] ec *evmclimocks.Client tracker *ocr.OCRContractTracker } @@ -81,7 +81,7 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack } uni.db = ocrmocks.NewOCRContractTrackerDB(t) uni.lb = logmocks.NewBroadcaster(t) - uni.hb = commonmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) + uni.hb = htmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) uni.ec = evmtest.NewEthClientMock(t) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go index 3de22e507c7..592563f0b04 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go @@ -12,7 +12,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v2" - commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" + htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -46,7 +46,7 @@ func TestGetActiveUpkeepKeys(t *testing.T) { actives[id] = activeUpkeep{ID: idNum} } - mht := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + mht := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) rg := &EvmRegistry{ HeadProvider: HeadProvider{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go index b984101bc16..fefbda77cd7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go @@ -11,7 +11,7 @@ import ( ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" - commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" + htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -275,7 +275,7 @@ func TestBlockSubscriber_Cleanup(t *testing.T) { func TestBlockSubscriber_Start(t *testing.T) { lggr := logger.TestLogger(t) - hb := commonmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) + hb := htmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) hb.On("Subscribe", mock.Anything).Return(&evmtypes.Head{Number: 42}, func() {}) lp := new(mocks.LogPoller) lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: 100}, nil) diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index e0769fe5b64..bd0f803cada 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -18,7 +18,7 @@ import ( mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" - commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" + htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -117,7 +117,7 @@ func TestMercury_Observe(t *testing.T) { spec := pipeline.Spec{} ds.spec = spec - h := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + h := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ds.mercuryChainReader = evm.NewMercuryChainReader(h) head := &evmtypes.Head{ @@ -208,7 +208,7 @@ func TestMercury_Observe(t *testing.T) { assert.Equal(t, head.Number-1, obs.MaxFinalizedBlockNumber.Val) }) t.Run("if no current block available", func(t *testing.T) { - h2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + h2 := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) h2.On("LatestChain").Return((*evmtypes.Head)(nil)) ds.mercuryChainReader = evm.NewMercuryChainReader(h2) @@ -319,7 +319,7 @@ func TestMercury_Observe(t *testing.T) { t.Run("LatestBlocks is populated correctly", func(t *testing.T) { t.Run("when chain length is zero", func(t *testing.T) { - ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + ht2 := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return((*evmtypes.Head)(nil)) ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) @@ -344,7 +344,7 @@ func TestMercury_Observe(t *testing.T) { Parent: h5, } - ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + ht2 := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(h6) ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) @@ -367,7 +367,7 @@ func TestMercury_Observe(t *testing.T) { } } - ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + ht2 := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(heads[len(heads)-1]) ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) @@ -412,7 +412,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { } t.Run("returns head from headtracker if present", func(t *testing.T) { - headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + headTracker := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) headTracker.On("LatestChain").Return(&h, nil) ds.mercuryChainReader = evm.NewMercuryChainReader(headTracker) @@ -429,7 +429,7 @@ func TestMercury_SetLatestBlocks(t *testing.T) { }) t.Run("if headtracker returns nil head", func(t *testing.T) { - headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) + headTracker := htmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) // This can happen in some cases e.g. RPC node is offline headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) ds.mercuryChainReader = evm.NewChainReader(headTracker) diff --git a/core/services/relay/evm/request_round_tracker_test.go b/core/services/relay/evm/request_round_tracker_test.go index 324b76dc6de..9feb4b77348 100644 --- a/core/services/relay/evm/request_round_tracker_test.go +++ b/core/services/relay/evm/request_round_tracker_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" + htmocks "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -46,7 +46,7 @@ func mustNewFilterer(t *testing.T, address gethCommon.Address) *ocr2aggregator.O type contractTrackerUni struct { db *mocks.RequestRoundDB lb *logmocks.Broadcaster - hb *commonmocks.HeadBroadcaster[*evmtypes.Head, common.Hash] + hb *htmocks.HeadBroadcaster[*evmtypes.Head, common.Hash] ec *evmclimocks.Client requestRoundTracker *evm.RequestRoundTracker } @@ -78,7 +78,7 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack } uni.db = mocks.NewRequestRoundDB(t) uni.lb = logmocks.NewBroadcaster(t) - uni.hb = commonmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) + uni.hb = htmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) uni.ec = evmclimocks.NewClient(t) db := pgtest.NewSqlxDB(t)