watchtower/wtpolicy: add basic validity constraints
This commit is contained in:
parent
37052f1561
commit
a543c781fe
|
@ -1069,6 +1069,10 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
||||||
policy.SweepFeeRate = sweepRateSatPerByte.FeePerKWeight()
|
policy.SweepFeeRate = sweepRateSatPerByte.FeePerKWeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := policy.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
s.towerClient, err = wtclient.New(&wtclient.Config{
|
s.towerClient, err = wtclient.New(&wtclient.Config{
|
||||||
Signer: cc.wallet.Cfg.Signer,
|
Signer: cc.wallet.Cfg.Signer,
|
||||||
NewAddress: newSweepPkScriptGen(cc.wallet),
|
NewAddress: newSweepPkScriptGen(cc.wallet),
|
||||||
|
|
|
@ -27,7 +27,11 @@ const (
|
||||||
|
|
||||||
// DefaultSweepFeeRate specifies the fee rate used to construct justice
|
// DefaultSweepFeeRate specifies the fee rate used to construct justice
|
||||||
// transactions. The value is expressed in satoshis per kilo-weight.
|
// 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 (
|
var (
|
||||||
|
@ -43,6 +47,17 @@ var (
|
||||||
// ErrCreatesDust signals that the session's policy would create a dust
|
// ErrCreatesDust signals that the session's policy would create a dust
|
||||||
// output for the victim.
|
// output for the victim.
|
||||||
ErrCreatesDust = errors.New("justice transaction creates dust at fee rate")
|
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
|
// DefaultPolicy returns a Policy containing the default parameters that can be
|
||||||
|
@ -50,11 +65,8 @@ var (
|
||||||
func DefaultPolicy() Policy {
|
func DefaultPolicy() Policy {
|
||||||
return Policy{
|
return Policy{
|
||||||
TxPolicy: TxPolicy{
|
TxPolicy: TxPolicy{
|
||||||
BlobType: blob.TypeAltruistCommit,
|
BlobType: blob.TypeAltruistCommit,
|
||||||
RewardRate: DefaultRewardRate,
|
SweepFeeRate: DefaultSweepFeeRate,
|
||||||
SweepFeeRate: lnwallet.SatPerKWeight(
|
|
||||||
DefaultSweepFeeRate,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
MaxUpdates: DefaultMaxUpdates,
|
MaxUpdates: DefaultMaxUpdates,
|
||||||
}
|
}
|
||||||
|
@ -107,6 +119,31 @@ func (p Policy) String() string {
|
||||||
p.SweepFeeRate)
|
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
|
// 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
|
// 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
|
// of the justice transaction and subtracting an amount that satisfies the
|
||||||
|
|
93
watchtower/wtpolicy/policy_test.go
Normal file
93
watchtower/wtpolicy/policy_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user