diff --git a/htlcswitch/mailbox.go b/htlcswitch/mailbox.go index d0b509d5..1c1ad5c4 100644 --- a/htlcswitch/mailbox.go +++ b/htlcswitch/mailbox.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lnwire" ) @@ -79,6 +80,14 @@ type mailBoxConfig struct { // be routed. A quit channel should be provided so that the call can // properly exit during shutdown. forwardPackets func(chan struct{}, ...*htlcPacket) chan error + + // clock is a time source for the mailbox. + clock clock.Clock + + // expiry is the interval after which Adds will be cancelled if they + // have not been yet been delivered. The computed deadline will expiry + // this long after the Adds are added via AddPacket. + expiry time.Duration } // memoryMailBox is an implementation of the MailBox struct backed by purely @@ -586,6 +595,14 @@ type mailOrchConfig struct { // fetchUpdate retreives the most recent channel update for the channel // this mailbox belongs to. fetchUpdate func(lnwire.ShortChannelID) (*lnwire.ChannelUpdate, error) + + // clock is a time source for the generated mailboxes. + clock clock.Clock + + // expiry is the interval after which Adds will be cancelled if they + // have not been yet been delivered. The computed deadline will expiry + // this long after the Adds are added to a mailbox via AddPacket. + expiry time.Duration } // newMailOrchestrator initializes a fresh mailOrchestrator. @@ -642,6 +659,8 @@ func (mo *mailOrchestrator) exclusiveGetOrCreateMailBox( shortChanID: shortChanID, fetchUpdate: mo.cfg.fetchUpdate, forwardPackets: mo.cfg.forwardPackets, + clock: mo.cfg.clock, + expiry: mo.cfg.expiry, }) mailbox.Start() mo.mailboxes[chanID] = mailbox diff --git a/htlcswitch/mailbox_test.go b/htlcswitch/mailbox_test.go index ccf35e87..040f2d34 100644 --- a/htlcswitch/mailbox_test.go +++ b/htlcswitch/mailbox_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/davecgh/go-spew/spew" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lnwire" ) @@ -19,7 +20,10 @@ func TestMailBoxCouriers(t *testing.T) { // First, we'll create new instance of the current default mailbox // type. - mailBox := newMemoryMailBox(&mailBoxConfig{}) + mailBox := newMemoryMailBox(&mailBoxConfig{ + clock: clock.NewDefaultClock(), + expiry: time.Minute, + }) mailBox.Start() defer mailBox.Stop() @@ -172,14 +176,17 @@ func TestMailBoxResetAfterShutdown(t *testing.T) { type mailboxContext struct { t *testing.T + clock *clock.TestClock mailbox MailBox forwards chan *htlcPacket } -func newMailboxContext(t *testing.T) *mailboxContext { +func newMailboxContext(t *testing.T, startTime time.Time, + expiry time.Duration) *mailboxContext { ctx := &mailboxContext{ t: t, + clock: clock.NewTestClock(startTime), forwards: make(chan *htlcPacket, 1), } ctx.mailbox = newMemoryMailBox(&mailBoxConfig{ @@ -190,6 +197,8 @@ func newMailboxContext(t *testing.T) *mailboxContext { }, nil }, forwardPackets: ctx.forward, + clock: ctx.clock, + expiry: expiry, }) ctx.mailbox.Start() @@ -282,7 +291,7 @@ func (c *mailboxContext) checkFails(adds []*htlcPacket) { // TestMailBoxFailAdd asserts that FailAdd returns a response to the switch // under various interleavings with other operations on the mailbox. func TestMailBoxFailAdd(t *testing.T) { - ctx := newMailboxContext(t) + ctx := newMailboxContext(t, time.Now(), time.Minute) defer ctx.mailbox.Stop() failAdds := func(adds []*htlcPacket) { @@ -316,7 +325,10 @@ func TestMailOrchestrator(t *testing.T) { t.Parallel() // First, we'll create a new instance of our orchestrator. - mo := newMailOrchestrator(&mailOrchConfig{}) + mo := newMailOrchestrator(&mailOrchConfig{ + clock: clock.NewDefaultClock(), + expiry: time.Minute, + }) defer mo.Stop() // We'll be delivering 10 htlc packets via the orchestrator. diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index c65e5fb0..e9a2a1ef 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -177,6 +177,8 @@ func initSwitchWithDB(startingHeight uint32, db *channeldb.DB) (*Switch, error) LogEventTicker: ticker.NewForce(DefaultLogInterval), AckEventTicker: ticker.NewForce(DefaultAckInterval), HtlcNotifier: &mockHTLCNotifier{}, + Clock: clock.NewDefaultClock(), + HTLCExpiry: time.Hour, } return New(cfg, startingHeight) diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index ba57ed11..06c597bf 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -15,6 +15,7 @@ import ( "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/kvdb" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/htlcswitch/hop" "github.com/lightningnetwork/lnd/lntypes" @@ -36,6 +37,10 @@ const ( // DefaultAckInterval is the duration between attempts to ack any settle // fails in a forwarding package. DefaultAckInterval = 15 * time.Second + + // DefaultHTLCExpiry is the duration after which Adds will be cancelled + // if they could not get added to an outgoing commitment. + DefaultHTLCExpiry = time.Minute ) var ( @@ -174,6 +179,15 @@ type Config struct { // RejectHTLC is a flag that instructs the htlcswitch to reject any // HTLCs that are not from the source hop. RejectHTLC bool + + // Clock is a time source for the switch. + Clock clock.Clock + + // HTLCExpiry is the interval after which Adds will be cancelled if they + // have not been yet been delivered to a link. The computed deadline + // will expiry this long after the Adds are added to a mailbox via + // AddPacket. + HTLCExpiry time.Duration } // Switch is the central messaging bus for all incoming/outgoing HTLCs. @@ -301,6 +315,8 @@ func New(cfg Config, currentHeight uint32) (*Switch, error) { s.mailOrchestrator = newMailOrchestrator(&mailOrchConfig{ fetchUpdate: s.cfg.FetchLastChannelUpdate, forwardPackets: s.ForwardPackets, + clock: s.cfg.Clock, + expiry: s.cfg.HTLCExpiry, }) return s, nil diff --git a/server.go b/server.go index f8c36b30..3fdffb2c 100644 --- a/server.go +++ b/server.go @@ -496,6 +496,8 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, AckEventTicker: ticker.New(htlcswitch.DefaultAckInterval), AllowCircularRoute: cfg.AllowCircularRoute, RejectHTLC: cfg.RejectHTLC, + Clock: clock.NewDefaultClock(), + HTLCExpiry: htlcswitch.DefaultHTLCExpiry, }, uint32(currentHeight)) if err != nil { return nil, err