mirror of
https://github.com/lightninglabs/loop
synced 2024-11-09 19:10:47 +00:00
9678c7817d
This commits adds an optional label to our swaps, and writes it to disk under a separate key in our swap bucket. This approach is chosen rather than an on-the-fly addition to our existing swap contract field so that we do not need to deal with EOF checking in the future. To allow creation of unique internal labels, we add a reserved prefix which can be used by the daemon to set labels that are distinct from client set ones.
217 lines
4.9 KiB
Go
217 lines
4.9 KiB
Go
package loopdb
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/coreos/bbolt"
|
|
"github.com/lightninglabs/loop/labels"
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
|
)
|
|
|
|
// 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
|
|
|
|
// LastHop is the last hop to use for the loop in swap (optional).
|
|
LastHop *route.Vertex
|
|
|
|
// ExternalHtlc specifies whether the htlc is published by an external
|
|
// source.
|
|
ExternalHtlc bool
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
var lastHop route.Vertex
|
|
if swap.LastHop != nil {
|
|
lastHop = *swap.LastHop
|
|
}
|
|
if err := binary.Write(&b, byteOrder, lastHop[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := binary.Write(&b, byteOrder, swap.ExternalHtlc); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return b.Bytes(), nil
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
if err := labels.Validate(label); err != nil {
|
|
return err
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
err = binary.Read(r, byteOrder, &contract.AmountRequested)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
var lastHop route.Vertex
|
|
if err := binary.Read(r, byteOrder, lastHop[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
var noLastHop route.Vertex
|
|
if lastHop != noLastHop {
|
|
contract.LastHop = &lastHop
|
|
}
|
|
|
|
if err := binary.Read(r, byteOrder, &contract.ExternalHtlc); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &contract, nil
|
|
}
|