instantout: add instantout store

pull/651/head
sputn1ck 5 months ago
parent 56ed6f7ccb
commit ee0309f942
No known key found for this signature in database
GPG Key ID: 671103D881A5F0E4

@ -0,0 +1,432 @@
package instantout
import (
"bytes"
"context"
"database/sql"
"fmt"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/loop/fsm"
"github.com/lightninglabs/loop/instantout/reservation"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/loopdb/sqlc"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// InstantOutBaseDB is the interface that contains all the queries generated
// by sqlc for the instantout table.
type InstantOutBaseDB interface {
// InsertSwap inserts a new base swap.
InsertSwap(ctx context.Context, arg sqlc.InsertSwapParams) error
// InsertHtlcKeys inserts the htlc keys for a swap.
InsertHtlcKeys(ctx context.Context, arg sqlc.InsertHtlcKeysParams) error
// InsertInstantOut inserts a new instant out swap.
InsertInstantOut(ctx context.Context,
arg sqlc.InsertInstantOutParams) error
// InsertInstantOutUpdate inserts a new instant out update.
InsertInstantOutUpdate(ctx context.Context,
arg sqlc.InsertInstantOutUpdateParams) error
// UpdateInstantOut updates an instant out swap.
UpdateInstantOut(ctx context.Context,
arg sqlc.UpdateInstantOutParams) error
// GetInstantOutSwap retrieves an instant out swap.
GetInstantOutSwap(ctx context.Context,
swapHash []byte) (sqlc.GetInstantOutSwapRow, error)
// GetInstantOutSwapUpdates retrieves all instant out swap updates.
GetInstantOutSwapUpdates(ctx context.Context,
swapHash []byte) ([]sqlc.InstantoutUpdate, error)
// GetInstantOutSwaps retrieves all instant out swaps.
GetInstantOutSwaps(ctx context.Context) ([]sqlc.GetInstantOutSwapsRow,
error)
// ExecTx allows for executing a function in the context of a database
// transaction.
ExecTx(ctx context.Context, txOptions loopdb.TxOptions,
txBody func(*sqlc.Queries) error) error
}
// ReservationStore is the interface that is required to load the reservations
// based on the stored reservation ids.
type ReservationStore interface {
// GetReservation returns the reservation for the given id.
GetReservation(ctx context.Context, id reservation.ID) (
*reservation.Reservation, error)
}
type SQLStore struct {
baseDb InstantOutBaseDB
reservationStore ReservationStore
clock clock.Clock
network *chaincfg.Params
}
// NewSQLStore creates a new SQLStore.
func NewSQLStore(db InstantOutBaseDB, clock clock.Clock,
reservationStore ReservationStore, network *chaincfg.Params) *SQLStore {
return &SQLStore{
baseDb: db,
clock: clock,
reservationStore: reservationStore,
}
}
// CreateInstantLoopOut adds a new instant loop out to the store.
func (s *SQLStore) CreateInstantLoopOut(ctx context.Context,
instantOut *InstantOut) error {
swapArgs := sqlc.InsertSwapParams{
SwapHash: instantOut.SwapHash[:],
Preimage: instantOut.swapPreimage[:],
InitiationTime: s.clock.Now(),
AmountRequested: int64(instantOut.value),
CltvExpiry: instantOut.cltvExpiry,
MaxMinerFee: 0,
MaxSwapFee: 0,
InitiationHeight: instantOut.initiationHeight,
ProtocolVersion: int32(instantOut.protocolVersion),
Label: "",
}
htlcKeyArgs := sqlc.InsertHtlcKeysParams{
SwapHash: instantOut.SwapHash[:],
SenderScriptPubkey: instantOut.serverPubkey.
SerializeCompressed(),
ReceiverScriptPubkey: instantOut.clientPubkey.
SerializeCompressed(),
ClientKeyFamily: int32(instantOut.keyLocator.Family),
ClientKeyIndex: int32(instantOut.keyLocator.Index),
}
reservationIdByteSlice := reservationIdsToByteSlice(
instantOut.reservations,
)
instantOutArgs := sqlc.InsertInstantOutParams{
SwapHash: instantOut.SwapHash[:],
Preimage: instantOut.swapPreimage[:],
SweepAddress: instantOut.sweepAddress.String(),
OutgoingChanSet: instantOut.outgoingChanSet.String(),
HtlcFeeRate: int64(instantOut.htlcFeeRate),
ReservationIds: reservationIdByteSlice,
SwapInvoice: instantOut.swapInvoice,
}
updateArgs := sqlc.InsertInstantOutUpdateParams{
SwapHash: instantOut.SwapHash[:],
UpdateTimestamp: s.clock.Now(),
UpdateState: string(instantOut.State),
}
return s.baseDb.ExecTx(ctx, &loopdb.SqliteTxOptions{},
func(q *sqlc.Queries) error {
err := q.InsertSwap(ctx, swapArgs)
if err != nil {
return err
}
err = q.InsertHtlcKeys(ctx, htlcKeyArgs)
if err != nil {
return err
}
err = q.InsertInstantOut(ctx, instantOutArgs)
if err != nil {
return err
}
return q.InsertInstantOutUpdate(ctx, updateArgs)
})
}
// UpdateInstantLoopOut updates an existing instant loop out in the
// store.
func (s *SQLStore) UpdateInstantLoopOut(ctx context.Context,
instantOut *InstantOut) error {
// Serialize the FinalHtlcTx.
var finalHtlcTx []byte
if instantOut.finalizedHtlcTx != nil {
var buffer bytes.Buffer
err := instantOut.finalizedHtlcTx.Serialize(
&buffer,
)
if err != nil {
return err
}
finalHtlcTx = buffer.Bytes()
}
var finalSweeplessSweepTx []byte
if instantOut.finalizedSweeplessSweepTx != nil {
var buffer bytes.Buffer
err := instantOut.finalizedSweeplessSweepTx.Serialize(
&buffer,
)
if err != nil {
return err
}
finalSweeplessSweepTx = buffer.Bytes()
}
var sweepTxHash []byte
if instantOut.SweepTxHash != nil {
sweepTxHash = instantOut.SweepTxHash[:]
}
updateParams := sqlc.UpdateInstantOutParams{
SwapHash: instantOut.SwapHash[:],
FinalizedHtlcTx: finalHtlcTx,
SweepTxHash: sweepTxHash,
FinalizedSweeplessSweepTx: finalSweeplessSweepTx,
SweepConfirmationHeight: serializeNullInt32(
int32(instantOut.sweepConfirmationHeight),
),
}
updateArgs := sqlc.InsertInstantOutUpdateParams{
SwapHash: instantOut.SwapHash[:],
UpdateTimestamp: s.clock.Now(),
UpdateState: string(instantOut.State),
}
return s.baseDb.ExecTx(ctx, &loopdb.SqliteTxOptions{},
func(q *sqlc.Queries) error {
err := q.UpdateInstantOut(ctx, updateParams)
if err != nil {
return err
}
return q.InsertInstantOutUpdate(ctx, updateArgs)
},
)
}
// GetInstantLoopOut returns the instant loop out for the given swap
// hash.
func (s *SQLStore) GetInstantLoopOut(ctx context.Context, swapHash []byte) (
*InstantOut, error) {
row, err := s.baseDb.GetInstantOutSwap(ctx, swapHash)
if err != nil {
return nil, err
}
updates, err := s.baseDb.GetInstantOutSwapUpdates(ctx, swapHash)
if err != nil {
return nil, err
}
return s.sqlInstantOutToInstantOut(ctx, row, updates)
}
// ListInstantLoopOuts returns all instant loop outs that are in the
// store.
func (s *SQLStore) ListInstantLoopOuts(ctx context.Context) ([]*InstantOut,
error) {
rows, err := s.baseDb.GetInstantOutSwaps(ctx)
if err != nil {
return nil, err
}
var instantOuts []*InstantOut
for _, row := range rows {
updates, err := s.baseDb.GetInstantOutSwapUpdates(
ctx, row.SwapHash,
)
if err != nil {
return nil, err
}
instantOut, err := s.sqlInstantOutToInstantOut(
ctx, sqlc.GetInstantOutSwapRow(row), updates,
)
if err != nil {
return nil, err
}
instantOuts = append(instantOuts, instantOut)
}
return instantOuts, nil
}
// sqlInstantOutToInstantOut converts sql rows to an instant out struct.
func (s *SQLStore) sqlInstantOutToInstantOut(ctx context.Context,
row sqlc.GetInstantOutSwapRow, updates []sqlc.InstantoutUpdate) (
*InstantOut, error) {
swapHash, err := lntypes.MakeHash(row.SwapHash)
if err != nil {
return nil, err
}
swapPreImage, err := lntypes.MakePreimage(row.Preimage)
if err != nil {
return nil, err
}
serverKey, err := btcec.ParsePubKey(row.SenderScriptPubkey)
if err != nil {
return nil, err
}
clientKey, err := btcec.ParsePubKey(row.ReceiverScriptPubkey)
if err != nil {
return nil, err
}
var finalizedHtlcTx *wire.MsgTx
if row.FinalizedHtlcTx != nil {
finalizedHtlcTx = &wire.MsgTx{}
err := finalizedHtlcTx.Deserialize(bytes.NewReader(
row.FinalizedHtlcTx,
))
if err != nil {
return nil, err
}
}
var finalizedSweepLessSweepTx *wire.MsgTx
if row.FinalizedSweeplessSweepTx != nil {
finalizedSweepLessSweepTx = &wire.MsgTx{}
err := finalizedSweepLessSweepTx.Deserialize(bytes.NewReader(
row.FinalizedSweeplessSweepTx,
))
if err != nil {
return nil, err
}
}
var sweepTxHash *chainhash.Hash
if row.SweepTxHash != nil {
sweepTxHash, err = chainhash.NewHash(row.SweepTxHash)
if err != nil {
return nil, err
}
}
var outgoingChanSet loopdb.ChannelSet
if row.OutgoingChanSet != "" {
outgoingChanSet, err = loopdb.ConvertOutgoingChanSet(
row.OutgoingChanSet,
)
if err != nil {
return nil, err
}
}
reservationIds, err := byteSliceToReservationIds(row.ReservationIds)
if err != nil {
return nil, err
}
reservations := make([]*reservation.Reservation, 0, len(reservationIds))
for _, id := range reservationIds {
reservation, err := s.reservationStore.GetReservation(
ctx, id,
)
if err != nil {
return nil, err
}
reservations = append(reservations, reservation)
}
sweepAddress, err := btcutil.DecodeAddress(row.SweepAddress, s.network)
if err != nil {
return nil, err
}
instantOut := &InstantOut{
SwapHash: swapHash,
swapPreimage: swapPreImage,
cltvExpiry: row.CltvExpiry,
outgoingChanSet: outgoingChanSet,
reservations: reservations,
protocolVersion: ProtocolVersion(row.ProtocolVersion),
initiationHeight: row.InitiationHeight,
value: btcutil.Amount(row.AmountRequested),
keyLocator: keychain.KeyLocator{
Family: keychain.KeyFamily(row.ClientKeyFamily),
Index: uint32(row.ClientKeyIndex),
},
clientPubkey: clientKey,
serverPubkey: serverKey,
swapInvoice: row.SwapInvoice,
htlcFeeRate: chainfee.SatPerKWeight(row.HtlcFeeRate),
sweepAddress: sweepAddress,
finalizedHtlcTx: finalizedHtlcTx,
SweepTxHash: sweepTxHash,
finalizedSweeplessSweepTx: finalizedSweepLessSweepTx,
sweepConfirmationHeight: uint32(deserializeNullInt32(
row.SweepConfirmationHeight,
)),
}
if len(updates) > 0 {
lastUpdate := updates[len(updates)-1]
instantOut.State = fsm.StateType(lastUpdate.UpdateState)
}
return instantOut, nil
}
// reservationIdsToByteSlice converts a slice of reservation ids to a byte
// slice.
func reservationIdsToByteSlice(reservations []*reservation.Reservation) []byte {
var reservationIds []byte
for _, reservation := range reservations {
reservationIds = append(reservationIds, reservation.ID[:]...)
}
return reservationIds
}
// byteSliceToReservationIds converts a byte slice to a slice of reservation
// ids.
func byteSliceToReservationIds(byteSlice []byte) ([]reservation.ID, error) {
if len(byteSlice)%32 != 0 {
return nil, fmt.Errorf("invalid byte slice length")
}
var reservationIds []reservation.ID
for i := 0; i < len(byteSlice); i += 32 {
var id reservation.ID
copy(id[:], byteSlice[i:i+32])
reservationIds = append(reservationIds, id)
}
return reservationIds, nil
}
// serializeNullInt32 serializes an int32 to a sql.NullInt32.
func serializeNullInt32(i int32) sql.NullInt32 {
return sql.NullInt32{
Int32: i,
Valid: true,
}
}
// deserializeNullInt32 deserializes an int32 from a sql.NullInt32.
func deserializeNullInt32(i sql.NullInt32) int32 {
if i.Valid {
return i.Int32
}
return 0
}

@ -0,0 +1,36 @@
package instantout
import (
"crypto/rand"
"testing"
"github.com/lightninglabs/loop/instantout/reservation"
"github.com/stretchr/testify/require"
)
func TestConvertingReservations(t *testing.T) {
var resId1, resId2 reservation.ID
// fill the ids with random values.
if _, err := rand.Read(resId1[:]); err != nil {
t.Fatal(err)
}
if _, err := rand.Read(resId2[:]); err != nil {
t.Fatal(err)
}
reservations := []*reservation.Reservation{
{ID: resId1}, {ID: resId2},
}
byteSlice := reservationIdsToByteSlice(reservations)
require.Len(t, byteSlice, 64)
reservationIds, err := byteSliceToReservationIds(byteSlice)
require.NoError(t, err)
require.Len(t, reservationIds, 2)
require.Equal(t, resId1, reservationIds[0])
require.Equal(t, resId2, reservationIds[1])
}

@ -543,7 +543,7 @@ func ConvertLoopOutRow(network *chaincfg.Params, row sqlc.GetLoopOutSwapRow,
}
if row.OutgoingChanSet != "" {
chanSet, err := convertOutgoingChanSet(row.OutgoingChanSet)
chanSet, err := ConvertOutgoingChanSet(row.OutgoingChanSet)
if err != nil {
return nil, err
}
@ -666,9 +666,9 @@ func getSwapEvents(updates []sqlc.SwapUpdate) ([]*LoopEvent, error) {
return events, nil
}
// convertOutgoingChanSet converts a comma separated string of channel IDs into
// ConvertOutgoingChanSet converts a comma separated string of channel IDs into
// a ChannelSet.
func convertOutgoingChanSet(outgoingChanSet string) (ChannelSet, error) {
func ConvertOutgoingChanSet(outgoingChanSet string) (ChannelSet, error) {
// Split the string into a slice of strings
chanStrings := strings.Split(outgoingChanSet, ",")
channels := make([]uint64, len(chanStrings))

@ -0,0 +1,329 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.17.2
// source: instantout.sql
package sqlc
import (
"context"
"database/sql"
"time"
)
const getInstantOutSwap = `-- name: GetInstantOutSwap :one
SELECT
swaps.id, swaps.swap_hash, swaps.preimage, swaps.initiation_time, swaps.amount_requested, swaps.cltv_expiry, swaps.max_miner_fee, swaps.max_swap_fee, swaps.initiation_height, swaps.protocol_version, swaps.label,
instantout_swaps.swap_hash, instantout_swaps.preimage, instantout_swaps.sweep_address, instantout_swaps.outgoing_chan_set, instantout_swaps.htlc_fee_rate, instantout_swaps.reservation_ids, instantout_swaps.swap_invoice, instantout_swaps.finalized_htlc_tx, instantout_swaps.sweep_tx_hash, instantout_swaps.finalized_sweepless_sweep_tx, instantout_swaps.sweep_confirmation_height,
htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index
FROM
swaps
JOIN
instantout_swaps ON swaps.swap_hash = instantout_swaps.swap_hash
JOIN
htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash
WHERE
swaps.swap_hash = $1
`
type GetInstantOutSwapRow struct {
ID int32
SwapHash []byte
Preimage []byte
InitiationTime time.Time
AmountRequested int64
CltvExpiry int32
MaxMinerFee int64
MaxSwapFee int64
InitiationHeight int32
ProtocolVersion int32
Label string
SwapHash_2 []byte
Preimage_2 []byte
SweepAddress string
OutgoingChanSet string
HtlcFeeRate int64
ReservationIds []byte
SwapInvoice string
FinalizedHtlcTx []byte
SweepTxHash []byte
FinalizedSweeplessSweepTx []byte
SweepConfirmationHeight sql.NullInt32
SwapHash_3 []byte
SenderScriptPubkey []byte
ReceiverScriptPubkey []byte
SenderInternalPubkey []byte
ReceiverInternalPubkey []byte
ClientKeyFamily int32
ClientKeyIndex int32
}
func (q *Queries) GetInstantOutSwap(ctx context.Context, swapHash []byte) (GetInstantOutSwapRow, error) {
row := q.db.QueryRowContext(ctx, getInstantOutSwap, swapHash)
var i GetInstantOutSwapRow
err := row.Scan(
&i.ID,
&i.SwapHash,
&i.Preimage,
&i.InitiationTime,
&i.AmountRequested,
&i.CltvExpiry,
&i.MaxMinerFee,
&i.MaxSwapFee,
&i.InitiationHeight,
&i.ProtocolVersion,
&i.Label,
&i.SwapHash_2,
&i.Preimage_2,
&i.SweepAddress,
&i.OutgoingChanSet,
&i.HtlcFeeRate,
&i.ReservationIds,
&i.SwapInvoice,
&i.FinalizedHtlcTx,
&i.SweepTxHash,
&i.FinalizedSweeplessSweepTx,
&i.SweepConfirmationHeight,
&i.SwapHash_3,
&i.SenderScriptPubkey,
&i.ReceiverScriptPubkey,
&i.SenderInternalPubkey,
&i.ReceiverInternalPubkey,
&i.ClientKeyFamily,
&i.ClientKeyIndex,
)
return i, err
}
const getInstantOutSwapUpdates = `-- name: GetInstantOutSwapUpdates :many
SELECT
instantout_updates.id, instantout_updates.swap_hash, instantout_updates.update_state, instantout_updates.update_timestamp
FROM
instantout_updates
WHERE
instantout_updates.swap_hash = $1
`
func (q *Queries) GetInstantOutSwapUpdates(ctx context.Context, swapHash []byte) ([]InstantoutUpdate, error) {
rows, err := q.db.QueryContext(ctx, getInstantOutSwapUpdates, swapHash)
if err != nil {
return nil, err
}
defer rows.Close()
var items []InstantoutUpdate
for rows.Next() {
var i InstantoutUpdate
if err := rows.Scan(
&i.ID,
&i.SwapHash,
&i.UpdateState,
&i.UpdateTimestamp,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getInstantOutSwaps = `-- name: GetInstantOutSwaps :many
SELECT
swaps.id, swaps.swap_hash, swaps.preimage, swaps.initiation_time, swaps.amount_requested, swaps.cltv_expiry, swaps.max_miner_fee, swaps.max_swap_fee, swaps.initiation_height, swaps.protocol_version, swaps.label,
instantout_swaps.swap_hash, instantout_swaps.preimage, instantout_swaps.sweep_address, instantout_swaps.outgoing_chan_set, instantout_swaps.htlc_fee_rate, instantout_swaps.reservation_ids, instantout_swaps.swap_invoice, instantout_swaps.finalized_htlc_tx, instantout_swaps.sweep_tx_hash, instantout_swaps.finalized_sweepless_sweep_tx, instantout_swaps.sweep_confirmation_height,
htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index
FROM
swaps
JOIN
instantout_swaps ON swaps.swap_hash = instantout_swaps.swap_hash
JOIN
htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash
ORDER BY
swaps.id
`
type GetInstantOutSwapsRow struct {
ID int32
SwapHash []byte
Preimage []byte
InitiationTime time.Time
AmountRequested int64
CltvExpiry int32
MaxMinerFee int64
MaxSwapFee int64
InitiationHeight int32
ProtocolVersion int32
Label string
SwapHash_2 []byte
Preimage_2 []byte
SweepAddress string
OutgoingChanSet string
HtlcFeeRate int64
ReservationIds []byte
SwapInvoice string
FinalizedHtlcTx []byte
SweepTxHash []byte
FinalizedSweeplessSweepTx []byte
SweepConfirmationHeight sql.NullInt32
SwapHash_3 []byte
SenderScriptPubkey []byte
ReceiverScriptPubkey []byte
SenderInternalPubkey []byte
ReceiverInternalPubkey []byte
ClientKeyFamily int32
ClientKeyIndex int32
}
func (q *Queries) GetInstantOutSwaps(ctx context.Context) ([]GetInstantOutSwapsRow, error) {
rows, err := q.db.QueryContext(ctx, getInstantOutSwaps)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetInstantOutSwapsRow
for rows.Next() {
var i GetInstantOutSwapsRow
if err := rows.Scan(
&i.ID,
&i.SwapHash,
&i.Preimage,
&i.InitiationTime,
&i.AmountRequested,
&i.CltvExpiry,
&i.MaxMinerFee,
&i.MaxSwapFee,
&i.InitiationHeight,
&i.ProtocolVersion,
&i.Label,
&i.SwapHash_2,
&i.Preimage_2,
&i.SweepAddress,
&i.OutgoingChanSet,
&i.HtlcFeeRate,
&i.ReservationIds,
&i.SwapInvoice,
&i.FinalizedHtlcTx,
&i.SweepTxHash,
&i.FinalizedSweeplessSweepTx,
&i.SweepConfirmationHeight,
&i.SwapHash_3,
&i.SenderScriptPubkey,
&i.ReceiverScriptPubkey,
&i.SenderInternalPubkey,
&i.ReceiverInternalPubkey,
&i.ClientKeyFamily,
&i.ClientKeyIndex,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const insertInstantOut = `-- name: InsertInstantOut :exec
INSERT INTO instantout_swaps (
swap_hash,
preimage,
sweep_address,
outgoing_chan_set,
htlc_fee_rate,
reservation_ids,
swap_invoice
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
)
`
type InsertInstantOutParams struct {
SwapHash []byte
Preimage []byte
SweepAddress string
OutgoingChanSet string
HtlcFeeRate int64
ReservationIds []byte
SwapInvoice string
}
func (q *Queries) InsertInstantOut(ctx context.Context, arg InsertInstantOutParams) error {
_, err := q.db.ExecContext(ctx, insertInstantOut,
arg.SwapHash,
arg.Preimage,
arg.SweepAddress,
arg.OutgoingChanSet,
arg.HtlcFeeRate,
arg.ReservationIds,
arg.SwapInvoice,
)
return err
}
const insertInstantOutUpdate = `-- name: InsertInstantOutUpdate :exec
INSERT INTO instantout_updates (
swap_hash,
update_state,
update_timestamp
) VALUES (
$1,
$2,
$3
)
`
type InsertInstantOutUpdateParams struct {
SwapHash []byte
UpdateState string
UpdateTimestamp time.Time
}
func (q *Queries) InsertInstantOutUpdate(ctx context.Context, arg InsertInstantOutUpdateParams) error {
_, err := q.db.ExecContext(ctx, insertInstantOutUpdate, arg.SwapHash, arg.UpdateState, arg.UpdateTimestamp)
return err
}
const updateInstantOut = `-- name: UpdateInstantOut :exec
UPDATE instantout_swaps
SET
finalized_htlc_tx = $2,
sweep_tx_hash = $3,
finalized_sweepless_sweep_tx = $4,
sweep_confirmation_height = $5
WHERE
instantout_swaps.swap_hash = $1
`
type UpdateInstantOutParams struct {
SwapHash []byte
FinalizedHtlcTx []byte
SweepTxHash []byte
FinalizedSweeplessSweepTx []byte
SweepConfirmationHeight sql.NullInt32
}
func (q *Queries) UpdateInstantOut(ctx context.Context, arg UpdateInstantOutParams) error {
_, err := q.db.ExecContext(ctx, updateInstantOut,
arg.SwapHash,
arg.FinalizedHtlcTx,
arg.SweepTxHash,
arg.FinalizedSweeplessSweepTx,
arg.SweepConfirmationHeight,
)
return err
}

@ -0,0 +1,4 @@
DROP INDEX IF EXISTS instantout_updates_swap_hash_idx;
DROP INDEX IF EXISTS instantout_swap_hash_idx;
DROP TABLE IF EXISTS instantout_updates;
DROP TABLE IF EXISTS instantout_swaps;

@ -0,0 +1,52 @@
CREATE TABLE IF NOT EXISTS instantout_swaps (
-- swap_hash points to the parent swap hash.
swap_hash BLOB PRIMARY KEY,
-- preimage is the preimage of the swap.
preimage BLOB NOT NULL,
-- sweep_address is the address that the server should sweep the funds to.
sweep_address TEXT NOT NULL,
-- outgoing_chan_set is the set of short ids of channels that may be used.
-- If empty, any channel may be used.
outgoing_chan_set TEXT NOT NULL,
-- htlc_fee_rate is the fee rate in sat/kw that is used for the htlc transaction.
htlc_fee_rate BIGINT NOT NULL,
-- reservation_ids is a list of ids of the reservations that are used for this swap.
reservation_ids BLOB NOT NULL,
-- swap_invoice is the invoice that is to be paid by the client to
-- initiate the loop out swap.
swap_invoice TEXT NOT NULL,
-- finalized_htlc_tx contains the fully signed htlc transaction.
finalized_htlc_tx BLOB,
-- sweep_tx_hash is the hash of the transaction that sweeps the htlc.
sweep_tx_hash BLOB,
-- finalized_sweepless_sweep_tx contains the fully signed sweepless sweep transaction.
finalized_sweepless_sweep_tx BLOB,
-- sweep_confirmation_height is the block height at which the sweep transaction is confirmed.
sweep_confirmation_height INTEGER
);
CREATE TABLE IF NOT EXISTS instantout_updates (
-- id is auto incremented for each update.
id INTEGER PRIMARY KEY,
-- swap_hash is the hash of the swap that this update is for.
swap_hash BLOB NOT NULL REFERENCES instantout_swaps(swap_hash),
-- update_state is the state of the swap at the time of the update.
update_state TEXT NOT NULL,
-- update_timestamp is the time at which the update was created.
update_timestamp TIMESTAMP NOT NULL
);
CREATE INDEX IF NOT EXISTS instantout_updates_swap_hash_idx ON instantout_updates(swap_hash);

@ -19,6 +19,27 @@ type HtlcKey struct {
ClientKeyIndex int32
}
type InstantoutSwap struct {
SwapHash []byte
Preimage []byte
SweepAddress string
OutgoingChanSet string
HtlcFeeRate int64
ReservationIds []byte
SwapInvoice string
FinalizedHtlcTx []byte
SweepTxHash []byte
FinalizedSweeplessSweepTx []byte
SweepConfirmationHeight sql.NullInt32
}
type InstantoutUpdate struct {
ID int32
SwapHash []byte
UpdateState string
UpdateTimestamp time.Time
}
type LiquidityParam struct {
ID int32
Params []byte

@ -13,6 +13,9 @@ type Querier interface {
CreateReservation(ctx context.Context, arg CreateReservationParams) error
FetchLiquidityParams(ctx context.Context) ([]byte, error)
GetBatchSweeps(ctx context.Context, batchID int32) ([]GetBatchSweepsRow, error)
GetInstantOutSwap(ctx context.Context, swapHash []byte) (GetInstantOutSwapRow, error)
GetInstantOutSwapUpdates(ctx context.Context, swapHash []byte) ([]InstantoutUpdate, error)
GetInstantOutSwaps(ctx context.Context) ([]GetInstantOutSwapsRow, error)
GetLoopInSwap(ctx context.Context, swapHash []byte) (GetLoopInSwapRow, error)
GetLoopInSwaps(ctx context.Context) ([]GetLoopInSwapsRow, error)
GetLoopOutSwap(ctx context.Context, swapHash []byte) (GetLoopOutSwapRow, error)
@ -25,12 +28,15 @@ type Querier interface {
GetUnconfirmedBatches(ctx context.Context) ([]SweepBatch, error)
InsertBatch(ctx context.Context, arg InsertBatchParams) (int32, error)
InsertHtlcKeys(ctx context.Context, arg InsertHtlcKeysParams) error
InsertInstantOut(ctx context.Context, arg InsertInstantOutParams) error
InsertInstantOutUpdate(ctx context.Context, arg InsertInstantOutUpdateParams) error
InsertLoopIn(ctx context.Context, arg InsertLoopInParams) error
InsertLoopOut(ctx context.Context, arg InsertLoopOutParams) error
InsertReservationUpdate(ctx context.Context, arg InsertReservationUpdateParams) error
InsertSwap(ctx context.Context, arg InsertSwapParams) error
InsertSwapUpdate(ctx context.Context, arg InsertSwapUpdateParams) error
UpdateBatch(ctx context.Context, arg UpdateBatchParams) error
UpdateInstantOut(ctx context.Context, arg UpdateInstantOutParams) error
UpdateReservation(ctx context.Context, arg UpdateReservationParams) error
UpsertLiquidityParams(ctx context.Context, params []byte) error
UpsertSweep(ctx context.Context, arg UpsertSweepParams) error

@ -0,0 +1,75 @@
-- name: InsertInstantOut :exec
INSERT INTO instantout_swaps (
swap_hash,
preimage,
sweep_address,
outgoing_chan_set,
htlc_fee_rate,
reservation_ids,
swap_invoice
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
);
-- name: UpdateInstantOut :exec
UPDATE instantout_swaps
SET
finalized_htlc_tx = $2,
sweep_tx_hash = $3,
finalized_sweepless_sweep_tx = $4,
sweep_confirmation_height = $5
WHERE
instantout_swaps.swap_hash = $1;
-- name: InsertInstantOutUpdate :exec
INSERT INTO instantout_updates (
swap_hash,
update_state,
update_timestamp
) VALUES (
$1,
$2,
$3
);
-- name: GetInstantOutSwap :one
SELECT
swaps.*,
instantout_swaps.*,
htlc_keys.*
FROM
swaps
JOIN
instantout_swaps ON swaps.swap_hash = instantout_swaps.swap_hash
JOIN
htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash
WHERE
swaps.swap_hash = $1;
-- name: GetInstantOutSwaps :many
SELECT
swaps.*,
instantout_swaps.*,
htlc_keys.*
FROM
swaps
JOIN
instantout_swaps ON swaps.swap_hash = instantout_swaps.swap_hash
JOIN
htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash
ORDER BY
swaps.id;
-- name: GetInstantOutSwapUpdates :many
SELECT
instantout_updates.*
FROM
instantout_updates
WHERE
instantout_updates.swap_hash = $1;
Loading…
Cancel
Save