@@ -1514,44 +1514,160 @@ func (k *kidOutput) Encode(w io.Writer) error {
1514
1514
// Decode takes a byte array representation of a kidOutput and converts it to an
1515
1515
// struct. Note that the witnessFunc method isn't added during deserialization
1516
1516
// and must be added later based on the value of the witnessType field.
1517
+ //
1518
+ // NOTE: We need to support both formats because we did not migrate the database
1519
+ // to the new format so the support for the legacy format is still needed.
1517
1520
func (k * kidOutput ) Decode (r io.Reader ) error {
1521
+ // Read all available data into a buffer first so we can try both
1522
+ // formats.
1523
+ //
1524
+ // NOTE: We can consume the whole reader here because every kidOutput is
1525
+ // saved separately via a key-value pair and we are only decoding them
1526
+ // individually so there is no risk of reading multiple kidOutputs.
1527
+ var buf bytes.Buffer
1528
+ _ , err := io .Copy (& buf , r )
1529
+ if err != nil {
1530
+ return err
1531
+ }
1532
+
1533
+ data := buf .Bytes ()
1534
+ bufReader := bytes .NewReader (data )
1535
+
1536
+ // Try the new format first. A successful decode must consume all bytes.
1537
+ newErr := k .decodeNewFormat (bufReader )
1538
+ if newErr == nil && bufReader .Len () == 0 {
1539
+ return nil
1540
+ }
1541
+
1542
+ // If that fails, reset the reader and try the legacy format.
1543
+ _ , err = bufReader .Seek (0 , io .SeekStart )
1544
+ if err != nil {
1545
+ return err
1546
+ }
1547
+
1548
+ legacyErr := k .decodeLegacyFormat (bufReader )
1549
+ if legacyErr != nil {
1550
+ return fmt .Errorf ("failed to decode with both new and " +
1551
+ "legacy formats: new=%v, legacy=%v" , newErr , legacyErr )
1552
+ }
1553
+
1554
+ // The legacy format must also consume all bytes.
1555
+ if bufReader .Len () > 0 {
1556
+ return fmt .Errorf ("legacy decode has %d trailing bytes" ,
1557
+ bufReader .Len ())
1558
+ }
1559
+
1560
+ return nil
1561
+ }
1562
+
1563
+ // decodeNewFormat decodes using the new format with variable-length outpoint
1564
+ // encoding.
1565
+ func (k * kidOutput ) decodeNewFormat (r * bytes.Reader ) error {
1518
1566
var scratch [8 ]byte
1519
1567
1520
- if _ , err := r . Read ( scratch [:]); err != nil {
1568
+ if _ , err := io . ReadFull ( r , scratch [:]); err != nil {
1521
1569
return err
1522
1570
}
1523
1571
k .amt = btcutil .Amount (byteOrder .Uint64 (scratch [:]))
1524
1572
1525
- err := graphdb . ReadOutpoint ( io . LimitReader ( r , 40 ), & k . outpoint )
1526
- if err != nil {
1573
+ // The outpoint does use the new format without a preceding varint.
1574
+ if err := graphdb . ReadOutpoint ( r , & k . outpoint ); err != nil {
1527
1575
return err
1528
1576
}
1529
1577
1530
- err = graphdb .ReadOutpoint (io .LimitReader (r , 40 ), & k .originChanPoint )
1531
- if err != nil {
1578
+ // The origin chan point does use the new format without a preceding
1579
+ // varint..
1580
+ if err := graphdb .ReadOutpoint (r , & k .originChanPoint ); err != nil {
1581
+ return err
1582
+ }
1583
+
1584
+ if err := binary .Read (r , byteOrder , & k .isHtlc ); err != nil {
1585
+ return err
1586
+ }
1587
+
1588
+ if _ , err := io .ReadFull (r , scratch [:4 ]); err != nil {
1589
+ return err
1590
+ }
1591
+ k .blocksToMaturity = byteOrder .Uint32 (scratch [:4 ])
1592
+
1593
+ if _ , err := io .ReadFull (r , scratch [:4 ]); err != nil {
1594
+ return err
1595
+ }
1596
+ k .absoluteMaturity = byteOrder .Uint32 (scratch [:4 ])
1597
+
1598
+ if _ , err := io .ReadFull (r , scratch [:4 ]); err != nil {
1599
+ return err
1600
+ }
1601
+ k .confHeight = byteOrder .Uint32 (scratch [:4 ])
1602
+
1603
+ if _ , err := io .ReadFull (r , scratch [:2 ]); err != nil {
1604
+ return err
1605
+ }
1606
+ k .witnessType = input .StandardWitnessType (byteOrder .Uint16 (scratch [:2 ]))
1607
+
1608
+ if err := input .ReadSignDescriptor (r , & k .signDesc ); err != nil {
1609
+ return err
1610
+ }
1611
+
1612
+ // If there's anything left in the reader, then this is a taproot
1613
+ // output that also wrote a control block.
1614
+ ctrlBlock , err := wire .ReadVarBytes (r , 0 , 1000 , "control block" )
1615
+ switch {
1616
+ // If there're no bytes remaining, then we'll return early.
1617
+ case errors .Is (err , io .EOF ):
1618
+ fallthrough
1619
+ case errors .Is (err , io .ErrUnexpectedEOF ):
1620
+ return nil
1621
+
1622
+ case err != nil :
1623
+ return err
1624
+ }
1625
+
1626
+ k .signDesc .ControlBlock = ctrlBlock
1627
+
1628
+ return nil
1629
+ }
1630
+
1631
+ // decodeLegacyFormat decodes using the legacy format with fixed-length outpoint
1632
+ // encoding.
1633
+ func (k * kidOutput ) decodeLegacyFormat (r * bytes.Reader ) error {
1634
+ var scratch [8 ]byte
1635
+
1636
+ if _ , err := io .ReadFull (r , scratch [:]); err != nil {
1637
+ return err
1638
+ }
1639
+ k .amt = btcutil .Amount (byteOrder .Uint64 (scratch [:]))
1640
+
1641
+ // Outpoint uses the legacy format with a preceding varint.
1642
+ if err := readOutpointVarBytes (r , & k .outpoint ); err != nil {
1643
+ return err
1644
+ }
1645
+
1646
+ // Origin chan point uses the legacy format with a preceding varint.
1647
+ if err := readOutpointVarBytes (r , & k .originChanPoint ); err != nil {
1532
1648
return err
1533
1649
}
1534
1650
1535
1651
if err := binary .Read (r , byteOrder , & k .isHtlc ); err != nil {
1536
1652
return err
1537
1653
}
1538
1654
1539
- if _ , err := r . Read ( scratch [:4 ]); err != nil {
1655
+ if _ , err := io . ReadFull ( r , scratch [:4 ]); err != nil {
1540
1656
return err
1541
1657
}
1542
1658
k .blocksToMaturity = byteOrder .Uint32 (scratch [:4 ])
1543
1659
1544
- if _ , err := r . Read ( scratch [:4 ]); err != nil {
1660
+ if _ , err := io . ReadFull ( r , scratch [:4 ]); err != nil {
1545
1661
return err
1546
1662
}
1547
1663
k .absoluteMaturity = byteOrder .Uint32 (scratch [:4 ])
1548
1664
1549
- if _ , err := r . Read ( scratch [:4 ]); err != nil {
1665
+ if _ , err := io . ReadFull ( r , scratch [:4 ]); err != nil {
1550
1666
return err
1551
1667
}
1552
1668
k .confHeight = byteOrder .Uint32 (scratch [:4 ])
1553
1669
1554
- if _ , err := r . Read ( scratch [:2 ]); err != nil {
1670
+ if _ , err := io . ReadFull ( r , scratch [:2 ]); err != nil {
1555
1671
return err
1556
1672
}
1557
1673
k .witnessType = input .StandardWitnessType (byteOrder .Uint16 (scratch [:2 ]))
@@ -1579,6 +1695,24 @@ func (k *kidOutput) Decode(r io.Reader) error {
1579
1695
return nil
1580
1696
}
1581
1697
1698
+ // readOutpointVarBytes reads an outpoint using the variable-length encoding.
1699
+ func readOutpointVarBytes (r io.Reader , o * wire.OutPoint ) error {
1700
+ scratch := make ([]byte , 4 )
1701
+
1702
+ txid , err := wire .ReadVarBytes (r , 0 , 32 , "prevout" )
1703
+ if err != nil {
1704
+ return err
1705
+ }
1706
+ copy (o .Hash [:], txid )
1707
+
1708
+ if _ , err := r .Read (scratch ); err != nil {
1709
+ return err
1710
+ }
1711
+ o .Index = byteOrder .Uint32 (scratch )
1712
+
1713
+ return nil
1714
+ }
1715
+
1582
1716
// Compile-time constraint to ensure kidOutput implements the
1583
1717
// Input interface.
1584
1718
0 commit comments