From b00ad6909571042947f615b8740c31c304bbf7ec Mon Sep 17 00:00:00 2001 From: Silas Lenihan <32529249+silaslenihan@users.noreply.github.com> Date: Mon, 20 May 2024 16:48:47 -0400 Subject: [PATCH] Update finality depth check headtracker (#13089) * Update finality depth check headtracker Signed-off-by: Silas Lenihan * added check for nil prevLatestFinalized * added changeset * updated changeset * cleaned up nil protection in LatestFinalizedHead * Added error tuple to LatestFinalizedHead * Added error tuple to LatestFinalizedHead * removed error from LatestFinalizedHead --------- Signed-off-by: Silas Lenihan --- .changeset/witty-onions-talk.md | 5 +++++ common/headtracker/head_tracker.go | 5 +++-- common/types/head.go | 3 +++ common/types/mocks/head.go | 20 ++++++++++++++++++++ core/chains/evm/types/models.go | 8 ++++++-- core/internal/cltest/cltest.go | 2 +- 6 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 .changeset/witty-onions-talk.md diff --git a/.changeset/witty-onions-talk.md b/.changeset/witty-onions-talk.md new file mode 100644 index 00000000000..ddb4e9dbcd3 --- /dev/null +++ b/.changeset/witty-onions-talk.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#internal Switched finality check in HeadTracker to use the underlying finality type diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index bc7a4910b39..6247e87c673 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -250,8 +250,9 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context } } else { ht.log.Debugw("Got out of order head", "blockNum", head.BlockNumber(), "head", head.BlockHash(), "prevHead", prevHead.BlockNumber()) - prevUnFinalizedHead := prevHead.BlockNumber() - int64(ht.config.FinalityDepth()) - if head.BlockNumber() < prevUnFinalizedHead { + prevLatestFinalized := prevHead.LatestFinalizedHead() + + if prevLatestFinalized != nil && head.BlockNumber() <= prevLatestFinalized.BlockNumber() { promOldHead.WithLabelValues(ht.chainID.String()).Inc() ht.log.Criticalf("Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber()) ht.SvcErrBuffer.Append(errors.New("got very old block")) diff --git a/common/types/head.go b/common/types/head.go index 4ecdb981c78..9d927d4f5e4 100644 --- a/common/types/head.go +++ b/common/types/head.go @@ -38,4 +38,7 @@ type Head[BLOCK_HASH Hashable] interface { BlockDifficulty() *big.Int // IsValid returns true if the head is valid. IsValid() bool + + // Returns the latest finalized based on finality tag or depth + LatestFinalizedHead() Head[BLOCK_HASH] } diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index a8cbca07355..8fcd57a33c9 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -202,6 +202,26 @@ func (_m *Head[BLOCK_HASH]) IsValid() bool { return r0 } +// LatestFinalizedHead provides a mock function with given fields: +func (_m *Head[BLOCK_HASH]) LatestFinalizedHead() types.Head[BLOCK_HASH] { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for LatestFinalizedHead") + } + + 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 +} + // 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](t interface { diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 7e9d41205bf..2af5b81ccf8 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -168,11 +168,15 @@ func (h *Head) ChainHashes() []common.Hash { } func (h *Head) LatestFinalizedHead() commontypes.Head[common.Hash] { - for h != nil && !h.IsFinalized { + for h != nil { + if h.IsFinalized { + return h + } + h = h.Parent } - return h + return nil } func (h *Head) ChainID() *big.Int { diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index f6a127a309d..f5ae71d9f46 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -991,7 +991,7 @@ func AssertEthTxAttemptCountStays(t testing.TB, txStore txmgr.TestEvmTxStore, wa return txaIds } -// Head given the value convert it into an Head +// Head given the value convert it into a Head func Head(val interface{}) *evmtypes.Head { var h evmtypes.Head time := uint64(0)