From 754809406d2b077618f6e3f87285d5bf537f630c Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 6 Sep 2019 17:21:54 -0700 Subject: [PATCH] channeldb: fix migration bug due to interplay between migration #9 and #10 In this commit, we fix an issue that was recently introduced as a result of migration #10. The new TLV format ended up modifying the serialization functions called in `serializePaymentAttemptInfo`. Migration #9, also used this `serializePaymentAttemptInfo` method to serialize the _new_ (pre TLV, but new payment attempt structure) routes into the database during its migration. However, migration #10 failed to copy over the existing unmodified `serializePaymentAttemptInfo` method into the legacy serialization for migration #9. As a result, once migration #9 was run, the routes/payments were serialized using the _new_ format, rather than the format used for v0.7.1. This then lead to de-serialization either failing, or causing partial payment corruption as migration #10 was expecting the "legacy" format (no TLV info). We fix this issue by adding a new fully enclosed `serializePaymentAttemptInfoMigration9`method that will be used for migration #9. Note that our tests didn't catch this, as they test the migration in isolation, rather than in series which is how users will encounter the migrations. Fixes #3463. --- .../migration_09_legacy_serialization.go | 48 +++++++++++++++++++ channeldb/migrations.go | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/channeldb/migration_09_legacy_serialization.go b/channeldb/migration_09_legacy_serialization.go index 56e36ab1..e5b3f712 100644 --- a/channeldb/migration_09_legacy_serialization.go +++ b/channeldb/migration_09_legacy_serialization.go @@ -7,6 +7,7 @@ import ( "github.com/coreos/bbolt" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/routing/route" ) var ( @@ -253,3 +254,50 @@ func deserializeOutgoingPayment(r io.Reader) (*outgoingPayment, error) { return p, nil } + +// serializePaymentAttemptInfoMigration9 is the serializePaymentAttemptInfo +// version as existed when migration #9 was created. We keep this around, along +// with the methods below to ensure that clients that upgrade will use the +// correct version of this method. +func serializePaymentAttemptInfoMigration9(w io.Writer, a *PaymentAttemptInfo) error { + if err := WriteElements(w, a.PaymentID, a.SessionKey); err != nil { + return err + } + + if err := serializeRouteMigration9(w, a.Route); err != nil { + return err + } + + return nil +} + +func serializeHopMigration9(w io.Writer, h *route.Hop) error { + if err := WriteElements(w, + h.PubKeyBytes[:], h.ChannelID, h.OutgoingTimeLock, + h.AmtToForward, + ); err != nil { + return err + } + + return nil +} + +func serializeRouteMigration9(w io.Writer, r route.Route) error { + if err := WriteElements(w, + r.TotalTimeLock, r.TotalAmount, r.SourcePubKey[:], + ); err != nil { + return err + } + + if err := WriteElements(w, uint32(len(r.Hops))); err != nil { + return err + } + + for _, h := range r.Hops { + if err := serializeHopMigration9(w, h); err != nil { + return err + } + } + + return nil +} diff --git a/channeldb/migrations.go b/channeldb/migrations.go index 3423a6d7..e009d833 100644 --- a/channeldb/migrations.go +++ b/channeldb/migrations.go @@ -845,7 +845,7 @@ func migrateOutgoingPayments(tx *bbolt.Tx) error { } var attemptBuf bytes.Buffer - if err := serializePaymentAttemptInfo(&attemptBuf, s); err != nil { + if err := serializePaymentAttemptInfoMigration9(&attemptBuf, s); err != nil { return err }