Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions loopd/swapclient_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,21 +156,22 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
return nil, err
}

// Infer if the publication deadline is set in milliseconds.
publicationDeadline := getPublicationDeadline(in.SwapPublicationDeadline)

req := &loop.OutRequest{
Amount: btcutil.Amount(in.Amt),
DestAddr: sweepAddr,
MaxMinerFee: btcutil.Amount(in.MaxMinerFee),
MaxPrepayAmount: btcutil.Amount(in.MaxPrepayAmt),
MaxPrepayRoutingFee: btcutil.Amount(in.MaxPrepayRoutingFee),
MaxSwapRoutingFee: btcutil.Amount(in.MaxSwapRoutingFee),
MaxSwapFee: btcutil.Amount(in.MaxSwapFee),
SweepConfTarget: sweepConfTarget,
HtlcConfirmations: in.HtlcConfirmations,
SwapPublicationDeadline: time.Unix(
int64(in.SwapPublicationDeadline), 0,
),
Label: in.Label,
Initiator: in.Initiator,
Amount: btcutil.Amount(in.Amt),
DestAddr: sweepAddr,
MaxMinerFee: btcutil.Amount(in.MaxMinerFee),
MaxPrepayAmount: btcutil.Amount(in.MaxPrepayAmt),
MaxPrepayRoutingFee: btcutil.Amount(in.MaxPrepayRoutingFee),
MaxSwapRoutingFee: btcutil.Amount(in.MaxSwapRoutingFee),
MaxSwapFee: btcutil.Amount(in.MaxSwapFee),
SweepConfTarget: sweepConfTarget,
HtlcConfirmations: in.HtlcConfirmations,
SwapPublicationDeadline: publicationDeadline,
Label: in.Label,
Initiator: in.Initiator,
}

switch {
Expand Down Expand Up @@ -538,13 +539,14 @@ func (s *swapClientServer) LoopOutQuote(ctx context.Context,
if err != nil {
return nil, err
}

publicactionDeadline := getPublicationDeadline(req.SwapPublicationDeadline)

quote, err := s.impl.LoopOutQuote(ctx, &loop.LoopOutQuoteRequest{
Amount: btcutil.Amount(req.Amt),
SweepConfTarget: confTarget,
SwapPublicationDeadline: time.Unix(
int64(req.SwapPublicationDeadline), 0,
),
Initiator: defaultLoopdInitiator,
Amount: btcutil.Amount(req.Amt),
SweepConfTarget: confTarget,
SwapPublicationDeadline: publicactionDeadline,
Initiator: defaultLoopdInitiator,
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -1249,3 +1251,19 @@ func hasBandwidth(channels []lndclient.ChannelInfo, amt btcutil.Amount,

return false, 0
}

// getPublicationDeadline returns the publication deadline for a swap given the
// unix timestamp. If the timestamp is believed to be in milliseconds, then it
// is converted to seconds.
func getPublicationDeadline(unixTimestamp uint64) time.Time {
length := len(fmt.Sprintf("%d", unixTimestamp))
if length >= 13 {
// Likely a millisecond timestamp
secs := unixTimestamp / 1000
nsecs := (unixTimestamp % 1000) * 1e6
return time.Unix(int64(secs), int64(nsecs))
} else {
// Likely a second timestamp
return time.Unix(int64(unixTimestamp), 0)
}
}
25 changes: 19 additions & 6 deletions loopdb/postgres.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package loopdb

import (
"context"
"database/sql"
"fmt"
"testing"
Expand Down Expand Up @@ -104,13 +105,25 @@ func NewPostgresStore(cfg *PostgresConfig,

queries := sqlc.New(rawDb)

baseDB := &BaseDB{
DB: rawDb,
Queries: queries,
network: network,
}

// Fix faulty timestamps in the database.
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

err = baseDB.FixFaultyTimestamps(ctx, parsePostgresTimeStamp)
if err != nil {
log.Errorf("Failed to fix faulty timestamps: %v", err)
return nil, err
}

return &PostgresStore{
cfg: cfg,
BaseDB: &BaseDB{
DB: rawDb,
Queries: queries,
network: network,
},
cfg: cfg,
BaseDB: baseDB,
}, nil
}

Expand Down
70 changes: 70 additions & 0 deletions loopdb/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,76 @@ func TestSqliteTypeConversion(t *testing.T) {

}

// TestIssue615 tests that on faulty timestamps, the database will be fixed.
// Reference: https://github.com/lightninglabs/lightning-terminal/issues/615
func TestIssue615(t *testing.T) {
ctxb := context.Background()

// Create a new sqlite store for testing.
sqlDB := NewTestDB(t)

// Create a faulty loopout swap.
destAddr := test.GetDestAddr(t, 0)
faultyTime, err := parseSqliteTimeStamp("55563-06-27 02:09:24 +0000 UTC")
require.NoError(t, err)

unrestrictedSwap := LoopOutContract{
SwapContract: SwapContract{
AmountRequested: 100,
Preimage: testPreimage,
CltvExpiry: 144,
HtlcKeys: HtlcKeys{
SenderScriptKey: senderKey,
ReceiverScriptKey: receiverKey,
SenderInternalPubKey: senderInternalKey,
ReceiverInternalPubKey: receiverInternalKey,
ClientScriptKeyLocator: keychain.KeyLocator{
Family: 1,
Index: 2,
},
},
MaxMinerFee: 10,
MaxSwapFee: 20,
InitiationHeight: 99,
InitiationTime: time.Now(),
ProtocolVersion: ProtocolVersionMuSig2,
},
MaxPrepayRoutingFee: 40,
PrepayInvoice: "prepayinvoice",
DestAddr: destAddr,
SwapInvoice: "swapinvoice",
MaxSwapRoutingFee: 30,
SweepConfTarget: 2,
HtlcConfirmations: 2,
SwapPublicationDeadline: faultyTime,
}

err = sqlDB.CreateLoopOut(ctxb, testPreimage.Hash(), &unrestrictedSwap)
require.NoError(t, err)

// This should fail because of the faulty timestamp.
_, err = sqlDB.GetLoopOutSwaps(ctxb)

// If we're using sqlite, we expect an error.
if testDBType == "sqlite" {
require.Error(t, err)
} else {
require.NoError(t, err)
}

parseFunc := parseSqliteTimeStamp
if testDBType == "postgres" {
parseFunc = parsePostgresTimeStamp
}

// Fix the faulty timestamp.
err = sqlDB.FixFaultyTimestamps(ctxb, parseFunc)
require.NoError(t, err)

_, err = sqlDB.GetLoopOutSwaps(ctxb)
require.NoError(t, err)
}

const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func randomString(length int) string {
Expand Down
Loading