watchtower/wtpolicy: add basic validity constraints

This commit is contained in:
Conner Fromknecht 2019-06-13 17:38:50 -07:00
parent 37052f1561
commit a543c781fe
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7
3 changed files with 140 additions and 6 deletions

View File

@ -1069,6 +1069,10 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
policy.SweepFeeRate = sweepRateSatPerByte.FeePerKWeight()
}
if err := policy.Validate(); err != nil {
return nil, err
}
s.towerClient, err = wtclient.New(&wtclient.Config{
Signer: cc.wallet.Cfg.Signer,
NewAddress: newSweepPkScriptGen(cc.wallet),

View File

@ -27,7 +27,11 @@ const (
// DefaultSweepFeeRate specifies the fee rate used to construct justice
// transactions. The value is expressed in satoshis per kilo-weight.
DefaultSweepFeeRate = 3000
DefaultSweepFeeRate = lnwallet.SatPerKWeight(12000)
// MinSweepFeeRate is the minimum sweep fee rate a client may use in its
// policy, the current value is 4 sat/kw.
MinSweepFeeRate = lnwallet.SatPerKWeight(4000)
)
var (
@ -43,6 +47,17 @@ var (
// ErrCreatesDust signals that the session's policy would create a dust
// output for the victim.
ErrCreatesDust = errors.New("justice transaction creates dust at fee rate")
// ErrAltruistReward signals that the policy is invalid because it
// contains a non-zero RewardBase or RewardRate on an altruist policy.
ErrAltruistReward = errors.New("altruist policy has reward params")
// ErrNoMaxUpdates signals that the policy specified zero MaxUpdates.
ErrNoMaxUpdates = errors.New("max updates must be positive")
// ErrSweepFeeRateTooLow signals that the policy's fee rate is too low
// to get into the mempool during low congestion.
ErrSweepFeeRateTooLow = errors.New("sweep fee rate too low")
)
// DefaultPolicy returns a Policy containing the default parameters that can be
@ -50,11 +65,8 @@ var (
func DefaultPolicy() Policy {
return Policy{
TxPolicy: TxPolicy{
BlobType: blob.TypeAltruistCommit,
RewardRate: DefaultRewardRate,
SweepFeeRate: lnwallet.SatPerKWeight(
DefaultSweepFeeRate,
),
BlobType: blob.TypeAltruistCommit,
SweepFeeRate: DefaultSweepFeeRate,
},
MaxUpdates: DefaultMaxUpdates,
}
@ -107,6 +119,31 @@ func (p Policy) String() string {
p.SweepFeeRate)
}
// Validate ensures that the policy satisfies some minimal correctness
// constraints.
func (p Policy) Validate() error {
// RewardBase and RewardRate should not be set if the policy doesn't
// have a reward.
if !p.BlobType.Has(blob.FlagReward) &&
(p.RewardBase != 0 || p.RewardRate != 0) {
return ErrAltruistReward
}
// MaxUpdates must be positive.
if p.MaxUpdates == 0 {
return ErrNoMaxUpdates
}
// SweepFeeRate must be sane enough to get in the mempool during low
// congestion.
if p.SweepFeeRate < MinSweepFeeRate {
return ErrSweepFeeRateTooLow
}
return nil
}
// ComputeAltruistOutput computes the lone output value of a justice transaction
// that pays no reward to the tower. The value is computed using the weight of
// of the justice transaction and subtracting an amount that satisfies the

View File

@ -0,0 +1,93 @@
package wtpolicy_test
import (
"testing"
"github.com/lightningnetwork/lnd/watchtower/blob"
"github.com/lightningnetwork/lnd/watchtower/wtpolicy"
)
var validationTests = []struct {
name string
policy wtpolicy.Policy
expErr error
}{
{
name: "fail no maxupdates",
policy: wtpolicy.Policy{
TxPolicy: wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
},
},
expErr: wtpolicy.ErrNoMaxUpdates,
},
{
name: "fail altruist with reward base",
policy: wtpolicy.Policy{
TxPolicy: wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
RewardBase: 1,
},
},
expErr: wtpolicy.ErrAltruistReward,
},
{
name: "fail altruist with reward rate",
policy: wtpolicy.Policy{
TxPolicy: wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
RewardRate: 1,
},
},
expErr: wtpolicy.ErrAltruistReward,
},
{
name: "fail sweep fee rate too low",
policy: wtpolicy.Policy{
TxPolicy: wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
},
MaxUpdates: 1,
},
expErr: wtpolicy.ErrSweepFeeRateTooLow,
},
{
name: "minimal valid altruist policy",
policy: wtpolicy.Policy{
TxPolicy: wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
SweepFeeRate: wtpolicy.MinSweepFeeRate,
},
MaxUpdates: 1,
},
},
{
name: "valid altruist policy with default sweep rate",
policy: wtpolicy.Policy{
TxPolicy: wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
SweepFeeRate: wtpolicy.DefaultSweepFeeRate,
},
MaxUpdates: 1,
},
},
{
name: "valid default policy",
policy: wtpolicy.DefaultPolicy(),
},
}
// TestPolicyValidate asserts that the sanity checks for policies behave as
// expected.
func TestPolicyValidate(t *testing.T) {
for i := range validationTests {
test := validationTests[i]
t.Run(test.name, func(t *testing.T) {
err := test.policy.Validate()
if err != test.expErr {
t.Fatalf("validation error mismatch, "+
"want: %v, got: %v", test.expErr, err)
}
})
}
}