Skip to content

Commit 9f2bf5c

Browse files
authored
Merge pull request #682 from sputn1ck/fix_faulty_timestamps
Fix faulty timestamps
2 parents 0c1a927 + d36c154 commit 9f2bf5c

File tree

2 files changed

+17
-203
lines changed

2 files changed

+17
-203
lines changed

loopdb/sql_test.go

Lines changed: 10 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,15 @@ func TestSqliteTypeConversion(t *testing.T) {
322322
func TestIssue615(t *testing.T) {
323323
ctxb := context.Background()
324324

325+
// Create an invoice to get the timestamp from.
326+
invoice := "lnbc5u1pje2dyusp5qs356crpns9u3we8hw7w9gntfz89zkcaxu6w6h6a" +
327+
"pw6jlgc0cynqpp5y2xdzu4eqasuttxp3nrk72vqdzce3wead7nmf693uqpgx" +
328+
"2hd533qdpcyfnx2etyyp3ks6trddjkuueqw3hkketwwv7kgvrd0py95d6vvv" +
329+
"65z0fzxqzfvcqpjrzjqd82srutzjx82prr234anxdlwvs6peklcc92lp9aqs" +
330+
"q296xnwmqd2rrf9gqqtwqqqqqqqqqqqqqqqqqq9q9qxpqysgq768236z7cx6" +
331+
"gyy766wajrmpnpt6wavkf5nypwyj6r3dcxm89aggq2jm2kznaxvr0lrsqgv7" +
332+
"592upfh5ruyrwzy5tethpzere78xfgwqp64jrpa"
333+
325334
// Create a new sqlite store for testing.
326335
sqlDB := NewTestDB(t)
327336

@@ -356,7 +365,7 @@ func TestIssue615(t *testing.T) {
356365
MaxPrepayRoutingFee: 40,
357366
PrepayInvoice: "prepayinvoice",
358367
DestAddr: destAddr,
359-
SwapInvoice: "swapinvoice",
368+
SwapInvoice: invoice,
360369
MaxSwapRoutingFee: 30,
361370
SweepConfTarget: 2,
362371
HtlcConfirmations: 2,
@@ -384,82 +393,6 @@ func TestIssue615(t *testing.T) {
384393
require.NoError(t, err)
385394
}
386395

387-
func TestTimeConversions(t *testing.T) {
388-
tests := []struct {
389-
timeString string
390-
expectedTime time.Time
391-
}{
392-
{
393-
timeString: "2018-11-01 00:00:00 +0000 UTC",
394-
expectedTime: time.Date(2018, 11, 1, 0, 0, 0, 0, time.UTC),
395-
},
396-
{
397-
timeString: "2018-11-01 00:00:01.10000 +0000 UTC",
398-
expectedTime: time.Date(2018, 11, 1, 0, 0, 1, 100000000, time.UTC),
399-
},
400-
{
401-
timeString: "2053-12-29T02:40:44.269009408Z",
402-
expectedTime: time.Date(
403-
time.Now().Year(), 12, 29, 2, 40, 44, 269009408, time.UTC,
404-
),
405-
},
406-
{
407-
timeString: "55563-06-27 02:09:24 +0000 UTC",
408-
expectedTime: time.Date(
409-
time.Now().Year(), 6, 27, 2, 9, 24, 0, time.UTC,
410-
),
411-
},
412-
{
413-
timeString: "2172-03-11 10:01:11.849906176 +0000 UTC",
414-
expectedTime: time.Date(
415-
time.Now().Year(), 3, 11, 10, 1, 11, 849906176, time.UTC,
416-
),
417-
},
418-
{
419-
timeString: "2023-08-04 16:07:49 +0800 CST",
420-
expectedTime: time.Date(
421-
2023, 8, 4, 8, 7, 49, 0, time.UTC,
422-
),
423-
},
424-
{
425-
timeString: "2023-08-04 16:07:49 -0700 MST",
426-
expectedTime: time.Date(
427-
2023, 8, 4, 23, 7, 49, 0, time.UTC,
428-
),
429-
},
430-
{
431-
timeString: "2023-08-04T16:07:49+08:00",
432-
expectedTime: time.Date(
433-
2023, 8, 4, 8, 7, 49, 0, time.UTC,
434-
),
435-
},
436-
{
437-
timeString: "2023-08-04T16:07:49+08:00",
438-
expectedTime: time.Date(
439-
2023, 8, 4, 8, 7, 49, 0, time.UTC,
440-
),
441-
},
442-
{
443-
timeString: "2188-02-29 15:34:23.847906176 +0000 UTC",
444-
expectedTime: time.Date(
445-
2023, 2, 28, 15, 34, 23, 847906176, time.UTC,
446-
),
447-
},
448-
{
449-
timeString: "2188-02-29T16:07:49+08:00",
450-
expectedTime: time.Date(
451-
2023, 2, 28, 8, 7, 49, 0, time.UTC,
452-
),
453-
},
454-
}
455-
456-
for _, test := range tests {
457-
time, err := fixTimeStamp(test.timeString)
458-
require.NoError(t, err)
459-
require.Equal(t, test.expectedTime, time)
460-
}
461-
}
462-
463396
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
464397

465398
func randomString(length int) string {

loopdb/sqlite.go

Lines changed: 7 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package loopdb
33
import (
44
"context"
55
"database/sql"
6-
"errors"
76
"fmt"
87
"net/url"
98
"path/filepath"
@@ -15,6 +14,7 @@ import (
1514
"github.com/btcsuite/btcd/chaincfg"
1615
sqlite_migrate "github.com/golang-migrate/migrate/v4/database/sqlite"
1716
"github.com/lightninglabs/loop/loopdb/sqlc"
17+
"github.com/lightningnetwork/lnd/zpay32"
1818

1919
"github.com/stretchr/testify/require"
2020
_ "modernc.org/sqlite" // Register relevant drivers.
@@ -213,7 +213,7 @@ func (db *BaseDB) ExecTx(ctx context.Context, txOptions TxOptions,
213213
func (b *BaseDB) FixFaultyTimestamps(ctx context.Context) error {
214214
// Manually fetch all the loop out swaps.
215215
rows, err := b.DB.QueryContext(
216-
ctx, "SELECT swap_hash, publication_deadline FROM loopout_swaps",
216+
ctx, "SELECT swap_hash, swap_invoice, publication_deadline FROM loopout_swaps",
217217
)
218218
if err != nil {
219219
return err
@@ -226,6 +226,7 @@ func (b *BaseDB) FixFaultyTimestamps(ctx context.Context) error {
226226
// the sqlite driver will fail on faulty timestamps.
227227
type LoopOutRow struct {
228228
Hash []byte `json:"swap_hash"`
229+
SwapInvoice string `json:"swap_invoice"`
229230
PublicationDeadline string `json:"publication_deadline"`
230231
}
231232

@@ -234,7 +235,7 @@ func (b *BaseDB) FixFaultyTimestamps(ctx context.Context) error {
234235
for rows.Next() {
235236
var swap LoopOutRow
236237
err := rows.Scan(
237-
&swap.Hash, &swap.PublicationDeadline,
238+
&swap.Hash, &swap.SwapInvoice, &swap.PublicationDeadline,
238239
)
239240
if err != nil {
240241
return err
@@ -264,14 +265,15 @@ func (b *BaseDB) FixFaultyTimestamps(ctx context.Context) error {
264265

265266
// Skip if the year is not in the future.
266267
thisYear := time.Now().Year()
267-
if year <= thisYear {
268+
if year > 2020 && year <= thisYear {
268269
continue
269270
}
270271

271-
fixedTime, err := fixTimeStamp(swap.PublicationDeadline)
272+
payReq, err := zpay32.Decode(swap.SwapInvoice, b.network)
272273
if err != nil {
273274
return err
274275
}
276+
fixedTime := payReq.Timestamp.Add(time.Minute * 30)
275277

276278
// Update the faulty time to a valid time.
277279
_, err = tx.ExecContext(
@@ -322,92 +324,6 @@ func (r *SqliteTxOptions) ReadOnly() bool {
322324
return r.readOnly
323325
}
324326

325-
// fixTimeStamp tries to parse a timestamp string with both the
326-
// parseSqliteTimeStamp and parsePostgresTimeStamp functions.
327-
// If both fail, it returns an error.
328-
func fixTimeStamp(dateTimeStr string) (time.Time, error) {
329-
year, err := getTimeStampYear(dateTimeStr)
330-
if err != nil {
331-
return time.Time{}, err
332-
}
333-
334-
// If the year is in the future. It was a faulty timestamp.
335-
thisYear := time.Now().Year()
336-
if year > thisYear {
337-
dateTimeStr = strings.Replace(
338-
dateTimeStr,
339-
fmt.Sprintf("%d", year),
340-
fmt.Sprintf("%d", thisYear),
341-
1,
342-
)
343-
}
344-
345-
// If the year is a leap year and the date is 29th of February, we
346-
// need to change it to 28th of February. Otherwise, the time.Parse
347-
// function will fail, as a non-leap year cannot have 29th of February.
348-
day, month, err := extractDayAndMonth(dateTimeStr)
349-
if err != nil {
350-
return time.Time{}, fmt.Errorf("unable to parse timestamp day "+
351-
"and month %v: %v", dateTimeStr, err)
352-
}
353-
354-
if !isLeapYear(thisYear) &&
355-
month == 2 && day == 29 {
356-
357-
dateTimeStr = strings.Replace(
358-
dateTimeStr,
359-
fmt.Sprintf("%d-02-29", thisYear),
360-
fmt.Sprintf("%d-02-28", thisYear),
361-
1,
362-
)
363-
}
364-
365-
parsedTime, err := parseLayouts(defaultLayouts(), dateTimeStr)
366-
if err != nil {
367-
return time.Time{}, fmt.Errorf("unable to parse timestamp %v: %v",
368-
dateTimeStr, err)
369-
}
370-
371-
return parsedTime.UTC(), nil
372-
}
373-
374-
// parseLayouts parses time based on a list of provided layouts.
375-
// If layouts is empty list or nil, the error with unknown layout will be returned.
376-
func parseLayouts(layouts []string, dateTime string) (time.Time, error) {
377-
for _, layout := range layouts {
378-
parsedTime, err := time.Parse(layout, dateTime)
379-
if err == nil {
380-
return parsedTime, nil
381-
}
382-
}
383-
384-
return time.Time{}, errors.New("unknown layout")
385-
}
386-
387-
// defaultLayouts returns a default list of ALL supported layouts.
388-
// This function returns new copy of a slice.
389-
func defaultLayouts() []string {
390-
return []string{
391-
"2006-01-02 15:04:05.99999 -0700 MST", // Custom sqlite layout.
392-
time.RFC3339Nano,
393-
time.RFC3339,
394-
time.RFC1123Z,
395-
time.RFC1123,
396-
time.RFC850,
397-
time.RFC822Z,
398-
time.RFC822,
399-
time.Layout,
400-
time.RubyDate,
401-
time.UnixDate,
402-
time.ANSIC,
403-
time.StampNano,
404-
time.StampMicro,
405-
time.StampMilli,
406-
time.Stamp,
407-
time.Kitchen,
408-
}
409-
}
410-
411327
// getTimeStampYear returns the year of a timestamp string.
412328
func getTimeStampYear(dateTimeStr string) (int, error) {
413329
parts := strings.Split(dateTimeStr, "-")
@@ -423,38 +339,3 @@ func getTimeStampYear(dateTimeStr string) (int, error) {
423339

424340
return year, nil
425341
}
426-
427-
// extractDayAndMonth extracts the day and month from a date string.
428-
func extractDayAndMonth(dateStr string) (int, int, error) {
429-
// Split the date string into parts using various delimiters.
430-
parts := strings.FieldsFunc(dateStr, func(r rune) bool {
431-
return r == '-' || r == ' ' || r == 'T' || r == ':' || r == '+' || r == 'Z'
432-
})
433-
434-
if len(parts) < 3 {
435-
return 0, 0, fmt.Errorf("Invalid date format: %s", dateStr)
436-
}
437-
438-
// Extract year, month, and day from the parts.
439-
_, err := strconv.Atoi(parts[0])
440-
if err != nil {
441-
return 0, 0, err
442-
}
443-
444-
month, err := strconv.Atoi(parts[1])
445-
if err != nil {
446-
return 0, 0, err
447-
}
448-
449-
day, err := strconv.Atoi(parts[2])
450-
if err != nil {
451-
return 0, 0, err
452-
}
453-
454-
return day, month, nil
455-
}
456-
457-
// isLeapYear returns true if the year is a leap year.
458-
func isLeapYear(year int) bool {
459-
return (year%4 == 0 && year%100 != 0) || (year%400 == 0)
460-
}

0 commit comments

Comments
 (0)