|
| 1 | +package loopdb |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "errors" |
| 6 | + "fmt" |
| 7 | + |
| 8 | + "github.com/btcsuite/btcd/chaincfg" |
| 9 | + "github.com/coreos/bbolt" |
| 10 | +) |
| 11 | + |
| 12 | +// migrateLastHop migrates the database to v03, replacing the never used loop in |
| 13 | +// channel by a last hop pubkey. |
| 14 | +func migrateLastHop(tx *bbolt.Tx, chainParams *chaincfg.Params) error { |
| 15 | + rootBucket := tx.Bucket(loopInBucketKey) |
| 16 | + if rootBucket == nil { |
| 17 | + return errors.New("bucket does not exist") |
| 18 | + } |
| 19 | + |
| 20 | + return rootBucket.ForEach(func(swapHash, v []byte) error { |
| 21 | + // Only go into things that we know are sub-bucket |
| 22 | + // keys. |
| 23 | + if v != nil { |
| 24 | + return nil |
| 25 | + } |
| 26 | + |
| 27 | + // From the root bucket, we'll grab the next swap |
| 28 | + // bucket for this swap from its swaphash. |
| 29 | + swapBucket := rootBucket.Bucket(swapHash) |
| 30 | + if swapBucket == nil { |
| 31 | + return fmt.Errorf("swap bucket %x not found", |
| 32 | + swapHash) |
| 33 | + } |
| 34 | + |
| 35 | + // With the main swap bucket obtained, we'll grab the |
| 36 | + // raw swap contract bytes. |
| 37 | + contractBytes := swapBucket.Get(contractKey) |
| 38 | + if contractBytes == nil { |
| 39 | + return errors.New("contract not found") |
| 40 | + } |
| 41 | + |
| 42 | + const ( |
| 43 | + // deprecatedLoopInChannelStart is the starting offset |
| 44 | + // of the old loop in channel field: 8 (initiation time) |
| 45 | + // + 32 (preimage) + 8 (amount requested) + 33 + 33 |
| 46 | + // (sender and receiver keys) + 4 (cltv expiry) + 8 + 8 |
| 47 | + // (max miner and swap fee) + 4 (initiation height) + 4 |
| 48 | + // (conf target) = 142. |
| 49 | + deprecatedLoopInChannelStart = 142 |
| 50 | + |
| 51 | + // expectedTotalLength is the expect total length of the |
| 52 | + // serialized contract. It adds 8 (old loop in channel) |
| 53 | + // + 1 (external htlc) = 9 bytes to |
| 54 | + // deprecatedLoopInChannelStart. |
| 55 | + expectedTotalLength = deprecatedLoopInChannelStart + 9 |
| 56 | + ) |
| 57 | + |
| 58 | + // Sanity check to see if the constants above match the contract |
| 59 | + // bytes. |
| 60 | + if len(contractBytes) != expectedTotalLength { |
| 61 | + return errors.New("invalid serialized contract length") |
| 62 | + } |
| 63 | + |
| 64 | + // Copy the unchanged fields into the buffer. |
| 65 | + b := &bytes.Buffer{} |
| 66 | + _, err := b.Write(contractBytes[:deprecatedLoopInChannelStart]) |
| 67 | + if err != nil { |
| 68 | + return err |
| 69 | + } |
| 70 | + |
| 71 | + // We now set the new last hop field to all zeroes to indicate |
| 72 | + // that there is no restriction. |
| 73 | + var noLastHop [33]byte |
| 74 | + if _, err := b.Write(noLastHop[:]); err != nil { |
| 75 | + return err |
| 76 | + } |
| 77 | + |
| 78 | + // Append the remaining field ExternalHtlc. |
| 79 | + _, err = b.Write(contractBytes[deprecatedLoopInChannelStart+8:]) |
| 80 | + if err != nil { |
| 81 | + return err |
| 82 | + } |
| 83 | + |
| 84 | + return swapBucket.Put(contractKey, b.Bytes()) |
| 85 | + }) |
| 86 | +} |
0 commit comments