Files
ark/server/internal/infrastructure/db/sqlite/sqlc/query.sql
Dusan Sekulic ae3ccb3579 Add support for announcing market hours (#380)
* feat: add market hour configuration for optimal payment timing

This commit adds market hour configuration to help users determine optimal
times for making payments with lower fees. The configuration is managed
through environment variables and exposed via the GetInfo RPC.

Changes:
- Add MarketHour message type to protobuf service definition
- Add market hour configuration fields to Config struct
- Update covenant and covenantless services to handle market hour data
- Extend GetInfo RPC response to include market hour information
- Set default market hour period to 24 hours
- Initialize market hour fields after other service fields

Configuration:
- ARK_FIRST_MARKET_HOUR: Initial market hour timestamp
  (default: current server start time)
- ARK_MARKET_HOUR_PERIOD: Time between market hours in seconds
  (default: 86400)
- ARK_MARKET_HOUR_ROUND_LIFETIME: Round lifetime for market hours
  (default: 0, falls back to ARK_ROUND_LIFETIME)

* feat: add admin RPC for updating market hour configuration

Add new UpdateMarketHour RPC to AdminService for configuring market hour parameters:
- Add request/response messages to admin.proto
- Add UpdateMarketHour method to Service interface
- Implement market hour updates in covenant and covenantless services
- Add validation for market hour parameters
- Implement admin gRPC handler

The RPC allows updating:
- First market hour timestamp
- Market hour period
- Market hour round lifetime (optional, defaults to round lifetime

* feat: add market hour persistence with sqlite

- Add MarketHourRepo interface in domain layer
- Implement market hour persistence using SQLite
- Add market hour queries to sqlc/query.sql
- Update service initialization to load market hours from DB
- Add fallback to config values if no DB entry exists
- Update RepoManager interface with new MarketHourRepo method
2024-11-22 10:36:51 +01:00

210 lines
6.8 KiB
SQL

-- name: UpsertTransaction :exec
INSERT INTO tx (
tx, round_id, type, position, txid, tree_level, parent_txid, is_leaf
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
tx = EXCLUDED.tx,
round_id = EXCLUDED.round_id,
type = EXCLUDED.type,
position = EXCLUDED.position,
txid = EXCLUDED.txid,
tree_level = EXCLUDED.tree_level,
parent_txid = EXCLUDED.parent_txid,
is_leaf = EXCLUDED.is_leaf;
-- name: UpsertRound :exec
INSERT INTO round (
id,
starting_timestamp,
ending_timestamp,
ended, failed,
stage_code,
txid,
unsigned_tx,
connector_address,
dust_amount,
version,
swept
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
starting_timestamp = EXCLUDED.starting_timestamp,
ending_timestamp = EXCLUDED.ending_timestamp,
ended = EXCLUDED.ended,
failed = EXCLUDED.failed,
stage_code = EXCLUDED.stage_code,
txid = EXCLUDED.txid,
unsigned_tx = EXCLUDED.unsigned_tx,
connector_address = EXCLUDED.connector_address,
dust_amount = EXCLUDED.dust_amount,
version = EXCLUDED.version,
swept = EXCLUDED.swept;
-- name: UpsertPayment :exec
INSERT INTO payment (id, round_id) VALUES (?, ?)
ON CONFLICT(id) DO UPDATE SET round_id = EXCLUDED.round_id;
-- name: UpsertReceiver :exec
INSERT INTO receiver (payment_id, pubkey, onchain_address, amount) VALUES (?, ?, ?, ?)
ON CONFLICT(payment_id, pubkey, onchain_address) DO UPDATE SET
amount = EXCLUDED.amount,
pubkey = EXCLUDED.pubkey,
onchain_address = EXCLUDED.onchain_address;
-- name: UpdateVtxoPaymentId :exec
UPDATE vtxo SET payment_id = ? WHERE txid = ? AND vout = ?;
-- name: SelectRoundWithRoundId :many
SELECT sqlc.embed(round),
sqlc.embed(round_payment_vw),
sqlc.embed(round_tx_vw),
sqlc.embed(payment_receiver_vw),
sqlc.embed(payment_vtxo_vw)
FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
WHERE round.id = ?;
-- name: SelectRoundWithRoundTxId :many
SELECT sqlc.embed(round),
sqlc.embed(round_payment_vw),
sqlc.embed(round_tx_vw),
sqlc.embed(payment_receiver_vw),
sqlc.embed(payment_vtxo_vw)
FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
WHERE round.txid = ?;
-- name: SelectSweepableRounds :many
SELECT sqlc.embed(round),
sqlc.embed(round_payment_vw),
sqlc.embed(round_tx_vw),
sqlc.embed(payment_receiver_vw),
sqlc.embed(payment_vtxo_vw)
FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
WHERE round.swept = false AND round.ended = true AND round.failed = false;
-- name: SelectSweptRounds :many
SELECT sqlc.embed(round),
sqlc.embed(round_payment_vw),
sqlc.embed(round_tx_vw),
sqlc.embed(payment_receiver_vw),
sqlc.embed(payment_vtxo_vw)
FROM round
LEFT OUTER JOIN round_payment_vw ON round.id=round_payment_vw.round_id
LEFT OUTER JOIN round_tx_vw ON round.id=round_tx_vw.round_id
LEFT OUTER JOIN payment_receiver_vw ON round_payment_vw.id=payment_receiver_vw.payment_id
LEFT OUTER JOIN payment_vtxo_vw ON round_payment_vw.id=payment_vtxo_vw.payment_id
WHERE round.swept = true AND round.failed = false AND round.ended = true AND round.connector_address <> '';
-- name: SelectRoundIdsInRange :many
SELECT id FROM round WHERE starting_timestamp > ? AND starting_timestamp < ?;
-- name: SelectRoundIds :many
SELECT id FROM round;
-- name: UpsertVtxo :exec
INSERT INTO vtxo (txid, vout, pubkey, amount, pool_tx, spent_by, spent, redeemed, swept, expire_at, created_at, redeem_tx)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(txid, vout) DO UPDATE SET
pubkey = EXCLUDED.pubkey,
amount = EXCLUDED.amount,
pool_tx = EXCLUDED.pool_tx,
spent_by = EXCLUDED.spent_by,
spent = EXCLUDED.spent,
redeemed = EXCLUDED.redeemed,
swept = EXCLUDED.swept,
expire_at = EXCLUDED.expire_at,
created_at = EXCLUDED.created_at,
redeem_tx = EXCLUDED.redeem_tx;
-- name: SelectSweepableVtxos :many
SELECT sqlc.embed(vtxo) FROM vtxo
WHERE redeemed = false AND swept = false;
-- name: SelectNotRedeemedVtxos :many
SELECT sqlc.embed(vtxo) FROM vtxo
WHERE redeemed = false;
-- name: SelectNotRedeemedVtxosWithPubkey :many
SELECT sqlc.embed(vtxo) FROM vtxo
WHERE redeemed = false AND pubkey = ?;
-- name: SelectVtxoByOutpoint :one
SELECT sqlc.embed(vtxo) FROM vtxo
WHERE txid = ? AND vout = ?;
-- name: SelectVtxosByPoolTxid :many
SELECT sqlc.embed(vtxo) FROM vtxo
WHERE pool_tx = ?;
-- name: MarkVtxoAsRedeemed :exec
UPDATE vtxo SET redeemed = true WHERE txid = ? AND vout = ?;
-- name: MarkVtxoAsSwept :exec
UPDATE vtxo SET swept = true WHERE txid = ? AND vout = ?;
-- name: MarkVtxoAsSpent :exec
UPDATE vtxo SET spent = true, spent_by = ? WHERE txid = ? AND vout = ?;
-- name: UpdateVtxoExpireAt :exec
UPDATE vtxo SET expire_at = ? WHERE txid = ? AND vout = ?;
-- name: UpsertEntity :one
INSERT INTO entity (nostr_recipient)
VALUES (?)
ON CONFLICT(nostr_recipient) DO UPDATE SET
nostr_recipient = EXCLUDED.nostr_recipient
RETURNING id;
-- name: UpsertEntityVtxo :exec
INSERT INTO entity_vtxo (entity_id, vtxo_txid, vtxo_vout)
VALUES (?, ?, ?)
ON CONFLICT(entity_id, vtxo_txid, vtxo_vout) DO UPDATE SET
entity_id = EXCLUDED.entity_id;
-- name: SelectEntitiesByVtxo :many
SELECT sqlc.embed(entity_vw) FROM entity_vw
WHERE vtxo_txid = ? AND vtxo_vout = ?;
-- name: DeleteEntityVtxo :exec
DELETE FROM entity_vtxo WHERE entity_id = ?;
-- name: DeleteEntity :exec
DELETE FROM entity WHERE id = ?;
-- name: InsertNote :exec
INSERT INTO note (id) VALUES (?);
-- name: ContainsNote :one
SELECT EXISTS(SELECT 1 FROM note WHERE id = ?);
-- name: InsertMarketHour :one
INSERT INTO market_hour (
start_time,
end_time,
period,
round_interval,
updated_at
) VALUES (?, ?, ?, ?, ?)
RETURNING *;
-- name: UpdateMarketHour :one
UPDATE market_hour
SET start_time = ?,
end_time = ?,
period = ?,
round_interval = ?,
updated_at = ?
WHERE id = ?
RETURNING *;
-- name: GetLatestMarketHour :one
SELECT * FROM market_hour ORDER BY updated_at DESC LIMIT 1;