Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/release-notes/release-notes-0.21.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
`maxchansize`. The `maxchansize` config option is intended only for limiting
incoming channel requests from peers, not outgoing ones.

- The `ForwardingHistory` RPC now [enforces the documented `max_events`
limit](https://github.com/lightningnetwork/lnd/pull/10512) (50,000) and
returns an error when callers exceed it, preventing potential gRPC message
size errors.

- Chain notifier RPCs now [return the gRPC `Unavailable`
status](https://github.com/lightningnetwork/lnd/pull/10352) while the
sub-server is still starting. This allows clients to reliably detect the
Expand Down
7 changes: 7 additions & 0 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8247,6 +8247,13 @@ func (r *rpcServer) ForwardingHistory(ctx context.Context,
numEvents = 100
}

// Enforce the maximum number of events that can be returned to avoid
// exceeding the max gRPC message size.
if numEvents > channeldb.MaxResponseEvents {
return nil, fmt.Errorf("max events %d exceeds maximum "+
"allowed %d", numEvents, channeldb.MaxResponseEvents)
}

// Create sets of incoming and outgoing channel IDs from the request
// for faster lookups for filtering.
incomingChanIDs := fn.NewSet(req.IncomingChanIds...)
Expand Down
76 changes: 76 additions & 0 deletions rpcserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,79 @@
})
}
}

// TestForwardingHistoryMaxEvents tests that the ForwardingHistory RPC
// enforces the maximum number of events that can be requested.
func TestForwardingHistoryMaxEvents(t *testing.T) {
t.Parallel()

tests := []struct {
name string
maxEvents uint32
expectErr bool
}{
{
name: "within limit",
maxEvents: 50000,
expectErr: false,
},
{
name: "at limit",
maxEvents: channeldb.MaxResponseEvents,
expectErr: false,
},
{
name: "exceeds limit",
maxEvents: 50001,
expectErr: true,
},
{
name: "far exceeds limit",
maxEvents: 999999999,
expectErr: true,
},
{
name: "zero defaults to 100",
maxEvents: 0,
expectErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a minimal rpcServer for testing.
cdb := channeldb.OpenForTesting(t, t.TempDir())
r := &rpcServer{
server: &server{
miscDB: cdb.Backend,

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Lint code

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion (typecheck)

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Check commits

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit-race tags="test_db_sqlite")

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit tags="kvdb_postgres")

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit tags="kvdb_sqlite")

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit tags="kvdb_etcd")

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit-race tags="test_db_postgres")

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit-cover)

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit tags="test_db_sqlite")

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit tags="test_db_postgres")

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion

Check failure on line 170 in rpcserver_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests (unit-race)

cannot use cdb.Backend (variable of interface type kvdb.Backend) as *channeldb.DB value in struct literal: need type assertion
implCfg: &ImplementationCfg{
AuxComponents: AuxComponents{},
},
},
}

req := &lnrpc.ForwardingHistoryRequest{
NumMaxEvents: tt.maxEvents,
}

// Note: This will fail when trying to flush forwarding
// events because htlcSwitch is nil, but that's after
// the validation we're testing. We just check if we
// get the expected error for max events.
_, err := r.ForwardingHistory(nil, req)

if tt.expectErr {
require.Error(t, err)
require.Contains(t, err.Error(),
"exceeds maximum allowed")
} else if tt.maxEvents != 0 && tt.maxEvents <= channeldb.MaxResponseEvents {
// For valid non-zero values, we expect a different
// error (htlcSwitch nil), not the max events error.
if err != nil {
require.NotContains(t, err.Error(),
"exceeds maximum allowed")
}
}
})
}
}
Loading