diff --git a/client.go b/client.go index 66ee81e6..f947cd08 100644 --- a/client.go +++ b/client.go @@ -22,6 +22,7 @@ import ( "github.com/lightninglabs/loop/sweepbatcher" "github.com/lightninglabs/loop/utils" "github.com/lightninglabs/taproot-assets/rpcutils" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/routing/route" "google.golang.org/grpc" @@ -485,7 +486,10 @@ func (s *Client) Run(ctx context.Context, statusChan chan<- SwapInfo) error { func (s *Client) resumeSwaps(ctx context.Context, loopOutSwaps []*loopdb.LoopOut, loopInSwaps []*loopdb.LoopIn) { - swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server, s.AssetClient) + swapCfg := newSwapConfig( + s.lndServices, s.Store, s.Server, s.AssetClient, + clock.NewDefaultClock(), + ) for _, pend := range loopOutSwaps { if pend.State().State.Type() != loopdb.StateTypePending { @@ -578,6 +582,7 @@ func (s *Client) LoopOut(globalCtx context.Context, // Create a new swap object for this swap. swapCfg := newSwapConfig( s.lndServices, s.Store, s.Server, s.AssetClient, + clock.NewDefaultClock(), ) initResult, err := newLoopOutSwap( @@ -759,7 +764,10 @@ func (s *Client) LoopIn(globalCtx context.Context, // Create a new swap object for this swap. initiationHeight := s.executor.height() - swapCfg := newSwapConfig(s.lndServices, s.Store, s.Server, s.AssetClient) + swapCfg := newSwapConfig( + s.lndServices, s.Store, s.Server, s.AssetClient, + clock.NewDefaultClock(), + ) initResult, err := newLoopInSwap( globalCtx, swapCfg, initiationHeight, request, ) diff --git a/cost_migration_test.go b/cost_migration_test.go index 6ff2fc96..082895f2 100644 --- a/cost_migration_test.go +++ b/cost_migration_test.go @@ -9,6 +9,7 @@ import ( "github.com/lightninglabs/lndclient" "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/test" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/stretchr/testify/require" @@ -25,6 +26,7 @@ func TestCalculateLoopOutCost(t *testing.T) { lnd: &lnd.LndServices, store: store, server: server, + clock: clock.NewTestClock(time.Unix(123, 0)), } height := int32(600) @@ -118,6 +120,7 @@ func TestCostMigration(t *testing.T) { lnd: &lnd.LndServices, store: store, server: server, + clock: clock.NewTestClock(time.Unix(123, 0)), } height := int32(600) diff --git a/loopd/daemon.go b/loopd/daemon.go index 32371df1..880e1962 100644 --- a/loopd/daemon.go +++ b/loopd/daemon.go @@ -1005,7 +1005,8 @@ func (d *Daemon) initialize(withMacaroonService bool) error { } loop.Resume( - d.mainCtx, notificationManager, swapClient.Store, d.impl.Conn, d.lnd, + d.mainCtx, notificationManager, swapClient.Store, + d.impl.Conn, d.lnd, clock.NewDefaultClock(), ) // Last, start our internal error handler. This will return exactly one diff --git a/loopin.go b/loopin.go index 989d6733..ae6802c8 100644 --- a/loopin.go +++ b/loopin.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "sync" - "time" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" @@ -264,7 +263,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig, // Instantiate a struct that contains all required data to start the // swap. - initiationTime := time.Now() + initiationTime := cfg.clock.Now() contract := loopdb.LoopInContract{ HtlcConfTarget: request.HtlcConfTarget, @@ -837,7 +836,7 @@ func (s *loopInSwap) publishOnChainHtlc(ctx context.Context) (bool, error) { // the fee for publishing the htlc. s.cost.Onchain = fee - s.lastUpdateTime = time.Now() + s.lastUpdateTime = s.clock.Now() if err := s.persistState(ctx); err != nil { return false, fmt.Errorf("persist htlc tx: %v", err) } @@ -1210,7 +1209,7 @@ func (s *loopInSwap) persistState(ctx context.Context) error { // setState updates the swap state and last update timestamp. func (s *loopInSwap) setState(state loopdb.SwapState) { - s.lastUpdateTime = time.Now() + s.lastUpdateTime = s.clock.Now() s.state = state } diff --git a/loopin_test.go b/loopin_test.go index 9ff97f73..156f1d60 100644 --- a/loopin_test.go +++ b/loopin_test.go @@ -13,6 +13,7 @@ import ( "github.com/lightninglabs/loop/test" "github.com/lightninglabs/loop/utils" "github.com/lightningnetwork/lnd/chainntnfs" + "github.com/lightningnetwork/lnd/clock" invpkg "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/routing/route" @@ -129,8 +130,12 @@ func testLoopInSuccess(t *testing.T) { ctx := newLoopInTestContext(t) height := int32(600) + startTime := time.Unix(123, 0) - cfg := newSwapConfig(&ctx.lnd.LndServices, ctx.store, ctx.server, nil) + cfg := newSwapConfig( + &ctx.lnd.LndServices, ctx.store, ctx.server, nil, + clock.NewTestClock(startTime), + ) expectedLastHop := &route.Vertex{0x02} @@ -144,6 +149,7 @@ func testLoopInSuccess(t *testing.T) { require.NoError(t, err) inSwap := initResult.swap + require.Equal(t, startTime, inSwap.InitiationTime) ctx.store.AssertLoopInStored() @@ -279,7 +285,10 @@ func testLoopInTimeout(t *testing.T, externalValue int64) { height := int32(600) - cfg := newSwapConfig(&ctx.lnd.LndServices, ctx.store, ctx.server, nil) + cfg := newSwapConfig( + &ctx.lnd.LndServices, ctx.store, ctx.server, nil, + clock.NewTestClock(time.Unix(123, 0)), + ) req := testLoopInRequest if externalValue != 0 { @@ -490,7 +499,10 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, ctxb := context.Background() ctx := newLoopInTestContext(t) - cfg := newSwapConfig(&ctx.lnd.LndServices, ctx.store, ctx.server, nil) + cfg := newSwapConfig( + &ctx.lnd.LndServices, ctx.store, ctx.server, nil, + clock.NewTestClock(time.Unix(123, 0)), + ) // Create sender and receiver keys. _, senderPubKey := test.CreateKey(1) @@ -845,7 +857,10 @@ func advanceToPublishedHtlc(t *testing.T, ctx *loopInTestContext) SwapInfo { func startNewLoopIn(t *testing.T, ctx *loopInTestContext, height int32) ( *swapConfig, *loopInSwap, error) { - cfg := newSwapConfig(&ctx.lnd.LndServices, ctx.store, ctx.server, nil) + cfg := newSwapConfig( + &ctx.lnd.LndServices, ctx.store, ctx.server, nil, + clock.NewTestClock(time.Unix(123, 0)), + ) req := &testLoopInRequest diff --git a/loopout.go b/loopout.go index 11990d57..a18c83ed 100644 --- a/loopout.go +++ b/loopout.go @@ -25,6 +25,7 @@ import ( "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/rfqmsg" "github.com/lightningnetwork/lnd/chainntnfs" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntypes" paymentsdb "github.com/lightningnetwork/lnd/payments/db" @@ -192,7 +193,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig, // Instantiate a struct that contains all required data to start the // swap. - initiationTime := time.Now() + initiationTime := cfg.clock.Now() contract := loopdb.LoopOutContract{ SwapInvoice: swapResp.swapInvoice, @@ -633,7 +634,7 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error { // persistState updates the swap state and sends out an update notification. func (s *loopOutSwap) persistState(ctx context.Context) error { - updateTime := time.Now() + updateTime := s.clock.Now() s.lastUpdateTime = updateTime @@ -864,12 +865,12 @@ func (s *loopOutSwap) payInvoiceAsync(ctx context.Context, payCtx, cancel := context.WithCancel(ctx) defer cancel() - start := time.Now() + start := s.clock.Now() paymentStatus, attempts, err := s.sendPaymentWithRetry( payCtx, hash, &req, maxRetries, routingPlugin, pluginType, ) - dt := time.Since(start) + dt := s.clock.Now().Sub(start) paymentSuccess := err == nil && paymentStatus.State == lnrpc.Payment_SUCCEEDED @@ -1543,6 +1544,7 @@ type resumeManager struct { swapStore loopdb.SwapStore swapClient swapserverrpc.SwapServerClient lnd *lndclient.GrpcLndServices + clock clock.Clock reqChan chan *swapserverrpc.ServerUnfinishedSwapNotification } @@ -1552,13 +1554,14 @@ type resumeManager struct { func Resume(ctx context.Context, ntfnManager NotificationManager, swapStore loopdb.SwapStore, swapClientConn *grpc.ClientConn, - lnd *lndclient.GrpcLndServices) { + lnd *lndclient.GrpcLndServices, clock clock.Clock) { resumeManager := &resumeManager{ ntfnManager: ntfnManager, swapStore: swapStore, swapClient: swapserverrpc.NewSwapServerClient(swapClientConn), lnd: lnd, + clock: clock, reqChan: make(chan *swapserverrpc.ServerUnfinishedSwapNotification, 1), } go resumeManager.start(ctx) @@ -1717,7 +1720,7 @@ func (m *resumeManager) resumeLoopOutPayment(ctx context.Context, cost.Server = payResp.Value.ToSatoshis() - amtRequested cost.Offchain = payResp.Fee.ToSatoshis() // Payment succeeded. - updateTime := time.Now() + updateTime := m.clock.Now() // Update state in store. err = m.swapStore.UpdateLoopOut( diff --git a/loopout_test.go b/loopout_test.go index 25c9e230..026d571c 100644 --- a/loopout_test.go +++ b/loopout_test.go @@ -18,6 +18,7 @@ import ( "github.com/lightninglabs/loop/sweep" "github.com/lightninglabs/loop/sweepbatcher" "github.com/lightninglabs/loop/test" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet/chainfee" @@ -57,11 +58,13 @@ func testLoopOutPaymentParameters(t *testing.T) { } height := int32(600) + startTime := time.Unix(123, 0) cfg := &swapConfig{ lnd: &lnd.LndServices, store: store, server: server, + clock: clock.NewTestClock(startTime), } sweeper := &sweep.Sweeper{Lnd: &lnd.LndServices} @@ -82,6 +85,7 @@ func testLoopOutPaymentParameters(t *testing.T) { ) require.NoError(t, err) swap := initResult.swap + require.Equal(t, startTime, swap.InitiationTime) // Execute the swap in its own goroutine. errChan := make(chan error) @@ -193,7 +197,10 @@ func testLateHtlcPublish(t *testing.T) { height := int32(600) - cfg := newSwapConfig(&lnd.LndServices, store, server, nil) + cfg := newSwapConfig( + &lnd.LndServices, store, server, nil, + clock.NewTestClock(time.Unix(123, 0)), + ) testRequest.Expiry = height + testLoopOutMinOnChainCltvDelta @@ -296,6 +303,7 @@ func testCustomSweepConfTarget(t *testing.T) { cfg := newSwapConfig( &lnd.LndServices, loopdb.NewStoreMock(t), server, nil, + clock.NewTestClock(time.Unix(123, 0)), ) initResult, err := newLoopOutSwap( @@ -539,6 +547,7 @@ func testPreimagePush(t *testing.T) { cfg := newSwapConfig( &lnd.LndServices, loopdb.NewStoreMock(t), server, nil, + clock.NewTestClock(time.Unix(123, 0)), ) initResult, err := newLoopOutSwap( @@ -797,6 +806,7 @@ func testFailedOffChainCancelation(t *testing.T) { cfg := newSwapConfig( &lnd.LndServices, loopdb.NewStoreMock(t), server, nil, + clock.NewTestClock(time.Unix(123, 0)), ) initResult, err := newLoopOutSwap( @@ -951,6 +961,7 @@ func TestLoopOutMuSig2Sweep(t *testing.T) { cfg := newSwapConfig( &lnd.LndServices, loopdb.NewStoreMock(t), server, nil, + clock.NewTestClock(time.Unix(123, 0)), ) initResult, err := newLoopOutSwap( diff --git a/swap.go b/swap.go index 204dd461..43a445eb 100644 --- a/swap.go +++ b/swap.go @@ -9,6 +9,7 @@ import ( "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/swap" "github.com/lightninglabs/loop/utils" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lntypes" ) @@ -83,15 +84,18 @@ type swapConfig struct { store loopdb.SwapStore server swapServerClient assets *assets.TapdClient + clock clock.Clock } func newSwapConfig(lnd *lndclient.LndServices, store loopdb.SwapStore, - server swapServerClient, assets *assets.TapdClient) *swapConfig { + server swapServerClient, assets *assets.TapdClient, + clock clock.Clock) *swapConfig { return &swapConfig{ lnd: lnd, store: store, server: server, assets: assets, + clock: clock, } }