diff --git a/docs/.misc/dev-guides/nix/getting-started.md b/docs/.misc/dev-guides/nix/getting-started.md index f55da4cad..a211ab598 100644 --- a/docs/.misc/dev-guides/nix/getting-started.md +++ b/docs/.misc/dev-guides/nix/getting-started.md @@ -46,7 +46,7 @@ cd pkg && golint ./... # lint your pkg directory cd integration-tests && golint ./... # lint integration tests # Or run directly without alias: -cd pkg && golangci-lint run --config <(curl -sSL https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/.golangci.yml | yq e '.formatters.settings.goimports.local-prefixes = ["github.com/smartcontractkit/chainlink-ton"]' -) --path-mode "abs" ./... +cd pkg && golangci-lint run --config <(curl -sSL https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/.golangci.yml | yq e '.formatters.settings.goimports.local-prefixes = ["github.com/smartcontractkit/chainlink-ton"] | .linters.enable += ["errcheck", "nilnil", "govet", "staticcheck"] | .linters.settings.errcheck = {"check-type-assertions": true, "check-blank": true} | .linters.settings.govet.enable += ["nilness"]' -) --path-mode "abs" ./... ``` This ensures you're always using the exact same lint rules as our CI without writing any config files locally. diff --git a/integration-tests/deployment/ccip/cs_add_lanes_test.go b/integration-tests/deployment/ccip/cs_add_lanes_test.go index 6f23354a5..c9c968ae8 100644 --- a/integration-tests/deployment/ccip/cs_add_lanes_test.go +++ b/integration-tests/deployment/ccip/cs_add_lanes_test.go @@ -11,9 +11,10 @@ import ( "github.com/Masterminds/semver/v3" chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-ccip/deployment/utils/mcms" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-ton/deployment/utils/sequence" @@ -75,7 +76,7 @@ func TestAddLanes(t *testing.T) { }, }) require.NoError(t, err, "Failed to apply DeployChainContracts changeset") - _ = out.DataStore.Merge(env.DataStore) + require.NoError(t, out.DataStore.Merge(env.DataStore)) env.DataStore = out.DataStore.Seal() // Get OnRamp Address from EVM diff --git a/integration-tests/deployment/ccip/cs_fast_curse_test.go b/integration-tests/deployment/ccip/cs_fast_curse_test.go index 2361029f2..8255c4057 100644 --- a/integration-tests/deployment/ccip/cs_fast_curse_test.go +++ b/integration-tests/deployment/ccip/cs_fast_curse_test.go @@ -7,9 +7,10 @@ import ( "github.com/Masterminds/semver/v3" chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-ccip/deployment/utils/mcms" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-ton/deployment/utils/sequence" @@ -70,7 +71,7 @@ func TestFastCurseTON(t *testing.T) { }, }) require.NoError(t, err, "Failed to apply DeployChainContracts changeset") - _ = out.DataStore.Merge(env.DataStore) + require.NoError(t, out.DataStore.Merge(env.DataStore)) env.DataStore = out.DataStore.Seal() // diff --git a/integration-tests/monitor/balance_test.go b/integration-tests/monitor/balance_test.go index a405d5086..d018100f9 100644 --- a/integration-tests/monitor/balance_test.go +++ b/integration-tests/monitor/balance_test.go @@ -150,7 +150,7 @@ func TestBalanceMonitor_Polling(t *testing.T) { err = balanceMonitor.Start(t.Context()) require.NoError(t, err) defer func() { - _ = balanceMonitor.Close() + require.NoError(t, balanceMonitor.Close()) }() // Wait a bit to allow the monitor to poll at least once diff --git a/integration-tests/smoke/chainaccessor/accessor_test.go b/integration-tests/smoke/chainaccessor/accessor_test.go index fdb861d3c..9ee594fe4 100644 --- a/integration-tests/smoke/chainaccessor/accessor_test.go +++ b/integration-tests/smoke/chainaccessor/accessor_test.go @@ -147,6 +147,7 @@ func Test_TonAccessor_MsgsBetweenSeqNums(t *testing.T) { func Test_TonAccessorCommitEventQueries(t *testing.T) { // Note: we don't test the API client interaction here, so we return empty client clientProvider := func(ctx context.Context) (ton.APIClientWrapped, error) { + //nolint:nilnil // mock return nil, nil } @@ -639,7 +640,8 @@ func testCommitReportsBasicHelper(t *testing.T, lp logpoller.Service, logStore l require.Equal(t, ccipocr3.SeqNum(1), merkleRoot.SeqNumsRange.Start(), "MinSeqNr should be 1") require.Equal(t, ccipocr3.SeqNum(1), merkleRoot.SeqNumsRange.End(), "MaxSeqNr should be 1") - expectedMerkleRootBytes, _ := hex.DecodeString("bea275bb6614f85036536bc670e540bc748118e90537b8441c950672f74607d5") + expectedMerkleRootBytes, err := hex.DecodeString("bea275bb6614f85036536bc670e540bc748118e90537b8441c950672f74607d5") + require.NoError(t, err) require.Equal(t, expectedMerkleRootBytes, merkleRoot.MerkleRoot[:], "MerkleRoot should match") // Validate PriceUpdates should be empty for this test (since we used merkleRootOnlyCell) @@ -695,11 +697,6 @@ func Test_TonAccessorExecutionStateChangedEventQueries(t *testing.T) { } func Test_TonAccessorExecutedMessages(t *testing.T) { - // Note: we don't test the API client interaction here, so we return empty client - clientProvider := func(ctx context.Context) (ton.APIClientWrapped, error) { - return nil, nil - } - // Setup in-memory store lggr := logger.Test(t) opts := &logpoller.ServiceOptions{ @@ -711,7 +708,8 @@ func Test_TonAccessorExecutedMessages(t *testing.T) { lp, err := logpoller.NewService( lggr, "test-chain", - clientProvider, + // Note: we don't test the API client interaction here, so we return empty client + mockClientProvider, opts, ) require.NoError(t, err) @@ -720,15 +718,15 @@ func Test_TonAccessorExecutedMessages(t *testing.T) { testExecutedMessagesHelper(t, lp, opts.LogStore, 1) } +func mockClientProvider(ctx context.Context) (ton.APIClientWrapped, error) { + //nolint:nilnil // mock + return nil, nil +} + // Test validation for MsgsBetweenSeqNums sequence number range func Test_TonAccessor_MsgsBetweenSeqNums_SequenceRangeValidation(t *testing.T) { lggr := logger.Test(t) - // Note: we don't test the API client interaction here, so we return empty client - clientProvider := func(ctx context.Context) (ton.APIClientWrapped, error) { - return nil, nil - } - opts := &logpoller.ServiceOptions{ Config: logpoller.DefaultConfigSet, FilterStore: inmemorystore.NewFilterStore("test-chain", lggr), @@ -738,7 +736,8 @@ func Test_TonAccessor_MsgsBetweenSeqNums_SequenceRangeValidation(t *testing.T) { lp, err := logpoller.NewService( lggr, "test-chain", - clientProvider, + // Note: we don't test the API client interaction here, so we return empty client + mockClientProvider, opts, ) require.NoError(t, err) @@ -788,11 +787,6 @@ func Test_TonAccessorExecutedMessages_WithPostgresStore(t *testing.T) { t.Skip("Skipping postgres test in short mode") } - // Note: we don't test the API client interaction here, so we return empty client - clientProvider := func(ctx context.Context) (ton.APIClientWrapped, error) { - return nil, nil - } - // Setup postgres store using testcontainers lggr := logger.Test(t) ds := pgtest.SetupTestDB(t) @@ -814,7 +808,8 @@ func Test_TonAccessorExecutedMessages_WithPostgresStore(t *testing.T) { lp, err := logpoller.NewService( lggr, "test-chain", - clientProvider, + // Note: we don't test the API client interaction here, so we return empty client + mockClientProvider, opts, ) require.NoError(t, err) diff --git a/integration-tests/smoke/logpoller/log_poller_test.go b/integration-tests/smoke/logpoller/log_poller_test.go index 4bfa4cc8a..fca15bec0 100644 --- a/integration-tests/smoke/logpoller/log_poller_test.go +++ b/integration-tests/smoke/logpoller/log_poller_test.go @@ -107,7 +107,8 @@ func Test_LogPoller(t *testing.T) { indexedCells := make([]*cell.Cell, 0, len(txs)) for _, tx := range txs { - msgs, _ := tx.Transaction.IO.Out.ToSlice() + msgs, serr := tx.Transaction.IO.Out.ToSlice() + require.NoError(t, serr) for _, msg := range msgs { // test contract only emits ExternalMessageOut if msg.MsgType == tlb.MsgTypeExternalOut { @@ -152,7 +153,8 @@ func Test_LogPoller(t *testing.T) { // Extract messages from the loaded transactions for _, tx := range txs { - msgs, _ := tx.Transaction.IO.Out.ToSlice() + msgs, serr := tx.Transaction.IO.Out.ToSlice() + require.NoError(t, serr) for _, msg := range msgs { if msg.MsgType == tlb.MsgTypeExternalOut { if extOut := msg.AsExternalOut(); extOut != nil { @@ -894,7 +896,8 @@ func Test_LogPoller(t *testing.T) { return counterValue == preReplayEvents }, 30*time.Second, 1*time.Second, "counter should reach expected value") - counterValue, _ := counter.GetValue(t.Context(), tonChain.Client, emitter.ContractAddress()) + counterValue, err := counter.GetValue(t.Context(), tonChain.Client, emitter.ContractAddress()) + require.NoError(t, err) require.Equal(t, preReplayEvents, int(counterValue)) // 3. Start LogPoller (with in-memory stores) @@ -922,10 +925,11 @@ func Test_LogPoller(t *testing.T) { defer func() { require.NoError(t, lp.Close()) }() // 5. Verify no logs before replay - logs, _, _, _ := lp.NewQuery(). + logs, _, _, err := lp.NewQuery(). WithSource(emitter.ContractAddress()). WithEventSig(counter.TopicCountIncreased). Execute(t.Context()) + require.NoError(t, err) require.Empty(t, logs, "should have no logs before replay") // 6. Request replay from block before events were emitted @@ -956,7 +960,8 @@ func Test_LogPoller(t *testing.T) { return false } - result, _ := query.DecodedLogs[counter.CountIncreased](logs) + result, serr := query.DecodedLogs[counter.CountIncreased](logs) + require.NoError(t, serr) t.Logf("found %d logs after replay", len(result)) return len(result) == preReplayEvents }, 60*time.Second, 2*time.Second, "replay should complete and index all events") @@ -969,11 +974,13 @@ func Test_LogPoller(t *testing.T) { } require.Eventually(t, func() bool { - logs, _, _, _ := lp.NewQuery(). + logs, _, _, err := lp.NewQuery(). WithSource(emitter.ContractAddress()). WithEventSig(counter.TopicCountIncreased). Execute(t.Context()) - result, _ := query.DecodedLogs[counter.CountIncreased](logs) + require.NoError(t, err) + result, err := query.DecodedLogs[counter.CountIncreased](logs) + require.NoError(t, err) return len(result) == preReplayEvents+postReplayEvents }, 30*time.Second, 2*time.Second, "should index new events after replay") }) diff --git a/pkg/bindings/test/examples/jetton/simple_jetton_receiver.go b/pkg/bindings/test/examples/jetton/simple_jetton_receiver.go index d7e96ac28..fa41ac236 100644 --- a/pkg/bindings/test/examples/jetton/simple_jetton_receiver.go +++ b/pkg/bindings/test/examples/jetton/simple_jetton_receiver.go @@ -72,6 +72,9 @@ func (r SimpleJettonReceiver) GetAmountChecker() (*tlb.Coins, error) { return &coins, nil } +// GetPayloadChecker retrieves the payload checker cell, if set +// Returns nil if no payload checker is set +// Returns an error if retrieval or parsing fails func (r SimpleJettonReceiver) GetPayloadChecker() (*cell.Cell, error) { result, err := r.Contract.Get("payloadChecker") if err != nil { @@ -85,6 +88,7 @@ func (r SimpleJettonReceiver) GetPayloadChecker() (*cell.Cell, error) { if isPayloadCheckerNil { fmt.Printf("Payload checker is nil, no payload validation will be performed\n") fmt.Printf("As tupple: %v\n", result.AsTuple()) + //nolint: nilnil // Explicit nil return return nil, nil // No payload checker set } diff --git a/pkg/ccip/bindings/common/common_test.go b/pkg/ccip/bindings/common/common_test.go index d2130ec9f..e8932bcbd 100644 --- a/pkg/ccip/bindings/common/common_test.go +++ b/pkg/ccip/bindings/common/common_test.go @@ -484,7 +484,9 @@ func TestLoadCrossChainAddressWithoutPrefix_Validation(t *testing.T) { setupFunc: func() *cell.Slice { builder := cell.BeginCell() addr := []byte{0x01, 0x02, 0x03, 0x04, 0x05} - _ = builder.StoreSlice(addr, uint(len(addr))*8) + if err := builder.StoreSlice(addr, uint(len(addr))*8); err != nil { + panic(err) + } return builder.EndCell().BeginParse() }, expectErr: "", @@ -502,7 +504,9 @@ func TestLoadCrossChainAddressWithoutPrefix_Validation(t *testing.T) { setupFunc: func() *cell.Slice { builder := cell.BeginCell() addr := make([]byte, 65) - _ = builder.StoreSlice(addr, uint(len(addr))*8) + if err := builder.StoreSlice(addr, uint(len(addr))*8); err != nil { + panic(err) + } return builder.EndCell().BeginParse() }, expectErr: "exceeds maximum of 64 bytes", @@ -531,14 +535,14 @@ func TestUnloadCellToByteArray_Validation(t *testing.T) { t.Run("exceeds maximum cell chain depth", func(t *testing.T) { // Create a cell chain that exceeds MaxCellChainDepth builder := cell.BeginCell() - _ = builder.StoreSlice([]byte{0x01}, 8) + require.NoError(t, builder.StoreSlice([]byte{0x01}, 8)) root := builder.EndCell() // Build a chain longer than MaxCellChainDepth for i := 0; i < MaxCellChainDepth+1; i++ { builder = cell.BeginCell() - _ = builder.StoreSlice([]byte{0x01}, 8) - _ = builder.StoreRef(root) + require.NoError(t, builder.StoreSlice([]byte{0x01}, 8)) + require.NoError(t, builder.StoreRef(root)) root = builder.EndCell() } @@ -577,28 +581,28 @@ func TestUnpackArrayWithRefChaining_Validation(t *testing.T) { // Create a cell chain that exceeds MaxCellChainDepth by building a deep chain // Start with a valid element cell elemBuilder := cell.BeginCell() - _ = elemBuilder.StoreSlice([]byte{0x01}, 8) + require.NoError(t, elemBuilder.StoreSlice([]byte{0x01}, 8)) elemCell := elemBuilder.EndCell() // Build initial cell with 3 data refs and 1 chain ref builder := cell.BeginCell() for i := 0; i < 3; i++ { - _ = builder.StoreRef(elemCell) + require.NoError(t, builder.StoreRef(elemCell)) } // Add a chain ref to continue chainBuilder := cell.BeginCell() - _ = chainBuilder.StoreRef(elemCell) + require.NoError(t, chainBuilder.StoreRef(elemCell)) chainCell := chainBuilder.EndCell() - _ = builder.StoreRef(chainCell) + require.NoError(t, builder.StoreRef(chainCell)) root := builder.EndCell() // Now extend the chain beyond MaxCellChainDepth for i := 0; i < MaxCellChainDepth; i++ { builder = cell.BeginCell() for j := 0; j < 3; j++ { - _ = builder.StoreRef(elemCell) + require.NoError(t, builder.StoreRef(elemCell)) } - _ = builder.StoreRef(root) + require.NoError(t, builder.StoreRef(root)) root = builder.EndCell() } @@ -682,24 +686,24 @@ func TestMaxArrayLength_Validation(t *testing.T) { // We'll create a chain with 4 refs each, where each ref contains data // This should be caught during unpacking elemBuilder := cell.BeginCell() - _ = elemBuilder.StoreSlice([]byte{0x01}, 8) + require.NoError(t, elemBuilder.StoreSlice([]byte{0x01}, 8)) elemCell := elemBuilder.EndCell() // Build chains that would exceed MaxArrayLength // Each cell can have 3 data refs + 1 chain ref // We need > 1000 elements, so > 334 cells (1000/3 = 333.33) builder := cell.BeginCell() - _ = builder.StoreRef(elemCell) - _ = builder.StoreRef(elemCell) - _ = builder.StoreRef(elemCell) + require.NoError(t, builder.StoreRef(elemCell)) + require.NoError(t, builder.StoreRef(elemCell)) + require.NoError(t, builder.StoreRef(elemCell)) root := builder.EndCell() for i := 0; i < MaxArrayLength/3+2; i++ { builder = cell.BeginCell() - _ = builder.StoreRef(elemCell) - _ = builder.StoreRef(elemCell) - _ = builder.StoreRef(elemCell) - _ = builder.StoreRef(root) + require.NoError(t, builder.StoreRef(elemCell)) + require.NoError(t, builder.StoreRef(elemCell)) + require.NoError(t, builder.StoreRef(elemCell)) + require.NoError(t, builder.StoreRef(root)) root = builder.EndCell() } diff --git a/pkg/ccip/chainaccessor/config.go b/pkg/ccip/chainaccessor/config.go index edaeffd92..4b9fd92a3 100644 --- a/pkg/ccip/chainaccessor/config.go +++ b/pkg/ccip/chainaccessor/config.go @@ -143,6 +143,7 @@ func (a *TONAccessor) GetOffRampSourceChainConfigs(ctx context.Context, block *t // if the dictionary is empty, we get back nil if len(sourceConfigsGot) == 0 { + //nolint:nilnil // returning nil map is acceptable here? return nil, nil } diff --git a/pkg/ccip/chainaccessor/ton_accessor.go b/pkg/ccip/chainaccessor/ton_accessor.go index 873dca25f..0db0254d0 100644 --- a/pkg/ccip/chainaccessor/ton_accessor.go +++ b/pkg/ccip/chainaccessor/ton_accessor.go @@ -621,6 +621,7 @@ func (a *TONAccessor) ExecutedMessages( if len(nonEmptyRangesPerChain) == 0 { lggr.Debugw("no sequence numbers to query", "nonEmptyRangesPerChain", nonEmptyRangesPerChain) + //nolint:nilnil // returning nil map is acceptable here? return nil, nil } diff --git a/pkg/ccip/codec/commitcodec_test.go b/pkg/ccip/codec/commitcodec_test.go index 4a2a20c57..09933bf54 100644 --- a/pkg/ccip/codec/commitcodec_test.go +++ b/pkg/ccip/codec/commitcodec_test.go @@ -183,7 +183,10 @@ func TestCommitPluginCodecV1(t *testing.T) { func randomBytes32() (r [32]byte) { b := make([]byte, 32) - _, _ = cryptorand.Read(b) // Assignment for errcheck. Only used in tests so we can ignore. + _, err := cryptorand.Read(b) + if err != nil { + panic(err) + } copy(r[:], b) return } diff --git a/pkg/ccip/model/offramp.go b/pkg/ccip/model/offramp.go index 4b24239df..a3bf8b676 100644 --- a/pkg/ccip/model/offramp.go +++ b/pkg/ccip/model/offramp.go @@ -233,13 +233,13 @@ func (s *OffRampStorage) FromBinding(raw *offramp.Storage) error { b = b.WithOCR3BaseChainID(int(raw.OCR3Base.ChainID)) // OCR3Base.Config.Commit - commit, err := ocr3ConfigToModel(raw.OCR3Base.Commit) + commit, err := maybeOcr3ConfigToModel(raw.OCR3Base.Commit) if err != nil { return fmt.Errorf("error while loading OCR3Base.Commit: %w", err) } // OCR3Base.Config.Execute - execute, err := ocr3ConfigToModel(raw.OCR3Base.Execute) + execute, err := maybeOcr3ConfigToModel(raw.OCR3Base.Execute) if err != nil { return fmt.Errorf("error while loading OCR3Base.Execute: %w", err) } @@ -295,119 +295,124 @@ func (s *OffRampStorage) FromBinding(raw *offramp.Storage) error { return nil } -func ocr3ConfigToModel(raw *offramp.OCR3Config) (*OCR3Config, error) { - if raw != nil { - // OCR3Base.Config.Signers - signersMap, err := raw.Signers.LoadAll() +// maybeOcr3ConfigToModel converts a binding OCR3Config to a model OCR3Config, +// returning nil if the input is nil. +func maybeOcr3ConfigToModel(raw *offramp.OCR3Config) (*OCR3Config, error) { + if raw == nil { + //nolint:nilnil // Explicit nil return + return nil, nil + } - if err != nil { - return nil, fmt.Errorf("error while loading signers: %w", err) - } + // OCR3Base.Config.Signers + signersMap, err := raw.Signers.LoadAll() - var signers []*big.Int - for _, signerEntry := range signersMap { - signer, err2 := signerEntry.Key.LoadBigUInt(256) - if err2 != nil { - return nil, fmt.Errorf("error while decoding signer: %w", err2) - } + if err != nil { + return nil, fmt.Errorf("error while loading signers: %w", err) + } - signers = append(signers, signer) + signers := make([]*big.Int, 0, len(signersMap)) + for _, signerEntry := range signersMap { + signer, err2 := signerEntry.Key.LoadBigUInt(256) + if err2 != nil { + return nil, fmt.Errorf("error while decoding signer: %w", err2) } - // OCR3Base.Config.Transmitters - transmittersMap, err := raw.Transmitters.LoadAll() + signers = append(signers, signer) + } - if err != nil { - return nil, fmt.Errorf("error while loading transmitters: %w", err) - } + // OCR3Base.Config.Transmitters + transmittersMap, err := raw.Transmitters.LoadAll() - var transmitters []*address.Address - for _, transmitterEntry := range transmittersMap { - var transmitter common.AddressWrap - if err2 := tlb.LoadFromCell(&transmitter, transmitterEntry.Key); err2 != nil { - return nil, fmt.Errorf("error while decoding transmitter value: %w", err2) - } + if err != nil { + return nil, fmt.Errorf("error while loading transmitters: %w", err) + } - transmitters = append(transmitters, transmitter.Val) + transmitters := make([]*address.Address, 0, len(transmittersMap)) + for _, transmitterEntry := range transmittersMap { + var transmitter common.AddressWrap + if err2 := tlb.LoadFromCell(&transmitter, transmitterEntry.Key); err2 != nil { + return nil, fmt.Errorf("error while decoding transmitter value: %w", err2) } - wrappedSigners, err := bigIntArrayToHexArray(signers, 32) // 256 bits = 32 bytes - if err != nil { - return nil, fmt.Errorf("error while loading transmitters: %w", err) - } + transmitters = append(transmitters, transmitter.Val) + } - commitConfig := OCR3Config{ - ConfigDigest: hex.EncodeToString(raw.ConfigInfo.ConfigDigest), - Signers: wrappedSigners, - Transmitters: transmitters, - F: int(raw.ConfigInfo.F), - N: int(raw.ConfigInfo.N), - IsSignatureVerificationEnabled: raw.ConfigInfo.IsSignatureVerificationEnabled, - } + wrappedSigners, err := bigIntArrayToHexArray(signers, 32) // 256 bits = 32 bytes + if err != nil { + return nil, fmt.Errorf("error while loading transmitters: %w", err) + } - return &commitConfig, nil + commitConfig := OCR3Config{ + ConfigDigest: hex.EncodeToString(raw.ConfigInfo.ConfigDigest), + Signers: wrappedSigners, + Transmitters: transmitters, + F: int(raw.ConfigInfo.F), + N: int(raw.ConfigInfo.N), + IsSignatureVerificationEnabled: raw.ConfigInfo.IsSignatureVerificationEnabled, } - return nil, nil + return &commitConfig, nil } -func ocr3ConfigToBinding(config *OCR3Config) (*offramp.OCR3Config, error) { - if config != nil { - // OCR3Base.Config.Signers - signers := cell.NewDict(256) - for _, rawSigner := range config.Signers { - signer, err := hexToBigInt(rawSigner) - if err != nil { - return nil, fmt.Errorf("error while decoding signer: %w", err) - } - - if err := signers.Set( - cell.BeginCell().MustStoreBigUInt(signer, 256).EndCell(), - cell.BeginCell().EndCell(), - ); err != nil { - return nil, fmt.Errorf("error while setting signers: %w", err) - } +// maybeOcr3ConfigToBinding converts a model OCR3Config to a binding OCR3Config, +// returning nil if the input is nil. +func maybeOcr3ConfigToBinding(config *OCR3Config) (*offramp.OCR3Config, error) { + if config == nil { + //nolint:nilnil // Explicit nil return + return nil, nil + } + // OCR3Base.Config.Signers + signers := cell.NewDict(256) + for _, rawSigner := range config.Signers { + signer, err := hexToBigInt(rawSigner) + if err != nil { + return nil, fmt.Errorf("error while decoding signer: %w", err) } - // OCR3Base.Config.Transmitters - transmitters := cell.NewDict(267) - for _, transmitter := range config.Transmitters { - if err := transmitters.Set( - cell.BeginCell().MustStoreAddr(transmitter).EndCell(), - cell.BeginCell().EndCell(), - ); err != nil { - return nil, fmt.Errorf("error while setting transmitters: %w", err) - } + if err := signers.Set( + cell.BeginCell().MustStoreBigUInt(signer, 256).EndCell(), + cell.BeginCell().EndCell(), + ); err != nil { + return nil, fmt.Errorf("error while setting signers: %w", err) } + } - if config.F < 0 || config.F > math.MaxUint8 { - return nil, fmt.Errorf("f in ocr3base %d overflows or underflows uint8", config.F) + // OCR3Base.Config.Transmitters + transmitters := cell.NewDict(267) + for _, transmitter := range config.Transmitters { + if err := transmitters.Set( + cell.BeginCell().MustStoreAddr(transmitter).EndCell(), + cell.BeginCell().EndCell(), + ); err != nil { + return nil, fmt.Errorf("error while setting transmitters: %w", err) } - fU8 := uint8(config.F) + } - if config.N < 0 || config.N > math.MaxUint8 { - return nil, fmt.Errorf("n in ocr3base %d overflows or underflows uint8", config.N) - } - nU8 := uint8(config.N) + if config.F < 0 || config.F > math.MaxUint8 { + return nil, fmt.Errorf("f in ocr3base %d overflows or underflows uint8", config.F) + } + fU8 := uint8(config.F) - configDigest, err := hex.DecodeString(config.ConfigDigest) - if err != nil { - return nil, fmt.Errorf("error while decoding configDigest: %w", err) - } + if config.N < 0 || config.N > math.MaxUint8 { + return nil, fmt.Errorf("n in ocr3base %d overflows or underflows uint8", config.N) + } + nU8 := uint8(config.N) - return &offramp.OCR3Config{ - Signers: signers, - Transmitters: transmitters, - ConfigInfo: offramp.ConfigInfo{ - ConfigDigest: configDigest, - F: fU8, - N: nU8, - IsSignatureVerificationEnabled: config.IsSignatureVerificationEnabled, - }, - }, nil + configDigest, err := hex.DecodeString(config.ConfigDigest) + if err != nil { + return nil, fmt.Errorf("error while decoding configDigest: %w", err) } - return nil, nil + return &offramp.OCR3Config{ + Signers: signers, + Transmitters: transmitters, + ConfigInfo: offramp.ConfigInfo{ + ConfigDigest: configDigest, + F: fU8, + N: nU8, + IsSignatureVerificationEnabled: config.IsSignatureVerificationEnabled, + }, + }, nil } func (s *OffRampStorage) ToBinding() (*offramp.Storage, error) { @@ -426,12 +431,12 @@ func (s *OffRampStorage) ToBinding() (*offramp.Storage, error) { return nil, fmt.Errorf("error while loading receive executor code: %w", err) } - commitOCR3Config, err := ocr3ConfigToBinding(s.OCR3Base.Commit) + commitOCR3Config, err := maybeOcr3ConfigToBinding(s.OCR3Base.Commit) if err != nil { return nil, fmt.Errorf("error while loading commit OCR3 config: %w", err) } - executeOCR3Config, err := ocr3ConfigToBinding(s.OCR3Base.Execute) + executeOCR3Config, err := maybeOcr3ConfigToBinding(s.OCR3Base.Execute) if err != nil { return nil, fmt.Errorf("error while loading execute OCR3 config: %w", err) } diff --git a/pkg/config/toml_test.go b/pkg/config/toml_test.go index 0009eadc1..8254ba359 100644 --- a/pkg/config/toml_test.go +++ b/pkg/config/toml_test.go @@ -266,7 +266,8 @@ func TestSetFromChain(t *testing.T) { func TestNodeValidation(t *testing.T) { // Valid node passes name := "test-node" - url, _ := config.ParseURL("http://localhost:8081") + url, err := config.ParseURL("http://localhost:8081") + require.NoError(t, err) node := &Node{Name: &name, URL: url} require.NoError(t, node.ValidateConfig()) diff --git a/pkg/logpoller/block.go b/pkg/logpoller/block.go index 7971b65db..eda95e72d 100644 --- a/pkg/logpoller/block.go +++ b/pkg/logpoller/block.go @@ -45,6 +45,7 @@ func (lp *service) getBlockRange(ctx context.Context, currentMasterchainBlock *t // if we've already processed this block, wait for the next one (chain is idle) if currentMasterchainBlock.SeqNo <= lastProcessedBlockSeqNo { + //nolint:nilnil // No new blocks to process return nil, nil } @@ -101,7 +102,7 @@ func (lp *service) lookupBlock(ctx context.Context, seqNo uint32, currentMasterc // resolvePreviousBlock determines the previous block reference based on the last processed sequence number func (lp *service) resolvePreviousBlock(ctx context.Context, lastProcessedBlockSeqNo uint32, toBlock *ton.BlockIDExt) (*ton.BlockIDExt, error) { if lastProcessedBlockSeqNo == 0 { - // No previous block reference - lookback window returned 0 + //nolint:nilnil // No previous block reference - lookback window returned 0 // (chain is shorter than configured lookback duration, likely localnet) return nil, nil } diff --git a/pkg/logpoller/o11y_log_provider.go b/pkg/logpoller/o11y_log_provider.go index e6c8b583e..8113fb4a8 100644 --- a/pkg/logpoller/o11y_log_provider.go +++ b/pkg/logpoller/o11y_log_provider.go @@ -78,7 +78,10 @@ func (tlp *tonO11yLogProvider) extractExternalMsgOutLogs(ctx context.Context, tx var allLogs []models.RawLog for _, tx := range txs { - msgs, _ := tx.Transaction.IO.Out.ToSlice() + msgs, err := tx.Transaction.IO.Out.ToSlice() + if err != nil { + return nil, fmt.Errorf("failed to parse out messages for txHash=%v, LT=%d: %w", tx.Transaction.Hash, tx.Transaction.LT, err) + } blockData, err := tlp.client.GetBlockData(ctx, tx.Block) if err != nil { diff --git a/pkg/logpoller/replay_test.go b/pkg/logpoller/replay_test.go index 38602e98c..17eeaad6a 100644 --- a/pkg/logpoller/replay_test.go +++ b/pkg/logpoller/replay_test.go @@ -425,12 +425,14 @@ func TestReplay(t *testing.T) { go func() { defer wg.Done() <-ready - _ = lp.Replay(context.Background(), 60) // higher than 40, should be ignored + err := lp.Replay(context.Background(), 60) // higher than 40, should be ignored + _ = err // Intentionally ignored in concurrent test }() go func() { defer wg.Done() <-ready - _ = lp.Replay(context.Background(), 20) // lower than 40, should win + err := lp.Replay(context.Background(), 20) // lower than 40, should win + _ = err // Intentionally ignored in concurrent test }() close(ready) @@ -570,7 +572,8 @@ func TestReplayComplete(t *testing.T) { go func() { defer wg.Done() <-ready - _ = lp.Replay(context.Background(), 20) // Request for earlier block + err := lp.Replay(context.Background(), 20) // Request for earlier block + _ = err // Intentionally ignored in concurrent test }() close(ready) diff --git a/pkg/logpoller/store/postgres/models_test.go b/pkg/logpoller/store/postgres/models_test.go index 95ab78c2f..6a1b0b730 100644 --- a/pkg/logpoller/store/postgres/models_test.go +++ b/pkg/logpoller/store/postgres/models_test.go @@ -173,8 +173,14 @@ func TestCalculateBOCHeaderLen(t *testing.T) { { name: "CCIP message sent event", buildCell: func() *cell.Cell { - sender, _ := address.ParseAddr("EQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPrHF") - feeToken, _ := address.ParseAddr("EQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPrHF") + sender, err := address.ParseAddr("EQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPrHF") + if err != nil { + panic(err) + } + feeToken, err := address.ParseAddr("EQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPrHF") + if err != nil { + panic(err) + } event := onramp.CCIPMessageSent{ Message: ocr.TVM2AnyRampMessage{ @@ -198,7 +204,10 @@ func TestCalculateBOCHeaderLen(t *testing.T) { }, } - c, _ := tlb.ToCell(event) + c, err := tlb.ToCell(event) + if err != nil { + panic(err) + } return c }, }, @@ -212,7 +221,10 @@ func TestCalculateBOCHeaderLen(t *testing.T) { State: 2, } - c, _ := tlb.ToCell(event) + c, err := tlb.ToCell(event) + if err != nil { + panic(err) + } return c }, }, @@ -275,7 +287,10 @@ func TestBOCPayloadByteFiltering(t *testing.T) { MessageID: make([]byte, 32), State: 0x02, } - c, _ := tlb.ToCell(event) + c, err := tlb.ToCell(event) + if err != nil { + panic(err) + } return c }, expectedBytes: map[int][]byte{ diff --git a/pkg/logpoller/store/postgres/queryparser_test.go b/pkg/logpoller/store/postgres/queryparser_test.go index 605a05114..47c3f70d5 100644 --- a/pkg/logpoller/store/postgres/queryparser_test.go +++ b/pkg/logpoller/store/postgres/queryparser_test.go @@ -306,7 +306,8 @@ func TestBuildLogQuery(t *testing.T) { require.True(t, sqlMatches(t, tt.expectedSQL, sql)) if tt.checkParams != nil { - params := args.(map[string]any) + params, ok := args.(map[string]any) + require.True(t, ok, "args should be map[string]any") tt.checkParams(t, params) } }) diff --git a/pkg/relay/monitor/balance_test.go b/pkg/relay/monitor/balance_test.go index 874355416..ced6beb1c 100644 --- a/pkg/relay/monitor/balance_test.go +++ b/pkg/relay/monitor/balance_test.go @@ -24,7 +24,8 @@ func TestDecodeHexPublicKey(t *testing.T) { } // Extract and convert the public key - expectedPubKey := testPrivateKey.Public().(ed25519.PublicKey) + expectedPubKey, ok := testPrivateKey.Public().(ed25519.PublicKey) + require.True(t, ok, "public key should be ed25519.PublicKey") hexPubKey := hex.EncodeToString(expectedPubKey) // Test the decoding @@ -63,7 +64,8 @@ func TestHexPublicKeyToWalletAddress(t *testing.T) { } // Extract and convert the public key - pubKey := testPrivateKey.Public().(ed25519.PublicKey) + pubKey, ok := testPrivateKey.Public().(ed25519.PublicKey) + require.True(t, ok, "public key should be ed25519.PublicKey") hexPubKey := hex.EncodeToString(pubKey) // Test the conversion (no client needed - pure cryptographic operation) diff --git a/pkg/ton/tracetracking/message.go b/pkg/ton/tracetracking/message.go index 8d427bdc8..c273a030a 100644 --- a/pkg/ton/tracetracking/message.go +++ b/pkg/ton/tracetracking/message.go @@ -396,6 +396,7 @@ func (m SentMessage) MapToReceivedMessageIfMatches(rTX *tlb.Transaction) (*Recei } incomingMessage := rTX.IO.In.AsInternal() if !m.MatchesReceived(incomingMessage) { + //nolint:nilnil // No match found for this sent message return nil, nil } receivedMessage, err := MapToReceivedMessage(rTX) diff --git a/shell.nix b/shell.nix index 017745136..253264cca 100644 --- a/shell.nix +++ b/shell.nix @@ -42,6 +42,15 @@ pkgs.mkShell { ]; shellHook = '' # use upstream golangci-lint config from core Chainlink repository, overriding the local prefixes - alias golint="golangci-lint run --config <(curl -sSL https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/.golangci.yml | yq e '.formatters.settings.goimports.local-prefixes = [\"github.com/smartcontractkit/chainlink-ton\"]' -) --path-mode \"abs\"" + alias golint="golangci-lint run --config <(curl -sSL https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/.golangci.yml | yq e \ + '.formatters.settings.goimports.local-prefixes = [\"github.com/smartcontractkit/chainlink-ton\"] \ + | .linters.enable += [ \ + \"errcheck\", \ + \"nilnil\", \ + \"govet\", \ + \"staticcheck\" \ + ] \ + | .linters.settings.errcheck = {\"check-type-assertions\": true, \"check-blank\": true} \ + | .linters.settings.govet.enable += [\"nilness\"]' -) --path-mode \"abs\"" ''; }