multi: validate payment params at RPC layer

With this patch, we'll fail out earlier in the cycle in case of
some wonky parameters, and not leave zombie payments in the router
which currently are not cleaned up.
This commit is contained in:
eugene
2021-05-12 14:44:56 -04:00
parent 6a2fb316ca
commit a70d0bef34
5 changed files with 127 additions and 4 deletions

View File

@@ -238,6 +238,14 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
if in.FinalCltvDelta != 0 {
finalCLTVDelta = uint16(in.FinalCltvDelta)
}
// Do bounds checking without block padding so we don't give routes
// that will leave the router in a zombie payment state.
err = routing.ValidateCLTVLimit(cltvLimit, finalCLTVDelta, false)
if err != nil {
return nil, err
}
cltvLimit -= uint32(finalCLTVDelta)
// Parse destination feature bits.
@@ -860,6 +868,15 @@ func (r *RouterBackend) extractIntentFromSendRequest(
payIntent.DestFeatures = features
}
// Do bounds checking with the block padding so the router isn't
// left with a zombie payment in case the user messes up.
err = routing.ValidateCLTVLimit(
payIntent.CltvLimit, payIntent.FinalCLTVDelta, true,
)
if err != nil {
return nil, err
}
// Check for disallowed payments to self.
if !rpcPayReq.AllowSelfPayment && payIntent.Target == r.SelfNode {
return nil, errors.New("self-payments not allowed")

View File

@@ -37,17 +37,22 @@ var (
// and passed onto path finding.
func TestQueryRoutes(t *testing.T) {
t.Run("no mission control", func(t *testing.T) {
testQueryRoutes(t, false, false)
testQueryRoutes(t, false, false, true)
})
t.Run("no mission control and msat", func(t *testing.T) {
testQueryRoutes(t, false, true)
testQueryRoutes(t, false, true, true)
})
t.Run("with mission control", func(t *testing.T) {
testQueryRoutes(t, true, false)
testQueryRoutes(t, true, false, true)
})
t.Run("no mission control bad cltv limit", func(t *testing.T) {
testQueryRoutes(t, false, false, false)
})
}
func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool) {
func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool,
setTimelock bool) {
ignoreNodeBytes, err := hex.DecodeString(ignoreNodeKey)
if err != nil {
t.Fatal(err)
@@ -207,7 +212,21 @@ func testQueryRoutes(t *testing.T, useMissionControl bool, useMsat bool) {
},
}
// If this is set, we'll populate MaxTotalTimelock. If this is not set,
// the test will fail as CltvLimit will be 0.
if setTimelock {
backend.MaxTotalTimelock = 1000
}
resp, err := backend.QueryRoutes(context.Background(), request)
// If no MaxTotalTimelock was set for the QueryRoutes request, make
// sure an error was returned.
if !setTimelock {
require.NotEmpty(t, err)
return
}
if err != nil {
t.Fatal(err)
}