diff --git a/loopdb/sqlc/migrations/000011_static_address_loop_in.down.sql b/loopdb/sqlc/migrations/000011_static_address_loop_in.down.sql new file mode 100644 index 00000000..fae889ca --- /dev/null +++ b/loopdb/sqlc/migrations/000011_static_address_loop_in.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS static_address_swaps; +DROP TABLE IF EXISTS static_address_swap_updates; diff --git a/loopdb/sqlc/migrations/000011_static_address_loop_in.up.sql b/loopdb/sqlc/migrations/000011_static_address_loop_in.up.sql new file mode 100644 index 00000000..dfff6d2d --- /dev/null +++ b/loopdb/sqlc/migrations/000011_static_address_loop_in.up.sql @@ -0,0 +1,59 @@ +-- static_address_swaps stores the static address loop-in specific data. +CREATE TABLE IF NOT EXISTS static_address_swaps ( + -- id is the auto incrementing primary key. + id INTEGER PRIMARY KEY, + + -- swap_hash of the swap is unique and is used to identify the swap. + swap_hash BLOB NOT NULL UNIQUE, + + -- swap_invoice is the invoice that needs to be paid by the server to + -- complete the loop-in swap. + swap_invoice TEXT NOT NULL, + + -- last_hop is an optional parameter that specifies the last hop to be + -- used for a loop in swap. + last_hop BLOB, + + -- payment_timeout_seconds is the time in seconds that the server has to + -- pay the invoice. + payment_timeout_seconds INTEGER NOT NULL, + + -- quoted_swap_fee_satoshis is the swap fee in sats that the server returned + -- in the swap quote. + quoted_swap_fee_satoshis BIGINT NOT NULL, + + -- deposit_outpoints is a concatenated list of outpoints that are used for + -- this swap. The list has the format txid1:idx;txid2:idx;... + deposit_outpoints TEXT NOT NULL, + + -- htlc_tx_fee_rate_sat_kw is the fee rate in sat/kw that is used for the + -- htlc transaction. + htlc_tx_fee_rate_sat_kw BIGINT NOT NULL, + + -- htlc_timeout_sweep_tx_hash contains the htlc timeout sweep tx id. + htlc_timeout_sweep_tx_id TEXT, + + -- htlc_timeout_sweep_address contains the address the htlc timeout sweep + -- transaction sends funds to. + htlc_timeout_sweep_address TEXT NOT NULL +); + +-- static_address_swap_updates contains all the updates to a loop-in swap. +CREATE TABLE IF NOT EXISTS static_address_swap_updates ( + -- id is the auto incrementing primary key. + id INTEGER PRIMARY KEY, + + -- deposit_id is the unique identifier for the deposit. + swap_hash BLOB NOT NULL REFERENCES static_address_swaps(swap_hash), + + -- update_state is the state of the loop-in at the time of the update. + -- Example states are InitHtlc, SignHtlcTx and others defined in + -- staticaddr/loopin/fsm.go. + update_state TEXT NOT NULL, + + -- update_timestamp is the timestamp of the update. + update_timestamp TIMESTAMP NOT NULL +); + +CREATE INDEX IF NOT EXISTS static_address_swap_hash_idx ON static_address_swap_updates(swap_hash); +CREATE INDEX IF NOT EXISTS static_address_update_state_idx ON static_address_swap_updates(update_state); diff --git a/loopdb/sqlc/models.go b/loopdb/sqlc/models.go index 59653882..59939ad7 100644 --- a/loopdb/sqlc/models.go +++ b/loopdb/sqlc/models.go @@ -124,6 +124,26 @@ type StaticAddress struct { ProtocolVersion int32 } +type StaticAddressSwap struct { + ID int32 + SwapHash []byte + SwapInvoice string + LastHop []byte + PaymentTimeoutSeconds int32 + QuotedSwapFeeSatoshis int64 + DepositOutpoints string + HtlcTxFeeRateSatKw int64 + HtlcTimeoutSweepTxID sql.NullString + HtlcTimeoutSweepAddress string +} + +type StaticAddressSwapUpdate struct { + ID int32 + SwapHash []byte + UpdateState string + UpdateTimestamp time.Time +} + type Swap struct { ID int32 SwapHash []byte diff --git a/loopdb/sqlc/querier.go b/loopdb/sqlc/querier.go index a942562c..648eb3b5 100644 --- a/loopdb/sqlc/querier.go +++ b/loopdb/sqlc/querier.go @@ -6,6 +6,7 @@ package sqlc import ( "context" + "database/sql" ) type Querier interface { @@ -26,6 +27,7 @@ type Querier interface { GetLastUpdateID(ctx context.Context, swapHash []byte) (int32, error) GetLatestDepositUpdate(ctx context.Context, depositID []byte) (DepositUpdate, error) GetLoopInSwap(ctx context.Context, swapHash []byte) (GetLoopInSwapRow, error) + GetLoopInSwapUpdates(ctx context.Context, swapHash []byte) ([]StaticAddressSwapUpdate, error) GetLoopInSwaps(ctx context.Context) ([]GetLoopInSwapsRow, error) GetLoopOutSwap(ctx context.Context, swapHash []byte) (GetLoopOutSwapRow, error) GetLoopOutSwaps(ctx context.Context) ([]GetLoopOutSwapsRow, error) @@ -35,6 +37,8 @@ type Querier interface { GetReservationUpdates(ctx context.Context, reservationID []byte) ([]ReservationUpdate, error) GetReservations(ctx context.Context) ([]Reservation, error) GetStaticAddress(ctx context.Context, pkscript []byte) (StaticAddress, error) + GetStaticAddressLoopInSwap(ctx context.Context, swapHash []byte) (GetStaticAddressLoopInSwapRow, error) + GetStaticAddressLoopInSwapsByStates(ctx context.Context, dollar_1 sql.NullString) ([]GetStaticAddressLoopInSwapsByStatesRow, error) GetSwapUpdates(ctx context.Context, swapHash []byte) ([]SwapUpdate, error) GetSweepStatus(ctx context.Context, swapHash []byte) (bool, error) GetUnconfirmedBatches(ctx context.Context) ([]SweepBatch, error) @@ -47,13 +51,17 @@ type Querier interface { InsertLoopOut(ctx context.Context, arg InsertLoopOutParams) error InsertMigration(ctx context.Context, arg InsertMigrationParams) error InsertReservationUpdate(ctx context.Context, arg InsertReservationUpdateParams) error + InsertStaticAddressLoopIn(ctx context.Context, arg InsertStaticAddressLoopInParams) error + InsertStaticAddressMetaUpdate(ctx context.Context, arg InsertStaticAddressMetaUpdateParams) error InsertSwap(ctx context.Context, arg InsertSwapParams) error InsertSwapUpdate(ctx context.Context, arg InsertSwapUpdateParams) error + IsStored(ctx context.Context, swapHash []byte) (bool, error) OverrideSwapCosts(ctx context.Context, arg OverrideSwapCostsParams) error UpdateBatch(ctx context.Context, arg UpdateBatchParams) error UpdateDeposit(ctx context.Context, arg UpdateDepositParams) error UpdateInstantOut(ctx context.Context, arg UpdateInstantOutParams) error UpdateReservation(ctx context.Context, arg UpdateReservationParams) error + UpdateStaticAddressLoopIn(ctx context.Context, arg UpdateStaticAddressLoopInParams) error UpsertLiquidityParams(ctx context.Context, params []byte) error UpsertSweep(ctx context.Context, arg UpsertSweepParams) error } diff --git a/loopdb/sqlc/queries/static_address_loopin.sql b/loopdb/sqlc/queries/static_address_loopin.sql new file mode 100644 index 00000000..ea4344b7 --- /dev/null +++ b/loopdb/sqlc/queries/static_address_loopin.sql @@ -0,0 +1,95 @@ +-- name: InsertStaticAddressLoopIn :exec +INSERT INTO static_address_swaps ( + swap_hash, + swap_invoice, + last_hop, + payment_timeout_seconds, + quoted_swap_fee_satoshis, + deposit_outpoints, + htlc_tx_fee_rate_sat_kw, + htlc_timeout_sweep_tx_id, + htlc_timeout_sweep_address +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9 +); + +-- name: UpdateStaticAddressLoopIn :exec +UPDATE static_address_swaps +SET + htlc_tx_fee_rate_sat_kw = $2, + htlc_timeout_sweep_tx_id = $3 +WHERE + swap_hash = $1; + +-- name: InsertStaticAddressMetaUpdate :exec +INSERT INTO static_address_swap_updates ( + swap_hash, + update_state, + update_timestamp +) VALUES ( + $1, + $2, + $3 + ); + +-- name: GetStaticAddressLoopInSwap :one +SELECT + swaps.*, + static_address_swaps.*, + htlc_keys.* +FROM + swaps + JOIN + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +WHERE + swaps.swap_hash = $1; + +-- name: GetStaticAddressLoopInSwapsByStates :many +SELECT + swaps.*, + static_address_swaps.*, + htlc_keys.* +FROM + swaps + JOIN + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash + JOIN + static_address_swap_updates u ON swaps.swap_hash = u.swap_hash + -- This subquery ensures that we are checking only the latest update for + -- each swap_hash. + AND u.update_timestamp = ( + SELECT MAX(update_timestamp) + FROM static_address_swap_updates + WHERE swap_hash = u.swap_hash + ) +WHERE + (',' || $1 || ',') LIKE ('%,' || u.update_state || ',%') +ORDER BY + swaps.id; + +-- name: GetLoopInSwapUpdates :many +SELECT + static_address_swap_updates.* +FROM + static_address_swap_updates +WHERE + swap_hash = $1; + +-- name: IsStored :one +SELECT EXISTS ( + SELECT 1 + FROM static_address_swaps + WHERE swap_hash = $1 +); diff --git a/loopdb/sqlc/static_address_loopin.sql.go b/loopdb/sqlc/static_address_loopin.sql.go new file mode 100644 index 00000000..22ee6438 --- /dev/null +++ b/loopdb/sqlc/static_address_loopin.sql.go @@ -0,0 +1,349 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.25.0 +// source: static_address_loopin.sql + +package sqlc + +import ( + "context" + "database/sql" + "time" +) + +const getLoopInSwapUpdates = `-- name: GetLoopInSwapUpdates :many +SELECT + static_address_swap_updates.id, static_address_swap_updates.swap_hash, static_address_swap_updates.update_state, static_address_swap_updates.update_timestamp +FROM + static_address_swap_updates +WHERE + swap_hash = $1 +` + +func (q *Queries) GetLoopInSwapUpdates(ctx context.Context, swapHash []byte) ([]StaticAddressSwapUpdate, error) { + rows, err := q.db.QueryContext(ctx, getLoopInSwapUpdates, swapHash) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StaticAddressSwapUpdate + for rows.Next() { + var i StaticAddressSwapUpdate + 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 getStaticAddressLoopInSwap = `-- name: GetStaticAddressLoopInSwap :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, + static_address_swaps.id, static_address_swaps.swap_hash, static_address_swaps.swap_invoice, static_address_swaps.last_hop, static_address_swaps.payment_timeout_seconds, static_address_swaps.quoted_swap_fee_satoshis, static_address_swaps.deposit_outpoints, static_address_swaps.htlc_tx_fee_rate_sat_kw, static_address_swaps.htlc_timeout_sweep_tx_id, static_address_swaps.htlc_timeout_sweep_address, + 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 + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +WHERE + swaps.swap_hash = $1 +` + +type GetStaticAddressLoopInSwapRow struct { + ID int32 + SwapHash []byte + Preimage []byte + InitiationTime time.Time + AmountRequested int64 + CltvExpiry int32 + MaxMinerFee int64 + MaxSwapFee int64 + InitiationHeight int32 + ProtocolVersion int32 + Label string + ID_2 int32 + SwapHash_2 []byte + SwapInvoice string + LastHop []byte + PaymentTimeoutSeconds int32 + QuotedSwapFeeSatoshis int64 + DepositOutpoints string + HtlcTxFeeRateSatKw int64 + HtlcTimeoutSweepTxID sql.NullString + HtlcTimeoutSweepAddress string + SwapHash_3 []byte + SenderScriptPubkey []byte + ReceiverScriptPubkey []byte + SenderInternalPubkey []byte + ReceiverInternalPubkey []byte + ClientKeyFamily int32 + ClientKeyIndex int32 +} + +func (q *Queries) GetStaticAddressLoopInSwap(ctx context.Context, swapHash []byte) (GetStaticAddressLoopInSwapRow, error) { + row := q.db.QueryRowContext(ctx, getStaticAddressLoopInSwap, swapHash) + var i GetStaticAddressLoopInSwapRow + 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.ID_2, + &i.SwapHash_2, + &i.SwapInvoice, + &i.LastHop, + &i.PaymentTimeoutSeconds, + &i.QuotedSwapFeeSatoshis, + &i.DepositOutpoints, + &i.HtlcTxFeeRateSatKw, + &i.HtlcTimeoutSweepTxID, + &i.HtlcTimeoutSweepAddress, + &i.SwapHash_3, + &i.SenderScriptPubkey, + &i.ReceiverScriptPubkey, + &i.SenderInternalPubkey, + &i.ReceiverInternalPubkey, + &i.ClientKeyFamily, + &i.ClientKeyIndex, + ) + return i, err +} + +const getStaticAddressLoopInSwapsByStates = `-- name: GetStaticAddressLoopInSwapsByStates :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, + static_address_swaps.id, static_address_swaps.swap_hash, static_address_swaps.swap_invoice, static_address_swaps.last_hop, static_address_swaps.payment_timeout_seconds, static_address_swaps.quoted_swap_fee_satoshis, static_address_swaps.deposit_outpoints, static_address_swaps.htlc_tx_fee_rate_sat_kw, static_address_swaps.htlc_timeout_sweep_tx_id, static_address_swaps.htlc_timeout_sweep_address, + 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 + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash + JOIN + static_address_swap_updates u ON swaps.swap_hash = u.swap_hash + -- This subquery ensures that we are checking only the latest update for + -- each swap_hash. + AND u.update_timestamp = ( + SELECT MAX(update_timestamp) + FROM static_address_swap_updates + WHERE swap_hash = u.swap_hash + ) +WHERE + (',' || $1 || ',') LIKE ('%,' || u.update_state || ',%') +ORDER BY + swaps.id +` + +type GetStaticAddressLoopInSwapsByStatesRow struct { + ID int32 + SwapHash []byte + Preimage []byte + InitiationTime time.Time + AmountRequested int64 + CltvExpiry int32 + MaxMinerFee int64 + MaxSwapFee int64 + InitiationHeight int32 + ProtocolVersion int32 + Label string + ID_2 int32 + SwapHash_2 []byte + SwapInvoice string + LastHop []byte + PaymentTimeoutSeconds int32 + QuotedSwapFeeSatoshis int64 + DepositOutpoints string + HtlcTxFeeRateSatKw int64 + HtlcTimeoutSweepTxID sql.NullString + HtlcTimeoutSweepAddress string + SwapHash_3 []byte + SenderScriptPubkey []byte + ReceiverScriptPubkey []byte + SenderInternalPubkey []byte + ReceiverInternalPubkey []byte + ClientKeyFamily int32 + ClientKeyIndex int32 +} + +func (q *Queries) GetStaticAddressLoopInSwapsByStates(ctx context.Context, dollar_1 sql.NullString) ([]GetStaticAddressLoopInSwapsByStatesRow, error) { + rows, err := q.db.QueryContext(ctx, getStaticAddressLoopInSwapsByStates, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetStaticAddressLoopInSwapsByStatesRow + for rows.Next() { + var i GetStaticAddressLoopInSwapsByStatesRow + 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.ID_2, + &i.SwapHash_2, + &i.SwapInvoice, + &i.LastHop, + &i.PaymentTimeoutSeconds, + &i.QuotedSwapFeeSatoshis, + &i.DepositOutpoints, + &i.HtlcTxFeeRateSatKw, + &i.HtlcTimeoutSweepTxID, + &i.HtlcTimeoutSweepAddress, + &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 insertStaticAddressLoopIn = `-- name: InsertStaticAddressLoopIn :exec +INSERT INTO static_address_swaps ( + swap_hash, + swap_invoice, + last_hop, + payment_timeout_seconds, + quoted_swap_fee_satoshis, + deposit_outpoints, + htlc_tx_fee_rate_sat_kw, + htlc_timeout_sweep_tx_id, + htlc_timeout_sweep_address +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9 +) +` + +type InsertStaticAddressLoopInParams struct { + SwapHash []byte + SwapInvoice string + LastHop []byte + PaymentTimeoutSeconds int32 + QuotedSwapFeeSatoshis int64 + DepositOutpoints string + HtlcTxFeeRateSatKw int64 + HtlcTimeoutSweepTxID sql.NullString + HtlcTimeoutSweepAddress string +} + +func (q *Queries) InsertStaticAddressLoopIn(ctx context.Context, arg InsertStaticAddressLoopInParams) error { + _, err := q.db.ExecContext(ctx, insertStaticAddressLoopIn, + arg.SwapHash, + arg.SwapInvoice, + arg.LastHop, + arg.PaymentTimeoutSeconds, + arg.QuotedSwapFeeSatoshis, + arg.DepositOutpoints, + arg.HtlcTxFeeRateSatKw, + arg.HtlcTimeoutSweepTxID, + arg.HtlcTimeoutSweepAddress, + ) + return err +} + +const insertStaticAddressMetaUpdate = `-- name: InsertStaticAddressMetaUpdate :exec +INSERT INTO static_address_swap_updates ( + swap_hash, + update_state, + update_timestamp +) VALUES ( + $1, + $2, + $3 + ) +` + +type InsertStaticAddressMetaUpdateParams struct { + SwapHash []byte + UpdateState string + UpdateTimestamp time.Time +} + +func (q *Queries) InsertStaticAddressMetaUpdate(ctx context.Context, arg InsertStaticAddressMetaUpdateParams) error { + _, err := q.db.ExecContext(ctx, insertStaticAddressMetaUpdate, arg.SwapHash, arg.UpdateState, arg.UpdateTimestamp) + return err +} + +const isStored = `-- name: IsStored :one +SELECT EXISTS ( + SELECT 1 + FROM static_address_swaps + WHERE swap_hash = $1 +) +` + +func (q *Queries) IsStored(ctx context.Context, swapHash []byte) (bool, error) { + row := q.db.QueryRowContext(ctx, isStored, swapHash) + var exists bool + err := row.Scan(&exists) + return exists, err +} + +const updateStaticAddressLoopIn = `-- name: UpdateStaticAddressLoopIn :exec +UPDATE static_address_swaps +SET + htlc_tx_fee_rate_sat_kw = $2, + htlc_timeout_sweep_tx_id = $3 +WHERE + swap_hash = $1 +` + +type UpdateStaticAddressLoopInParams struct { + SwapHash []byte + HtlcTxFeeRateSatKw int64 + HtlcTimeoutSweepTxID sql.NullString +} + +func (q *Queries) UpdateStaticAddressLoopIn(ctx context.Context, arg UpdateStaticAddressLoopInParams) error { + _, err := q.db.ExecContext(ctx, updateStaticAddressLoopIn, arg.SwapHash, arg.HtlcTxFeeRateSatKw, arg.HtlcTimeoutSweepTxID) + return err +}