2019-03-12 15:09:57 +00:00
|
|
|
package loopdb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
2020-02-11 12:25:03 +00:00
|
|
|
|
2020-08-03 08:55:58 +00:00
|
|
|
"github.com/coreos/bbolt"
|
|
|
|
"github.com/lightninglabs/loop/labels"
|
2020-02-11 12:25:03 +00:00
|
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
2019-03-12 15:09:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// LoopInContract contains the data that is serialized to persistent storage for
|
|
|
|
// pending loop in swaps.
|
|
|
|
type LoopInContract struct {
|
|
|
|
SwapContract
|
|
|
|
|
|
|
|
// SweepConfTarget specifies the targeted confirmation target for the
|
|
|
|
// client sweep tx.
|
|
|
|
HtlcConfTarget int32
|
|
|
|
|
2020-02-11 12:25:03 +00:00
|
|
|
// LastHop is the last hop to use for the loop in swap (optional).
|
|
|
|
LastHop *route.Vertex
|
2019-03-28 12:29:21 +00:00
|
|
|
|
|
|
|
// ExternalHtlc specifies whether the htlc is published by an external
|
|
|
|
// source.
|
|
|
|
ExternalHtlc bool
|
2020-08-03 08:55:58 +00:00
|
|
|
|
|
|
|
// Label contains an optional label for the swap. Note that this field
|
|
|
|
// is stored separately to the rest of the contract on disk.
|
|
|
|
Label string
|
2019-03-12 15:09:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoopIn is a combination of the contract and the updates.
|
|
|
|
type LoopIn struct {
|
|
|
|
Loop
|
|
|
|
|
|
|
|
Contract *LoopInContract
|
|
|
|
}
|
|
|
|
|
|
|
|
// LastUpdateTime returns the last update time of this swap.
|
|
|
|
func (s *LoopIn) LastUpdateTime() time.Time {
|
|
|
|
lastUpdate := s.LastUpdate()
|
|
|
|
if lastUpdate == nil {
|
|
|
|
return s.Contract.InitiationTime
|
|
|
|
}
|
|
|
|
|
|
|
|
return lastUpdate.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
// serializeLoopInContract serialize the loop in contract into a byte slice.
|
|
|
|
func serializeLoopInContract(swap *LoopInContract) (
|
|
|
|
[]byte, error) {
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.InitiationTime.UnixNano()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.Preimage); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.AmountRequested); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err := b.Write(swap.SenderKey[:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if n != keyLength {
|
|
|
|
return nil, fmt.Errorf("sender key has invalid length")
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err = b.Write(swap.ReceiverKey[:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if n != keyLength {
|
|
|
|
return nil, fmt.Errorf("receiver key has invalid length")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.CltvExpiry); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.MaxMinerFee); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.MaxSwapFee); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.InitiationHeight); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.HtlcConfTarget); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-11 12:25:03 +00:00
|
|
|
var lastHop route.Vertex
|
|
|
|
if swap.LastHop != nil {
|
|
|
|
lastHop = *swap.LastHop
|
2019-03-12 15:09:57 +00:00
|
|
|
}
|
2020-02-11 12:25:03 +00:00
|
|
|
if err := binary.Write(&b, byteOrder, lastHop[:]); err != nil {
|
2019-03-12 15:09:57 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-03-28 12:29:21 +00:00
|
|
|
if err := binary.Write(&b, byteOrder, swap.ExternalHtlc); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
return b.Bytes(), nil
|
|
|
|
}
|
|
|
|
|
2020-08-03 08:55:58 +00:00
|
|
|
// putLabel performs validation of a label and writes it to the bucket provided
|
|
|
|
// under the label key if it is non-zero.
|
|
|
|
func putLabel(bucket *bbolt.Bucket, label string) error {
|
|
|
|
if len(label) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-12 11:34:52 +00:00
|
|
|
// Check that the label does not exceed our maximum length.
|
|
|
|
if len(label) > labels.MaxLength {
|
|
|
|
return labels.ErrLabelTooLong
|
2020-08-03 08:55:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return bucket.Put(labelKey, []byte(label))
|
|
|
|
}
|
|
|
|
|
|
|
|
// getLabel attempts to get an optional label stored under the label key in a
|
|
|
|
// bucket. If it is not present, an empty label is returned.
|
|
|
|
func getLabel(bucket *bbolt.Bucket) string {
|
|
|
|
label := bucket.Get(labelKey)
|
|
|
|
if label == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(label)
|
|
|
|
}
|
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
// deserializeLoopInContract deserializes the loop in contract from a byte slice.
|
|
|
|
func deserializeLoopInContract(value []byte) (*LoopInContract, error) {
|
|
|
|
r := bytes.NewReader(value)
|
|
|
|
|
|
|
|
contract := LoopInContract{}
|
|
|
|
var err error
|
|
|
|
var unixNano int64
|
|
|
|
if err := binary.Read(r, byteOrder, &unixNano); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
contract.InitiationTime = time.Unix(0, unixNano)
|
|
|
|
|
|
|
|
if err := binary.Read(r, byteOrder, &contract.Preimage); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-10-07 15:29:24 +00:00
|
|
|
err = binary.Read(r, byteOrder, &contract.AmountRequested)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-03-12 15:09:57 +00:00
|
|
|
|
|
|
|
n, err := r.Read(contract.SenderKey[:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if n != keyLength {
|
|
|
|
return nil, fmt.Errorf("sender key has invalid length")
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err = r.Read(contract.ReceiverKey[:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if n != keyLength {
|
|
|
|
return nil, fmt.Errorf("receiver key has invalid length")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Read(r, byteOrder, &contract.CltvExpiry); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := binary.Read(r, byteOrder, &contract.MaxMinerFee); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Read(r, byteOrder, &contract.MaxSwapFee); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Read(r, byteOrder, &contract.InitiationHeight); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Read(r, byteOrder, &contract.HtlcConfTarget); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-11 12:25:03 +00:00
|
|
|
var lastHop route.Vertex
|
|
|
|
if err := binary.Read(r, byteOrder, lastHop[:]); err != nil {
|
2019-03-12 15:09:57 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2020-02-11 12:25:03 +00:00
|
|
|
var noLastHop route.Vertex
|
|
|
|
if lastHop != noLastHop {
|
|
|
|
contract.LastHop = &lastHop
|
2019-03-12 15:09:57 +00:00
|
|
|
}
|
|
|
|
|
2019-03-28 12:29:21 +00:00
|
|
|
if err := binary.Read(r, byteOrder, &contract.ExternalHtlc); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-03-12 15:09:57 +00:00
|
|
|
return &contract, nil
|
|
|
|
}
|