Skip to content

Commit

Permalink
Merge pull request #1229 from wpaulino/randomize-link-fee-updates
Browse files Browse the repository at this point in the history
htlcswitch: randomize link fee updates
  • Loading branch information
Roasbeef committed Jun 14, 2018
2 parents 4a0d7b0 + 8198466 commit 39f2739
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 261 deletions.
77 changes: 46 additions & 31 deletions htlcswitch/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ package htlcswitch

import (
"bytes"
"crypto/sha256"
"fmt"
prand "math/rand"
"sync"
"sync/atomic"
"time"

"crypto/sha256"

"github.com/davecgh/go-spew/spew"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/htlcswitch/hodl"
Expand All @@ -21,6 +20,10 @@ import (
"github.com/roasbeef/btcd/chaincfg/chainhash"
)

func init() {
prand.Seed(time.Now().UnixNano())
}

const (
// expiryGraceDelta is a grace period that the timeout of incoming
// HTLC's that pay directly to us (i.e we're the "exit node") must up
Expand All @@ -36,6 +39,12 @@ const (
// for a new fee update. We'll use this as a fee floor when proposing
// and accepting updates.
minCommitFeePerKw = 253

// DefaultMinLinkFeeUpdateTimeout and DefaultMaxLinkFeeUpdateTimeout
// represent the default timeout bounds in which a link should propose
// to update its commitment fee rate.
DefaultMinLinkFeeUpdateTimeout = 10 * time.Minute
DefaultMaxLinkFeeUpdateTimeout = 60 * time.Minute
)

// ForwardingPolicy describes the set of constraints that a given ChannelLink
Expand Down Expand Up @@ -202,13 +211,6 @@ type ChannelLinkConfig struct {
// transaction to ensure timely confirmation.
FeeEstimator lnwallet.FeeEstimator

// BlockEpochs is an active block epoch event stream backed by an
// active ChainNotifier instance. The ChannelLink will use new block
// notifications sent over this channel to decide when a _new_ HTLC is
// too close to expiry, and also when any active HTLC's have expired
// (or are close to expiry).
BlockEpochs *chainntnfs.BlockEpochEvent

// DebugHTLC should be turned on if you want all HTLCs sent to a node
// with the debug htlc R-Hash are immediately settled in the next
// available state transition.
Expand Down Expand Up @@ -248,6 +250,12 @@ type ChannelLinkConfig struct {
// in testing, it is here to ensure the sphinx replay detection on the
// receiving node is persistent.
UnsafeReplay bool

// MinFeeUpdateTimeout and MaxFeeUpdateTimeout represent the timeout
// interval bounds in which a link will propose to update its commitment
// fee rate. A random timeout will be selected between these values.
MinFeeUpdateTimeout time.Duration
MaxFeeUpdateTimeout time.Duration
}

// channelLink is the service which drives a channel's commitment update
Expand All @@ -273,10 +281,6 @@ type channelLink struct {
// method in state machine.
batchCounter uint32

// bestHeight is the best known height of the main chain. The link will
// use this information to govern decisions based on HTLC timeouts.
bestHeight uint32

// keystoneBatch represents a volatile list of keystones that must be
// written before attempting to sign the next commitment txn. These
// represent all the HTLC's forwarded to the link from the switch. Once
Expand Down Expand Up @@ -342,6 +346,10 @@ type channelLink struct {
logCommitTimer *time.Timer
logCommitTick <-chan time.Time

// updateFeeTimer is the timer responsible for updating the link's
// commitment fee every time it fires.
updateFeeTimer *time.Timer

sync.RWMutex

wg sync.WaitGroup
Expand All @@ -350,8 +358,8 @@ type channelLink struct {

// NewChannelLink creates a new instance of a ChannelLink given a configuration
// and active channel that will be used to verify/apply updates to.
func NewChannelLink(cfg ChannelLinkConfig, channel *lnwallet.LightningChannel,
currentHeight uint32) ChannelLink {
func NewChannelLink(cfg ChannelLinkConfig,
channel *lnwallet.LightningChannel) ChannelLink {

return &channelLink{
cfg: cfg,
Expand All @@ -360,7 +368,6 @@ func NewChannelLink(cfg ChannelLinkConfig, channel *lnwallet.LightningChannel,
// TODO(roasbeef): just do reserve here?
logCommitTimer: time.NewTimer(300 * time.Millisecond),
overflowQueue: newPacketQueue(lnwallet.MaxHTLCNumber / 2),
bestHeight: currentHeight,
htlcUpdates: make(chan []channeldb.HTLC),
quit: make(chan struct{}),
}
Expand Down Expand Up @@ -427,6 +434,8 @@ func (l *channelLink) Start() error {
}
}

l.updateFeeTimer = time.NewTimer(l.randomFeeUpdateTimeout())

l.wg.Add(1)
go l.htlcManager()

Expand All @@ -449,8 +458,8 @@ func (l *channelLink) Stop() {
l.cfg.ChainEvents.Cancel()
}

l.updateFeeTimer.Stop()
l.channel.Stop()

l.overflowQueue.Stop()

close(l.quit)
Expand Down Expand Up @@ -781,7 +790,6 @@ func (l *channelLink) fwdPkgGarbager() {
func (l *channelLink) htlcManager() {
defer func() {
l.wg.Done()
l.cfg.BlockEpochs.Cancel()
log.Infof("ChannelLink(%v) has exited", l)
}()

Expand Down Expand Up @@ -835,7 +843,6 @@ func (l *channelLink) htlcManager() {

out:
for {

// We must always check if we failed at some point processing
// the last update before processing the next.
if l.failed {
Expand All @@ -844,16 +851,10 @@ out:
}

select {

// A new block has arrived, we'll check the network fee to see
// if we should adjust our commitment fee, and also update our
// track of the best current height.
case blockEpoch, ok := <-l.cfg.BlockEpochs.Epochs:
if !ok {
break out
}

l.bestHeight = uint32(blockEpoch.Height)
// Our update fee timer has fired, so we'll check the network
// fee to see if we should adjust our commitment fee.
case <-l.updateFeeTimer.C:
l.updateFeeTimer.Reset(l.randomFeeUpdateTimeout())

// If we're not the initiator of the channel, don't we
// don't control the fees, so we can ignore this.
Expand Down Expand Up @@ -983,6 +984,20 @@ out:
}
}

// randomFeeUpdateTimeout returns a random timeout between the bounds defined
// within the link's configuration that will be used to determine when the link
// should propose an update to its commitment fee rate.
func (l *channelLink) randomFeeUpdateTimeout() time.Duration {
lower := int64(l.cfg.MinFeeUpdateTimeout)
upper := int64(l.cfg.MaxFeeUpdateTimeout)
rand := prand.Int63n(upper)
if rand < lower {
rand = lower
}

return time.Duration(rand)
}

// handleDownStreamPkt processes an HTLC packet sent from the downstream HTLC
// Switch. Possible messages sent by the switch include requests to forward new
// HTLCs, timeout previously cleared HTLCs, and finally to settle currently
Expand Down Expand Up @@ -2065,7 +2080,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
continue
}

heightNow := l.bestHeight
heightNow := l.cfg.Switch.BestHeight()

fwdInfo := chanIterator.ForwardingInstructions()
switch fwdInfo.NextHop {
Expand Down
Loading

0 comments on commit 39f2739

Please sign in to comment.