graph/db+sqldb: use batch fetching during channel&policy migration

Restructue the `migrateChannelsAndPolicies` function so that it does the
validation of migrated channels and policies in batches. So instead of
fetching channel and its policies individually after migrating it, we
wait for a minimum batch size to be reached and then validate a batch of
them together. This lets us make way fewer DB round trips.
This commit is contained in:
Elle Mouton committed 2025-08-14 08:00:06 +02:00
1 parent 03ef2740a6
commit 81c54611c1
5 files changed
+452 -81

No files matched your search

+179 -81
View File
@@ -394,6 +394,24 @@ func migrateSourceNode(ctx context.Context, kvdb kvdb.Backend,
return nil return nil
} }
// migChanInfo holds the information about a channel and its policies.
type migChanInfo struct {
// edge is the channel object as read from the KVDB source.
edge *models.ChannelEdgeInfo
// policy1 is the first channel policy for the channel as read from
// the KVDB source.
policy1 *models.ChannelEdgePolicy
// policy2 is the second channel policy for the channel as read
// from the KVDB source.
policy2 *models.ChannelEdgePolicy
// dbInfo holds location info (in the form of DB IDs) of the channel
// and its policies in the native-SQL destination.
dbInfo *dbChanInfo
}
// migrateChannelsAndPolicies migrates all channels and their policies // migrateChannelsAndPolicies migrates all channels and their policies
// from the KV backend to the SQL database. // from the KV backend to the SQL database.
func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig, func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
@@ -434,6 +452,11 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
return nil return nil
} }
// batch is used to collect migrated channel info that we will
// batch-validate. Each entry is indexed by the DB ID of the channel
// in the SQL database.
batch := make(map[int64]*migChanInfo, cfg.QueryCfg.MaxBatchSize)
// Iterate over each channel in the KV store and migrate it and its // Iterate over each channel in the KV store and migrate it and its
// policies to the SQL database. // policies to the SQL database.
err := forEachChannel(kvBackend, func(channel *models.ChannelEdgeInfo, err := forEachChannel(kvBackend, func(channel *models.ChannelEdgeInfo,
@@ -489,14 +512,47 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
channelCount++ channelCount++
chunk++ chunk++
err = migrateSingleChannel( // Migrate the channel info along with its policies.
ctx, cfg, sqlDB, channel, policy1, policy2, dbChanInfo, err := insertChannel(ctx, sqlDB, channel)
migChanPolicy,
)
if err != nil { if err != nil {
return fmt.Errorf("could not migrate channel %d: %w", return fmt.Errorf("could not insert record for "+
"channel %d in SQL store: %w", scid, err)
}
// Now, migrate the two channel policies for the channel.
err = migChanPolicy(policy1)
if err != nil {
return fmt.Errorf("could not migrate policy1(%d): %w",
scid, err) scid, err)
} }
err = migChanPolicy(policy2)
if err != nil {
return fmt.Errorf("could not migrate policy2(%d): %w",
scid, err)
}
// Collect the migrated channel info and policies in a batch for
// later validation.
batch[dbChanInfo.channelID] = &migChanInfo{
edge: channel,
policy1: policy1,
policy2: policy2,
dbInfo: dbChanInfo,
}
if len(batch) >= cfg.QueryCfg.MaxBatchSize {
// Do batch validation.
err := validateMigratedChannels(ctx, cfg, sqlDB, batch)
if err != nil {
return fmt.Errorf("could not validate "+
"channel batch: %w", err)
}
batch = make(
map[int64]*migChanInfo,
cfg.QueryCfg.MaxBatchSize,
)
}
s.Do(func() { s.Do(func() {
elapsed := time.Since(t0).Seconds() elapsed := time.Since(t0).Seconds()
@@ -518,6 +574,17 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
err) err)
} }
if len(batch) > 0 {
// Do a final batch validation for any remaining channels.
err := validateMigratedChannels(ctx, cfg, sqlDB, batch)
if err != nil {
return fmt.Errorf("could not validate final channel "+
"batch: %w", err)
}
batch = make(map[int64]*migChanInfo, cfg.QueryCfg.MaxBatchSize)
}
log.Infof("Migrated %d channels and %d policies from KV to SQL "+ log.Infof("Migrated %d channels and %d policies from KV to SQL "+
"(skipped %d channels and %d policies due to invalid TLV "+ "(skipped %d channels and %d policies due to invalid TLV "+
"streams)", channelCount, policyCount, skippedChanCount, "streams)", channelCount, policyCount, skippedChanCount,
@@ -526,70 +593,142 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
return nil return nil
} }
func migrateSingleChannel(ctx context.Context, cfg *SQLStoreConfig, // validateMigratedChannels validates the channels in the batch after they have
sqlDB SQLQueries, channel *models.ChannelEdgeInfo, // been migrated to the SQL database. It batch fetches all channels by their IDs
policy1, policy2 *models.ChannelEdgePolicy, // and compares the migrated channels and their policies with the original ones
migChanPolicy func(*models.ChannelEdgePolicy) error) error { // to ensure they match using batch construction patterns.
func validateMigratedChannels(ctx context.Context, cfg *SQLStoreConfig,
sqlDB SQLQueries, batch map[int64]*migChanInfo) error {
scid := channel.ChannelID // Convert batch keys (DB IDs) to an int slice for the batch query.
dbChanIDs := make([]int64, 0, len(batch))
// First, migrate the channel info along with its policies. for id := range batch {
dbChanInfo, err := insertChannel(ctx, sqlDB, channel) dbChanIDs = append(dbChanIDs, id)
if err != nil {
return fmt.Errorf("could not insert record for channel %d "+
"in SQL store: %w", scid, err)
} }
// Now, migrate the two channel policies. // Batch fetch all channels with their policies.
err = migChanPolicy(policy1) rows, err := sqlDB.GetChannelsByIDs(ctx, dbChanIDs)
if err != nil { if err != nil {
return fmt.Errorf("could not migrate policy1(%d): %w", scid, return fmt.Errorf("could not batch get channels by IDs: %w",
err)
}
err = migChanPolicy(policy2)
if err != nil {
return fmt.Errorf("could not migrate policy2(%d): %w", scid,
err) err)
} }
// Now, fetch the channel and its policies from the SQL DB. // Sanity check that the same number of channels were returned
row, err := sqlDB.GetChannelBySCIDWithPolicies( // as requested.
ctx, sqlc.GetChannelBySCIDWithPoliciesParams{ if len(rows) != len(dbChanIDs) {
Scid: channelIDToBytes(scid), return fmt.Errorf("expected to fetch %d channels, "+
Version: int16(ProtocolV1), "but got %d", len(dbChanIDs), len(rows))
}, }
// Collect all policy IDs needed for batch data loading.
dbPolicyIDs := make([]int64, 0, len(dbChanIDs)*2)
for _, row := range rows {
scid := byteOrder.Uint64(row.GraphChannel.Scid)
dbPol1, dbPol2, err := extractChannelPolicies(row)
if err != nil {
return fmt.Errorf("could not extract channel policies"+
" for SCID %d: %w", scid, err)
}
if dbPol1 != nil {
dbPolicyIDs = append(dbPolicyIDs, dbPol1.ID)
}
if dbPol2 != nil {
dbPolicyIDs = append(dbPolicyIDs, dbPol2.ID)
}
}
// Batch load all channel and policy data (features, extras).
batchData, err := batchLoadChannelData(
ctx, cfg.QueryCfg, sqlDB, dbChanIDs, dbPolicyIDs,
) )
if err != nil { if err != nil {
return fmt.Errorf("could not get channel by SCID(%d): %w", scid, return fmt.Errorf("could not batch load channel and policy "+
err) "data: %w", err)
} }
// Validate each channel in the batch using pre-loaded data.
for _, row := range rows {
kvdbChan, ok := batch[row.GraphChannel.ID]
if !ok {
return fmt.Errorf("channel with ID %d not found "+
"in batch", row.GraphChannel.ID)
}
scid := byteOrder.Uint64(row.GraphChannel.Scid)
err = validateMigratedChannelWithBatchData(
cfg, scid, kvdbChan, row, batchData,
)
if err != nil {
return fmt.Errorf("channel %d validation failed "+
"after migration: %w", scid, err)
}
}
return nil
}
// validateMigratedChannelWithBatchData validates a single migrated channel
// using pre-fetched batch data for optimal performance.
func validateMigratedChannelWithBatchData(cfg *SQLStoreConfig,
scid uint64, info *migChanInfo, row sqlc.GetChannelsByIDsRow,
batchData *batchChannelData) error {
dbChanInfo := info.dbInfo
channel := info.edge
// Assert that the DB IDs for the channel and nodes are as expected // Assert that the DB IDs for the channel and nodes are as expected
// given the inserted channel info. // given the inserted channel info.
err = sqldb.CompareRecords( err := sqldb.CompareRecords(
dbChanInfo.channelID, row.GraphChannel.ID, "channel DB ID", dbChanInfo.channelID, row.GraphChannel.ID, "channel DB ID",
) )
if err != nil { if err != nil {
return err return err
} }
err = sqldb.CompareRecords( err = sqldb.CompareRecords(
dbChanInfo.node1ID, row.GraphNode.ID, "node1 DB ID", dbChanInfo.node1ID, row.Node1ID, "node1 DB ID",
) )
if err != nil { if err != nil {
return err return err
} }
err = sqldb.CompareRecords( err = sqldb.CompareRecords(
dbChanInfo.node2ID, row.GraphNode_2.ID, "node2 DB ID", dbChanInfo.node2ID, row.Node2ID, "node2 DB ID",
) )
if err != nil { if err != nil {
return err return err
} }
migChan, migPol1, migPol2, err := getAndBuildChanAndPolicies( // Build node vertices from the row data.
ctx, cfg, sqlDB, row, node1, node2, err := buildNodeVertices(
row.Node1PubKey, row.Node2PubKey,
) )
if err != nil { if err != nil {
return fmt.Errorf("could not build migrated channel and "+ return err
}
// Build channel info using batch data.
migChan, err := buildEdgeInfoWithBatchData(
cfg.ChainHash, row.GraphChannel, node1, node2, batchData,
)
if err != nil {
return fmt.Errorf("could not build migrated channel info: %w",
err)
}
// Extract channel policies from the row.
dbPol1, dbPol2, err := extractChannelPolicies(row)
if err != nil {
return fmt.Errorf("could not extract channel policies: %w", err)
}
// Build channel policies using batch data.
migPol1, migPol2, err := buildChanPoliciesWithBatchData(
dbPol1, dbPol2, scid, node1, node2, batchData,
)
if err != nil {
return fmt.Errorf("could not build migrated channel "+
"policies: %w", err) "policies: %w", err)
} }
@@ -639,13 +778,13 @@ func migrateSingleChannel(ctx context.Context, cfg *SQLStoreConfig,
) )
} }
err = checkPolicy(policy1, migPol1) err = checkPolicy(info.policy1, migPol1)
if err != nil { if err != nil {
return fmt.Errorf("policy1 mismatch for channel %d: %w", scid, return fmt.Errorf("policy1 mismatch for channel %d: %w", scid,
err) err)
} }
err = checkPolicy(policy2, migPol2) err = checkPolicy(info.policy2, migPol2)
if err != nil { if err != nil {
return fmt.Errorf("policy2 mismatch for channel %d: %w", scid, return fmt.Errorf("policy2 mismatch for channel %d: %w", scid,
err) err)
@@ -778,47 +917,6 @@ func migratePruneLog(ctx context.Context, kvBackend kvdb.Backend,
return nil return nil
} }
// getAndBuildChanAndPolicies is a helper that builds the channel edge info
// and policies from the given row returned by the SQL query
// GetChannelBySCIDWithPolicies.
func getAndBuildChanAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
db SQLQueries,
row sqlc.GetChannelBySCIDWithPoliciesRow) (*models.ChannelEdgeInfo,
*models.ChannelEdgePolicy, *models.ChannelEdgePolicy, error) {
node1, node2, err := buildNodeVertices(
row.GraphNode.PubKey, row.GraphNode_2.PubKey,
)
if err != nil {
return nil, nil, nil, err
}
edge, err := getAndBuildEdgeInfo(
ctx, cfg, db, row.GraphChannel, node1, node2,
)
if err != nil {
return nil, nil, nil, fmt.Errorf("unable to build channel "+
"info: %w", err)
}
dbPol1, dbPol2, err := extractChannelPolicies(row)
if err != nil {
return nil, nil, nil, fmt.Errorf("unable to extract channel "+
"policies: %w", err)
}
policy1, policy2, err := getAndBuildChanPolicies(
ctx, cfg.QueryCfg, db, dbPol1, dbPol2, edge.ChannelID, node1,
node2,
)
if err != nil {
return nil, nil, nil, fmt.Errorf("unable to build channel "+
"policies: %w", err)
}
return edge, policy1, policy2, nil
}
// forEachPruneLogEntry iterates over each prune log entry in the KV // forEachPruneLogEntry iterates over each prune log entry in the KV
// backend and calls the provided callback function for each entry. // backend and calls the provided callback function for each entry.
func forEachPruneLogEntry(db kvdb.Backend, cb func(height uint32, func forEachPruneLogEntry(db kvdb.Backend, cb func(height uint32,
+46
View File
@@ -98,6 +98,7 @@ type SQLQueries interface {
GetChannelsBySCIDRange(ctx context.Context, arg sqlc.GetChannelsBySCIDRangeParams) ([]sqlc.GetChannelsBySCIDRangeRow, error) GetChannelsBySCIDRange(ctx context.Context, arg sqlc.GetChannelsBySCIDRangeParams) ([]sqlc.GetChannelsBySCIDRangeRow, error)
GetChannelBySCIDWithPolicies(ctx context.Context, arg sqlc.GetChannelBySCIDWithPoliciesParams) (sqlc.GetChannelBySCIDWithPoliciesRow, error) GetChannelBySCIDWithPolicies(ctx context.Context, arg sqlc.GetChannelBySCIDWithPoliciesParams) (sqlc.GetChannelBySCIDWithPoliciesRow, error)
GetChannelsBySCIDWithPolicies(ctx context.Context, arg sqlc.GetChannelsBySCIDWithPoliciesParams) ([]sqlc.GetChannelsBySCIDWithPoliciesRow, error) GetChannelsBySCIDWithPolicies(ctx context.Context, arg sqlc.GetChannelsBySCIDWithPoliciesParams) ([]sqlc.GetChannelsBySCIDWithPoliciesRow, error)
GetChannelsByIDs(ctx context.Context, ids []int64) ([]sqlc.GetChannelsByIDsRow, error)
GetChannelAndNodesBySCID(ctx context.Context, arg sqlc.GetChannelAndNodesBySCIDParams) (sqlc.GetChannelAndNodesBySCIDRow, error) GetChannelAndNodesBySCID(ctx context.Context, arg sqlc.GetChannelAndNodesBySCIDParams) (sqlc.GetChannelAndNodesBySCIDRow, error)
HighestSCID(ctx context.Context, version int16) ([]byte, error) HighestSCID(ctx context.Context, version int16) ([]byte, error)
ListChannelsByNodeID(ctx context.Context, arg sqlc.ListChannelsByNodeIDParams) ([]sqlc.ListChannelsByNodeIDRow, error) ListChannelsByNodeID(ctx context.Context, arg sqlc.ListChannelsByNodeIDParams) ([]sqlc.ListChannelsByNodeIDRow, error)
@@ -4519,6 +4520,51 @@ func extractChannelPolicies(row any) (*sqlc.GraphChannelPolicy,
} }
return policy1, policy2, nil return policy1, policy2, nil
case sqlc.GetChannelsByIDsRow:
if r.Policy1ID.Valid {
policy1 = &sqlc.GraphChannelPolicy{
ID: r.Policy1ID.Int64,
Version: r.Policy1Version.Int16,
ChannelID: r.GraphChannel.ID,
NodeID: r.Policy1NodeID.Int64,
Timelock: r.Policy1Timelock.Int32,
FeePpm: r.Policy1FeePpm.Int64,
BaseFeeMsat: r.Policy1BaseFeeMsat.Int64,
MinHtlcMsat: r.Policy1MinHtlcMsat.Int64,
MaxHtlcMsat: r.Policy1MaxHtlcMsat,
LastUpdate: r.Policy1LastUpdate,
InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat,
Disabled: r.Policy1Disabled,
MessageFlags: r.Policy1MessageFlags,
ChannelFlags: r.Policy1ChannelFlags,
Signature: r.Policy1Signature,
}
}
if r.Policy2ID.Valid {
policy2 = &sqlc.GraphChannelPolicy{
ID: r.Policy2ID.Int64,
Version: r.Policy2Version.Int16,
ChannelID: r.GraphChannel.ID,
NodeID: r.Policy2NodeID.Int64,
Timelock: r.Policy2Timelock.Int32,
FeePpm: r.Policy2FeePpm.Int64,
BaseFeeMsat: r.Policy2BaseFeeMsat.Int64,
MinHtlcMsat: r.Policy2MinHtlcMsat.Int64,
MaxHtlcMsat: r.Policy2MaxHtlcMsat,
LastUpdate: r.Policy2LastUpdate,
InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat,
InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat,
Disabled: r.Policy2Disabled,
MessageFlags: r.Policy2MessageFlags,
ChannelFlags: r.Policy2ChannelFlags,
Signature: r.Policy2Signature,
}
}
return policy1, policy2, nil
default: default:
return nil, nil, fmt.Errorf("unexpected row type in "+ return nil, nil, fmt.Errorf("unexpected row type in "+
"extractChannelPolicies: %T", r) "extractChannelPolicies: %T", r)
+173
View File
@@ -873,6 +873,179 @@ func (q *Queries) GetChannelPolicyExtraTypesBatch(ctx context.Context, policyIds
return items, nil return items, nil
} }
const getChannelsByIDs = `-- name: GetChannelsByIDs :many
SELECT
c.id, c.version, c.scid, c.node_id_1, c.node_id_2, c.outpoint, c.capacity, c.bitcoin_key_1, c.bitcoin_key_2, c.node_1_signature, c.node_2_signature, c.bitcoin_1_signature, c.bitcoin_2_signature,
-- Minimal node data.
n1.id AS node1_id,
n1.pub_key AS node1_pub_key,
n2.id AS node2_id,
n2.pub_key AS node2_pub_key,
-- Policy 1
cp1.id AS policy1_id,
cp1.node_id AS policy1_node_id,
cp1.version AS policy1_version,
cp1.timelock AS policy1_timelock,
cp1.fee_ppm AS policy1_fee_ppm,
cp1.base_fee_msat AS policy1_base_fee_msat,
cp1.min_htlc_msat AS policy1_min_htlc_msat,
cp1.max_htlc_msat AS policy1_max_htlc_msat,
cp1.last_update AS policy1_last_update,
cp1.disabled AS policy1_disabled,
cp1.inbound_base_fee_msat AS policy1_inbound_base_fee_msat,
cp1.inbound_fee_rate_milli_msat AS policy1_inbound_fee_rate_milli_msat,
cp1.message_flags AS policy1_message_flags,
cp1.channel_flags AS policy1_channel_flags,
cp1.signature AS policy1_signature,
-- Policy 2
cp2.id AS policy2_id,
cp2.node_id AS policy2_node_id,
cp2.version AS policy2_version,
cp2.timelock AS policy2_timelock,
cp2.fee_ppm AS policy2_fee_ppm,
cp2.base_fee_msat AS policy2_base_fee_msat,
cp2.min_htlc_msat AS policy2_min_htlc_msat,
cp2.max_htlc_msat AS policy2_max_htlc_msat,
cp2.last_update AS policy2_last_update,
cp2.disabled AS policy2_disabled,
cp2.inbound_base_fee_msat AS policy2_inbound_base_fee_msat,
cp2.inbound_fee_rate_milli_msat AS policy2_inbound_fee_rate_milli_msat,
cp2.message_flags AS policy2_message_flags,
cp2.channel_flags AS policy2_channel_flags,
cp2.signature AS policy2_signature
FROM graph_channels c
JOIN graph_nodes n1 ON c.node_id_1 = n1.id
JOIN graph_nodes n2 ON c.node_id_2 = n2.id
LEFT JOIN graph_channel_policies cp1
ON cp1.channel_id = c.id AND cp1.node_id = c.node_id_1 AND cp1.version = c.version
LEFT JOIN graph_channel_policies cp2
ON cp2.channel_id = c.id AND cp2.node_id = c.node_id_2 AND cp2.version = c.version
WHERE c.id IN (/*SLICE:ids*/?)
`
type GetChannelsByIDsRow struct {
GraphChannel GraphChannel
Node1ID int64
Node1PubKey []byte
Node2ID int64
Node2PubKey []byte
Policy1ID sql.NullInt64
Policy1NodeID sql.NullInt64
Policy1Version sql.NullInt16
Policy1Timelock sql.NullInt32
Policy1FeePpm sql.NullInt64
Policy1BaseFeeMsat sql.NullInt64
Policy1MinHtlcMsat sql.NullInt64
Policy1MaxHtlcMsat sql.NullInt64
Policy1LastUpdate sql.NullInt64
Policy1Disabled sql.NullBool
Policy1InboundBaseFeeMsat sql.NullInt64
Policy1InboundFeeRateMilliMsat sql.NullInt64
Policy1MessageFlags sql.NullInt16
Policy1ChannelFlags sql.NullInt16
Policy1Signature []byte
Policy2ID sql.NullInt64
Policy2NodeID sql.NullInt64
Policy2Version sql.NullInt16
Policy2Timelock sql.NullInt32
Policy2FeePpm sql.NullInt64
Policy2BaseFeeMsat sql.NullInt64
Policy2MinHtlcMsat sql.NullInt64
Policy2MaxHtlcMsat sql.NullInt64
Policy2LastUpdate sql.NullInt64
Policy2Disabled sql.NullBool
Policy2InboundBaseFeeMsat sql.NullInt64
Policy2InboundFeeRateMilliMsat sql.NullInt64
Policy2MessageFlags sql.NullInt16
Policy2ChannelFlags sql.NullInt16
Policy2Signature []byte
}
func (q *Queries) GetChannelsByIDs(ctx context.Context, ids []int64) ([]GetChannelsByIDsRow, error) {
query := getChannelsByIDs
var queryParams []interface{}
if len(ids) > 0 {
for _, v := range ids {
queryParams = append(queryParams, v)
}
query = strings.Replace(query, "/*SLICE:ids*/?", makeQueryParams(len(queryParams), len(ids)), 1)
} else {
query = strings.Replace(query, "/*SLICE:ids*/?", "NULL", 1)
}
rows, err := q.db.QueryContext(ctx, query, queryParams...)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetChannelsByIDsRow
for rows.Next() {
var i GetChannelsByIDsRow
if err := rows.Scan(
&i.GraphChannel.ID,
&i.GraphChannel.Version,
&i.GraphChannel.Scid,
&i.GraphChannel.NodeID1,
&i.GraphChannel.NodeID2,
&i.GraphChannel.Outpoint,
&i.GraphChannel.Capacity,
&i.GraphChannel.BitcoinKey1,
&i.GraphChannel.BitcoinKey2,
&i.GraphChannel.Node1Signature,
&i.GraphChannel.Node2Signature,
&i.GraphChannel.Bitcoin1Signature,
&i.GraphChannel.Bitcoin2Signature,
&i.Node1ID,
&i.Node1PubKey,
&i.Node2ID,
&i.Node2PubKey,
&i.Policy1ID,
&i.Policy1NodeID,
&i.Policy1Version,
&i.Policy1Timelock,
&i.Policy1FeePpm,
&i.Policy1BaseFeeMsat,
&i.Policy1MinHtlcMsat,
&i.Policy1MaxHtlcMsat,
&i.Policy1LastUpdate,
&i.Policy1Disabled,
&i.Policy1InboundBaseFeeMsat,
&i.Policy1InboundFeeRateMilliMsat,
&i.Policy1MessageFlags,
&i.Policy1ChannelFlags,
&i.Policy1Signature,
&i.Policy2ID,
&i.Policy2NodeID,
&i.Policy2Version,
&i.Policy2Timelock,
&i.Policy2FeePpm,
&i.Policy2BaseFeeMsat,
&i.Policy2MinHtlcMsat,
&i.Policy2MaxHtlcMsat,
&i.Policy2LastUpdate,
&i.Policy2Disabled,
&i.Policy2InboundBaseFeeMsat,
&i.Policy2InboundFeeRateMilliMsat,
&i.Policy2MessageFlags,
&i.Policy2ChannelFlags,
&i.Policy2Signature,
); 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 getChannelsByOutpoints = `-- name: GetChannelsByOutpoints :many const getChannelsByOutpoints = `-- name: GetChannelsByOutpoints :many
SELECT SELECT
c.id, c.version, c.scid, c.node_id_1, c.node_id_2, c.outpoint, c.capacity, c.bitcoin_key_1, c.bitcoin_key_2, c.node_1_signature, c.node_2_signature, c.bitcoin_1_signature, c.bitcoin_2_signature, c.id, c.version, c.scid, c.node_id_1, c.node_id_2, c.outpoint, c.capacity, c.bitcoin_key_1, c.bitcoin_key_2, c.node_1_signature, c.node_2_signature, c.bitcoin_1_signature, c.bitcoin_2_signature,
+1
View File
@@ -42,6 +42,7 @@ type Querier interface {
GetChannelFeaturesBatch(ctx context.Context, chanIds []int64) ([]GraphChannelFeature, error) GetChannelFeaturesBatch(ctx context.Context, chanIds []int64) ([]GraphChannelFeature, error)
GetChannelPolicyByChannelAndNode(ctx context.Context, arg GetChannelPolicyByChannelAndNodeParams) (GraphChannelPolicy, error) GetChannelPolicyByChannelAndNode(ctx context.Context, arg GetChannelPolicyByChannelAndNodeParams) (GraphChannelPolicy, error)
GetChannelPolicyExtraTypesBatch(ctx context.Context, policyIds []int64) ([]GetChannelPolicyExtraTypesBatchRow, error) GetChannelPolicyExtraTypesBatch(ctx context.Context, policyIds []int64) ([]GetChannelPolicyExtraTypesBatchRow, error)
GetChannelsByIDs(ctx context.Context, ids []int64) ([]GetChannelsByIDsRow, error)
GetChannelsByOutpoints(ctx context.Context, outpoints []string) ([]GetChannelsByOutpointsRow, error) GetChannelsByOutpoints(ctx context.Context, outpoints []string) ([]GetChannelsByOutpointsRow, error)
GetChannelsByPolicyLastUpdateRange(ctx context.Context, arg GetChannelsByPolicyLastUpdateRangeParams) ([]GetChannelsByPolicyLastUpdateRangeRow, error) GetChannelsByPolicyLastUpdateRange(ctx context.Context, arg GetChannelsByPolicyLastUpdateRangeParams) ([]GetChannelsByPolicyLastUpdateRangeRow, error)
GetChannelsBySCIDRange(ctx context.Context, arg GetChannelsBySCIDRangeParams) ([]GetChannelsBySCIDRangeRow, error) GetChannelsBySCIDRange(ctx context.Context, arg GetChannelsBySCIDRangeParams) ([]GetChannelsBySCIDRangeRow, error)
+53
View File
@@ -335,6 +335,59 @@ WHERE
c.version = @version c.version = @version
AND c.scid IN (sqlc.slice('scids')/*SLICE:scids*/); AND c.scid IN (sqlc.slice('scids')/*SLICE:scids*/);
-- name: GetChannelsByIDs :many
SELECT
sqlc.embed(c),
-- Minimal node data.
n1.id AS node1_id,
n1.pub_key AS node1_pub_key,
n2.id AS node2_id,
n2.pub_key AS node2_pub_key,
-- Policy 1
cp1.id AS policy1_id,
cp1.node_id AS policy1_node_id,
cp1.version AS policy1_version,
cp1.timelock AS policy1_timelock,
cp1.fee_ppm AS policy1_fee_ppm,
cp1.base_fee_msat AS policy1_base_fee_msat,
cp1.min_htlc_msat AS policy1_min_htlc_msat,
cp1.max_htlc_msat AS policy1_max_htlc_msat,
cp1.last_update AS policy1_last_update,
cp1.disabled AS policy1_disabled,
cp1.inbound_base_fee_msat AS policy1_inbound_base_fee_msat,
cp1.inbound_fee_rate_milli_msat AS policy1_inbound_fee_rate_milli_msat,
cp1.message_flags AS policy1_message_flags,
cp1.channel_flags AS policy1_channel_flags,
cp1.signature AS policy1_signature,
-- Policy 2
cp2.id AS policy2_id,
cp2.node_id AS policy2_node_id,
cp2.version AS policy2_version,
cp2.timelock AS policy2_timelock,
cp2.fee_ppm AS policy2_fee_ppm,
cp2.base_fee_msat AS policy2_base_fee_msat,
cp2.min_htlc_msat AS policy2_min_htlc_msat,
cp2.max_htlc_msat AS policy2_max_htlc_msat,
cp2.last_update AS policy2_last_update,
cp2.disabled AS policy2_disabled,
cp2.inbound_base_fee_msat AS policy2_inbound_base_fee_msat,
cp2.inbound_fee_rate_milli_msat AS policy2_inbound_fee_rate_milli_msat,
cp2.message_flags AS policy2_message_flags,
cp2.channel_flags AS policy2_channel_flags,
cp2.signature AS policy2_signature
FROM graph_channels c
JOIN graph_nodes n1 ON c.node_id_1 = n1.id
JOIN graph_nodes n2 ON c.node_id_2 = n2.id
LEFT JOIN graph_channel_policies cp1
ON cp1.channel_id = c.id AND cp1.node_id = c.node_id_1 AND cp1.version = c.version
LEFT JOIN graph_channel_policies cp2
ON cp2.channel_id = c.id AND cp2.node_id = c.node_id_2 AND cp2.version = c.version
WHERE c.id IN (sqlc.slice('ids')/*SLICE:ids*/);
-- name: GetChannelsByPolicyLastUpdateRange :many -- name: GetChannelsByPolicyLastUpdateRange :many
SELECT SELECT
sqlc.embed(c), sqlc.embed(c),