|
| 1 | +package migration27 |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "fmt" |
| 6 | + |
| 7 | + lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" |
| 8 | + mig25 "github.com/lightningnetwork/lnd/channeldb/migration25" |
| 9 | + mig26 "github.com/lightningnetwork/lnd/channeldb/migration26" |
| 10 | + mig "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11" |
| 11 | + "github.com/lightningnetwork/lnd/kvdb" |
| 12 | + "github.com/lightningnetwork/lnd/tlv" |
| 13 | +) |
| 14 | + |
| 15 | +const ( |
| 16 | + // A tlv type definition used to serialize and deserialize a KeyLocator |
| 17 | + // from the database. |
| 18 | + keyLocType tlv.Type = 1 |
| 19 | + |
| 20 | + // A tlv type used to serialize and deserialize the |
| 21 | + // `InitialLocalBalance` field. |
| 22 | + initialLocalBalanceType tlv.Type = 2 |
| 23 | + |
| 24 | + // A tlv type used to serialize and deserialize the |
| 25 | + // `InitialRemoteBalance` field. |
| 26 | + initialRemoteBalanceType tlv.Type = 3 |
| 27 | +) |
| 28 | + |
| 29 | +var ( |
| 30 | + // chanInfoKey can be accessed within the bucket for a channel |
| 31 | + // (identified by its chanPoint). This key stores all the static |
| 32 | + // information for a channel which is decided at the end of the |
| 33 | + // funding flow. |
| 34 | + chanInfoKey = []byte("chan-info-key") |
| 35 | + |
| 36 | + // localUpfrontShutdownKey can be accessed within the bucket for a |
| 37 | + // channel (identified by its chanPoint). This key stores an optional |
| 38 | + // upfront shutdown script for the local peer. |
| 39 | + localUpfrontShutdownKey = []byte("local-upfront-shutdown-key") |
| 40 | + |
| 41 | + // remoteUpfrontShutdownKey can be accessed within the bucket for a |
| 42 | + // channel (identified by its chanPoint). This key stores an optional |
| 43 | + // upfront shutdown script for the remote peer. |
| 44 | + remoteUpfrontShutdownKey = []byte("remote-upfront-shutdown-key") |
| 45 | + |
| 46 | + // lastWasRevokeKey is a key that stores true when the last update we |
| 47 | + // sent was a revocation and false when it was a commitment signature. |
| 48 | + // This is nil in the case of new channels with no updates exchanged. |
| 49 | + lastWasRevokeKey = []byte("last-was-revoke") |
| 50 | + |
| 51 | + // ErrNoChanInfoFound is returned when a particular channel does not |
| 52 | + // have any channels state. |
| 53 | + ErrNoChanInfoFound = fmt.Errorf("no chan info found") |
| 54 | +) |
| 55 | + |
| 56 | +// OpenChannel embeds a mig26.OpenChannel with the extra update-to-date |
| 57 | +// serialization and deserialization methods. |
| 58 | +// |
| 59 | +// NOTE: doesn't have the Packager field as it's not used in current migration. |
| 60 | +type OpenChannel struct { |
| 61 | + mig26.OpenChannel |
| 62 | + |
| 63 | + // chanStatus is the current status of this channel. If it is not in |
| 64 | + // the state Default, it should not be used for forwarding payments. |
| 65 | + chanStatus mig25.ChannelStatus |
| 66 | +} |
| 67 | + |
| 68 | +// FetchChanInfo deserializes the channel info based on the legacy boolean. |
| 69 | +func FetchChanInfo(chanBucket kvdb.RBucket, c *OpenChannel, legacy bool) error { |
| 70 | + infoBytes := chanBucket.Get(chanInfoKey) |
| 71 | + if infoBytes == nil { |
| 72 | + return ErrNoChanInfoFound |
| 73 | + } |
| 74 | + r := bytes.NewReader(infoBytes) |
| 75 | + |
| 76 | + var ( |
| 77 | + chanType mig.ChannelType |
| 78 | + chanStatus mig.ChannelStatus |
| 79 | + ) |
| 80 | + |
| 81 | + if err := mig.ReadElements(r, |
| 82 | + &chanType, &c.ChainHash, &c.FundingOutpoint, |
| 83 | + &c.ShortChannelID, &c.IsPending, &c.IsInitiator, |
| 84 | + &chanStatus, &c.FundingBroadcastHeight, |
| 85 | + &c.NumConfsRequired, &c.ChannelFlags, |
| 86 | + &c.IdentityPub, &c.Capacity, &c.TotalMSatSent, |
| 87 | + &c.TotalMSatReceived, |
| 88 | + ); err != nil { |
| 89 | + return fmt.Errorf("ReadElements got: %v", err) |
| 90 | + } |
| 91 | + |
| 92 | + c.ChanType = mig25.ChannelType(chanType) |
| 93 | + c.chanStatus = mig25.ChannelStatus(chanStatus) |
| 94 | + |
| 95 | + // For single funder channels that we initiated and have the funding |
| 96 | + // transaction to, read the funding txn. |
| 97 | + if c.FundingTxPresent() { |
| 98 | + if err := mig.ReadElement(r, &c.FundingTxn); err != nil { |
| 99 | + return fmt.Errorf("read FundingTxn got: %v", err) |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + if err := mig.ReadChanConfig(r, &c.LocalChanCfg); err != nil { |
| 104 | + return fmt.Errorf("read LocalChanCfg got: %v", err) |
| 105 | + } |
| 106 | + if err := mig.ReadChanConfig(r, &c.RemoteChanCfg); err != nil { |
| 107 | + return fmt.Errorf("read RemoteChanCfg got: %v", err) |
| 108 | + } |
| 109 | + |
| 110 | + // Retrieve the boolean stored under lastWasRevokeKey. |
| 111 | + lastWasRevokeBytes := chanBucket.Get(lastWasRevokeKey) |
| 112 | + if lastWasRevokeBytes == nil { |
| 113 | + // If nothing has been stored under this key, we store false in |
| 114 | + // the OpenChannel struct. |
| 115 | + c.LastWasRevoke = false |
| 116 | + } else { |
| 117 | + // Otherwise, read the value into the LastWasRevoke field. |
| 118 | + revokeReader := bytes.NewReader(lastWasRevokeBytes) |
| 119 | + err := mig.ReadElements(revokeReader, &c.LastWasRevoke) |
| 120 | + if err != nil { |
| 121 | + return fmt.Errorf("read LastWasRevoke got: %v", err) |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + // Make the tlv stream based on the legacy param. |
| 126 | + var ( |
| 127 | + ts *tlv.Stream |
| 128 | + err error |
| 129 | + localBalance uint64 |
| 130 | + remoteBalance uint64 |
| 131 | + ) |
| 132 | + |
| 133 | + keyLocRecord := mig25.MakeKeyLocRecord( |
| 134 | + keyLocType, &c.RevocationKeyLocator, |
| 135 | + ) |
| 136 | + |
| 137 | + // If it's legacy, create the stream with a single tlv record. |
| 138 | + if legacy { |
| 139 | + ts, err = tlv.NewStream(keyLocRecord) |
| 140 | + } else { |
| 141 | + // Otherwise, for the new format, we will encode the balance |
| 142 | + // fields in the tlv stream too. |
| 143 | + ts, err = tlv.NewStream( |
| 144 | + keyLocRecord, |
| 145 | + tlv.MakePrimitiveRecord( |
| 146 | + initialLocalBalanceType, &localBalance, |
| 147 | + ), |
| 148 | + tlv.MakePrimitiveRecord( |
| 149 | + initialRemoteBalanceType, &remoteBalance, |
| 150 | + ), |
| 151 | + ) |
| 152 | + } |
| 153 | + if err != nil { |
| 154 | + return fmt.Errorf("create tlv stream got: %v", err) |
| 155 | + } |
| 156 | + |
| 157 | + if err := ts.Decode(r); err != nil { |
| 158 | + return fmt.Errorf("decode tlv stream got: %v", err) |
| 159 | + } |
| 160 | + |
| 161 | + // For the new format, attach the balance fields. |
| 162 | + if !legacy { |
| 163 | + c.InitialLocalBalance = lnwire.MilliSatoshi(localBalance) |
| 164 | + c.InitialRemoteBalance = lnwire.MilliSatoshi(remoteBalance) |
| 165 | + } |
| 166 | + |
| 167 | + // Finally, read the optional shutdown scripts. |
| 168 | + if err := mig25.GetOptionalUpfrontShutdownScript( |
| 169 | + chanBucket, localUpfrontShutdownKey, &c.LocalShutdownScript, |
| 170 | + ); err != nil { |
| 171 | + return fmt.Errorf("local shutdown script got: %v", err) |
| 172 | + } |
| 173 | + |
| 174 | + return mig25.GetOptionalUpfrontShutdownScript( |
| 175 | + chanBucket, remoteUpfrontShutdownKey, &c.RemoteShutdownScript, |
| 176 | + ) |
| 177 | +} |
| 178 | + |
| 179 | +// PutChanInfo serializes the channel info based on the legacy boolean. |
| 180 | +func PutChanInfo(chanBucket kvdb.RwBucket, c *OpenChannel, legacy bool) error { |
| 181 | + var w bytes.Buffer |
| 182 | + if err := mig.WriteElements(&w, |
| 183 | + mig.ChannelType(c.ChanType), c.ChainHash, c.FundingOutpoint, |
| 184 | + c.ShortChannelID, c.IsPending, c.IsInitiator, |
| 185 | + mig.ChannelStatus(c.chanStatus), c.FundingBroadcastHeight, |
| 186 | + c.NumConfsRequired, c.ChannelFlags, |
| 187 | + c.IdentityPub, c.Capacity, c.TotalMSatSent, |
| 188 | + c.TotalMSatReceived, |
| 189 | + ); err != nil { |
| 190 | + return err |
| 191 | + } |
| 192 | + |
| 193 | + // For single funder channels that we initiated, and we have the |
| 194 | + // funding transaction, then write the funding txn. |
| 195 | + if c.FundingTxPresent() { |
| 196 | + if err := mig.WriteElement(&w, c.FundingTxn); err != nil { |
| 197 | + return err |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + if err := mig.WriteChanConfig(&w, &c.LocalChanCfg); err != nil { |
| 202 | + return err |
| 203 | + } |
| 204 | + if err := mig.WriteChanConfig(&w, &c.RemoteChanCfg); err != nil { |
| 205 | + return err |
| 206 | + } |
| 207 | + |
| 208 | + // Make the tlv stream based on the legacy param. |
| 209 | + tlvStream, err := mig26.MakeTlvStream(&c.OpenChannel, legacy) |
| 210 | + if err != nil { |
| 211 | + return err |
| 212 | + } |
| 213 | + |
| 214 | + if err := tlvStream.Encode(&w); err != nil { |
| 215 | + return err |
| 216 | + } |
| 217 | + |
| 218 | + if err := chanBucket.Put(chanInfoKey, w.Bytes()); err != nil { |
| 219 | + return err |
| 220 | + } |
| 221 | + |
| 222 | + // Finally, add optional shutdown scripts for the local and remote peer |
| 223 | + // if they are present. |
| 224 | + if err := mig25.PutOptionalUpfrontShutdownScript( |
| 225 | + chanBucket, localUpfrontShutdownKey, c.LocalShutdownScript, |
| 226 | + ); err != nil { |
| 227 | + return err |
| 228 | + } |
| 229 | + |
| 230 | + return mig25.PutOptionalUpfrontShutdownScript( |
| 231 | + chanBucket, remoteUpfrontShutdownKey, c.RemoteShutdownScript, |
| 232 | + ) |
| 233 | +} |
0 commit comments