diff --git a/channeldb/channel.go b/channeldb/channel.go index 34597c2a8..7bc83c4dc 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -57,14 +57,16 @@ var ( // sequential prefix scans, and second to eliminate write amplification // caused by serializing/deserializing the *entire* struct with each // update. - chanCapacityPrefix = []byte("ccp") - selfBalancePrefix = []byte("sbp") - theirBalancePrefix = []byte("tbp") - minFeePerKbPrefix = []byte("mfp") - updatePrefix = []byte("uup") - satSentPrefix = []byte("ssp") - satReceivedPrefix = []byte("srp") - netFeesPrefix = []byte("ntp") + chanCapacityPrefix = []byte("ccp") + selfBalancePrefix = []byte("sbp") + theirBalancePrefix = []byte("tbp") + minFeePerKbPrefix = []byte("mfp") + theirDustLimitPrefix = []byte("tdlp") + ourDustLimitPrefix = []byte("odlp") + updatePrefix = []byte("uup") + satSentPrefix = []byte("ssp") + satReceivedPrefix = []byte("srp") + netFeesPrefix = []byte("ntp") // chanIDKey stores the node, and channelID for an active channel. chanIDKey = []byte("cik") @@ -138,6 +140,16 @@ type OpenChannel struct { // channel as on-chain conditions change. MinFeePerKb btcutil.Amount + // TheirDustLimit is the threshold below which no HTLC output should be + // generated for their commitment transaction; ie. HTLCs below + // this amount are not enforceable onchain from their point of view. + TheirDustLimit btcutil.Amount + + // OurDustLimit is the threshold below which no HTLC output should be + // generated for our commitment transaction; ie. HTLCs below + // this amount are not enforceable onchain from out point of view. + OurDustLimit btcutil.Amount + // OurCommitKey is the key to be used within our commitment transaction // to generate the scripts for outputs paying to ourself, and // revocation clauses. @@ -674,6 +686,12 @@ func putOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket, if err := putChanMinFeePerKb(openChanBucket, channel); err != nil { return err } + if err := putChanTheirDustLimit(openChanBucket, channel); err != nil { + return err + } + if err := putChanOurDustLimit(openChanBucket, channel); err != nil { + return err + } if err := putChanNumUpdates(openChanBucket, channel); err != nil { return err } @@ -751,6 +769,12 @@ func fetchOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket, if err = fetchChanMinFeePerKb(openChanBucket, channel); err != nil { return nil, err } + if err = fetchChanTheirDustLimit(openChanBucket, channel); err != nil { + return nil, err + } + if err = fetchChanOurDustLimit(openChanBucket, channel); err != nil { + return nil, err + } if err = fetchChanNumUpdates(openChanBucket, channel); err != nil { return nil, err } @@ -893,6 +917,38 @@ func putChanMinFeePerKb(openChanBucket *bolt.Bucket, channel *OpenChannel) error return openChanBucket.Put(keyPrefix, scratch) } +func putChanTheirDustLimit(openChanBucket *bolt.Bucket, channel *OpenChannel) error { + scratch := make([]byte, 8) + byteOrder.PutUint64(scratch, uint64(channel.TheirDustLimit)) + + var b bytes.Buffer + if err := writeOutpoint(&b, channel.ChanID); err != nil { + return err + } + + keyPrefix := make([]byte, 3+b.Len()) + copy(keyPrefix, theirDustLimitPrefix) + copy(keyPrefix[3:], b.Bytes()) + + return openChanBucket.Put(keyPrefix, scratch) +} + +func putChanOurDustLimit(openChanBucket *bolt.Bucket, channel *OpenChannel) error { + scratch := make([]byte, 8) + byteOrder.PutUint64(scratch, uint64(channel.OurDustLimit)) + + var b bytes.Buffer + if err := writeOutpoint(&b, channel.ChanID); err != nil { + return err + } + + keyPrefix := make([]byte, 3+b.Len()) + copy(keyPrefix, ourDustLimitPrefix) + copy(keyPrefix[3:], b.Bytes()) + + return openChanBucket.Put(keyPrefix, scratch) +} + func deleteChanMinFeePerKb(openChanBucket *bolt.Bucket, chanID []byte) error { keyPrefix := make([]byte, 3+len(chanID)) copy(keyPrefix, minFeePerKbPrefix) @@ -916,6 +972,38 @@ func fetchChanMinFeePerKb(openChanBucket *bolt.Bucket, channel *OpenChannel) err return nil } +func fetchChanTheirDustLimit(openChanBucket *bolt.Bucket, channel *OpenChannel) error { + var b bytes.Buffer + if err := writeOutpoint(&b, channel.ChanID); err != nil { + return err + } + + keyPrefix := make([]byte, 3+b.Len()) + copy(keyPrefix, theirDustLimitPrefix) + copy(keyPrefix[3:], b.Bytes()) + + dustLimitBytes := openChanBucket.Get(keyPrefix) + channel.TheirDustLimit = btcutil.Amount(byteOrder.Uint64(dustLimitBytes)) + + return nil +} + +func fetchChanOurDustLimit(openChanBucket *bolt.Bucket, channel *OpenChannel)error { + var b bytes.Buffer + if err := writeOutpoint(&b, channel.ChanID); err != nil { + return err + } + + keyPrefix := make([]byte, 3+b.Len()) + copy(keyPrefix, ourDustLimitPrefix) + copy(keyPrefix[3:], b.Bytes()) + + dustLimitBytes := openChanBucket.Get(keyPrefix) + channel.OurDustLimit = btcutil.Amount(byteOrder.Uint64(dustLimitBytes)) + + return nil +} + func putChanNumUpdates(openChanBucket *bolt.Bucket, channel *OpenChannel) error { scratch := make([]byte, 8) byteOrder.PutUint64(scratch, channel.NumUpdates) diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index af936b63f..0e429dcef 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -140,6 +140,8 @@ func createTestChannelState(cdb *DB) (*OpenChannel, error) { IdentityPub: pubKey, ChanID: id, MinFeePerKb: btcutil.Amount(5000), + TheirDustLimit: btcutil.Amount(200), + OurDustLimit: btcutil.Amount(200), OurCommitKey: privKey.PubKey(), TheirCommitKey: pubKey, Capacity: btcutil.Amount(10000), @@ -182,7 +184,7 @@ func TestOpenChannelPutGetDelete(t *testing.T) { t.Fatalf("unable to create channel state: %v", err) } state.Htlcs = []*HTLC{ - &HTLC{ + { Incoming: true, Amt: 10, RHash: key, @@ -212,6 +214,12 @@ func TestOpenChannelPutGetDelete(t *testing.T) { if state.MinFeePerKb != newState.MinFeePerKb { t.Fatalf("fee/kb doesn't match") } + if state.TheirDustLimit != newState.TheirDustLimit { + t.Fatalf("their dust limit doesn't match") + } + if state.OurDustLimit != newState.OurDustLimit { + t.Fatalf("our dust limit doesn't match") + } if state.IsInitiator != newState.IsInitiator { t.Fatalf("initiator status doesn't match") } diff --git a/lnwallet/parameters.go b/lnwallet/parameters.go new file mode 100644 index 000000000..1b8891774 --- /dev/null +++ b/lnwallet/parameters.go @@ -0,0 +1,12 @@ +package lnwallet + +import ( + "github.com/roasbeef/btcwallet/wallet/txrules" + "github.com/roasbeef/btcutil" +) + +// DefaultDustLimit is used to calculate the dust HTLC amount which will be +// proposed to other node during channel creation. +func DefaultDustLimit() btcutil.Amount { + return txrules.GetDustThreshold(P2WSHSize, txrules.DefaultRelayFeePerKb) +}