diff --git a/channeldb/meta_test.go b/channeldb/meta_test.go index ab3c410ed..014d5966c 100644 --- a/channeldb/meta_test.go +++ b/channeldb/meta_test.go @@ -70,6 +70,9 @@ func applyMigration(t *testing.T, beforeMigration, afterMigration func(d *DB), // Sync with the latest version - applying migration function. err = cdb.syncVersions(versions) + if err != nil { + log.Error(err) + } } // TestVersionFetchPut checks the propernces of fetch/put methods diff --git a/channeldb/migration_11_invoices.go b/channeldb/migration_11_invoices.go index e242309ba..b4e607338 100644 --- a/channeldb/migration_11_invoices.go +++ b/channeldb/migration_11_invoices.go @@ -69,6 +69,11 @@ func migrateInvoices(tx *bbolt.Tx) error { return err } + if invoice.Terms.State == ContractAccepted { + return fmt.Errorf("cannot upgrade with invoice(s) " + + "in accepted state, see release notes") + } + // Try to decode the payment request for every possible net to // avoid passing a the active network to channeldb. This would // be a layering violation, while this migration is only running diff --git a/channeldb/migration_11_invoices_test.go b/channeldb/migration_11_invoices_test.go index 9739af80a..34cb1a92b 100644 --- a/channeldb/migration_11_invoices_test.go +++ b/channeldb/migration_11_invoices_test.go @@ -24,6 +24,43 @@ var ( testCltvDelta = int32(50) ) +// beforeMigrationFuncV11 insert the test invoices in the database. +func beforeMigrationFuncV11(t *testing.T, d *DB, invoices []Invoice) { + err := d.Update(func(tx *bbolt.Tx) error { + invoicesBucket, err := tx.CreateBucketIfNotExists( + invoiceBucket, + ) + if err != nil { + return err + } + + invoiceNum := uint32(1) + for _, invoice := range invoices { + var invoiceKey [4]byte + byteOrder.PutUint32(invoiceKey[:], invoiceNum) + invoiceNum++ + + var buf bytes.Buffer + err := serializeInvoiceLegacy(&buf, &invoice) // nolint:scopelint + if err != nil { + return err + } + + err = invoicesBucket.Put( + invoiceKey[:], buf.Bytes(), + ) + if err != nil { + return err + } + } + + return nil + }) + if err != nil { + t.Fatal(err) + } +} + // TestMigrateInvoices checks that invoices are migrated correctly. func TestMigrateInvoices(t *testing.T) { t.Parallel() @@ -49,42 +86,6 @@ func TestMigrateInvoices(t *testing.T) { }, } - beforeMigrationFunc := func(d *DB) { - err := d.Update(func(tx *bbolt.Tx) error { - invoicesBucket, err := tx.CreateBucketIfNotExists( - invoiceBucket, - ) - if err != nil { - return err - } - - invoiceNum := uint32(1) - for _, invoice := range invoices { - var invoiceKey [4]byte - byteOrder.PutUint32(invoiceKey[:], invoiceNum) - invoiceNum++ - - var buf bytes.Buffer - err := serializeInvoiceLegacy(&buf, &invoice) - if err != nil { - return err - } - - err = invoicesBucket.Put( - invoiceKey[:], buf.Bytes(), - ) - if err != nil { - return err - } - } - - return nil - }) - if err != nil { - t.Fatal(err) - } - } - // Verify that all invoices were migrated. afterMigrationFunc := func(d *DB) { meta, err := d.FetchMeta(nil) @@ -120,12 +121,38 @@ func TestMigrateInvoices(t *testing.T) { } applyMigration(t, - beforeMigrationFunc, + func(d *DB) { beforeMigrationFuncV11(t, d, invoices) }, afterMigrationFunc, migrateInvoices, false) } +// TestMigrateInvoicesHodl checks that a hodl invoice in the accepted state +// fails the migration. +func TestMigrateInvoicesHodl(t *testing.T) { + t.Parallel() + + payReqBtc, err := getPayReq(&bitcoinCfg.MainNetParams) + if err != nil { + t.Fatal(err) + } + + invoices := []Invoice{ + { + PaymentRequest: []byte(payReqBtc), + Terms: ContractTerm{ + State: ContractAccepted, + }, + }, + } + + applyMigration(t, + func(d *DB) { beforeMigrationFuncV11(t, d, invoices) }, + func(d *DB) {}, + migrateInvoices, + true) +} + // signDigestCompact generates a test signature to be used in the generation of // test payment requests. func signDigestCompact(hash []byte) ([]byte, error) {