What changed, and why it matters
This commit is a routine code cleanup titled 'fix linter'. It removes blank lines, unused test variables, and outdated linter suppression comments. The only functional change is adding a type-safety check when reading payment updates from a stream, which now returns a clear error instead of potentially panicking if an unexpected type appears. There is no indication this fixes an active security vulnerability.
No urgent action. Treat as normal maintenance. If reviewing, verify the new type checks do not break legitimate payment update types and that the `errors.As` change handles all expected UnknownElementType wrapping correctly.
Security signals we found
Defensive type assertion hardening in payment streaming path
Use of errors.As for wrapped error type detection in codec
Removal of unused code and linter suppressions
Evidence from the diff
The diff is overwhelmingly lint/test hygiene: whitespace, comment formatting, removal of unused testHop3, test := test loop captures, and //nolint:unused///nolint:ll directives. Two small behavioral changes exist: (1) payments/db/codec.go switches from err.(UnknownElementType) type assertion to errors.As, which is more robust for wrapped errors; (2) lnrpc/routerrpc/router_server.go and several tests replace unchecked item.(*paymentsdb.MPPayment) type assertions with checked conversions that return/abort on mismatch. These reduce panic surface but are defensive hardening, not vulnerability fixes.
Changed components
lnrpc/routerrpc/router_server.gopayments/db/codec.gorouting/control_tower_test.gopayments/db/kv_store_test.gopayments/db/log.gopayments/db/payment.gopayments/db/payment_test.gochanneldb/codec.gorouting/mock_test.goInspect captured patch +50 / −35
diff --git a/channeldb/codec.go b/channeldb/codec.go
index b82a258..e5bab3d 100644
--- a/channeldb/codec.go
+++ b/channeldb/codec.go
@@ -488,5 +488,6 @@ func serializeTime(w io.Writer, t time.Time) error {
byteOrder.PutUint64(scratch[:], uint64(unixNano))
_, err := w.Write(scratch[:])
+
return err
}
diff --git a/lnrpc/routerrpc/router_server.go b/lnrpc/routerrpc/router_server.go
index 10967d9..894edf2 100644
--- a/lnrpc/routerrpc/router_server.go
+++ b/lnrpc/routerrpc/router_server.go
@@ -1448,7 +1448,11 @@ func (s *Server) trackPaymentStream(context context.Context,
// No more payment updates.
return nil
}
- result := item.(*paymentsdb.MPPayment)
+ result, ok := item.(*paymentsdb.MPPayment)
+ if !ok {
+ return fmt.Errorf("unexpected payment type: %T",
+ item)
+ }
log.Tracef("Payment %v updated to state %v",
result.Info.PaymentIdentifier, result.Status)
diff --git a/payments/db/codec.go b/payments/db/codec.go
index 997dab0..cd9c0c7 100644
--- a/payments/db/codec.go
+++ b/payments/db/codec.go
@@ -2,6 +2,7 @@ package paymentsdb
import (
"encoding/binary"
+ "errors"
"io"
"time"
@@ -19,21 +20,20 @@ type UnknownElementType = channeldb.UnknownElementType
func ReadElement(r io.Reader, element interface{}) error {
err := channeldb.ReadElement(r, element)
switch {
-
// Known to channeldb codec.
case err == nil:
return nil
// Fail if error is not UnknownElementType.
default:
- if _, ok := err.(UnknownElementType); !ok {
+ var unknownElementType UnknownElementType
+ if !errors.As(err, &unknownElementType) {
return err
}
}
// Process any paymentsdb-specific extensions to the codec.
switch e := element.(type) {
-
case *paymentIndexType:
if err := binary.Read(r, byteOrder, e); err != nil {
return err
@@ -53,21 +53,20 @@ func ReadElement(r io.Reader, element interface{}) error {
func WriteElement(w io.Writer, element interface{}) error {
err := channeldb.WriteElement(w, element)
switch {
-
// Known to channeldb codec.
case err == nil:
return nil
// Fail if error is not UnknownElementType.
default:
- if _, ok := err.(UnknownElementType); !ok {
+ var unknownElementType UnknownElementType
+ if !errors.As(err, &unknownElementType) {
return err
}
}
// Process any paymentsdb-specific extensions to the codec.
switch e := element.(type) {
-
case paymentIndexType:
if err := binary.Write(w, byteOrder, e); err != nil {
return err
@@ -137,5 +136,6 @@ func serializeTime(w io.Writer, t time.Time) error {
byteOrder.PutUint64(scratch[:], uint64(unixNano))
_, err := w.Write(scratch[:])
+
return err
}
diff --git a/payments/db/kv_store_test.go b/payments/db/kv_store_test.go
index cc64776..49e80df 100644
--- a/payments/db/kv_store_test.go
+++ b/payments/db/kv_store_test.go
@@ -954,7 +954,6 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
}
for _, test := range tests {
- test := test
subTest := fmt.Sprintf("first=%v, second=%v",
test.settleFirst, test.settleLast)
@@ -1643,9 +1642,8 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
}
for _, test := range tests {
- test := test
-
t.Run(test.name, func(t *testing.T) {
+ //nolint:ll
err := kvdb.Update(
paymentDB.db, func(tx walletdb.ReadWriteTx) error {
var seqNrBytes [8]byte
diff --git a/payments/db/log.go b/payments/db/log.go
index 08994ef..8a77dbc 100644
--- a/payments/db/log.go
+++ b/payments/db/log.go
@@ -8,8 +8,6 @@ import (
// log is a logger that is initialized with no output filters. This
// means the package will not perform any logging by default until the caller
// requests it.
-//
-//nolint:unused
var log btclog.Logger
// Subsystem defines the logging identifier for this subsystem.
diff --git a/payments/db/payment.go b/payments/db/payment.go
index a5ad753..72338a4 100644
--- a/payments/db/payment.go
+++ b/payments/db/payment.go
@@ -255,8 +255,8 @@ const (
// reason.
HTLCFailUnknown HTLCFailReason = 0
- // HTLCFailUnreadable is recorded for htlcs that had a failure message that
- // couldn't be decrypted.
+ // HTLCFailUnreadable is recorded for htlcs that had a failure message
+ // that couldn't be decrypted.
HTLCFailUnreadable HTLCFailReason = 1
// HTLCFailInternal is recorded for htlcs that failed because of an
diff --git a/payments/db/payment_test.go b/payments/db/payment_test.go
index 2f6bf40..9889f9d 100644
--- a/payments/db/payment_test.go
+++ b/payments/db/payment_test.go
@@ -60,19 +60,6 @@ var (
LegacyPayload: true,
}
- testHop3 = &route.Hop{
- PubKeyBytes: route.NewVertex(pub),
- ChannelID: 12345,
- OutgoingTimeLock: 111,
- AmtToForward: 555,
- CustomRecords: record.CustomSet{
- 65536: []byte{},
- 80001: []byte{},
- },
- AMP: record.NewAMP([32]byte{0x69}, [32]byte{0x42}, 1),
- Metadata: []byte{1, 2, 3},
- }
-
testRoute = route.Route{
TotalTimeLock: 123,
TotalAmount: 1234567,
diff --git a/routing/control_tower_test.go b/routing/control_tower_test.go
index 9a49377..3e01065 100644
--- a/routing/control_tower_test.go
+++ b/routing/control_tower_test.go
@@ -130,15 +130,23 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
for result == nil || !result.Terminated() {
select {
case item := <-s.Updates():
- result = item.(*paymentsdb.MPPayment)
+ payment, ok := item.(*paymentsdb.MPPayment)
+ require.True(
+ t, ok, "unexpected payment type: %T",
+ item)
+
+ result = payment
+
case <-time.After(testTimeout):
t.Fatal("timeout waiting for payment result")
}
}
- require.Equalf(t, paymentsdb.StatusSucceeded, result.GetStatus(),
- "subscriber %v failed, want %s, got %s", i,
- paymentsdb.StatusSucceeded, result.GetStatus())
+ require.Equalf(t, paymentsdb.StatusSucceeded,
+ result.GetStatus(), "subscriber %v failed, want %s, "+
+ "got %s", i, paymentsdb.StatusSucceeded,
+ result.GetStatus(),
+ )
attempt, _ := result.TerminalInfo()
if attempt.Settle.Preimage != preimg {
@@ -261,8 +269,14 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
for i := 0; i < 6; i++ {
select {
case item := <-subscription.Updates():
- id := item.(*paymentsdb.MPPayment).Info.PaymentIdentifier
- results[id] = item.(*paymentsdb.MPPayment)
+ payment, ok := item.(*paymentsdb.MPPayment)
+ require.True(
+ t, ok, "unexpected payment type: %T",
+ item)
+
+ id := payment.Info.PaymentIdentifier
+ results[id] = payment
+
case <-time.After(testTimeout):
require.Fail(t, "timeout waiting for payment result")
}
@@ -337,11 +351,17 @@ func TestKVPaymentsDBSubscribeAllImmediate(t *testing.T) {
select {
case update := <-subscription.Updates():
require.NotNil(t, update)
+ payment, ok := update.(*paymentsdb.MPPayment)
+ if !ok {
+ t.Fatalf("unexpected payment type: %T", update)
+ }
+
require.Equal(
t, info.PaymentIdentifier,
- update.(*paymentsdb.MPPayment).Info.PaymentIdentifier,
+ payment.Info.PaymentIdentifier,
)
require.Len(t, subscription.Updates(), 0)
+
case <-time.After(testTimeout):
require.Fail(t, "timeout waiting for payment result")
}
@@ -502,7 +522,12 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
for result == nil || !result.Terminated() {
select {
case item := <-s.Updates():
- result = item.(*paymentsdb.MPPayment)
+ payment, ok := item.(*paymentsdb.MPPayment)
+ require.True(
+ t, ok, "unexpected payment type: %T",
+ item)
+
+ result = payment
case <-time.After(testTimeout):
t.Fatal("timeout waiting for payment result")
}
diff --git a/routing/mock_test.go b/routing/mock_test.go
index 596b511..9cb938f 100644
--- a/routing/mock_test.go
+++ b/routing/mock_test.go
@@ -441,6 +441,7 @@ func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
// Mark the payment successful on first settled attempt.
m.successful[phash] = struct{}{}
+
return &paymentsdb.HTLCAttempt{
Settle: settleInfo,
}, nil
@@ -479,6 +480,7 @@ func (m *mockControlTowerOld) FailAttempt(phash lntypes.Hash, pid uint64,
}
p.attempts[i].Failure = failInfo
+
return &paymentsdb.HTLCAttempt{
Failure: failInfo,
}, nil
Why this scored 19/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.