浏览代码

ci: Add nolintlint to golangci-lint (#4346)

* ci: Add nolintlint tool

* nolint --> nosec
John Saigle 7 月之前
父节点
当前提交
eae85c9978

+ 18 - 0
.golangci.yml

@@ -24,6 +24,8 @@ linters:
     # Check for simple misspellings of words. 
     - misspell
     - noctx
+    # Require explanations for nolint comments
+    - nolintlint
     - prealloc
     # Overwriting predeclared Golang names such as 'len' and 'min'.
     - predeclared
@@ -88,6 +90,19 @@ linters:
         - weakCond
       # performance lints
         - indexAlloc
+    nolintlint:
+      # Disable to ensure that all nolint directives actually have an effect.
+      # Default: false
+      allow-unused: false
+      # Exclude following linters from requiring an explanation.
+      # Default: []
+      allow-no-explanation: [dupWord]
+      # Enable to require an explanation of nonzero length after each nolint directive.
+      # Default: false
+      require-explanation: true
+      # Enable to require nolint directives to mention the specific linter being suppressed.
+      # Default: false
+      require-specific: true
     staticcheck:
       checks:
         # All of these lints should eventually be added.
@@ -117,9 +132,12 @@ linters:
       - linters:
           - godox
         path: node/hack/
+      # Ignore test files for these tools.
       - linters:
           - contextcheck
+          - dupWord
           - exhaustruct
+          - nolintlint
         path: _test\.go
       - linters:
           - exhaustruct

+ 1 - 2
node/cmd/txverifier/evm.go

@@ -36,9 +36,8 @@ var (
 )
 
 // Function to initialize the configuration for the TransferVerifierCmdEvm flags.
-// The MarkFlagRequired calls will cause the script to fail on their own. No need to handle the errors manually.
 //
-//nolint:errcheck
+//nolint:errcheck // The MarkFlagRequired calls will cause the script to fail on their own. No need to handle the errors manually.
 func init() {
 	evmRpc = TransferVerifierCmdEvm.Flags().String("rpcUrl", "ws://localhost:8546", "RPC url")
 	evmCoreContract = TransferVerifierCmdEvm.Flags().String("coreContract", "", "core bridge address")

+ 1 - 2
node/cmd/txverifier/sui.go

@@ -36,9 +36,8 @@ var TransferVerifierCmdSui = &cobra.Command{
 }
 
 // CLI parameters
-// The MarkFlagRequired calls will cause the script to fail on their own. No need to handle the errors manually.
 //
-//nolint:errcheck
+//nolint:errcheck // The MarkFlagRequired calls will cause the script to fail on their own. No need to handle the errors manually.
 func init() {
 	suiRPC = TransferVerifierCmdSui.Flags().String("suiRPC", "", "Sui RPC url")
 	suiCoreContract = TransferVerifierCmdSui.Flags().String("suiCoreContract", "", "Sui core contract address")

+ 3 - 1
node/hack/release_verification/guardian_vaa_stats.go

@@ -30,7 +30,9 @@ func getValidatorIndexForChain(chainId vaa.ChainID, onlyafter time.Time) (map[ui
 	method := "GET"
 
 	client := &http.Client{}
-	req, err := http.NewRequest(method, url, nil) //nolint
+
+	//nolint:noctx // TODO: this function should use a context.
+	req, err := http.NewRequest(method, url, nil)
 
 	if err != nil {
 		return nil, err

+ 5 - 5
node/pkg/adminrpc/adminserver.go

@@ -361,7 +361,7 @@ func wormchainStoreCode(req *nodev1.WormchainStoreCode, timestamp time.Time, gua
 
 // wormchainInstantiateContract converts a nodev1.WormchainInstantiateContract to its canonical VAA representation
 // Returns an error if the data is invalid
-func wormchainInstantiateContract(req *nodev1.WormchainInstantiateContract, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
+func wormchainInstantiateContract(req *nodev1.WormchainInstantiateContract, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
 	instantiationParams_hash := vaa.CreateInstatiateCosmwasmContractHash(req.CodeId, req.Label, []byte(req.InstantiationMsg))
 
 	body, err := vaa.BodyWormchainInstantiateContract{
@@ -377,7 +377,7 @@ func wormchainInstantiateContract(req *nodev1.WormchainInstantiateContract, time
 }
 
 // wormchainMigrateContract converts a nodev1.WormchainMigrateContract to its canonical VAA representation
-func wormchainMigrateContract(req *nodev1.WormchainMigrateContract, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
+func wormchainMigrateContract(req *nodev1.WormchainMigrateContract, timestamp time.Time, guardianSetIndex uint32, nonce uint32, sequence uint64) (*vaa.VAA, error) {
 	instantiationParams_hash := vaa.CreateMigrateCosmwasmContractHash(req.CodeId, req.Contract, []byte(req.InstantiationMsg))
 
 	body, err := vaa.BodyWormchainMigrateContract{
@@ -398,7 +398,7 @@ func wormchainWasmInstantiateAllowlist(
 	guardianSetIndex uint32,
 	nonce uint32,
 	sequence uint64,
-) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
+) (*vaa.VAA, error) {
 	decodedAddr, err := sdktypes.GetFromBech32(req.Contract, "wormhole")
 	if err != nil {
 		return nil, err
@@ -435,7 +435,7 @@ func gatewayScheduleUpgrade(
 	guardianSetIndex uint32,
 	nonce uint32,
 	sequence uint64,
-) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
+) (*vaa.VAA, error) {
 
 	body, err := vaa.BodyGatewayScheduleUpgrade{
 		Name:   req.Name,
@@ -455,7 +455,7 @@ func gatewayCancelUpgrade(
 	guardianSetIndex uint32,
 	nonce uint32,
 	sequence uint64,
-) (*vaa.VAA, error) { //nolint:unparam // error is always nil but kept to mirror function signature of other functions
+) (*vaa.VAA, error) {
 
 	body, err := vaa.EmptyPayloadVaa(vaa.GatewayModuleStr, vaa.ActionCancelUpgrade, vaa.ChainIDWormchain)
 

+ 0 - 1
node/pkg/adminrpc/prototext_test.go

@@ -1,4 +1,3 @@
-//nolint:unparam
 package adminrpc
 
 type adminCommandTestEntry struct {

+ 1 - 1
node/pkg/common/armoredKey.go

@@ -8,7 +8,7 @@ import (
 	"os"
 
 	ethcrypto "github.com/ethereum/go-ethereum/crypto"
-	"golang.org/x/crypto/openpgp/armor" //nolint // Package is deprecated but we need it in the codebase still.
+	"golang.org/x/crypto/openpgp/armor" //nolint:staticcheck // Package is deprecated but we need it in the codebase still.
 	"google.golang.org/protobuf/proto"
 
 	nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1"

+ 5 - 5
node/pkg/common/chainlock_test.go

@@ -30,7 +30,7 @@ func encodePayloadBytes(payload *vaa.TransferPayloadHdr) []byte {
 }
 
 func TestSerializeAndDeserializeOfMessagePublication(t *testing.T) {
-	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E") //nolint:gosec
+	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E")
 	require.NoError(t, err)
 
 	targetAddress, err := vaa.StringToAddress("0x707f9118e33a9b8998bea41dd0d46f38bb963fc8")
@@ -90,7 +90,7 @@ func TestSerializeAndDeserializeOfMessagePublication(t *testing.T) {
 }
 
 func TestSerializeAndDeserializeOfMessagePublicationWithEmptyTxID(t *testing.T) {
-	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E") //nolint:gosec
+	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E")
 	require.NoError(t, err)
 
 	targetAddress, err := vaa.StringToAddress("0x707f9118e33a9b8998bea41dd0d46f38bb963fc8")
@@ -135,7 +135,7 @@ func TestSerializeAndDeserializeOfMessagePublicationWithEmptyTxID(t *testing.T)
 }
 
 func TestSerializeAndDeserializeOfMessagePublicationWithArbitraryTxID(t *testing.T) {
-	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E") //nolint:gosec
+	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E")
 	require.NoError(t, err)
 
 	targetAddress, err := vaa.StringToAddress("0x707f9118e33a9b8998bea41dd0d46f38bb963fc8")
@@ -233,7 +233,7 @@ func TestSerializeAndDeserializeOfMessagePublicationWithBigPayload(t *testing.T)
 }
 
 func TestMarshalUnmarshalJSONOfMessagePublication(t *testing.T) {
-	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E") //nolint:gosec
+	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E")
 	require.NoError(t, err)
 
 	targetAddress, err := vaa.StringToAddress("0x707f9118e33a9b8998bea41dd0d46f38bb963fc8")
@@ -279,7 +279,7 @@ func TestMarshalUnmarshalJSONOfMessagePublication(t *testing.T) {
 }
 
 func TestMarshalUnmarshalJSONOfMessagePublicationWithArbitraryTxID(t *testing.T) {
-	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E") //nolint:gosec
+	originAddress, err := vaa.StringToAddress("0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E")
 	require.NoError(t, err)
 
 	targetAddress, err := vaa.StringToAddress("0x707f9118e33a9b8998bea41dd0d46f38bb963fc8")

+ 2 - 2
node/pkg/governor/governor.go

@@ -144,8 +144,8 @@ func (ce *chainEntry) addFlowCancelTransfer(transfer transfer) error {
 	if transfer.dbTransfer.Value > math.MaxInt64 {
 		return fmt.Errorf("value for transfer.dbTransfer exceeds MaxInt64: %d", transfer.dbTransfer.Value)
 	}
-	// Type conversion is safe here because of the MaxInt64 bounds check above
-	if value != -int64(transfer.dbTransfer.Value) { // nolint:gosec
+	//#nosec G115: Type conversion is safe here because of the MaxInt64 bounds check above
+	if value != -int64(transfer.dbTransfer.Value) {
 		return fmt.Errorf("transfer is invalid: transfer.value %d must equal the inverse of transfer.dbTransfer.Value %d", value, transfer.dbTransfer.Value)
 	}
 	if targetChain != ce.emitterChainId {

+ 2 - 1
node/pkg/governor/governor_prices.go

@@ -257,7 +257,8 @@ func (gov *ChainGovernor) queryCoinGeckoChunk(query string) (map[string]interfac
 	var result map[string]interface{}
 
 	gov.logger.Debug("executing CoinGecko query", zap.String("query", query))
-	response, err := http.Get(query) //nolint:gosec,noctx
+	// #nosec G107 // the URL is hard-coded to the CoinGecko API. See [createCoinGeckoQuery].
+	response, err := http.Get(query) //nolint:noctx // TODO: a context should be added here.
 	if err != nil {
 		return result, fmt.Errorf("failed to query CoinGecko: %w", err)
 	}

+ 5 - 5
node/pkg/governor/governor_test.go

@@ -942,7 +942,7 @@ func TestFlowCancelProcessMsgForTimeFullCancel(t *testing.T) {
 	tokenBridgeAddrStrEthereum := "0x0290fb167208af455bb137780163b7b7a9a10c16" //nolint:gosec
 	tokenBridgeAddrEthereum, err := vaa.StringToAddress(tokenBridgeAddrStrEthereum)
 	require.NoError(t, err)
-	recipientEthereum := "0x707f9118e33a9b8998bea41dd0d46f38bb963fc8" //nolint:gosec
+	recipientEthereum := "0x707f9118e33a9b8998bea41dd0d46f38bb963fc8"
 
 	// Data for Sui
 	tokenBridgeAddrStrSui := "0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9" //nolint:gosec
@@ -1181,13 +1181,13 @@ func TestFlowCancelProcessMsgForTimePartialCancel(t *testing.T) {
 	tokenBridgeAddrStrEthereum := "0x0290fb167208af455bb137780163b7b7a9a10c16" //nolint:gosec
 	tokenBridgeAddrEthereum, err := vaa.StringToAddress(tokenBridgeAddrStrEthereum)
 	require.NoError(t, err)
-	recipientEthereum := "0x707f9118e33a9b8998bea41dd0d46f38bb963fc8" //nolint:gosec
+	recipientEthereum := "0x707f9118e33a9b8998bea41dd0d46f38bb963fc8"
 
 	// Data for Sui
 	tokenBridgeAddrStrSui := "0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9" //nolint:gosec
 	tokenBridgeAddrSui, err := vaa.StringToAddress(tokenBridgeAddrStrSui)
 	require.NoError(t, err)
-	recipientSui := "0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31" //nolint:gosec
+	recipientSui := "0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31"
 
 	// Add chain entries to `gov`
 	err = gov.setChainForTesting(vaa.ChainIDEthereum, tokenBridgeAddrStrEthereum, 10000, 0)
@@ -1716,7 +1716,7 @@ func TestPendingTransferFlowCancelsWhenReleased(t *testing.T) {
 	tokenBridgeAddrStrEthereum := "0x0290fb167208af455bb137780163b7b7a9a10c16" //nolint:gosec
 	tokenBridgeAddrEthereum, err := vaa.StringToAddress(tokenBridgeAddrStrEthereum)
 	require.NoError(t, err)
-	recipientEthereum := "0x707f9118e33a9b8998bea41dd0d46f38bb963fc8" //nolint:gosec
+	recipientEthereum := "0x707f9118e33a9b8998bea41dd0d46f38bb963fc8"
 
 	// Data for Sui
 	tokenBridgeAddrStrSui := "0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9" //nolint:gosec
@@ -2634,7 +2634,7 @@ func TestDontReloadDuplicates(t *testing.T) {
 	require.NoError(t, err)
 	assert.NotNil(t, gov)
 
-	emitterAddrStr := "0x0290fb167208af455bb137780163b7b7a9a10c16" //nolint:gosec
+	emitterAddrStr := "0x0290fb167208af455bb137780163b7b7a9a10c16"
 	emitterAddr, err := vaa.StringToAddress(emitterAddrStr)
 	require.NoError(t, err)
 

+ 1 - 1
node/pkg/guardiansigner/filesigner.go

@@ -13,7 +13,7 @@ import (
 	"google.golang.org/protobuf/proto"
 
 	nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1"
-	"golang.org/x/crypto/openpgp/armor" // nolint
+	"golang.org/x/crypto/openpgp/armor" //nolint:staticcheck // Package is deprecated but we need it in the codebase still.
 )
 
 // FileSigner is a signer that loads a guardian key from a file. The URI is expected to be

+ 1 - 1
node/pkg/guardiansigner/guardiansigner.go

@@ -60,7 +60,7 @@ func NewGuardianSignerFromUri(ctx context.Context, signerUri string, unsafeDevMo
 	// Create the new guardian signer, based on the signerType. If an invalid
 	// signer type is supplied, an error is returned; or if the signer creation
 	// returns an error, the error is bubbled up.
-	// nolint:exhaustive // default is sufficient for handling errors
+	//nolint:exhaustive // default is sufficient for handling errors
 	switch signerType {
 	case FileSignerType:
 		guardianSigner, err = NewFileSigner(ctx, unsafeDevMode, signerKeyConfig)

+ 2 - 1
node/pkg/node/node_test.go

@@ -366,7 +366,8 @@ type testCase struct {
 }
 
 func randomTime() time.Time {
-	return time.Unix(int64(math_rand.Uint32()%1700000000), 0) // nolint // convert time to unix and back to match what is done during serialization/de-serialization
+	// #nosec G404 we don't need cryptographic randomness here.
+	return time.Unix(int64(math_rand.Uint32()%1700000000), 0) // convert time to unix and back to match what is done during serialization/de-serialization
 }
 
 var someMsgSequenceCounter uint64 = 0

+ 2 - 1
node/pkg/processor/backoff.go

@@ -8,6 +8,7 @@ import (
 func nextRetryDuration(ctr uint) time.Duration {
 	m := 1 << ctr
 	wait := FirstRetryMinWait * time.Duration(m)
-	jitter := time.Duration(mathrand.Int63n(int64(wait))) // nolint:gosec
+	// #nosec G404 we don't need cryptographic randomness here.
+	jitter := time.Duration(mathrand.Int63n(int64(wait)))
 	return wait + jitter
 }

+ 1 - 1
node/pkg/processor/cleanup.go

@@ -1,4 +1,4 @@
-// nolint:unparam // this will be refactored in https://github.com/wormhole-foundation/wormhole/pull/1953
+//nolint:unparam // this will be refactored in https://github.com/wormhole-foundation/wormhole/pull/1953
 package processor
 
 import (

+ 0 - 1
node/pkg/processor/observation.go

@@ -1,4 +1,3 @@
-//nolint:unparam // this will be refactored in https://github.com/wormhole-foundation/wormhole/pull/1953
 package processor
 
 import (

+ 6 - 6
node/pkg/query/request.go

@@ -635,11 +635,11 @@ func (ecd *EthCallQueryRequest) Validate() error {
 		if len(callData.To) != EvmContractAddressLength {
 			return fmt.Errorf("invalid length for To contract")
 		}
-		//nolint:dupword // Data should be repeated in this context. This is the same for the other six in this file.
+		//nolint:dupword // callData.Data is fine in the context of EVM.
 		if callData.Data == nil || len(callData.Data) <= 0 {
 			return fmt.Errorf("no call data data")
 		}
-		//nolint:dupword
+		//nolint:dupword // callData.Data is fine in the context of EVM.
 		if len(callData.Data) > math.MaxUint32 {
 			return fmt.Errorf("call data data too long")
 		}
@@ -799,11 +799,11 @@ func (ecd *EthCallByTimestampQueryRequest) Validate() error {
 		if len(callData.To) != EvmContractAddressLength {
 			return fmt.Errorf("invalid length for To contract")
 		}
-		//nolint:dupword
+		//nolint:dupword // callData.Data is fine in the context of EVM.
 		if callData.Data == nil || len(callData.Data) <= 0 {
 			return fmt.Errorf("no call data data")
 		}
-		//nolint:dupword
+		//nolint:dupword // callData.Data is fine in the context of EVM.
 		if len(callData.Data) > math.MaxUint32 {
 			return fmt.Errorf("call data data too long")
 		}
@@ -964,11 +964,11 @@ func (ecd *EthCallWithFinalityQueryRequest) Validate() error {
 			return fmt.Errorf("invalid length for To contract")
 		}
 
-		//nolint:dupword
+		//nolint:dupword // callData.Data is fine in the context of EVM.
 		if callData.Data == nil || len(callData.Data) <= 0 {
 			return fmt.Errorf("no call data data")
 		}
-		//nolint:dupword
+		//nolint:dupword // callData.Data is fine in the context of EVM.
 		if len(callData.Data) > math.MaxUint32 {
 			return fmt.Errorf("call data data too long")
 		}

+ 1 - 2
node/pkg/txverifier/sui.go

@@ -205,7 +205,6 @@ func (s *SuiTransferVerifier) ProcessDigest(digest string, suiApiConnection SuiA
 			zap.String("amountIn", amountIn.String()))
 	}
 
-	//nolint:gosec
 	logger.Info("Digest processed", zap.String("txDigest", digest), zap.Uint("numEventsProcessed", numEventsProcessed), zap.Uint("numChangesProcessed", numChangesProcessed))
 
 	return numEventsProcessed, nil
@@ -221,7 +220,7 @@ func suiApiRequest[T SuiApiResponse](rpc string, method string, params string) (
 	// Create the request
 	requestBody := fmt.Sprintf(`{"jsonrpc":"2.0", "id": 1, "method": "%s", "params": %s}`, method, params)
 
-	//nolint:noctx
+	//nolint:noctx // TODO: this function should use a context
 	req, err := http.NewRequest("POST", rpc, strings.NewReader(requestBody))
 	if err != nil {
 		return defaultT, fmt.Errorf("cannot create request: %w", err)

+ 4 - 3
node/pkg/watchers/aptos/watcher.go

@@ -41,13 +41,12 @@ type (
 )
 
 var (
-	//nolint:exhaustruct // Intentional design of CounterOpts to not include all items in the struct.
 	aptosMessagesConfirmed = promauto.NewCounterVec(
 		prometheus.CounterOpts{
 			Name: "wormhole_aptos_observations_confirmed_total",
 			Help: "Total number of verified observations found for the chain",
 		}, []string{"chain_name"})
-	//nolint:exhaustruct // Intentional design of GaugeOpts to not include all items in the struct.
+
 	currentAptosHeight = promauto.NewGaugeVec(
 		prometheus.GaugeOpts{
 			Name: "wormhole_aptos_current_height",
@@ -269,8 +268,10 @@ func (e *Watcher) Run(ctx context.Context) error {
 	}
 }
 
+//nolint:noctx // TODO: this function should use a context. (Also this line flags nolintlint unless placed here.)
 func (e *Watcher) retrievePayload(s string) ([]byte, error) {
-	res, err := http.Get(s) // nolint
+	//nolint:gosec // the URL is hard-coded to the Aptos RPC endpoint.
+	res, err := http.Get(s)
 	if err != nil {
 		return nil, err
 	}

+ 3 - 1
node/pkg/watchers/evm/ccq.go

@@ -713,7 +713,9 @@ func ccqBuildBatchFromCallData(req EthCallDataIntf, callBlockArg interface{}) ([
 }
 
 // ccqVerifyBlockResult does basic verification on the results of the block query.
-func (w *Watcher) ccqVerifyBlockResult(blockError error, blockResult connectors.BlockMarshaller) error { //nolint:unparam
+//
+//nolint:unparam // Reports "always receives nil" but this is the intention.
+func (w *Watcher) ccqVerifyBlockResult(blockError error, blockResult connectors.BlockMarshaller) error {
 	if blockError != nil {
 		return blockError
 	}

+ 1 - 1
node/pkg/watchers/ibc/watcher.go

@@ -248,7 +248,7 @@ func (w *Watcher) Run(ctx context.Context) error {
 		p2p.DefaultRegistry.SetNetworkStats(ce.chainID, &gossipv1.Heartbeat_Network{ContractAddress: w.contractAddress})
 	}
 
-	// nolint:bodyclose // Misses the close below
+	//nolint:bodyclose // Misses the close below
 	c, _, err := websocket.Dial(ctx, w.wsUrl, nil)
 	if err != nil {
 		ibcErrors.WithLabelValues("websocket_dial_error").Inc()

+ 5 - 3
node/pkg/watchers/near/finalizer.go

@@ -10,7 +10,7 @@ import (
 )
 
 type Finalizer struct {
-	// internal cache of which blocks have been finalized, mapping blockHack => blockTimestamp.
+	// internal cache of which blocks have been finalized, mapping blockHash => blockTimestamp.
 	// The timestamp is persisted because we'll need it again later.
 	// thread-safe
 	finalizedBlocksCache *lru.Cache
@@ -38,7 +38,8 @@ func (f Finalizer) isFinalizedCached(logger *zap.Logger, blockHash string) (near
 	}
 
 	if b, ok := f.finalizedBlocksCache.Get(blockHash); ok {
-		blockHeader := b.(nearapi.BlockHeader) //nolint:forcetypeassert
+		//nolint:forcetypeassert // The cache must only hold valid block hashes.
+		blockHeader := b.(nearapi.BlockHeader)
 		// SECURITY In blocks < 74473147 message timestamps were computed differently and we don't want to re-observe these messages
 		if !f.mainnet || blockHeader.Height > 74473147 {
 			return blockHeader, true
@@ -113,7 +114,8 @@ func (f Finalizer) setFinalized(blockHeader nearapi.BlockHeader) {
 	f.finalizedBlocksCache.Add(blockHeader.Hash, blockHeader)
 }
 
-func (f Finalizer) setFinalizedHash(logger *zap.Logger, ctx context.Context, blockHash string) error { //nolint Ignore unused function for now; might come in handy later
+//nolint:unused // Ignore unused function for now; might come in handy later
+func (f Finalizer) setFinalizedHash(logger *zap.Logger, ctx context.Context, blockHash string) error {
 	logger.Debug("setFinalizedHash()", zap.String("blockHash", blockHash))
 	// SECURITY defense-in-depth: don't cache obviously corrupted data.
 	if nearapi.IsWellFormedHash(blockHash) != nil {

+ 3 - 1
node/pkg/watchers/near/nearapi/nearapi.go

@@ -50,7 +50,9 @@ type (
 
 func NewHttpNearRpc(nearRPC string) HttpNearRpc {
 	// Customize the Transport to have larger connection pool (default is only 2 per host)
-	t := http.DefaultTransport.(*http.Transport).Clone() //nolint:forcetypeassert
+
+	//nolint:forcetypeassert // This should always succeed, and the function is only called on start-up.
+	t := http.DefaultTransport.(*http.Transport).Clone()
 	t.MaxConnsPerHost = nearRPCConcurrentConnections
 	t.MaxIdleConnsPerHost = nearRPCConcurrentConnections
 	var httpClient = &http.Client{