lint: enable deprecation checks

Enable staticcheck's SA1019 check in golangci-lint so deprecated
identifiers are caught in CI.

Replace deprecated standard library and bbolt APIs with their current
equivalents. Keep intentional compatibility reads and writes of
deprecated Loop RPC fields behind narrow nolint annotations, because
older clients and persisted liquidity parameters still depend on those
fields.
This commit is contained in:
Boris Nagaev 2026-06-20 17:55:35 -05:00
parent d324b4bfd8
commit 5d8a5019cf
No known key found for this signature in database
12 changed files with 42 additions and 52 deletions

View file

@ -55,14 +55,16 @@ linters:
- wsl_v5 - wsl_v5
- noinlineerr - noinlineerr
settings: settings:
staticcheck:
checks:
- all
- -QF*
- -ST*
gosec: gosec:
excludes: excludes:
- G402 - G402
- G306 - G306
- G115 - G115
staticcheck:
checks:
- -SA1019
tagliatelle: tagliatelle:
case: case:
rules: rules:

View file

@ -207,7 +207,7 @@ func loopIn(ctx context.Context, cmd *cli.Command) error {
} }
fmt.Printf("Swap initiated\n") fmt.Printf("Swap initiated\n")
fmt.Printf("ID: %v\n", resp.Id) fmt.Printf("ID: %x\n", resp.IdBytes)
if resp.HtlcAddressP2Tr != "" { if resp.HtlcAddressP2Tr != "" {
fmt.Printf("HTLC address (P2TR): %v\n", resp.HtlcAddressP2Tr) fmt.Printf("HTLC address (P2TR): %v\n", resp.HtlcAddressP2Tr)

View file

@ -6,7 +6,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
@ -646,7 +645,7 @@ func getClientConn(address, tlsCertPath, macaroonPath string) (daemonConn,
// gRPC dial options from it. // gRPC dial options from it.
func readMacaroon(macPath string) (grpc.DialOption, error) { func readMacaroon(macPath string) (grpc.DialOption, error) {
// Load the specified macaroon file. // Load the specified macaroon file.
macBytes, err := ioutil.ReadFile(macPath) macBytes, err := os.ReadFile(macPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to read macaroon path : %v", err) return nil, fmt.Errorf("unable to read macaroon path : %v", err)
} }

View file

@ -559,8 +559,11 @@ func RpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters,
req.AutoloopBudgetSat != 0 { req.AutoloopBudgetSat != 0 {
params.AutoFeeRefreshPeriod = InfiniteDuration params.AutoFeeRefreshPeriod = InfiniteDuration
// Keep reading the legacy start field so old stored
// liquidity parameters migrate to the refresh-period model.
budgetStartSec := req.AutoloopBudgetStartSec //nolint:staticcheck
params.AutoloopBudgetLastRefresh = time.Unix( params.AutoloopBudgetLastRefresh = time.Unix(
int64(req.AutoloopBudgetStartSec), 0) int64(budgetStartSec), 0)
} }
for _, rule := range req.Rules { for _, rule := range req.Rules {

View file

@ -33,7 +33,7 @@ import (
"github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/macaroons"
"go.etcd.io/bbolt" bbolterrors "go.etcd.io/bbolt/errors"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
"gopkg.in/macaroon-bakery.v2/bakery" "gopkg.in/macaroon-bakery.v2/bakery"
@ -161,7 +161,7 @@ func (d *Daemon) Start() error {
// and error handlers. If this fails, then nothing has been started yet, // and error handlers. If this fails, then nothing has been started yet,
// and we can just return the error. // and we can just return the error.
err = d.initialize(true) err = d.initialize(true)
if errors.Is(err, bbolt.ErrTimeout) { if errors.Is(err, bbolterrors.ErrTimeout) {
// We're trying to be started as a standalone Loop daemon, most // We're trying to be started as a standalone Loop daemon, most
// likely LiT is already running and blocking the DB // likely LiT is already running and blocking the DB
return fmt.Errorf("%v: make sure no other loop daemon process "+ return fmt.Errorf("%v: make sure no other loop daemon process "+
@ -211,7 +211,7 @@ func (d *Daemon) StartAsSubserver(lndGrpc *lndclient.GrpcLndServices,
// handlers. If this fails, then nothing has been started yet, and we // handlers. If this fails, then nothing has been started yet, and we
// can just return the error. // can just return the error.
err := d.initialize(withMacaroonService) err := d.initialize(withMacaroonService)
if errors.Is(err, bbolt.ErrTimeout) { if errors.Is(err, bbolterrors.ErrTimeout) {
// We're trying to be started inside LiT so there most likely is // We're trying to be started inside LiT so there most likely is
// another standalone Loop process blocking the DB. // another standalone Loop process blocking the DB.
return fmt.Errorf("%v: make sure no other loop daemon "+ return fmt.Errorf("%v: make sure no other loop daemon "+
@ -994,7 +994,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error {
d.wg.Go(func() { d.wg.Go(func() {
infof("Starting static address open channel manager") infof("Starting static address open channel manager")
err := openChannelManager.Run(d.mainCtx) err := openChannelManager.Run(d.mainCtx)
if err != nil && !errors.Is(context.Canceled, err) { if err != nil && !errors.Is(err, context.Canceled) {
d.internalErrChan <- err d.internalErrChan <- err
} }
infof("Static address open channel manager stopped") infof("Static address open channel manager stopped")

View file

@ -251,6 +251,7 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
req.AssetSwapRfqId = in.AssetRfqInfo.SwapRfqId req.AssetSwapRfqId = in.AssetRfqInfo.SwapRfqId
} }
// Keep accepting the deprecated single-channel field for older clients.
switch { switch {
case in.LoopOutChannel != 0 && len(in.OutgoingChanSet) > 0: // nolint:staticcheck case in.LoopOutChannel != 0 && len(in.OutgoingChanSet) > 0: // nolint:staticcheck
return nil, errors.New("loop_out_channel and outgoing_" + return nil, errors.New("loop_out_channel and outgoing_" +
@ -273,7 +274,7 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
resp := &looprpc.SwapResponse{ resp := &looprpc.SwapResponse{
Id: info.SwapHash.String(), Id: info.SwapHash.String(),
IdBytes: info.SwapHash[:], IdBytes: info.SwapHash[:],
HtlcAddress: htlcAddress, HtlcAddress: htlcAddress, //nolint:staticcheck
ServerMessage: info.ServerMessage, ServerMessage: info.ServerMessage,
} }
@ -1182,11 +1183,11 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
if loopdb.CurrentProtocolVersion() < loopdb.ProtocolVersionHtlcV3 { if loopdb.CurrentProtocolVersion() < loopdb.ProtocolVersionHtlcV3 {
p2wshAddr := swapInfo.HtlcAddressP2WSH.String() p2wshAddr := swapInfo.HtlcAddressP2WSH.String()
response.HtlcAddress = p2wshAddr response.HtlcAddress = p2wshAddr //nolint:staticcheck
response.HtlcAddressP2Wsh = p2wshAddr response.HtlcAddressP2Wsh = p2wshAddr
} else { } else {
p2trAddr := swapInfo.HtlcAddressP2TR.String() p2trAddr := swapInfo.HtlcAddressP2TR.String()
response.HtlcAddress = p2trAddr response.HtlcAddress = p2trAddr //nolint:staticcheck
response.HtlcAddressP2Tr = p2trAddr response.HtlcAddressP2Tr = p2trAddr
} }

View file

@ -2,8 +2,6 @@ package loopdb
import ( import (
"context" "context"
"io/ioutil"
"os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -48,9 +46,7 @@ func TestMigrationUpdates(t *testing.T) {
ctxb := context.Background() ctxb := context.Background()
// Restore a legacy database. // Restore a legacy database.
tempDirName, err := ioutil.TempDir("", "clientstore") tempDirName := t.TempDir()
require.NoError(t, err)
defer os.RemoveAll(tempDirName)
tempPath := filepath.Join(tempDirName, dbFileName) tempPath := filepath.Join(tempDirName, dbFileName)
db, err := bbolt.Open(tempPath, 0600, nil) db, err := bbolt.Open(tempPath, 0600, nil)

View file

@ -15,6 +15,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
bbolterrors "go.etcd.io/bbolt/errors"
) )
var ( var (
@ -197,9 +198,9 @@ func NewBoltSwapStore(dbPath string, chainParams *chaincfg.Params) (
bdb, err := bboltOpen(path, 0600, &bbolt.Options{ bdb, err := bboltOpen(path, 0600, &bbolt.Options{
Timeout: DefaultLoopDBTimeout, Timeout: DefaultLoopDBTimeout,
}) })
if errors.Is(err, bbolt.ErrTimeout) { if errors.Is(err, bbolterrors.ErrTimeout) {
return nil, fmt.Errorf("%w: couldn't obtain exclusive lock on "+ return nil, fmt.Errorf("%w: couldn't obtain exclusive lock on "+
"%s, timed out after %v", bbolt.ErrTimeout, path, "%s, timed out after %v", bbolterrors.ErrTimeout, path,
DefaultLoopDBTimeout) DefaultLoopDBTimeout)
} }
if err != nil { if err != nil {

View file

@ -4,7 +4,6 @@ import (
"context" "context"
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -18,6 +17,7 @@ import (
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
bbolterrors "go.etcd.io/bbolt/errors"
) )
var ( var (
@ -62,7 +62,7 @@ func TestNewBoltSwapStoreTimeout(t *testing.T) {
bboltOpen = origOpen bboltOpen = origOpen
}) })
wrappedErr := fmt.Errorf("wrapped: %w", bbolt.ErrTimeout) wrappedErr := fmt.Errorf("wrapped: %w", bbolterrors.ErrTimeout)
bboltOpen = func(path string, mode os.FileMode, bboltOpen = func(path string, mode os.FileMode,
options *bbolt.Options) (*bbolt.DB, error) { options *bbolt.Options) (*bbolt.DB, error) {
@ -74,7 +74,7 @@ func TestNewBoltSwapStoreTimeout(t *testing.T) {
store, err := NewBoltSwapStore(tempDir, &chaincfg.MainNetParams) store, err := NewBoltSwapStore(tempDir, &chaincfg.MainNetParams)
require.Nil(t, store) require.Nil(t, store)
require.ErrorIs(t, err, bbolt.ErrTimeout) require.ErrorIs(t, err, bbolterrors.ErrTimeout)
require.ErrorContains(t, err, "couldn't obtain exclusive lock") require.ErrorContains(t, err, "couldn't obtain exclusive lock")
} }
@ -142,10 +142,7 @@ func TestLoopOutStore(t *testing.T) {
// testLoopOutStore tests the basic functionality of the current bbolt // testLoopOutStore tests the basic functionality of the current bbolt
// swap store for specific swap parameters. // swap store for specific swap parameters.
func testLoopOutStore(t *testing.T, pendingSwap *LoopOutContract) { func testLoopOutStore(t *testing.T, pendingSwap *LoopOutContract) {
tempDirName, err := ioutil.TempDir("", "clientstore") tempDirName := t.TempDir()
require.NoError(t, err)
defer os.RemoveAll(tempDirName)
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams) store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
require.NoError(t, err) require.NoError(t, err)
@ -284,9 +281,7 @@ func TestLoopInStore(t *testing.T) {
} }
func testLoopInStore(t *testing.T, pendingSwap LoopInContract) { func testLoopInStore(t *testing.T, pendingSwap LoopInContract) {
tempDirName, err := ioutil.TempDir("", "clientstore") tempDirName := t.TempDir()
require.NoError(t, err)
defer os.RemoveAll(tempDirName)
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams) store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
require.NoError(t, err) require.NoError(t, err)
@ -366,11 +361,7 @@ func testLoopInStore(t *testing.T, pendingSwap LoopInContract) {
// TestVersionNew tests that a new database is initialized with the current // TestVersionNew tests that a new database is initialized with the current
// version. // version.
func TestVersionNew(t *testing.T) { func TestVersionNew(t *testing.T) {
tempDirName, err := ioutil.TempDir("", "clientstore") tempDirName := t.TempDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDirName)
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams) store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
if err != nil { if err != nil {
@ -390,11 +381,7 @@ func TestVersionNew(t *testing.T) {
// TestVersionMigrated tests that an existing version zero database is migrated // TestVersionMigrated tests that an existing version zero database is migrated
// to the latest version. // to the latest version.
func TestVersionMigrated(t *testing.T) { func TestVersionMigrated(t *testing.T) {
tempDirName, err := ioutil.TempDir("", "clientstore") tempDirName := t.TempDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDirName)
createVersionZeroDb(t, tempDirName) createVersionZeroDb(t, tempDirName)
@ -459,11 +446,7 @@ func TestLegacyOutgoingChannel(t *testing.T) {
} }
// Restore a legacy database. // Restore a legacy database.
tempDirName, err := ioutil.TempDir("", "clientstore") tempDirName := t.TempDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDirName)
tempPath := filepath.Join(tempDirName, dbFileName) tempPath := filepath.Join(tempDirName, dbFileName)
db, err := bbolt.Open(tempPath, 0600, nil) db, err := bbolt.Open(tempPath, 0600, nil)
@ -498,9 +481,7 @@ func TestLegacyOutgoingChannel(t *testing.T) {
// TestLiquidityParams checks that reading and writing to liquidty bucket are // TestLiquidityParams checks that reading and writing to liquidty bucket are
// as expected. // as expected.
func TestLiquidityParams(t *testing.T) { func TestLiquidityParams(t *testing.T) {
tempDirName, err := ioutil.TempDir("", "clientstore") tempDirName := t.TempDir()
require.NoError(t, err, "failed to db")
defer os.RemoveAll(tempDirName)
ctxb := context.Background() ctxb := context.Background()

View file

@ -66,6 +66,10 @@ func (m *mockStaticAddressClient) PushStaticAddressHtlcSigs(ctx context.Context,
args.Error(1) args.Error(1)
} }
// ServerWithdrawDeposits implements the deprecated RPC required by the
// generated client interface. Production code uses ServerPsbtWithdrawDeposits.
//
//nolint:staticcheck
func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context, func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context,
in *swapserverrpc.ServerWithdrawRequest, in *swapserverrpc.ServerWithdrawRequest,
opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse, opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse,

View file

@ -71,6 +71,10 @@ func (m *mockStaticAddressClient) PushStaticAddressHtlcSigs(ctx context.Context,
args.Error(1) args.Error(1)
} }
// ServerWithdrawDeposits implements the deprecated RPC required by the
// generated client interface. Production code uses ServerPsbtWithdrawDeposits.
//
//nolint:staticcheck
func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context, func (m *mockStaticAddressClient) ServerWithdrawDeposits(ctx context.Context,
in *swapserverrpc.ServerWithdrawRequest, in *swapserverrpc.ServerWithdrawRequest,
opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse, opts ...grpc.CallOption) (*swapserverrpc.ServerWithdrawResponse,

View file

@ -310,6 +310,8 @@ func (m *Manager) OpenChannel(ctx context.Context,
return nil, err return nil, err
} }
// If a local funding amount is set, coin-select deposits to
// cover it. Otherwise fundmax uses all available deposits.
if req.LocalFundingAmount != 0 { if req.LocalFundingAmount != 0 {
deposits, err = staticutil.SelectDeposits( deposits, err = staticutil.SelectDeposits(
deposits, req.LocalFundingAmount, deposits, req.LocalFundingAmount,
@ -319,9 +321,6 @@ func (m *Manager) OpenChannel(ctx context.Context,
return nil, fmt.Errorf("error selecting "+ return nil, fmt.Errorf("error selecting "+
"deposits: %w", err) "deposits: %w", err)
} }
} else {
// The fundmax flag is set, hence we select all deposits
// for funding the channel.
} }
} }