github.com/decred/dcrlnd@v0.7.6/channeldb/migration21/current/current_encoding.go (about) 1 package current 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "io" 9 10 lnwire "github.com/decred/dcrlnd/channeldb/migration/lnwire21" 11 "github.com/decred/dcrlnd/channeldb/migration21/common" 12 "github.com/decred/dcrlnd/kvdb" 13 ) 14 15 func serializeChanCommit(w io.Writer, c *common.ChannelCommitment) error { // nolint: dupl 16 if err := WriteElements(w, 17 c.CommitHeight, c.LocalLogIndex, c.LocalHtlcIndex, 18 c.RemoteLogIndex, c.RemoteHtlcIndex, c.LocalBalance, 19 c.RemoteBalance, c.CommitFee, c.FeePerKB, c.CommitTx, 20 c.CommitSig, 21 ); err != nil { 22 return err 23 } 24 25 return serializeHtlcs(w, c.Htlcs...) 26 } 27 28 func SerializeLogUpdates(w io.Writer, logUpdates []common.LogUpdate) error { // nolint: dupl 29 numUpdates := uint16(len(logUpdates)) 30 if err := binary.Write(w, byteOrder, numUpdates); err != nil { 31 return err 32 } 33 34 for _, diff := range logUpdates { 35 err := WriteElements(w, diff.LogIndex, diff.UpdateMsg) 36 if err != nil { 37 return err 38 } 39 } 40 41 return nil 42 } 43 44 func serializeHtlcs(b io.Writer, htlcs ...common.HTLC) error { // nolint: dupl 45 numHtlcs := uint16(len(htlcs)) 46 if err := WriteElement(b, numHtlcs); err != nil { 47 return err 48 } 49 50 for _, htlc := range htlcs { 51 if err := WriteElements(b, 52 htlc.Signature, htlc.RHash, htlc.Amt, htlc.RefundTimeout, 53 htlc.OutputIndex, htlc.Incoming, htlc.OnionBlob, 54 htlc.HtlcIndex, htlc.LogIndex, 55 ); err != nil { 56 return err 57 } 58 } 59 60 return nil 61 } 62 63 func SerializeCommitDiff(w io.Writer, diff *common.CommitDiff) error { // nolint: dupl 64 if err := serializeChanCommit(w, &diff.Commitment); err != nil { 65 return err 66 } 67 68 if err := WriteElements(w, diff.CommitSig); err != nil { 69 return err 70 } 71 72 if err := SerializeLogUpdates(w, diff.LogUpdates); err != nil { 73 return err 74 } 75 76 numOpenRefs := uint16(len(diff.OpenedCircuitKeys)) 77 if err := binary.Write(w, byteOrder, numOpenRefs); err != nil { 78 return err 79 } 80 81 for _, openRef := range diff.OpenedCircuitKeys { 82 err := WriteElements(w, openRef.ChanID, openRef.HtlcID) 83 if err != nil { 84 return err 85 } 86 } 87 88 numClosedRefs := uint16(len(diff.ClosedCircuitKeys)) 89 if err := binary.Write(w, byteOrder, numClosedRefs); err != nil { 90 return err 91 } 92 93 for _, closedRef := range diff.ClosedCircuitKeys { 94 err := WriteElements(w, closedRef.ChanID, closedRef.HtlcID) 95 if err != nil { 96 return err 97 } 98 } 99 100 return nil 101 } 102 103 func deserializeHtlcs(r io.Reader) ([]common.HTLC, error) { // nolint: dupl 104 var numHtlcs uint16 105 if err := ReadElement(r, &numHtlcs); err != nil { 106 return nil, err 107 } 108 109 var htlcs []common.HTLC 110 if numHtlcs == 0 { 111 return htlcs, nil 112 } 113 114 htlcs = make([]common.HTLC, numHtlcs) 115 for i := uint16(0); i < numHtlcs; i++ { 116 if err := ReadElements(r, 117 &htlcs[i].Signature, &htlcs[i].RHash, &htlcs[i].Amt, 118 &htlcs[i].RefundTimeout, &htlcs[i].OutputIndex, 119 &htlcs[i].Incoming, &htlcs[i].OnionBlob, 120 &htlcs[i].HtlcIndex, &htlcs[i].LogIndex, 121 ); err != nil { 122 return htlcs, err 123 } 124 } 125 126 return htlcs, nil 127 } 128 129 func deserializeChanCommit(r io.Reader) (common.ChannelCommitment, error) { // nolint: dupl 130 var c common.ChannelCommitment 131 132 err := ReadElements(r, 133 &c.CommitHeight, &c.LocalLogIndex, &c.LocalHtlcIndex, &c.RemoteLogIndex, 134 &c.RemoteHtlcIndex, &c.LocalBalance, &c.RemoteBalance, 135 &c.CommitFee, &c.FeePerKB, &c.CommitTx, &c.CommitSig, 136 ) 137 if err != nil { 138 return c, err 139 } 140 141 c.Htlcs, err = deserializeHtlcs(r) 142 if err != nil { 143 return c, err 144 } 145 146 return c, nil 147 } 148 149 func DeserializeLogUpdates(r io.Reader) ([]common.LogUpdate, error) { // nolint: dupl 150 var numUpdates uint16 151 if err := binary.Read(r, byteOrder, &numUpdates); err != nil { 152 return nil, err 153 } 154 155 logUpdates := make([]common.LogUpdate, numUpdates) 156 for i := 0; i < int(numUpdates); i++ { 157 err := ReadElements(r, 158 &logUpdates[i].LogIndex, &logUpdates[i].UpdateMsg, 159 ) 160 if err != nil { 161 return nil, err 162 } 163 } 164 return logUpdates, nil 165 } 166 167 func DeserializeCommitDiff(r io.Reader) (*common.CommitDiff, error) { // nolint: dupl 168 var ( 169 d common.CommitDiff 170 err error 171 ) 172 173 d.Commitment, err = deserializeChanCommit(r) 174 if err != nil { 175 return nil, err 176 } 177 178 var msg lnwire.Message 179 if err := ReadElements(r, &msg); err != nil { 180 return nil, err 181 } 182 commitSig, ok := msg.(*lnwire.CommitSig) 183 if !ok { 184 return nil, fmt.Errorf("expected lnwire.CommitSig, instead "+ 185 "read: %T", msg) 186 } 187 d.CommitSig = commitSig 188 189 d.LogUpdates, err = DeserializeLogUpdates(r) 190 if err != nil { 191 return nil, err 192 } 193 194 var numOpenRefs uint16 195 if err := binary.Read(r, byteOrder, &numOpenRefs); err != nil { 196 return nil, err 197 } 198 199 d.OpenedCircuitKeys = make([]common.CircuitKey, numOpenRefs) 200 for i := 0; i < int(numOpenRefs); i++ { 201 err := ReadElements(r, 202 &d.OpenedCircuitKeys[i].ChanID, 203 &d.OpenedCircuitKeys[i].HtlcID) 204 if err != nil { 205 return nil, err 206 } 207 } 208 209 var numClosedRefs uint16 210 if err := binary.Read(r, byteOrder, &numClosedRefs); err != nil { 211 return nil, err 212 } 213 214 d.ClosedCircuitKeys = make([]common.CircuitKey, numClosedRefs) 215 for i := 0; i < int(numClosedRefs); i++ { 216 err := ReadElements(r, 217 &d.ClosedCircuitKeys[i].ChanID, 218 &d.ClosedCircuitKeys[i].HtlcID) 219 if err != nil { 220 return nil, err 221 } 222 } 223 224 return &d, nil 225 } 226 227 func SerializeNetworkResult(w io.Writer, n *common.NetworkResult) error { // nolint: dupl 228 return WriteElements(w, n.Msg, n.Unencrypted, n.IsResolution) 229 } 230 231 func DeserializeNetworkResult(r io.Reader) (*common.NetworkResult, error) { // nolint: dupl 232 n := &common.NetworkResult{} 233 234 if err := ReadElements(r, 235 &n.Msg, &n.Unencrypted, &n.IsResolution, 236 ); err != nil { 237 return nil, err 238 } 239 240 return n, nil 241 } 242 243 func writeChanConfig(b io.Writer, c *common.ChannelConfig) error { // nolint: dupl 244 return WriteElements(b, 245 c.DustLimit, c.MaxPendingAmount, c.ChanReserve, c.MinHTLC, 246 c.MaxAcceptedHtlcs, c.CsvDelay, c.MultiSigKey, 247 c.RevocationBasePoint, c.PaymentBasePoint, c.DelayBasePoint, 248 c.HtlcBasePoint, 249 ) 250 } 251 252 func SerializeChannelCloseSummary(w io.Writer, cs *common.ChannelCloseSummary) error { // nolint: dupl 253 err := WriteElements(w, 254 cs.ChanPoint, cs.ShortChanID, cs.ChainHash, cs.ClosingTXID, 255 cs.CloseHeight, cs.RemotePub, cs.Capacity, cs.SettledBalance, 256 cs.TimeLockedBalance, cs.CloseType, cs.IsPending, 257 ) 258 if err != nil { 259 return err 260 } 261 262 // If this is a close channel summary created before the addition of 263 // the new fields, then we can exit here. 264 if cs.RemoteCurrentRevocation == nil { 265 return WriteElements(w, false) 266 } 267 268 // If fields are present, write boolean to indicate this, and continue. 269 if err := WriteElements(w, true); err != nil { 270 return err 271 } 272 273 if err := WriteElements(w, cs.RemoteCurrentRevocation); err != nil { 274 return err 275 } 276 277 if err := writeChanConfig(w, &cs.LocalChanConfig); err != nil { 278 return err 279 } 280 281 // The RemoteNextRevocation field is optional, as it's possible for a 282 // channel to be closed before we learn of the next unrevoked 283 // revocation point for the remote party. Write a boolen indicating 284 // whether this field is present or not. 285 if err := WriteElements(w, cs.RemoteNextRevocation != nil); err != nil { 286 return err 287 } 288 289 // Write the field, if present. 290 if cs.RemoteNextRevocation != nil { 291 if err = WriteElements(w, cs.RemoteNextRevocation); err != nil { 292 return err 293 } 294 } 295 296 // Write whether the channel sync message is present. 297 if err := WriteElements(w, cs.LastChanSyncMsg != nil); err != nil { 298 return err 299 } 300 301 // Write the channel sync message, if present. 302 if cs.LastChanSyncMsg != nil { 303 if err := WriteElements(w, cs.LastChanSyncMsg); err != nil { 304 return err 305 } 306 } 307 308 return nil 309 } 310 311 func readChanConfig(b io.Reader, c *common.ChannelConfig) error { 312 return ReadElements(b, 313 &c.DustLimit, &c.MaxPendingAmount, &c.ChanReserve, 314 &c.MinHTLC, &c.MaxAcceptedHtlcs, &c.CsvDelay, 315 &c.MultiSigKey, &c.RevocationBasePoint, 316 &c.PaymentBasePoint, &c.DelayBasePoint, 317 &c.HtlcBasePoint, 318 ) 319 } 320 321 func DeserializeCloseChannelSummary(r io.Reader) (*common.ChannelCloseSummary, error) { // nolint: dupl 322 c := &common.ChannelCloseSummary{} 323 324 err := ReadElements(r, 325 &c.ChanPoint, &c.ShortChanID, &c.ChainHash, &c.ClosingTXID, 326 &c.CloseHeight, &c.RemotePub, &c.Capacity, &c.SettledBalance, 327 &c.TimeLockedBalance, &c.CloseType, &c.IsPending, 328 ) 329 if err != nil { 330 return nil, err 331 } 332 333 // We'll now check to see if the channel close summary was encoded with 334 // any of the additional optional fields. 335 var hasNewFields bool 336 err = ReadElements(r, &hasNewFields) 337 if err != nil { 338 return nil, err 339 } 340 341 // If fields are not present, we can return. 342 if !hasNewFields { 343 return c, nil 344 } 345 346 // Otherwise read the new fields. 347 if err := ReadElements(r, &c.RemoteCurrentRevocation); err != nil { 348 return nil, err 349 } 350 351 if err := readChanConfig(r, &c.LocalChanConfig); err != nil { 352 return nil, err 353 } 354 355 // Finally, we'll attempt to read the next unrevoked commitment point 356 // for the remote party. If we closed the channel before receiving a 357 // funding locked message then this might not be present. A boolean 358 // indicating whether the field is present will come first. 359 var hasRemoteNextRevocation bool 360 err = ReadElements(r, &hasRemoteNextRevocation) 361 if err != nil { 362 return nil, err 363 } 364 365 // If this field was written, read it. 366 if hasRemoteNextRevocation { 367 err = ReadElements(r, &c.RemoteNextRevocation) 368 if err != nil { 369 return nil, err 370 } 371 } 372 373 // Check if we have a channel sync message to read. 374 var hasChanSyncMsg bool 375 err = ReadElements(r, &hasChanSyncMsg) 376 if err == io.EOF { 377 return c, nil 378 } else if err != nil { 379 return nil, err 380 } 381 382 // If a chan sync message is present, read it. 383 if hasChanSyncMsg { 384 // We must pass in reference to a lnwire.Message for the codec 385 // to support it. 386 var msg lnwire.Message 387 if err := ReadElements(r, &msg); err != nil { 388 return nil, err 389 } 390 391 chanSync, ok := msg.(*lnwire.ChannelReestablish) 392 if !ok { 393 return nil, errors.New("unable cast db Message to " + 394 "ChannelReestablish") 395 } 396 c.LastChanSyncMsg = chanSync 397 } 398 399 return c, nil 400 } 401 402 // ErrCorruptedFwdPkg signals that the on-disk structure of the forwarding 403 // package has potentially been mangled. 404 var ErrCorruptedFwdPkg = errors.New("fwding package db has been corrupted") 405 406 var ( 407 // fwdPackagesKey is the root-level bucket that all forwarding packages 408 // are written. This bucket is further subdivided based on the short 409 // channel ID of each channel. 410 fwdPackagesKey = []byte("fwd-packages") 411 412 // addBucketKey is the bucket to which all Add log updates are written. 413 addBucketKey = []byte("add-updates") 414 415 // failSettleBucketKey is the bucket to which all Settle/Fail log 416 // updates are written. 417 failSettleBucketKey = []byte("fail-settle-updates") 418 419 // fwdFilterKey is a key used to write the set of Adds that passed 420 // validation and are to be forwarded to the switch. 421 // NOTE: The presence of this key within a forwarding package indicates 422 // that the package has reached FwdStateProcessed. 423 fwdFilterKey = []byte("fwd-filter-key") 424 425 // ackFilterKey is a key used to access the PkgFilter indicating which 426 // Adds have received a Settle/Fail. This response may come from a 427 // number of sources, including: exitHop settle/fails, switch failures, 428 // chain arbiter interjections, as well as settle/fails from the 429 // next hop in the route. 430 ackFilterKey = []byte("ack-filter-key") 431 432 // settleFailFilterKey is a key used to access the PkgFilter indicating 433 // which Settles/Fails in have been received and processed by the link 434 // that originally received the Add. 435 settleFailFilterKey = []byte("settle-fail-filter-key") 436 ) 437 438 func makeLogKey(updateNum uint64) [8]byte { 439 var key [8]byte 440 byteOrder.PutUint64(key[:], updateNum) 441 return key 442 } 443 444 // uint16Key writes the provided 16-bit unsigned integer to a 2-byte slice. 445 func uint16Key(i uint16) []byte { 446 key := make([]byte, 2) 447 byteOrder.PutUint16(key, i) 448 return key 449 } 450 451 // ChannelPackager is used by a channel to manage the lifecycle of its forwarding 452 // packages. The packager is tied to a particular source channel ID, allowing it 453 // to create and edit its own packages. Each packager also has the ability to 454 // remove fail/settle htlcs that correspond to an add contained in one of 455 // source's packages. 456 type ChannelPackager struct { 457 source lnwire.ShortChannelID 458 } 459 460 // NewChannelPackager creates a new packager for a single channel. 461 func NewChannelPackager(source lnwire.ShortChannelID) *ChannelPackager { 462 return &ChannelPackager{ 463 source: source, 464 } 465 } 466 467 // AddFwdPkg writes a newly locked in forwarding package to disk. 468 func (*ChannelPackager) AddFwdPkg(tx kvdb.RwTx, fwdPkg *common.FwdPkg) error { // nolint: dupl 469 fwdPkgBkt, err := tx.CreateTopLevelBucket(fwdPackagesKey) 470 if err != nil { 471 return err 472 } 473 474 source := makeLogKey(fwdPkg.Source.ToUint64()) 475 sourceBkt, err := fwdPkgBkt.CreateBucketIfNotExists(source[:]) 476 if err != nil { 477 return err 478 } 479 480 heightKey := makeLogKey(fwdPkg.Height) 481 heightBkt, err := sourceBkt.CreateBucketIfNotExists(heightKey[:]) 482 if err != nil { 483 return err 484 } 485 486 // Write ADD updates we received at this commit height. 487 addBkt, err := heightBkt.CreateBucketIfNotExists(addBucketKey) 488 if err != nil { 489 return err 490 } 491 492 // Write SETTLE/FAIL updates we received at this commit height. 493 failSettleBkt, err := heightBkt.CreateBucketIfNotExists(failSettleBucketKey) 494 if err != nil { 495 return err 496 } 497 498 for i := range fwdPkg.Adds { 499 err = putLogUpdate(addBkt, uint16(i), &fwdPkg.Adds[i]) 500 if err != nil { 501 return err 502 } 503 } 504 505 // Persist the initialized pkg filter, which will be used to determine 506 // when we can remove this forwarding package from disk. 507 var ackFilterBuf bytes.Buffer 508 if err := fwdPkg.AckFilter.Encode(&ackFilterBuf); err != nil { 509 return err 510 } 511 512 if err := heightBkt.Put(ackFilterKey, ackFilterBuf.Bytes()); err != nil { 513 return err 514 } 515 516 for i := range fwdPkg.SettleFails { 517 err = putLogUpdate(failSettleBkt, uint16(i), &fwdPkg.SettleFails[i]) 518 if err != nil { 519 return err 520 } 521 } 522 523 var settleFailFilterBuf bytes.Buffer 524 err = fwdPkg.SettleFailFilter.Encode(&settleFailFilterBuf) 525 if err != nil { 526 return err 527 } 528 529 return heightBkt.Put(settleFailFilterKey, settleFailFilterBuf.Bytes()) 530 } 531 532 // putLogUpdate writes an htlc to the provided `bkt`, using `index` as the key. 533 func putLogUpdate(bkt kvdb.RwBucket, idx uint16, htlc *common.LogUpdate) error { 534 var b bytes.Buffer 535 if err := serializeLogUpdate(&b, htlc); err != nil { 536 return err 537 } 538 539 return bkt.Put(uint16Key(idx), b.Bytes()) 540 } 541 542 // LoadFwdPkgs scans the forwarding log for any packages that haven't been 543 // processed, and returns their deserialized log updates in a map indexed by the 544 // remote commitment height at which the updates were locked in. 545 func (p *ChannelPackager) LoadFwdPkgs(tx kvdb.RTx) ([]*common.FwdPkg, error) { 546 return loadChannelFwdPkgs(tx, p.source) 547 } 548 549 // loadChannelFwdPkgs loads all forwarding packages owned by `source`. 550 func loadChannelFwdPkgs(tx kvdb.RTx, source lnwire.ShortChannelID) ([]*common.FwdPkg, error) { // nolint: dupl 551 fwdPkgBkt := tx.ReadBucket(fwdPackagesKey) 552 if fwdPkgBkt == nil { 553 return nil, nil 554 } 555 556 sourceKey := makeLogKey(source.ToUint64()) 557 sourceBkt := fwdPkgBkt.NestedReadBucket(sourceKey[:]) 558 if sourceBkt == nil { 559 return nil, nil 560 } 561 562 var heights []uint64 563 if err := sourceBkt.ForEach(func(k, _ []byte) error { 564 if len(k) != 8 { 565 return ErrCorruptedFwdPkg 566 } 567 568 heights = append(heights, byteOrder.Uint64(k)) 569 570 return nil 571 }); err != nil { 572 return nil, err 573 } 574 575 // Load the forwarding package for each retrieved height. 576 fwdPkgs := make([]*common.FwdPkg, 0, len(heights)) 577 for _, height := range heights { 578 fwdPkg, err := loadFwdPkg(fwdPkgBkt, source, height) 579 if err != nil { 580 return nil, err 581 } 582 583 fwdPkgs = append(fwdPkgs, fwdPkg) 584 } 585 586 return fwdPkgs, nil 587 } 588 589 // loadFwdPkg reads the packager's fwd pkg at a given height, and determines the 590 // appropriate FwdState. 591 func loadFwdPkg(fwdPkgBkt kvdb.RBucket, source lnwire.ShortChannelID, 592 height uint64) (*common.FwdPkg, error) { 593 594 sourceKey := makeLogKey(source.ToUint64()) 595 sourceBkt := fwdPkgBkt.NestedReadBucket(sourceKey[:]) 596 if sourceBkt == nil { 597 return nil, ErrCorruptedFwdPkg 598 } 599 600 heightKey := makeLogKey(height) 601 heightBkt := sourceBkt.NestedReadBucket(heightKey[:]) 602 if heightBkt == nil { 603 return nil, ErrCorruptedFwdPkg 604 } 605 606 // Load ADDs from disk. 607 addBkt := heightBkt.NestedReadBucket(addBucketKey) 608 if addBkt == nil { 609 return nil, ErrCorruptedFwdPkg 610 } 611 612 adds, err := loadHtlcs(addBkt) 613 if err != nil { 614 return nil, err 615 } 616 617 // Load ack filter from disk. 618 ackFilterBytes := heightBkt.Get(ackFilterKey) 619 if ackFilterBytes == nil { 620 return nil, ErrCorruptedFwdPkg 621 } 622 ackFilterReader := bytes.NewReader(ackFilterBytes) 623 624 ackFilter := &common.PkgFilter{} 625 if err := ackFilter.Decode(ackFilterReader); err != nil { 626 return nil, err 627 } 628 629 // Load SETTLE/FAILs from disk. 630 failSettleBkt := heightBkt.NestedReadBucket(failSettleBucketKey) 631 if failSettleBkt == nil { 632 return nil, ErrCorruptedFwdPkg 633 } 634 635 failSettles, err := loadHtlcs(failSettleBkt) 636 if err != nil { 637 return nil, err 638 } 639 640 // Load settle fail filter from disk. 641 settleFailFilterBytes := heightBkt.Get(settleFailFilterKey) 642 if settleFailFilterBytes == nil { 643 return nil, ErrCorruptedFwdPkg 644 } 645 settleFailFilterReader := bytes.NewReader(settleFailFilterBytes) 646 647 settleFailFilter := &common.PkgFilter{} 648 if err := settleFailFilter.Decode(settleFailFilterReader); err != nil { 649 return nil, err 650 } 651 652 // Initialize the fwding package, which always starts in the 653 // FwdStateLockedIn. We can determine what state the package was left in 654 // by examining constraints on the information loaded from disk. 655 fwdPkg := &common.FwdPkg{ 656 Source: source, 657 State: common.FwdStateLockedIn, 658 Height: height, 659 Adds: adds, 660 AckFilter: ackFilter, 661 SettleFails: failSettles, 662 SettleFailFilter: settleFailFilter, 663 } 664 665 // Check to see if we have written the set exported filter adds to 666 // disk. If we haven't, processing of this package was never started, or 667 // failed during the last attempt. 668 fwdFilterBytes := heightBkt.Get(fwdFilterKey) 669 if fwdFilterBytes == nil { 670 nAdds := uint16(len(adds)) 671 fwdPkg.FwdFilter = common.NewPkgFilter(nAdds) 672 return fwdPkg, nil 673 } 674 675 fwdFilterReader := bytes.NewReader(fwdFilterBytes) 676 fwdPkg.FwdFilter = &common.PkgFilter{} 677 if err := fwdPkg.FwdFilter.Decode(fwdFilterReader); err != nil { 678 return nil, err 679 } 680 681 // Otherwise, a complete round of processing was completed, and we 682 // advance the package to FwdStateProcessed. 683 fwdPkg.State = common.FwdStateProcessed 684 685 // If every add, settle, and fail has been fully acknowledged, we can 686 // safely set the package's state to FwdStateCompleted, signalling that 687 // it can be garbage collected. 688 if fwdPkg.AckFilter.IsFull() && fwdPkg.SettleFailFilter.IsFull() { 689 fwdPkg.State = common.FwdStateCompleted 690 } 691 692 return fwdPkg, nil 693 } 694 695 // loadHtlcs retrieves all serialized htlcs in a bucket, returning 696 // them in order of the indexes they were written under. 697 func loadHtlcs(bkt kvdb.RBucket) ([]common.LogUpdate, error) { 698 var htlcs []common.LogUpdate 699 if err := bkt.ForEach(func(_, v []byte) error { 700 htlc, err := deserializeLogUpdate(bytes.NewReader(v)) 701 if err != nil { 702 return err 703 } 704 705 htlcs = append(htlcs, *htlc) 706 707 return nil 708 }); err != nil { 709 return nil, err 710 } 711 712 return htlcs, nil 713 } 714 715 // serializeLogUpdate writes a log update to the provided io.Writer. 716 func serializeLogUpdate(w io.Writer, l *common.LogUpdate) error { 717 return WriteElements(w, l.LogIndex, l.UpdateMsg) 718 } 719 720 // deserializeLogUpdate reads a log update from the provided io.Reader. 721 func deserializeLogUpdate(r io.Reader) (*common.LogUpdate, error) { 722 l := &common.LogUpdate{} 723 if err := ReadElements(r, &l.LogIndex, &l.UpdateMsg); err != nil { 724 return nil, err 725 } 726 727 return l, nil 728 }