github.com/decred/dcrlnd@v0.7.6/channeldb/migration_01_to_11/migration_09_legacy_serialization.go (about) 1 package migration_01_to_11 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io" 8 "sort" 9 10 lnwire "github.com/decred/dcrlnd/channeldb/migration/lnwire21" 11 "github.com/decred/dcrlnd/kvdb" 12 "github.com/decred/dcrlnd/lntypes" 13 ) 14 15 var ( 16 // paymentBucket is the name of the bucket within the database that 17 // stores all data related to payments. 18 // 19 // Within the payments bucket, each invoice is keyed by its invoice ID 20 // which is a monotonically increasing uint64. BoltDB's sequence 21 // feature is used for generating monotonically increasing id. 22 // 23 // NOTE: Deprecated. Kept around for migration purposes. 24 paymentBucket = []byte("payments") 25 26 // paymentStatusBucket is the name of the bucket within the database 27 // that stores the status of a payment indexed by the payment's 28 // preimage. 29 // 30 // NOTE: Deprecated. Kept around for migration purposes. 31 paymentStatusBucket = []byte("payment-status") 32 ) 33 34 // outgoingPayment represents a successful payment between the daemon and a 35 // remote node. Details such as the total fee paid, and the time of the payment 36 // are stored. 37 // 38 // NOTE: Deprecated. Kept around for migration purposes. 39 type outgoingPayment struct { 40 Invoice 41 42 // Fee is the total fee paid for the payment in milli-satoshis. 43 Fee lnwire.MilliAtom 44 45 // TotalTimeLock is the total cumulative time-lock in the HTLC extended 46 // from the second-to-last hop to the destination. 47 TimeLockLength uint32 48 49 // Path encodes the path the payment took through the network. The path 50 // excludes the outgoing node and consists of the hex-encoded 51 // compressed public key of each of the nodes involved in the payment. 52 Path [][33]byte 53 54 // PaymentPreimage is the preImage of a successful payment. This is used 55 // to calculate the PaymentHash as well as serve as a proof of payment. 56 PaymentPreimage [32]byte 57 } 58 59 // addPayment saves a successful payment to the database. It is assumed that 60 // all payment are sent using unique payment hashes. 61 // 62 // NOTE: Deprecated. Kept around for migration purposes. 63 func (db *DB) addPayment(payment *outgoingPayment) error { 64 // Validate the field of the inner voice within the outgoing payment, 65 // these must also adhere to the same constraints as regular invoices. 66 if err := validateInvoice(&payment.Invoice); err != nil { 67 return err 68 } 69 70 // We first serialize the payment before starting the database 71 // transaction so we can avoid creating a DB payment in the case of a 72 // serialization error. 73 var b bytes.Buffer 74 if err := serializeOutgoingPayment(&b, payment); err != nil { 75 return err 76 } 77 paymentBytes := b.Bytes() 78 79 return kvdb.Update(db, func(tx kvdb.RwTx) error { 80 payments, err := tx.CreateTopLevelBucket(paymentBucket) 81 if err != nil { 82 return err 83 } 84 85 // Obtain the new unique sequence number for this payment. 86 paymentID, err := payments.NextSequence() 87 if err != nil { 88 return err 89 } 90 91 // We use BigEndian for keys as it orders keys in 92 // ascending order. This allows bucket scans to order payments 93 // in the order in which they were created. 94 paymentIDBytes := make([]byte, 8) 95 binary.BigEndian.PutUint64(paymentIDBytes, paymentID) 96 97 return payments.Put(paymentIDBytes, paymentBytes) 98 }, func() {}) 99 } 100 101 // fetchAllPayments returns all outgoing payments in DB. 102 // 103 // NOTE: Deprecated. Kept around for migration purposes. 104 func (db *DB) fetchAllPayments() ([]*outgoingPayment, error) { 105 var payments []*outgoingPayment 106 107 err := kvdb.View(db, func(tx kvdb.RTx) error { 108 bucket := tx.ReadBucket(paymentBucket) 109 if bucket == nil { 110 return ErrNoPaymentsCreated 111 } 112 113 return bucket.ForEach(func(k, v []byte) error { 114 // If the value is nil, then we ignore it as it may be 115 // a sub-bucket. 116 if v == nil { 117 return nil 118 } 119 120 r := bytes.NewReader(v) 121 payment, err := deserializeOutgoingPayment(r) 122 if err != nil { 123 return err 124 } 125 126 payments = append(payments, payment) 127 return nil 128 }) 129 }, func() { 130 payments = nil 131 }) 132 if err != nil { 133 return nil, err 134 } 135 136 return payments, nil 137 } 138 139 // fetchPaymentStatus returns the payment status for outgoing payment. 140 // If status of the payment isn't found, it will default to "StatusUnknown". 141 // 142 // NOTE: Deprecated. Kept around for migration purposes. 143 func (db *DB) fetchPaymentStatus(paymentHash [32]byte) (PaymentStatus, error) { 144 var paymentStatus = StatusUnknown 145 err := kvdb.View(db, func(tx kvdb.RTx) error { 146 var err error 147 paymentStatus, err = fetchPaymentStatusTx(tx, paymentHash) 148 return err 149 }, func() { 150 paymentStatus = StatusUnknown 151 }) 152 if err != nil { 153 return StatusUnknown, err 154 } 155 156 return paymentStatus, nil 157 } 158 159 // fetchPaymentStatusTx is a helper method that returns the payment status for 160 // outgoing payment. If status of the payment isn't found, it will default to 161 // "StatusUnknown". It accepts the bboltdb transactions such that this method 162 // can be composed into other atomic operations. 163 // 164 // NOTE: Deprecated. Kept around for migration purposes. 165 func fetchPaymentStatusTx(tx kvdb.RTx, paymentHash [32]byte) (PaymentStatus, error) { 166 // The default status for all payments that aren't recorded in database. 167 var paymentStatus = StatusUnknown 168 169 bucket := tx.ReadBucket(paymentStatusBucket) 170 if bucket == nil { 171 return paymentStatus, nil 172 } 173 174 paymentStatusBytes := bucket.Get(paymentHash[:]) 175 if paymentStatusBytes == nil { 176 return paymentStatus, nil 177 } 178 179 paymentStatus.FromBytes(paymentStatusBytes) 180 181 return paymentStatus, nil 182 } 183 184 func serializeOutgoingPayment(w io.Writer, p *outgoingPayment) error { 185 var scratch [8]byte 186 187 if err := serializeInvoiceLegacy(w, &p.Invoice); err != nil { 188 return err 189 } 190 191 byteOrder.PutUint64(scratch[:], uint64(p.Fee)) 192 if _, err := w.Write(scratch[:]); err != nil { 193 return err 194 } 195 196 // First write out the length of the bytes to prefix the value. 197 pathLen := uint32(len(p.Path)) 198 byteOrder.PutUint32(scratch[:4], pathLen) 199 if _, err := w.Write(scratch[:4]); err != nil { 200 return err 201 } 202 203 // Then with the path written, we write out the series of public keys 204 // involved in the path. 205 for _, hop := range p.Path { 206 if _, err := w.Write(hop[:]); err != nil { 207 return err 208 } 209 } 210 211 byteOrder.PutUint32(scratch[:4], p.TimeLockLength) 212 if _, err := w.Write(scratch[:4]); err != nil { 213 return err 214 } 215 216 if _, err := w.Write(p.PaymentPreimage[:]); err != nil { 217 return err 218 } 219 220 return nil 221 } 222 223 func deserializeOutgoingPayment(r io.Reader) (*outgoingPayment, error) { 224 var scratch [8]byte 225 226 p := &outgoingPayment{} 227 228 inv, err := deserializeInvoiceLegacy(r) 229 if err != nil { 230 return nil, err 231 } 232 p.Invoice = inv 233 234 if _, err := r.Read(scratch[:]); err != nil { 235 return nil, err 236 } 237 p.Fee = lnwire.MilliAtom(byteOrder.Uint64(scratch[:])) 238 239 if _, err = r.Read(scratch[:4]); err != nil { 240 return nil, err 241 } 242 pathLen := byteOrder.Uint32(scratch[:4]) 243 244 path := make([][33]byte, pathLen) 245 for i := uint32(0); i < pathLen; i++ { 246 if _, err := r.Read(path[i][:]); err != nil { 247 return nil, err 248 } 249 } 250 p.Path = path 251 252 if _, err = r.Read(scratch[:4]); err != nil { 253 return nil, err 254 } 255 p.TimeLockLength = byteOrder.Uint32(scratch[:4]) 256 257 if _, err := r.Read(p.PaymentPreimage[:]); err != nil { 258 return nil, err 259 } 260 261 return p, nil 262 } 263 264 // serializePaymentAttemptInfoMigration9 is the serializePaymentAttemptInfo 265 // version as existed when migration #9 was created. We keep this around, along 266 // with the methods below to ensure that clients that upgrade will use the 267 // correct version of this method. 268 func serializePaymentAttemptInfoMigration9(w io.Writer, a *PaymentAttemptInfo) error { 269 if err := WriteElements(w, a.PaymentID, a.SessionKey); err != nil { 270 return err 271 } 272 273 if err := serializeRouteMigration9(w, a.Route); err != nil { 274 return err 275 } 276 277 return nil 278 } 279 280 func serializeHopMigration9(w io.Writer, h *Hop) error { 281 if err := WriteElements(w, 282 h.PubKeyBytes[:], h.ChannelID, h.OutgoingTimeLock, 283 h.AmtToForward, 284 ); err != nil { 285 return err 286 } 287 288 return nil 289 } 290 291 func serializeRouteMigration9(w io.Writer, r Route) error { 292 if err := WriteElements(w, 293 r.TotalTimeLock, r.TotalAmount, r.SourcePubKey[:], 294 ); err != nil { 295 return err 296 } 297 298 if err := WriteElements(w, uint32(len(r.Hops))); err != nil { 299 return err 300 } 301 302 for _, h := range r.Hops { 303 if err := serializeHopMigration9(w, h); err != nil { 304 return err 305 } 306 } 307 308 return nil 309 } 310 311 func deserializePaymentAttemptInfoMigration9(r io.Reader) (*PaymentAttemptInfo, error) { 312 a := &PaymentAttemptInfo{} 313 err := ReadElements(r, &a.PaymentID, &a.SessionKey) 314 if err != nil { 315 return nil, err 316 } 317 a.Route, err = deserializeRouteMigration9(r) 318 if err != nil { 319 return nil, err 320 } 321 return a, nil 322 } 323 324 func deserializeRouteMigration9(r io.Reader) (Route, error) { 325 rt := Route{} 326 if err := ReadElements(r, 327 &rt.TotalTimeLock, &rt.TotalAmount, 328 ); err != nil { 329 return rt, err 330 } 331 332 var pub []byte 333 if err := ReadElements(r, &pub); err != nil { 334 return rt, err 335 } 336 copy(rt.SourcePubKey[:], pub) 337 338 var numHops uint32 339 if err := ReadElements(r, &numHops); err != nil { 340 return rt, err 341 } 342 343 var hops []*Hop 344 for i := uint32(0); i < numHops; i++ { 345 hop, err := deserializeHopMigration9(r) 346 if err != nil { 347 return rt, err 348 } 349 hops = append(hops, hop) 350 } 351 rt.Hops = hops 352 353 return rt, nil 354 } 355 356 func deserializeHopMigration9(r io.Reader) (*Hop, error) { 357 h := &Hop{} 358 359 var pub []byte 360 if err := ReadElements(r, &pub); err != nil { 361 return nil, err 362 } 363 copy(h.PubKeyBytes[:], pub) 364 365 if err := ReadElements(r, 366 &h.ChannelID, &h.OutgoingTimeLock, &h.AmtToForward, 367 ); err != nil { 368 return nil, err 369 } 370 371 return h, nil 372 } 373 374 // fetchPaymentsMigration9 returns all sent payments found in the DB using the 375 // payment attempt info format that was present as of migration #9. We need 376 // this as otherwise, the current FetchPayments version will use the latest 377 // decoding format. Note that we only need this for the 378 // TestOutgoingPaymentsMigration migration test case. 379 func (db *DB) fetchPaymentsMigration9() ([]*Payment, error) { 380 var payments []*Payment 381 382 err := kvdb.View(db, func(tx kvdb.RTx) error { 383 paymentsBucket := tx.ReadBucket(paymentsRootBucket) 384 if paymentsBucket == nil { 385 return nil 386 } 387 388 return paymentsBucket.ForEach(func(k, v []byte) error { 389 bucket := paymentsBucket.NestedReadBucket(k) 390 if bucket == nil { 391 // We only expect sub-buckets to be found in 392 // this top-level bucket. 393 return fmt.Errorf("non bucket element in " + 394 "payments bucket") 395 } 396 397 p, err := fetchPaymentMigration9(bucket) 398 if err != nil { 399 return err 400 } 401 402 payments = append(payments, p) 403 404 // For older versions of lnd, duplicate payments to a 405 // payment has was possible. These will be found in a 406 // sub-bucket indexed by their sequence number if 407 // available. 408 dup := bucket.NestedReadBucket(paymentDuplicateBucket) 409 if dup == nil { 410 return nil 411 } 412 413 return dup.ForEach(func(k, v []byte) error { 414 subBucket := dup.NestedReadBucket(k) 415 if subBucket == nil { 416 // We one bucket for each duplicate to 417 // be found. 418 return fmt.Errorf("non bucket element" + 419 "in duplicate bucket") 420 } 421 422 p, err := fetchPaymentMigration9(subBucket) 423 if err != nil { 424 return err 425 } 426 427 payments = append(payments, p) 428 return nil 429 }) 430 }) 431 }, func() { 432 payments = nil 433 }) 434 if err != nil { 435 return nil, err 436 } 437 438 // Before returning, sort the payments by their sequence number. 439 sort.Slice(payments, func(i, j int) bool { 440 return payments[i].sequenceNum < payments[j].sequenceNum 441 }) 442 443 return payments, nil 444 } 445 446 func fetchPaymentMigration9(bucket kvdb.RBucket) (*Payment, error) { 447 var ( 448 err error 449 p = &Payment{} 450 ) 451 452 seqBytes := bucket.Get(paymentSequenceKey) 453 if seqBytes == nil { 454 return nil, fmt.Errorf("sequence number not found") 455 } 456 457 p.sequenceNum = binary.BigEndian.Uint64(seqBytes) 458 459 // Get the payment status. 460 p.Status = fetchPaymentStatus(bucket) 461 462 // Get the PaymentCreationInfo. 463 b := bucket.Get(paymentCreationInfoKey) 464 if b == nil { 465 return nil, fmt.Errorf("creation info not found") 466 } 467 468 r := bytes.NewReader(b) 469 p.Info, err = deserializePaymentCreationInfo(r) 470 if err != nil { 471 return nil, err 472 473 } 474 475 // Get the PaymentAttemptInfo. This can be unset. 476 b = bucket.Get(paymentAttemptInfoKey) 477 if b != nil { 478 r = bytes.NewReader(b) 479 p.Attempt, err = deserializePaymentAttemptInfoMigration9(r) 480 if err != nil { 481 return nil, err 482 } 483 } 484 485 // Get the payment preimage. This is only found for 486 // completed payments. 487 b = bucket.Get(paymentSettleInfoKey) 488 if b != nil { 489 var preimg lntypes.Preimage 490 copy(preimg[:], b[:]) 491 p.PaymentPreimage = &preimg 492 } 493 494 // Get failure reason if available. 495 b = bucket.Get(paymentFailInfoKey) 496 if b != nil { 497 reason := FailureReason(b[0]) 498 p.Failure = &reason 499 } 500 501 return p, nil 502 }