lint: enable copyloopvar and remove redundant loop var copies in non-test files
What changed, and why it matters
This commit is a routine code cleanup: it removes 53 lines of the form `x := x` inside Go loops and enables a linter to prevent them in the future. Since Go 1.22, loop variables are already scoped per-iteration, so these copies were unnecessary. The change does not alter program behavior or fix any security bug.
No security action required. Treat as normal maintenance/refactoring. Ensure CI passes with the newly enabled `copyloopvar` linter.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch enables the copyloopvar linter in .golangci.yml and deletes redundant loop-variable rebindings across 25 files. In Go 1.22+, range and for loop variables are per-iteration, making the x := x pattern redundant. All removed copies were either used synchronously inside the loop body or passed to goroutines where per-iteration scoping now provides the same semantics. No functional or security-relevant logic was changed.
Changed components
.golangci.ymlchainntnfs/mempool.gochanneldb/height_hint.gochanneldb/invoices.gocontractcourt/breach_arbitrator.gocontractcourt/briefcase.gocontractcourt/chain_arbitrator.gocontractcourt/channel_arbitrator.gocontractcourt/taproot_briefcase.godiscovery/gossiper.gofunding/batch.goinvoices/invoiceregistry.golnrpc/devrpc/dev_server.golnrpc/walletrpc/walletkit_server.golnwallet/btcwallet/btcwallet.golnwallet/channel.golnwallet/test/test_interface.golnwallet/wallet.gopayments/db/migration1/payment.gopayments/db/payment.gorouting/missioncontrol.gorouting/payment_lifecycle.gorouting/router.gorpcserver.gosweep/sweeper.goInspect captured patch +0 / −53
diff --git a/.golangci.yml b/.golangci.yml
index 7d3b1a5..c661443 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -114,7 +114,6 @@ linters:
- testifylint
- perfsprint
- inamedparam
- - copyloopvar
- tagalign
- protogetter
- revive
diff --git a/chainntnfs/mempool.go b/chainntnfs/mempool.go
index 2e31751..037bde9 100644
--- a/chainntnfs/mempool.go
+++ b/chainntnfs/mempool.go
@@ -298,8 +298,6 @@ func (m *MempoolNotifier) notifySpent(spentInputs inputsWithTx) {
// Iterate the spent inputs to notify the subscribers concurrently.
for op, tx := range spentInputs {
- op, tx := op, tx
-
m.wg.Add(1)
go notifyAll(tx, op)
}
diff --git a/channeldb/height_hint.go b/channeldb/height_hint.go
index 9744c17..5c44d33 100644
--- a/channeldb/height_hint.go
+++ b/channeldb/height_hint.go
@@ -91,7 +91,6 @@ func (c *HeightHintCache) CommitSpendHint(height uint32,
}
for _, spendRequest := range spendRequests {
- spendRequest := spendRequest
spendHintKey, err := spendHintKey(&spendRequest)
if err != nil {
return err
@@ -161,7 +160,6 @@ func (c *HeightHintCache) PurgeSpendHint(
}
for _, spendRequest := range spendRequests {
- spendRequest := spendRequest
spendHintKey, err := spendHintKey(&spendRequest)
if err != nil {
return err
@@ -198,7 +196,6 @@ func (c *HeightHintCache) CommitConfirmHint(height uint32,
}
for _, confRequest := range confRequests {
- confRequest := confRequest
confHintKey, err := confHintKey(&confRequest)
if err != nil {
return err
@@ -269,7 +266,6 @@ func (c *HeightHintCache) PurgeConfirmHint(
}
for _, confRequest := range confRequests {
- confRequest := confRequest
confHintKey, err := confHintKey(&confRequest)
if err != nil {
return err
diff --git a/channeldb/invoices.go b/channeldb/invoices.go
index ab8d142..cee6164 100644
--- a/channeldb/invoices.go
+++ b/channeldb/invoices.go
@@ -938,7 +938,6 @@ func (k *kvInvoiceUpdater) storeAddHtlcsUpdate() error {
// As we don't update the settle index above for AMP invoices, we'll do
// it here for each sub-AMP invoice that was settled.
for settledSetID := range k.settledSetIDs {
- settledSetID := settledSetID
err := k.setSettleMetaFields(&settledSetID)
if err != nil {
return err
@@ -1862,7 +1861,6 @@ func ampStateEncoder(w io.Writer, val interface{}, buf *[8]byte) error {
// inner length prefix.
for setID, ampState := range *v {
setID := [32]byte(setID)
- ampState := ampState
htlcState := uint8(ampState.State)
settleDate := ampState.SettleDate
diff --git a/contractcourt/breach_arbitrator.go b/contractcourt/breach_arbitrator.go
index 2c12f25..130efcb 100644
--- a/contractcourt/breach_arbitrator.go
+++ b/contractcourt/breach_arbitrator.go
@@ -912,7 +912,6 @@ Loop:
}
for _, tx := range justiceTxs.spendSecondLevelHTLCs {
- tx := tx
brarLog.Debugf("Broadcasting justice tx "+
"spending second-level HTLC output: %v",
diff --git a/contractcourt/briefcase.go b/contractcourt/briefcase.go
index 3e58147..2e7efe0 100644
--- a/contractcourt/briefcase.go
+++ b/contractcourt/briefcase.go
@@ -1582,7 +1582,6 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
htlcBlobs := newAuxHtlcBlobs()
for _, htlc := range c.HtlcResolutions.IncomingHTLCs {
- htlc := htlc
htlcSignDesc := htlc.SweepSignDesc
ctrlBlock := htlcSignDesc.ControlBlock
@@ -1619,7 +1618,6 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
})
}
for _, htlc := range c.HtlcResolutions.OutgoingHTLCs {
- htlc := htlc
htlcSignDesc := htlc.SweepSignDesc
ctrlBlock := htlcSignDesc.ControlBlock
diff --git a/contractcourt/chain_arbitrator.go b/contractcourt/chain_arbitrator.go
index 1b8b00e..1b448cb 100644
--- a/contractcourt/chain_arbitrator.go
+++ b/contractcourt/chain_arbitrator.go
@@ -1359,7 +1359,6 @@ func (c *ChainArbitrator) loadOpenChannels() error {
// ChannelArbitrator.
for _, channel := range openChannels {
chanPoint := channel.FundingOutpoint
- channel := channel
// First, we'll create an active chainWatcher for this channel
// to ensure that we detect any relevant on chain events.
diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go
index 458a8a0..ac7e259 100644
--- a/contractcourt/channel_arbitrator.go
+++ b/contractcourt/channel_arbitrator.go
@@ -615,7 +615,6 @@ func maybeAugmentTaprootResolvers(chanType channeldb.ChannelType,
//nolint:ll
htlcResolutions := contractResolutions.HtlcResolutions.OutgoingHTLCs
for _, htlcRes := range htlcResolutions {
- htlcRes := htlcRes
if r.htlcResolution.ClaimOutpoint ==
htlcRes.ClaimOutpoint {
@@ -628,7 +627,6 @@ func maybeAugmentTaprootResolvers(chanType channeldb.ChannelType,
//nolint:ll
htlcResolutions := contractResolutions.HtlcResolutions.OutgoingHTLCs
for _, htlcRes := range htlcResolutions {
- htlcRes := htlcRes
if r.htlcResolution.ClaimOutpoint ==
htlcRes.ClaimOutpoint {
@@ -641,7 +639,6 @@ func maybeAugmentTaprootResolvers(chanType channeldb.ChannelType,
//nolint:ll
htlcResolutions := contractResolutions.HtlcResolutions.IncomingHTLCs
for _, htlcRes := range htlcResolutions {
- htlcRes := htlcRes
if r.htlcResolution.ClaimOutpoint ==
htlcRes.ClaimOutpoint {
@@ -653,7 +650,6 @@ func maybeAugmentTaprootResolvers(chanType channeldb.ChannelType,
//nolint:ll
htlcResolutions := contractResolutions.HtlcResolutions.IncomingHTLCs
for _, htlcRes := range htlcResolutions {
- htlcRes := htlcRes
if r.htlcResolution.ClaimOutpoint ==
htlcRes.ClaimOutpoint {
@@ -724,7 +720,6 @@ func (c *ChannelArbitrator) relaunchResolvers(commitSet *CommitSet,
// order to ensure we have complete coverage.
htlcMap := make(map[wire.OutPoint]*channeldb.HTLC)
for _, htlc := range confirmedHTLCs {
- htlc := htlc
outpoint := wire.OutPoint{
Hash: commitHash,
Index: uint32(htlc.OutputIndex),
@@ -2450,7 +2445,6 @@ func (c *ChannelArbitrator) prepContractResolutions(
// claim the HTLC (second-level or directly), then add the pre
case HtlcClaimAction:
for _, htlc := range htlcs {
- htlc := htlc
htlcOp := wire.OutPoint{
Hash: commitHash,
@@ -2481,7 +2475,6 @@ func (c *ChannelArbitrator) prepContractResolutions(
// backwards.
case HtlcTimeoutAction:
for _, htlc := range htlcs {
- htlc := htlc
htlcOp := wire.OutPoint{
Hash: commitHash,
@@ -2518,7 +2511,6 @@ func (c *ChannelArbitrator) prepContractResolutions(
// learn of the pre-image, or let the remote party time out.
case HtlcIncomingWatchAction:
for _, htlc := range htlcs {
- htlc := htlc
htlcOp := wire.OutPoint{
Hash: commitHash,
@@ -2551,7 +2543,6 @@ func (c *ChannelArbitrator) prepContractResolutions(
// backwards), or just timeout.
case HtlcOutgoingWatchAction:
for _, htlc := range htlcs {
- htlc := htlc
htlcOp := wire.OutPoint{
Hash: commitHash,
diff --git a/contractcourt/taproot_briefcase.go b/contractcourt/taproot_briefcase.go
index 4b703dd..c197c94 100644
--- a/contractcourt/taproot_briefcase.go
+++ b/contractcourt/taproot_briefcase.go
@@ -167,7 +167,6 @@ func (r *resolverCtrlBlocks) Encode(w io.Writer) error {
}
for id, ctrlBlock := range *r {
- ctrlBlock := ctrlBlock
if _, err := w.Write(id[:]); err != nil {
return err
@@ -486,7 +485,6 @@ func (h *htlcTapTweaks) Encode(w io.Writer) error {
}
for id, tweak := range *h {
- tweak := tweak
if _, err := w.Write(id[:]); err != nil {
return err
diff --git a/discovery/gossiper.go b/discovery/gossiper.go
index 0c533d4..6a778bb 100644
--- a/discovery/gossiper.go
+++ b/discovery/gossiper.go
@@ -1457,7 +1457,6 @@ func (d *AuthenticatedGossiper) sendRemoteBatch(ctx context.Context,
}
for _, msgChunk := range annBatch {
- msgChunk := msgChunk
// With the syncers taken care of, we'll merge the sender map
// with the set of syncers, so we don't send out duplicate
diff --git a/funding/batch.go b/funding/batch.go
index d95941e..23733d3 100644
--- a/funding/batch.go
+++ b/funding/batch.go
@@ -301,7 +301,6 @@ func (b *Batcher) BatchFund(ctx context.Context,
// Launch a goroutine that waits for the initial response on
// either the update or error chan.
- channel := channel
eg.Go(func() error {
return b.waitForUpdate(channel, true)
})
@@ -415,7 +414,6 @@ func (b *Batcher) BatchFund(ctx context.Context,
for _, channel := range b.channels {
// Launch another goroutine that waits for the channel pending
// response on the update chan.
- channel := channel
eg.Go(func() error {
return b.waitForUpdate(channel, false)
})
diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go
index 6528c4b..8ad92e1 100644
--- a/invoices/invoiceregistry.go
+++ b/invoices/invoiceregistry.go
@@ -196,7 +196,6 @@ func (i *InvoiceRegistry) scanInvoicesOnStart(ctx context.Context) error {
var pending []invoiceExpiry
for paymentHash, invoice := range pendingInvoices {
- invoice := invoice
expiryRef := makeInvoiceExpiry(paymentHash, &invoice)
if expiryRef != nil {
pending = append(pending, expiryRef)
@@ -509,7 +508,6 @@ func (i *InvoiceRegistry) deliverBacklogEvents(ctx context.Context,
for _, addEvent := range addEvents {
// We re-bind the loop variable to ensure we don't hold onto
// the loop reference causing is to point to the same item.
- addEvent := addEvent
select {
case client.ntfnQueue.ChanIn() <- &invoiceEvent{
@@ -523,7 +521,6 @@ func (i *InvoiceRegistry) deliverBacklogEvents(ctx context.Context,
for _, settleEvent := range settleEvents {
// We re-bind the loop variable to ensure we don't hold onto
// the loop reference causing is to point to the same item.
- settleEvent := settleEvent
select {
case client.ntfnQueue.ChanIn() <- &invoiceEvent{
diff --git a/lnrpc/devrpc/dev_server.go b/lnrpc/devrpc/dev_server.go
index 3cecb36..e338a9b 100644
--- a/lnrpc/devrpc/dev_server.go
+++ b/lnrpc/devrpc/dev_server.go
@@ -270,7 +270,6 @@ func (s *Server) ImportGraph(ctx context.Context,
}
for _, rpcEdge := range graph.Edges {
- rpcEdge := rpcEdge
node1, err := parsePubKey(rpcEdge.Node1Pub)
if err != nil {
diff --git a/lnrpc/walletrpc/walletkit_server.go b/lnrpc/walletrpc/walletkit_server.go
index bece600..e04bcdd 100644
--- a/lnrpc/walletrpc/walletkit_server.go
+++ b/lnrpc/walletrpc/walletkit_server.go
@@ -2273,7 +2273,6 @@ func (w *WalletKit) handleChange(packet *psbt.Packet, changeIndex int32,
func marshallLeases(locks []*base.ListLeasedOutputResult) []*UtxoLease {
rpcLocks := make([]*UtxoLease, len(locks))
for idx, lock := range locks {
- lock := lock
rpcLocks[idx] = &UtxoLease{
Id: lock.LockID[:],
diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go
index 354238d..92b5f40 100644
--- a/lnwallet/btcwallet/btcwallet.go
+++ b/lnwallet/btcwallet/btcwallet.go
@@ -618,7 +618,6 @@ func (b *BtcWallet) ListAccounts(name string,
return nil, err
}
for _, account := range accounts.Accounts {
- account := account
res = append(res, &account.AccountProperties)
}
@@ -631,7 +630,6 @@ func (b *BtcWallet) ListAccounts(name string,
return nil, err
}
for _, account := range accounts.Accounts {
- account := account
res = append(res, &account.AccountProperties)
}
}
@@ -644,7 +642,6 @@ func (b *BtcWallet) ListAccounts(name string,
return nil, err
}
for _, account := range accounts.Accounts {
- account := account
res = append(res, &account.AccountProperties)
}
}
diff --git a/lnwallet/channel.go b/lnwallet/channel.go
index 78ca895..b4966d3 100644
--- a/lnwallet/channel.go
+++ b/lnwallet/channel.go
@@ -603,8 +603,6 @@ func (lc *LightningChannel) extractPayDescs(feeRate chainfee.SatPerKWeight,
// persist state w.r.t to if forwarded or not, or can
// inadvertently trigger replays
- htlc := htlc
-
auxLeaf := fn.FlatMapOption(
func(l CommitAuxLeaves) input.AuxTapLeaf {
leaves := l.OutgoingHtlcLeaves
@@ -1774,7 +1772,6 @@ func (lc *LightningChannel) restorePendingRemoteUpdates(
len(unsignedAckedUpdates))
for _, logUpdate := range unsignedAckedUpdates {
- logUpdate := logUpdate
payDesc, err := lc.remoteLogUpdateToPayDesc(
&logUpdate, lc.updateLogs.Local, localCommitmentHeight,
@@ -1854,7 +1851,6 @@ func (lc *LightningChannel) restorePeerLocalUpdates(updates []channeldb.LogUpdat
len(updates))
for _, logUpdate := range updates {
- logUpdate := logUpdate
payDesc, err := lc.localLogUpdateToPayDesc(
&logUpdate, lc.updateLogs.Remote,
@@ -1908,7 +1904,6 @@ func (lc *LightningChannel) restorePendingLocalUpdates(
// If we did have a dangling commit, then we'll examine which updates
// we included in that state and re-insert them into our update log.
for _, logUpdate := range pendingRemoteCommitDiff.LogUpdates {
- logUpdate := logUpdate
payDesc, err := lc.logUpdateToPayDesc(
&logUpdate, lc.updateLogs.Remote, pendingHeight,
@@ -8189,7 +8184,6 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight,
incomingResolutions := make([]IncomingHtlcResolution, 0, len(htlcs))
outgoingResolutions := make([]OutgoingHtlcResolution, 0, len(htlcs))
for _, htlc := range htlcs {
- htlc := htlc
// We'll skip any HTLC's which were dust on the commitment
// transaction, as these don't have a corresponding output
diff --git a/lnwallet/test/test_interface.go b/lnwallet/test/test_interface.go
index 8d180ca..90ea46d 100644
--- a/lnwallet/test/test_interface.go
+++ b/lnwallet/test/test_interface.go
@@ -3540,8 +3540,6 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver,
// wallet state after each step.
for _, walletTest := range walletTests {
- walletTest := walletTest
-
testName := fmt.Sprintf("%v/%v:%v", walletType, backEnd,
walletTest.name)
success := t.Run(testName, func(t *testing.T) {
diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go
index daba099..09cfca1 100644
--- a/lnwallet/wallet.go
+++ b/lnwallet/wallet.go
@@ -619,7 +619,6 @@ func (l *LightningWallet) ListUnspentWitnessFromDefaultAccount(
func (l *LightningWallet) LockedOutpoints() []*wire.OutPoint {
outPoints := make([]*wire.OutPoint, 0, len(l.lockedOutPoints))
for outPoint := range l.lockedOutPoints {
- outPoint := outPoint
outPoints = append(outPoints, &outPoint)
}
diff --git a/payments/db/migration1/payment.go b/payments/db/migration1/payment.go
index 78599c3..fbc1b21 100644
--- a/payments/db/migration1/payment.go
+++ b/payments/db/migration1/payment.go
@@ -335,7 +335,6 @@ func (m *MPPayment) InFlightHTLCs() []HTLCAttempt {
func (m *MPPayment) GetAttempt(id uint64) (*HTLCAttempt, error) {
// TODO(yy): iteration can be slow, make it into a tree or use BS.
for _, htlc := range m.HTLCs {
- htlc := htlc
if htlc.AttemptID == id {
return &htlc, nil
}
diff --git a/payments/db/payment.go b/payments/db/payment.go
index ddceedf..0c928b4 100644
--- a/payments/db/payment.go
+++ b/payments/db/payment.go
@@ -416,7 +416,6 @@ func (m *MPPayment) InFlightHTLCs() []HTLCAttempt {
func (m *MPPayment) GetAttempt(id uint64) (*HTLCAttempt, error) {
// TODO(yy): iteration can be slow, make it into a tree or use BS.
for _, htlc := range m.HTLCs {
- htlc := htlc
if htlc.AttemptID == id {
return &htlc, nil
}
diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go
index b03724a..c31a223 100644
--- a/routing/missioncontrol.go
+++ b/routing/missioncontrol.go
@@ -709,7 +709,6 @@ func (m *MissionControl) applyPaymentResult(
}
for pair, pairResult := range i.pairResults {
- pairResult := pairResult
if pairResult.success {
m.log.Debugf("Reporting pair success to Mission "+
diff --git a/routing/payment_lifecycle.go b/routing/payment_lifecycle.go
index 488df5b..2b8180c 100644
--- a/routing/payment_lifecycle.go
+++ b/routing/payment_lifecycle.go
@@ -1148,8 +1148,6 @@ func (p *paymentLifecycle) reloadInflightAttempts(
}
for _, a := range payment.InFlightHTLCs() {
- a := a
-
log.Infof("Resuming HTLC attempt %v for payment %v",
a.AttemptID, p.identifier)
diff --git a/routing/router.go b/routing/router.go
index 37aeef2..956bc12 100644
--- a/routing/router.go
+++ b/routing/router.go
@@ -1476,7 +1476,6 @@ func (r *ChannelRouter) resumePayments() error {
// Get the hashes used for the outstanding HTLCs.
htlcs := make(map[uint64]lntypes.Hash)
for _, a := range payment.HTLCs {
- a := a
// We check whether the individual attempts have their
// HTLC hash set, if not we'll fall back to the overall
diff --git a/rpcserver.go b/rpcserver.go
index 8b40192..13b96aa 100644
--- a/rpcserver.go
+++ b/rpcserver.go
@@ -6016,7 +6016,6 @@ func (r *rpcServer) ListInvoices(ctx context.Context,
LastIndexOffset: invoiceSlice.LastIndexOffset,
}
for i, invoice := range invoiceSlice.Invoices {
- invoice := invoice
resp.Invoices[i], err = invoicesrpc.CreateRPCInvoice(
&invoice, r.cfg.ActiveNetParams.Params,
)
@@ -7027,7 +7026,6 @@ func (r *rpcServer) ListPayments(ctx context.Context,
}
for _, payment := range paymentsQuerySlice.Payments {
- payment := payment
rpcPayment, err := r.routerBackend.MarshallPayment(payment)
if err != nil {
diff --git a/sweep/sweeper.go b/sweep/sweeper.go
index e2163f6..379300e 100644
--- a/sweep/sweeper.go
+++ b/sweep/sweeper.go
@@ -747,7 +747,6 @@ func (s *UtxoSweeper) collector() {
// those inputs will be removed from the wallet.
func (s *UtxoSweeper) removeExclusiveGroup(group uint64, op wire.OutPoint) {
for outpoint, input := range s.inputs {
- outpoint := outpoint
// Skip the input that caused the exclusive group to be removed.
if outpoint == op {
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.