From e948c94b95aed5d8ff78e1f9dfd9336784727f1d Mon Sep 17 00:00:00 2001 From: Slyghtning Date: Wed, 2 Apr 2025 14:29:48 +0200 Subject: [PATCH] staticaddr: method to fetch deposits by outpoints --- loopdb/sqlc/querier.go | 1 + .../sqlc/queries/static_address_deposits.sql | 10 +++++ loopdb/sqlc/static_address_deposits.sql.go | 33 +++++++++++++++ staticaddr/deposit/interface.go | 4 ++ staticaddr/deposit/manager.go | 33 +++++++++++++++ staticaddr/deposit/manager_test.go | 7 ++++ staticaddr/deposit/sql_store.go | 42 +++++++++++++++++++ staticaddr/loopin/interface.go | 5 +++ 8 files changed, 135 insertions(+) diff --git a/loopdb/sqlc/querier.go b/loopdb/sqlc/querier.go index 15b2e388f..26e4c0554 100644 --- a/loopdb/sqlc/querier.go +++ b/loopdb/sqlc/querier.go @@ -18,6 +18,7 @@ type Querier interface { CreateStaticAddress(ctx context.Context, arg CreateStaticAddressParams) error CreateWithdrawal(ctx context.Context, arg CreateWithdrawalParams) error CreateWithdrawalDeposit(ctx context.Context, arg CreateWithdrawalDepositParams) error + DepositForOutpoint(ctx context.Context, arg DepositForOutpointParams) (Deposit, error) FetchLiquidityParams(ctx context.Context) ([]byte, error) GetAllWithdrawals(ctx context.Context) ([]Withdrawal, error) GetBatchSweeps(ctx context.Context, batchID int32) ([]Sweep, error) diff --git a/loopdb/sqlc/queries/static_address_deposits.sql b/loopdb/sqlc/queries/static_address_deposits.sql index bc782bbb2..2987e469e 100644 --- a/loopdb/sqlc/queries/static_address_deposits.sql +++ b/loopdb/sqlc/queries/static_address_deposits.sql @@ -49,6 +49,16 @@ FROM WHERE deposit_id = $1; +-- name: DepositForOutpoint :one +SELECT + * +FROM + deposits +WHERE + tx_hash = $1 +AND + out_index = $2; + -- name: AllDeposits :many SELECT * diff --git a/loopdb/sqlc/static_address_deposits.sql.go b/loopdb/sqlc/static_address_deposits.sql.go index 75645c8e1..3a5c8076b 100644 --- a/loopdb/sqlc/static_address_deposits.sql.go +++ b/loopdb/sqlc/static_address_deposits.sql.go @@ -100,6 +100,39 @@ func (q *Queries) CreateDeposit(ctx context.Context, arg CreateDepositParams) er return err } +const depositForOutpoint = `-- name: DepositForOutpoint :one +SELECT + id, deposit_id, tx_hash, out_index, amount, confirmation_height, timeout_sweep_pk_script, expiry_sweep_txid, finalized_withdrawal_tx +FROM + deposits +WHERE + tx_hash = $1 +AND + out_index = $2 +` + +type DepositForOutpointParams struct { + TxHash []byte + OutIndex int32 +} + +func (q *Queries) DepositForOutpoint(ctx context.Context, arg DepositForOutpointParams) (Deposit, error) { + row := q.db.QueryRowContext(ctx, depositForOutpoint, arg.TxHash, arg.OutIndex) + var i Deposit + err := row.Scan( + &i.ID, + &i.DepositID, + &i.TxHash, + &i.OutIndex, + &i.Amount, + &i.ConfirmationHeight, + &i.TimeoutSweepPkScript, + &i.ExpirySweepTxid, + &i.FinalizedWithdrawalTx, + ) + return i, err +} + const getDeposit = `-- name: GetDeposit :one SELECT id, deposit_id, tx_hash, out_index, amount, confirmation_height, timeout_sweep_pk_script, expiry_sweep_txid, finalized_withdrawal_tx diff --git a/staticaddr/deposit/interface.go b/staticaddr/deposit/interface.go index d38cfbaac..c18011bc3 100644 --- a/staticaddr/deposit/interface.go +++ b/staticaddr/deposit/interface.go @@ -26,6 +26,10 @@ type Store interface { // GetDeposit retrieves a deposit with depositID from the database. GetDeposit(ctx context.Context, depositID ID) (*Deposit, error) + // DepositForOutpoint retrieves the deposit with the given outpoint. + DepositForOutpoint(ctx context.Context, outpoint string) (*Deposit, + error) + // AllDeposits retrieves all deposits from the store. AllDeposits(ctx context.Context) ([]*Deposit, error) } diff --git a/staticaddr/deposit/manager.go b/staticaddr/deposit/manager.go index 44ca40d2c..cdea4949a 100644 --- a/staticaddr/deposit/manager.go +++ b/staticaddr/deposit/manager.go @@ -572,3 +572,36 @@ func (m *Manager) toActiveDeposits(outpoints *[]wire.OutPoint) ([]*FSM, return fsms, deposits } + +// DepositsForOutpoints returns all deposits that are behind the given +// outpoints. +func (m *Manager) DepositsForOutpoints(ctx context.Context, + outpoints []string) ([]*Deposit, error) { + + // Check for duplicates. + existingOutpoints := make(map[string]struct{}, len(outpoints)) + for i, o := range outpoints { + if _, ok := existingOutpoints[o]; ok { + return nil, fmt.Errorf("duplicate outpoint %s "+ + "at index %d", o, i) + } + existingOutpoints[o] = struct{}{} + } + + deposits := make([]*Deposit, 0, len(outpoints)) + for _, o := range outpoints { + op, err := wire.NewOutPointFromString(o) + if err != nil { + return nil, err + } + + deposit, err := m.cfg.Store.DepositForOutpoint(ctx, op.String()) + if err != nil { + return nil, err + } + + deposits = append(deposits, deposit) + } + + return deposits, nil +} diff --git a/staticaddr/deposit/manager_test.go b/staticaddr/deposit/manager_test.go index 0c4c6ea23..1f0b2cf95 100644 --- a/staticaddr/deposit/manager_test.go +++ b/staticaddr/deposit/manager_test.go @@ -165,6 +165,13 @@ func (s *mockStore) GetDeposit(ctx context.Context, depositID ID) (*Deposit, return args.Get(0).(*Deposit), args.Error(1) } +func (s *mockStore) DepositForOutpoint(ctx context.Context, + outpoint string) (*Deposit, error) { + + args := s.Called(ctx, outpoint) + return args.Get(0).(*Deposit), args.Error(1) +} + func (s *mockStore) AllDeposits(ctx context.Context) ([]*Deposit, error) { args := s.Called(ctx) return args.Get(0).([]*Deposit), args.Error(1) diff --git a/staticaddr/deposit/sql_store.go b/staticaddr/deposit/sql_store.go index 6a52ae282..1303c6a70 100644 --- a/staticaddr/deposit/sql_store.go +++ b/staticaddr/deposit/sql_store.go @@ -149,6 +149,48 @@ func (s *SqlStore) GetDeposit(ctx context.Context, id ID) (*Deposit, error) { return deposit, nil } +// DepositForOutpoint retrieves the deposit with the given outpoint from the +// database. +func (s *SqlStore) DepositForOutpoint(ctx context.Context, + outpoint string) (*Deposit, error) { + + var deposit *Deposit + err := s.baseDB.ExecTx(ctx, loopdb.NewSqlReadOpts(), + func(q *sqlc.Queries) error { + op, err := wire.NewOutPointFromString(outpoint) + if err != nil { + return err + } + params := sqlc.DepositForOutpointParams{ + TxHash: op.Hash[:], + OutIndex: int32(op.Index), + } + row, err := q.DepositForOutpoint(ctx, params) + if err != nil { + return err + } + + latestUpdate, err := q.GetLatestDepositUpdate( + ctx, row.DepositID, + ) + if err != nil { + return err + } + + deposit, err = s.toDeposit(row, latestUpdate) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return nil, err + } + + return deposit, nil +} + // AllDeposits retrieves all known deposits to our static address. func (s *SqlStore) AllDeposits(ctx context.Context) ([]*Deposit, error) { var allDeposits []*Deposit diff --git a/staticaddr/loopin/interface.go b/staticaddr/loopin/interface.go index e4e73862c..cf95f838b 100644 --- a/staticaddr/loopin/interface.go +++ b/staticaddr/loopin/interface.go @@ -48,6 +48,11 @@ type DepositManager interface { // invalid. TransitionDeposits(ctx context.Context, deposits []*deposit.Deposit, event fsm.EventType, expectedFinalState fsm.StateType) error + + // DepositsForOutpoints returns all deposits that behind the given + // outpoints. + DepositsForOutpoints(ctx context.Context, outpoints []string) ( + []*deposit.Deposit, error) } // StaticAddressLoopInStore provides access to the static address loop-in DB.