Merge pull request #10161 from ellemouton/graphRetry
graph/db+sqldb: Make the SQL migration retry-safe/idempotent
This commit is contained in:
6 files changed
+891
-160
No files matched your search
+322
-17
@@ -273,7 +273,7 @@ func migrateNodes(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
// production.
|
// production.
|
||||||
|
|
||||||
// Write the node to the SQL database.
|
// Write the node to the SQL database.
|
||||||
id, err := upsertNode(ctx, sqlDB, node)
|
id, err := insertNodeSQLMig(ctx, sqlDB, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not persist node(%x): %w", pub,
|
return fmt.Errorf("could not persist node(%x): %w", pub,
|
||||||
err)
|
err)
|
||||||
@@ -303,8 +303,11 @@ func migrateNodes(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}, func() {
|
}, func() {
|
||||||
// No reset is needed since if a retry occurs, the entire
|
count = 0
|
||||||
// migration will be retried from the start.
|
chunk = 0
|
||||||
|
skipped = 0
|
||||||
|
t0 = time.Now()
|
||||||
|
batch = make(map[int64]*models.LightningNode, cfg.MaxBatchSize)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate nodes: %w", err)
|
return fmt.Errorf("could not migrate nodes: %w", err)
|
||||||
@@ -437,7 +440,9 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
|
|||||||
Interval: 10 * time.Second,
|
Interval: 10 * time.Second,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
migChanPolicy := func(policy *models.ChannelEdgePolicy) error {
|
migChanPolicy := func(dbChanInfo *dbChanInfo,
|
||||||
|
policy *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
// If the policy is nil, we can skip it.
|
// If the policy is nil, we can skip it.
|
||||||
if policy == nil {
|
if policy == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -451,7 +456,7 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
|
|||||||
|
|
||||||
policyCount++
|
policyCount++
|
||||||
|
|
||||||
_, _, _, err := updateChanEdgePolicy(ctx, sqlDB, policy)
|
err := insertChanEdgePolicyMig(ctx, sqlDB, dbChanInfo, policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate channel "+
|
return fmt.Errorf("could not migrate channel "+
|
||||||
"policy %d: %w", policy.ChannelID, err)
|
"policy %d: %w", policy.ChannelID, err)
|
||||||
@@ -521,19 +526,19 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
|
|||||||
chunk++
|
chunk++
|
||||||
|
|
||||||
// Migrate the channel info along with its policies.
|
// Migrate the channel info along with its policies.
|
||||||
dbChanInfo, err := insertChannel(ctx, sqlDB, channel)
|
dbChanInfo, err := insertChannelMig(ctx, sqlDB, channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not insert record for "+
|
return fmt.Errorf("could not insert record for "+
|
||||||
"channel %d in SQL store: %w", scid, err)
|
"channel %d in SQL store: %w", scid, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, migrate the two channel policies for the channel.
|
// Now, migrate the two channel policies for the channel.
|
||||||
err = migChanPolicy(policy1)
|
err = migChanPolicy(dbChanInfo, policy1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate policy1(%d): %w",
|
return fmt.Errorf("could not migrate policy1(%d): %w",
|
||||||
scid, err)
|
scid, err)
|
||||||
}
|
}
|
||||||
err = migChanPolicy(policy2)
|
err = migChanPolicy(dbChanInfo, policy2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate policy2(%d): %w",
|
return fmt.Errorf("could not migrate policy2(%d): %w",
|
||||||
scid, err)
|
scid, err)
|
||||||
@@ -574,8 +579,13 @@ func migrateChannelsAndPolicies(ctx context.Context, cfg *SQLStoreConfig,
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}, func() {
|
}, func() {
|
||||||
// No reset is needed since if a retry occurs, the entire
|
channelCount = 0
|
||||||
// migration will be retried from the start.
|
policyCount = 0
|
||||||
|
chunk = 0
|
||||||
|
skippedChanCount = 0
|
||||||
|
skippedPolicyCount = 0
|
||||||
|
t0 = time.Now()
|
||||||
|
batch = make(map[int64]*migChanInfo, cfg.QueryCfg.MaxBatchSize)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate channels and policies: %w",
|
return fmt.Errorf("could not migrate channels and policies: %w",
|
||||||
@@ -923,6 +933,14 @@ func migratePruneLog(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
func() {
|
||||||
|
count = 0
|
||||||
|
chunk = 0
|
||||||
|
t0 = time.Now()
|
||||||
|
batch = make(
|
||||||
|
map[uint32]chainhash.Hash, cfg.MaxBatchSize,
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate prune log: %w", err)
|
return fmt.Errorf("could not migrate prune log: %w", err)
|
||||||
@@ -975,7 +993,7 @@ func migratePruneLog(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
// 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,
|
||||||
hash *chainhash.Hash) error) error {
|
hash *chainhash.Hash) error, reset func()) error {
|
||||||
|
|
||||||
return kvdb.View(db, func(tx kvdb.RTx) error {
|
return kvdb.View(db, func(tx kvdb.RTx) error {
|
||||||
metaBucket := tx.ReadBucket(graphMetaBucket)
|
metaBucket := tx.ReadBucket(graphMetaBucket)
|
||||||
@@ -997,7 +1015,7 @@ func forEachPruneLogEntry(db kvdb.Backend, cb func(height uint32,
|
|||||||
|
|
||||||
return cb(blockHeight, &blockHash)
|
return cb(blockHeight, &blockHash)
|
||||||
})
|
})
|
||||||
}, func() {})
|
}, reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrateClosedSCIDIndex migrates the closed SCID index from the KV backend to
|
// migrateClosedSCIDIndex migrates the closed SCID index from the KV backend to
|
||||||
@@ -1091,7 +1109,14 @@ func migrateClosedSCIDIndex(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := forEachClosedSCID(kvBackend, migrateSingleClosedSCID)
|
err := forEachClosedSCID(
|
||||||
|
kvBackend, migrateSingleClosedSCID, func() {
|
||||||
|
count = 0
|
||||||
|
chunk = 0
|
||||||
|
t0 = time.Now()
|
||||||
|
batch = make([][]byte, 0, cfg.MaxBatchSize)
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate closed SCID index: %w",
|
return fmt.Errorf("could not migrate closed SCID index: %w",
|
||||||
err)
|
err)
|
||||||
@@ -1270,6 +1295,11 @@ func migrateZombieIndex(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
}, func() {
|
||||||
|
count = 0
|
||||||
|
chunk = 0
|
||||||
|
t0 = time.Now()
|
||||||
|
batch = make(map[uint64]*zombieEntry, cfg.MaxBatchSize)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not migrate zombie index: %w", err)
|
return fmt.Errorf("could not migrate zombie index: %w", err)
|
||||||
@@ -1293,7 +1323,7 @@ func migrateZombieIndex(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
// forEachZombieEntry iterates over each zombie channel entry in the
|
// forEachZombieEntry iterates over each zombie channel entry in the
|
||||||
// KV backend and calls the provided callback function for each entry.
|
// KV backend and calls the provided callback function for each entry.
|
||||||
func forEachZombieEntry(db kvdb.Backend, cb func(chanID uint64, pubKey1,
|
func forEachZombieEntry(db kvdb.Backend, cb func(chanID uint64, pubKey1,
|
||||||
pubKey2 [33]byte) error) error {
|
pubKey2 [33]byte) error, reset func()) error {
|
||||||
|
|
||||||
return kvdb.View(db, func(tx kvdb.RTx) error {
|
return kvdb.View(db, func(tx kvdb.RTx) error {
|
||||||
edges := tx.ReadBucket(edgeBucket)
|
edges := tx.ReadBucket(edgeBucket)
|
||||||
@@ -1312,13 +1342,13 @@ func forEachZombieEntry(db kvdb.Backend, cb func(chanID uint64, pubKey1,
|
|||||||
|
|
||||||
return cb(byteOrder.Uint64(k), pubKey1, pubKey2)
|
return cb(byteOrder.Uint64(k), pubKey1, pubKey2)
|
||||||
})
|
})
|
||||||
}, func() {})
|
}, reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// forEachClosedSCID iterates over each closed SCID in the KV backend and calls
|
// forEachClosedSCID iterates over each closed SCID in the KV backend and calls
|
||||||
// the provided callback function for each SCID.
|
// the provided callback function for each SCID.
|
||||||
func forEachClosedSCID(db kvdb.Backend,
|
func forEachClosedSCID(db kvdb.Backend,
|
||||||
cb func(lnwire.ShortChannelID) error) error {
|
cb func(lnwire.ShortChannelID) error, reset func()) error {
|
||||||
|
|
||||||
return kvdb.View(db, func(tx kvdb.RTx) error {
|
return kvdb.View(db, func(tx kvdb.RTx) error {
|
||||||
closedScids := tx.ReadBucket(closedScidBucket)
|
closedScids := tx.ReadBucket(closedScidBucket)
|
||||||
@@ -1331,5 +1361,280 @@ func forEachClosedSCID(db kvdb.Backend,
|
|||||||
byteOrder.Uint64(k),
|
byteOrder.Uint64(k),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}, func() {})
|
}, reset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertNodeSQLMig inserts the node record into the database during the graph
|
||||||
|
// SQL migration. No error is expected if the node already exists. Unlike the
|
||||||
|
// main upsertNode function, this function does not require that a new node
|
||||||
|
// update have a newer timestamp than the existing one. This is because we want
|
||||||
|
// the migration to be idempotent and dont want to error out if we re-insert the
|
||||||
|
// exact same node.
|
||||||
|
func insertNodeSQLMig(ctx context.Context, db SQLQueries,
|
||||||
|
node *models.LightningNode) (int64, error) {
|
||||||
|
|
||||||
|
params := sqlc.InsertNodeMigParams{
|
||||||
|
Version: int16(ProtocolV1),
|
||||||
|
PubKey: node.PubKeyBytes[:],
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.HaveNodeAnnouncement {
|
||||||
|
params.LastUpdate = sqldb.SQLInt64(node.LastUpdate.Unix())
|
||||||
|
params.Color = sqldb.SQLStr(EncodeHexColor(node.Color))
|
||||||
|
params.Alias = sqldb.SQLStr(node.Alias)
|
||||||
|
params.Signature = node.AuthSigBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeID, err := db.InsertNodeMig(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("upserting node(%x): %w", node.PubKeyBytes,
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can exit here if we don't have the announcement yet.
|
||||||
|
if !node.HaveNodeAnnouncement {
|
||||||
|
return nodeID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the node's features.
|
||||||
|
for feature := range node.Features.Features() {
|
||||||
|
err = db.InsertNodeFeature(ctx, sqlc.InsertNodeFeatureParams{
|
||||||
|
NodeID: nodeID,
|
||||||
|
FeatureBit: int32(feature),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("unable to insert node(%d) "+
|
||||||
|
"feature(%v): %w", nodeID, feature, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the node's addresses.
|
||||||
|
newAddresses, err := collectAddressRecords(node.Addresses)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any remaining entries in newAddresses are new addresses that need to
|
||||||
|
// be added to the database for the first time.
|
||||||
|
for addrType, addrList := range newAddresses {
|
||||||
|
for position, addr := range addrList {
|
||||||
|
err := db.UpsertNodeAddress(
|
||||||
|
ctx, sqlc.UpsertNodeAddressParams{
|
||||||
|
NodeID: nodeID,
|
||||||
|
Type: int16(addrType),
|
||||||
|
Address: addr,
|
||||||
|
Position: int32(position),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("unable to insert "+
|
||||||
|
"node(%d) address(%v): %w", nodeID,
|
||||||
|
addr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the flat extra opaque data into a map of TLV types to
|
||||||
|
// values.
|
||||||
|
extra, err := marshalExtraOpaqueData(node.ExtraOpaqueData)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("unable to marshal extra opaque data: %w",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the node's extra signed fields.
|
||||||
|
for tlvType, value := range extra {
|
||||||
|
err = db.UpsertNodeExtraType(
|
||||||
|
ctx, sqlc.UpsertNodeExtraTypeParams{
|
||||||
|
NodeID: nodeID,
|
||||||
|
Type: int64(tlvType),
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("unable to upsert node(%d) extra "+
|
||||||
|
"signed field(%v): %w", nodeID, tlvType, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbChanInfo holds the DB level IDs of a channel and the nodes involved in the
|
||||||
|
// channel.
|
||||||
|
type dbChanInfo struct {
|
||||||
|
channelID int64
|
||||||
|
node1ID int64
|
||||||
|
node2ID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertChannelMig inserts a new channel record into the database during the
|
||||||
|
// graph SQL migration.
|
||||||
|
func insertChannelMig(ctx context.Context, db SQLQueries,
|
||||||
|
edge *models.ChannelEdgeInfo) (*dbChanInfo, error) {
|
||||||
|
|
||||||
|
// Make sure that at least a "shell" entry for each node is present in
|
||||||
|
// the nodes table.
|
||||||
|
//
|
||||||
|
// NOTE: we need this even during the SQL migration where nodes are
|
||||||
|
// migrated first because there are cases were some nodes may have
|
||||||
|
// been skipped due to invalid TLV data.
|
||||||
|
node1DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey1Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create shell node: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
node2DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey2Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create shell node: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var capacity sql.NullInt64
|
||||||
|
if edge.Capacity != 0 {
|
||||||
|
capacity = sqldb.SQLInt64(int64(edge.Capacity))
|
||||||
|
}
|
||||||
|
|
||||||
|
createParams := sqlc.InsertChannelMigParams{
|
||||||
|
Version: int16(ProtocolV1),
|
||||||
|
Scid: channelIDToBytes(edge.ChannelID),
|
||||||
|
NodeID1: node1DBID,
|
||||||
|
NodeID2: node2DBID,
|
||||||
|
Outpoint: edge.ChannelPoint.String(),
|
||||||
|
Capacity: capacity,
|
||||||
|
BitcoinKey1: edge.BitcoinKey1Bytes[:],
|
||||||
|
BitcoinKey2: edge.BitcoinKey2Bytes[:],
|
||||||
|
}
|
||||||
|
|
||||||
|
if edge.AuthProof != nil {
|
||||||
|
proof := edge.AuthProof
|
||||||
|
|
||||||
|
createParams.Node1Signature = proof.NodeSig1Bytes
|
||||||
|
createParams.Node2Signature = proof.NodeSig2Bytes
|
||||||
|
createParams.Bitcoin1Signature = proof.BitcoinSig1Bytes
|
||||||
|
createParams.Bitcoin2Signature = proof.BitcoinSig2Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the new channel record.
|
||||||
|
dbChanID, err := db.InsertChannelMig(ctx, createParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert any channel features.
|
||||||
|
for feature := range edge.Features.Features() {
|
||||||
|
err = db.InsertChannelFeature(
|
||||||
|
ctx, sqlc.InsertChannelFeatureParams{
|
||||||
|
ChannelID: dbChanID,
|
||||||
|
FeatureBit: int32(feature),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to insert channel(%d) "+
|
||||||
|
"feature(%v): %w", dbChanID, feature, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, insert any extra TLV fields in the channel announcement.
|
||||||
|
extra, err := marshalExtraOpaqueData(edge.ExtraOpaqueData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to marshal extra opaque "+
|
||||||
|
"data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for tlvType, value := range extra {
|
||||||
|
err := db.UpsertChannelExtraType(
|
||||||
|
ctx, sqlc.UpsertChannelExtraTypeParams{
|
||||||
|
ChannelID: dbChanID,
|
||||||
|
Type: int64(tlvType),
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to upsert "+
|
||||||
|
"channel(%d) extra signed field(%v): %w",
|
||||||
|
edge.ChannelID, tlvType, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dbChanInfo{
|
||||||
|
channelID: dbChanID,
|
||||||
|
node1ID: node1DBID,
|
||||||
|
node2ID: node2DBID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertChanEdgePolicyMig inserts the channel policy info we have stored for
|
||||||
|
// a channel we already know of. This is used during the SQL migration
|
||||||
|
// process to insert channel policies.
|
||||||
|
func insertChanEdgePolicyMig(ctx context.Context, tx SQLQueries,
|
||||||
|
dbChan *dbChanInfo, edge *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
|
// Figure out which node this edge is from.
|
||||||
|
isNode1 := edge.ChannelFlags&lnwire.ChanUpdateDirection == 0
|
||||||
|
nodeID := dbChan.node1ID
|
||||||
|
if !isNode1 {
|
||||||
|
nodeID = dbChan.node2ID
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
inboundBase sql.NullInt64
|
||||||
|
inboundRate sql.NullInt64
|
||||||
|
)
|
||||||
|
edge.InboundFee.WhenSome(func(fee lnwire.Fee) {
|
||||||
|
inboundRate = sqldb.SQLInt64(fee.FeeRate)
|
||||||
|
inboundBase = sqldb.SQLInt64(fee.BaseFee)
|
||||||
|
})
|
||||||
|
|
||||||
|
id, err := tx.InsertEdgePolicyMig(ctx, sqlc.InsertEdgePolicyMigParams{
|
||||||
|
Version: int16(ProtocolV1),
|
||||||
|
ChannelID: dbChan.channelID,
|
||||||
|
NodeID: nodeID,
|
||||||
|
Timelock: int32(edge.TimeLockDelta),
|
||||||
|
FeePpm: int64(edge.FeeProportionalMillionths),
|
||||||
|
BaseFeeMsat: int64(edge.FeeBaseMSat),
|
||||||
|
MinHtlcMsat: int64(edge.MinHTLC),
|
||||||
|
LastUpdate: sqldb.SQLInt64(edge.LastUpdate.Unix()),
|
||||||
|
Disabled: sql.NullBool{
|
||||||
|
Valid: true,
|
||||||
|
Bool: edge.IsDisabled(),
|
||||||
|
},
|
||||||
|
MaxHtlcMsat: sql.NullInt64{
|
||||||
|
Valid: edge.MessageFlags.HasMaxHtlc(),
|
||||||
|
Int64: int64(edge.MaxHTLC),
|
||||||
|
},
|
||||||
|
MessageFlags: sqldb.SQLInt16(edge.MessageFlags),
|
||||||
|
ChannelFlags: sqldb.SQLInt16(edge.ChannelFlags),
|
||||||
|
InboundBaseFeeMsat: inboundBase,
|
||||||
|
InboundFeeRateMilliMsat: inboundRate,
|
||||||
|
Signature: edge.SigBytes,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to upsert edge policy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the flat extra opaque data into a map of TLV types to
|
||||||
|
// values.
|
||||||
|
extra, err := marshalExtraOpaqueData(edge.ExtraOpaqueData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to marshal extra opaque data: %w",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert all new extra signed fields for the channel policy.
|
||||||
|
for tlvType, value := range extra {
|
||||||
|
err = tx.UpsertChanPolicyExtraType(
|
||||||
|
ctx, sqlc.UpsertChanPolicyExtraTypeParams{
|
||||||
|
ChannelPolicyID: id,
|
||||||
|
Type: int64(tlvType),
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to insert "+
|
||||||
|
"channel_policy(%d) extra signed field(%v): %w",
|
||||||
|
id, tlvType, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,13 @@ var (
|
|||||||
// for to ensure that our migration from a graph store backed by a KV DB to a
|
// for to ensure that our migration from a graph store backed by a KV DB to a
|
||||||
// SQL database works as expected. At the end of each test, the DBs are compared
|
// SQL database works as expected. At the end of each test, the DBs are compared
|
||||||
// and expected to have the exact same data in them.
|
// and expected to have the exact same data in them.
|
||||||
|
// This test also ensures that the migration is "retry-safe". This is needed
|
||||||
|
// because the migration is hooked up to 2 dbs: the source DB and the
|
||||||
|
// destination. The source DB is a db behind the kvdb.Backend interface and
|
||||||
|
// the migration makes use of methods on this interface that may be retried
|
||||||
|
// under the hood. The migration often does logic inside call-back functions
|
||||||
|
// passed to the source DB methods which may be retried, and so we need to
|
||||||
|
// ensure that the migration can handle this.
|
||||||
func TestMigrateGraphToSQL(t *testing.T) {
|
func TestMigrateGraphToSQL(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -157,6 +164,59 @@ func TestMigrateGraphToSQL(t *testing.T) {
|
|||||||
srcNodeSet: true,
|
srcNodeSet: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "channel with no policies",
|
||||||
|
write: writeUpdate,
|
||||||
|
objects: []any{
|
||||||
|
// A channel with unknown nodes. This will
|
||||||
|
// result in two shell nodes being created.
|
||||||
|
// - channel count += 1
|
||||||
|
// - node count += 2
|
||||||
|
makeTestChannel(t),
|
||||||
|
|
||||||
|
// Insert some nodes.
|
||||||
|
// - node count += 1
|
||||||
|
makeTestNode(t, func(n *models.LightningNode) {
|
||||||
|
n.PubKeyBytes = node1
|
||||||
|
}),
|
||||||
|
// - node count += 1
|
||||||
|
makeTestNode(t, func(n *models.LightningNode) {
|
||||||
|
n.PubKeyBytes = node2
|
||||||
|
}),
|
||||||
|
|
||||||
|
// A channel with known nodes.
|
||||||
|
// - channel count += 1
|
||||||
|
makeTestChannel(
|
||||||
|
t, func(c *models.ChannelEdgeInfo) {
|
||||||
|
c.ChannelID = chanID1
|
||||||
|
|
||||||
|
c.NodeKey1Bytes = node1
|
||||||
|
c.NodeKey2Bytes = node2
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// Insert a channel with no auth proof, no
|
||||||
|
// extra opaque data, and empty features.
|
||||||
|
// Use known nodes.
|
||||||
|
// - channel count += 1
|
||||||
|
makeTestChannel(
|
||||||
|
t, func(c *models.ChannelEdgeInfo) {
|
||||||
|
c.ChannelID = chanID2
|
||||||
|
|
||||||
|
c.NodeKey1Bytes = node1
|
||||||
|
c.NodeKey2Bytes = node2
|
||||||
|
|
||||||
|
c.AuthProof = nil
|
||||||
|
c.ExtraOpaqueData = nil
|
||||||
|
c.Features = testEmptyFeatures
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
expGraphStats: graphStats{
|
||||||
|
numNodes: 4,
|
||||||
|
numChannels: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "channels and policies",
|
name: "channels and policies",
|
||||||
write: writeUpdate,
|
write: writeUpdate,
|
||||||
@@ -338,6 +398,12 @@ func TestMigrateGraphToSQL(t *testing.T) {
|
|||||||
|
|
||||||
// Validate that the two databases are now in sync.
|
// Validate that the two databases are now in sync.
|
||||||
assertInSync(t, kvDB, sql, test.expGraphStats)
|
assertInSync(t, kvDB, sql, test.expGraphStats)
|
||||||
|
|
||||||
|
// The migration should be retry-safe, so running it
|
||||||
|
// again should not change the state of the databases.
|
||||||
|
err = MigrateGraphToSQL(ctx, sql.cfg, kvDB.db, sql.db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertInSync(t, kvDB, sql, test.expGraphStats)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -513,6 +579,7 @@ func checkKVPruneLogEntries(t *testing.T, kv *KVStore, sql *SQLStore,
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
func() {},
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -544,7 +611,7 @@ func checkClosedSCIDIndex(t *testing.T, kv kvdb.Backend, sql *SQLStore) {
|
|||||||
require.True(t, closed)
|
require.True(t, closed)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
}, func() {})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,7 +643,7 @@ func checkZombieIndex(t *testing.T, kv kvdb.Backend, sql *SQLStore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
}, func() {})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,6 +783,7 @@ func makeTestPolicy(chanID uint64, toNode route.Vertex, isNode1 bool,
|
|||||||
FeeBaseMSat: math.MaxUint64,
|
FeeBaseMSat: math.MaxUint64,
|
||||||
FeeProportionalMillionths: math.MaxUint64,
|
FeeProportionalMillionths: math.MaxUint64,
|
||||||
ToNode: toNode,
|
ToNode: toNode,
|
||||||
|
ExtraOpaqueData: testExtraData,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@@ -1205,6 +1273,8 @@ func TestMigrateGraphToSQLRapid(t *testing.T) {
|
|||||||
// SQL store, generates random nodes and channels, populates the KV store,
|
// SQL store, generates random nodes and channels, populates the KV store,
|
||||||
// runs the migration, and asserts that the SQL store contains the expected
|
// runs the migration, and asserts that the SQL store contains the expected
|
||||||
// state.
|
// state.
|
||||||
|
//
|
||||||
|
// The migration is run twice in order to test idempotency and retry-safety.
|
||||||
func testMigrateGraphToSQLRapidOnce(t *testing.T, rt *rapid.T,
|
func testMigrateGraphToSQLRapidOnce(t *testing.T, rt *rapid.T,
|
||||||
dbFixture *sqldb.TestPgFixture, maxNumNodes, maxNumChannels int) {
|
dbFixture *sqldb.TestPgFixture, maxNumNodes, maxNumChannels int) {
|
||||||
|
|
||||||
@@ -1355,6 +1425,15 @@ func testMigrateGraphToSQLRapidOnce(t *testing.T, rt *rapid.T,
|
|||||||
nodes: nodesSlice,
|
nodes: nodesSlice,
|
||||||
chans: chanSetForState,
|
chans: chanSetForState,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// The migration is expected to be idempotent and retry-safe. So running
|
||||||
|
// it again should yield the same result.
|
||||||
|
err = MigrateGraphToSQL(ctx, sql.cfg, kvDB.db, sql.db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertResultState(t, sql, dbState{
|
||||||
|
nodes: nodesSlice,
|
||||||
|
chans: chanSetForState,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// genRandomChannel is a rapid generator for creating random channel edge infos.
|
// genRandomChannel is a rapid generator for creating random channel edge infos.
|
||||||
|
|||||||
+70
-57
@@ -70,7 +70,7 @@ type SQLQueries interface {
|
|||||||
UpsertNodeExtraType(ctx context.Context, arg sqlc.UpsertNodeExtraTypeParams) error
|
UpsertNodeExtraType(ctx context.Context, arg sqlc.UpsertNodeExtraTypeParams) error
|
||||||
DeleteExtraNodeType(ctx context.Context, arg sqlc.DeleteExtraNodeTypeParams) error
|
DeleteExtraNodeType(ctx context.Context, arg sqlc.DeleteExtraNodeTypeParams) error
|
||||||
|
|
||||||
InsertNodeAddress(ctx context.Context, arg sqlc.InsertNodeAddressParams) error
|
UpsertNodeAddress(ctx context.Context, arg sqlc.UpsertNodeAddressParams) error
|
||||||
GetNodeAddresses(ctx context.Context, nodeID int64) ([]sqlc.GetNodeAddressesRow, error)
|
GetNodeAddresses(ctx context.Context, nodeID int64) ([]sqlc.GetNodeAddressesRow, error)
|
||||||
GetNodeAddressesBatch(ctx context.Context, ids []int64) ([]sqlc.GraphNodeAddress, error)
|
GetNodeAddressesBatch(ctx context.Context, ids []int64) ([]sqlc.GraphNodeAddress, error)
|
||||||
DeleteNodeAddresses(ctx context.Context, nodeID int64) error
|
DeleteNodeAddresses(ctx context.Context, nodeID int64) error
|
||||||
@@ -112,7 +112,7 @@ type SQLQueries interface {
|
|||||||
GetSCIDByOutpoint(ctx context.Context, arg sqlc.GetSCIDByOutpointParams) ([]byte, error)
|
GetSCIDByOutpoint(ctx context.Context, arg sqlc.GetSCIDByOutpointParams) ([]byte, error)
|
||||||
DeleteChannels(ctx context.Context, ids []int64) error
|
DeleteChannels(ctx context.Context, ids []int64) error
|
||||||
|
|
||||||
CreateChannelExtraType(ctx context.Context, arg sqlc.CreateChannelExtraTypeParams) error
|
UpsertChannelExtraType(ctx context.Context, arg sqlc.UpsertChannelExtraTypeParams) error
|
||||||
GetChannelExtrasBatch(ctx context.Context, chanIds []int64) ([]sqlc.GraphChannelExtraType, error)
|
GetChannelExtrasBatch(ctx context.Context, chanIds []int64) ([]sqlc.GraphChannelExtraType, error)
|
||||||
InsertChannelFeature(ctx context.Context, arg sqlc.InsertChannelFeatureParams) error
|
InsertChannelFeature(ctx context.Context, arg sqlc.InsertChannelFeatureParams) error
|
||||||
GetChannelFeaturesBatch(ctx context.Context, chanIds []int64) ([]sqlc.GraphChannelFeature, error)
|
GetChannelFeaturesBatch(ctx context.Context, chanIds []int64) ([]sqlc.GraphChannelFeature, error)
|
||||||
@@ -124,7 +124,7 @@ type SQLQueries interface {
|
|||||||
GetChannelPolicyByChannelAndNode(ctx context.Context, arg sqlc.GetChannelPolicyByChannelAndNodeParams) (sqlc.GraphChannelPolicy, error)
|
GetChannelPolicyByChannelAndNode(ctx context.Context, arg sqlc.GetChannelPolicyByChannelAndNodeParams) (sqlc.GraphChannelPolicy, error)
|
||||||
GetV1DisabledSCIDs(ctx context.Context) ([][]byte, error)
|
GetV1DisabledSCIDs(ctx context.Context) ([][]byte, error)
|
||||||
|
|
||||||
InsertChanPolicyExtraType(ctx context.Context, arg sqlc.InsertChanPolicyExtraTypeParams) error
|
UpsertChanPolicyExtraType(ctx context.Context, arg sqlc.UpsertChanPolicyExtraTypeParams) error
|
||||||
GetChannelPolicyExtraTypesBatch(ctx context.Context, policyIds []int64) ([]sqlc.GetChannelPolicyExtraTypesBatchRow, error)
|
GetChannelPolicyExtraTypesBatch(ctx context.Context, policyIds []int64) ([]sqlc.GetChannelPolicyExtraTypesBatchRow, error)
|
||||||
DeleteChannelPolicyExtraTypes(ctx context.Context, channelPolicyID int64) error
|
DeleteChannelPolicyExtraTypes(ctx context.Context, channelPolicyID int64) error
|
||||||
|
|
||||||
@@ -153,6 +153,18 @@ type SQLQueries interface {
|
|||||||
InsertClosedChannel(ctx context.Context, scid []byte) error
|
InsertClosedChannel(ctx context.Context, scid []byte) error
|
||||||
IsClosedChannel(ctx context.Context, scid []byte) (bool, error)
|
IsClosedChannel(ctx context.Context, scid []byte) (bool, error)
|
||||||
GetClosedChannelsSCIDs(ctx context.Context, scids [][]byte) ([][]byte, error)
|
GetClosedChannelsSCIDs(ctx context.Context, scids [][]byte) ([][]byte, error)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Migration specific queries.
|
||||||
|
|
||||||
|
NOTE: these should not be used in code other than migrations.
|
||||||
|
Once sqldbv2 is in place, these can be removed from this struct
|
||||||
|
as then migrations will have their own dedicated queries
|
||||||
|
structs.
|
||||||
|
*/
|
||||||
|
InsertNodeMig(ctx context.Context, arg sqlc.InsertNodeMigParams) (int64, error)
|
||||||
|
InsertChannelMig(ctx context.Context, arg sqlc.InsertChannelMigParams) (int64, error)
|
||||||
|
InsertEdgePolicyMig(ctx context.Context, arg sqlc.InsertEdgePolicyMigParams) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatchedSQLQueries is a version of SQLQueries that's capable of batched
|
// BatchedSQLQueries is a version of SQLQueries that's capable of batched
|
||||||
@@ -617,9 +629,7 @@ func (s *SQLStore) AddChannelEdge(ctx context.Context,
|
|||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = insertChannel(ctx, tx, edge)
|
return insertChannel(ctx, tx, edge)
|
||||||
|
|
||||||
return err
|
|
||||||
},
|
},
|
||||||
OnCommit: func(err error) error {
|
OnCommit: func(err error) error {
|
||||||
switch {
|
switch {
|
||||||
@@ -3523,23 +3533,11 @@ const (
|
|||||||
addressTypeOpaque dbAddressType = math.MaxInt8
|
addressTypeOpaque dbAddressType = math.MaxInt8
|
||||||
)
|
)
|
||||||
|
|
||||||
// upsertNodeAddresses updates the node's addresses in the database. This
|
// collectAddressRecords collects the addresses from the provided
|
||||||
// includes deleting any existing addresses and inserting the new set of
|
// net.Addr slice and returns a map of dbAddressType to a slice of address
|
||||||
// addresses. The deletion is necessary since the ordering of the addresses may
|
// strings.
|
||||||
// change, and we need to ensure that the database reflects the latest set of
|
func collectAddressRecords(addresses []net.Addr) (map[dbAddressType][]string,
|
||||||
// addresses so that at the time of reconstructing the node announcement, the
|
error) {
|
||||||
// order is preserved and the signature over the message remains valid.
|
|
||||||
func upsertNodeAddresses(ctx context.Context, db SQLQueries, nodeID int64,
|
|
||||||
addresses []net.Addr) error {
|
|
||||||
|
|
||||||
// Delete any existing addresses for the node. This is required since
|
|
||||||
// even if the new set of addresses is the same, the ordering may have
|
|
||||||
// changed for a given address type.
|
|
||||||
err := db.DeleteNodeAddresses(ctx, nodeID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to delete node(%d) addresses: %w",
|
|
||||||
nodeID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the nodes latest set of addresses.
|
// Copy the nodes latest set of addresses.
|
||||||
newAddresses := map[dbAddressType][]string{
|
newAddresses := map[dbAddressType][]string{
|
||||||
@@ -3561,8 +3559,8 @@ func upsertNodeAddresses(ctx context.Context, db SQLQueries, nodeID int64,
|
|||||||
} else if ip6 := addr.IP.To16(); ip6 != nil {
|
} else if ip6 := addr.IP.To16(); ip6 != nil {
|
||||||
addAddr(addressTypeIPv6, addr)
|
addAddr(addressTypeIPv6, addr)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("unhandled IP address: %v",
|
return nil, fmt.Errorf("unhandled IP "+
|
||||||
addr)
|
"address: %v", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *tor.OnionAddr:
|
case *tor.OnionAddr:
|
||||||
@@ -3572,24 +3570,51 @@ func upsertNodeAddresses(ctx context.Context, db SQLQueries, nodeID int64,
|
|||||||
case tor.V3Len:
|
case tor.V3Len:
|
||||||
addAddr(addressTypeTorV3, addr)
|
addAddr(addressTypeTorV3, addr)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid length for a tor " +
|
return nil, fmt.Errorf("invalid length for " +
|
||||||
"address")
|
"a tor address")
|
||||||
}
|
}
|
||||||
|
|
||||||
case *lnwire.OpaqueAddrs:
|
case *lnwire.OpaqueAddrs:
|
||||||
addAddr(addressTypeOpaque, addr)
|
addAddr(addressTypeOpaque, addr)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unhandled address type: %T", addr)
|
return nil, fmt.Errorf("unhandled address type: %T",
|
||||||
|
addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newAddresses, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// upsertNodeAddresses updates the node's addresses in the database. This
|
||||||
|
// includes deleting any existing addresses and inserting the new set of
|
||||||
|
// addresses. The deletion is necessary since the ordering of the addresses may
|
||||||
|
// change, and we need to ensure that the database reflects the latest set of
|
||||||
|
// addresses so that at the time of reconstructing the node announcement, the
|
||||||
|
// order is preserved and the signature over the message remains valid.
|
||||||
|
func upsertNodeAddresses(ctx context.Context, db SQLQueries, nodeID int64,
|
||||||
|
addresses []net.Addr) error {
|
||||||
|
|
||||||
|
// Delete any existing addresses for the node. This is required since
|
||||||
|
// even if the new set of addresses is the same, the ordering may have
|
||||||
|
// changed for a given address type.
|
||||||
|
err := db.DeleteNodeAddresses(ctx, nodeID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to delete node(%d) addresses: %w",
|
||||||
|
nodeID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newAddresses, err := collectAddressRecords(addresses)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Any remaining entries in newAddresses are new addresses that need to
|
// Any remaining entries in newAddresses are new addresses that need to
|
||||||
// be added to the database for the first time.
|
// be added to the database for the first time.
|
||||||
for addrType, addrList := range newAddresses {
|
for addrType, addrList := range newAddresses {
|
||||||
for position, addr := range addrList {
|
for position, addr := range addrList {
|
||||||
err := db.InsertNodeAddress(
|
err := db.UpsertNodeAddress(
|
||||||
ctx, sqlc.InsertNodeAddressParams{
|
ctx, sqlc.UpsertNodeAddressParams{
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
Type: int16(addrType),
|
Type: int16(addrType),
|
||||||
Address: addr,
|
Address: addr,
|
||||||
@@ -3774,28 +3799,20 @@ func marshalExtraOpaqueData(data []byte) (map[uint64][]byte, error) {
|
|||||||
return records, nil
|
return records, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// dbChanInfo holds the DB level IDs of a channel and the nodes involved in the
|
|
||||||
// channel.
|
|
||||||
type dbChanInfo struct {
|
|
||||||
channelID int64
|
|
||||||
node1ID int64
|
|
||||||
node2ID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// insertChannel inserts a new channel record into the database.
|
// insertChannel inserts a new channel record into the database.
|
||||||
func insertChannel(ctx context.Context, db SQLQueries,
|
func insertChannel(ctx context.Context, db SQLQueries,
|
||||||
edge *models.ChannelEdgeInfo) (*dbChanInfo, error) {
|
edge *models.ChannelEdgeInfo) error {
|
||||||
|
|
||||||
// Make sure that at least a "shell" entry for each node is present in
|
// Make sure that at least a "shell" entry for each node is present in
|
||||||
// the nodes table.
|
// the nodes table.
|
||||||
node1DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey1Bytes)
|
node1DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey1Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create shell node: %w", err)
|
return fmt.Errorf("unable to create shell node: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
node2DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey2Bytes)
|
node2DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey2Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create shell node: %w", err)
|
return fmt.Errorf("unable to create shell node: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var capacity sql.NullInt64
|
var capacity sql.NullInt64
|
||||||
@@ -3826,7 +3843,7 @@ func insertChannel(ctx context.Context, db SQLQueries,
|
|||||||
// Insert the new channel record.
|
// Insert the new channel record.
|
||||||
dbChanID, err := db.CreateChannel(ctx, createParams)
|
dbChanID, err := db.CreateChannel(ctx, createParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert any channel features.
|
// Insert any channel features.
|
||||||
@@ -3838,7 +3855,7 @@ func insertChannel(ctx context.Context, db SQLQueries,
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to insert channel(%d) "+
|
return fmt.Errorf("unable to insert channel(%d) "+
|
||||||
"feature(%v): %w", dbChanID, feature, err)
|
"feature(%v): %w", dbChanID, feature, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3846,30 +3863,26 @@ func insertChannel(ctx context.Context, db SQLQueries,
|
|||||||
// Finally, insert any extra TLV fields in the channel announcement.
|
// Finally, insert any extra TLV fields in the channel announcement.
|
||||||
extra, err := marshalExtraOpaqueData(edge.ExtraOpaqueData)
|
extra, err := marshalExtraOpaqueData(edge.ExtraOpaqueData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to marshal extra opaque "+
|
return fmt.Errorf("unable to marshal extra opaque data: %w",
|
||||||
"data: %w", err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for tlvType, value := range extra {
|
for tlvType, value := range extra {
|
||||||
err := db.CreateChannelExtraType(
|
err := db.UpsertChannelExtraType(
|
||||||
ctx, sqlc.CreateChannelExtraTypeParams{
|
ctx, sqlc.UpsertChannelExtraTypeParams{
|
||||||
ChannelID: dbChanID,
|
ChannelID: dbChanID,
|
||||||
Type: int64(tlvType),
|
Type: int64(tlvType),
|
||||||
Value: value,
|
Value: value,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to upsert "+
|
return fmt.Errorf("unable to upsert channel(%d) "+
|
||||||
"channel(%d) extra signed field(%v): %w",
|
"extra signed field(%v): %w", edge.ChannelID,
|
||||||
edge.ChannelID, tlvType, err)
|
tlvType, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &dbChanInfo{
|
return nil
|
||||||
channelID: dbChanID,
|
|
||||||
node1ID: node1DBID,
|
|
||||||
node2ID: node2DBID,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybeCreateShellNode checks if a shell node entry exists for the
|
// maybeCreateShellNode checks if a shell node entry exists for the
|
||||||
@@ -3921,8 +3934,8 @@ func upsertChanPolicyExtraSignedFields(ctx context.Context, db SQLQueries,
|
|||||||
|
|
||||||
// Insert all new extra signed fields for the channel policy.
|
// Insert all new extra signed fields for the channel policy.
|
||||||
for tlvType, value := range extraFields {
|
for tlvType, value := range extraFields {
|
||||||
err = db.InsertChanPolicyExtraType(
|
err = db.UpsertChanPolicyExtraType(
|
||||||
ctx, sqlc.InsertChanPolicyExtraTypeParams{
|
ctx, sqlc.UpsertChanPolicyExtraTypeParams{
|
||||||
ChannelPolicyID: chanPolicyID,
|
ChannelPolicyID: chanPolicyID,
|
||||||
Type: int64(tlvType),
|
Type: int64(tlvType),
|
||||||
Value: value,
|
Value: value,
|
||||||
|
|||||||
+282
-73
@@ -120,29 +120,6 @@ func (q *Queries) CreateChannel(ctx context.Context, arg CreateChannelParams) (i
|
|||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const createChannelExtraType = `-- name: CreateChannelExtraType :exec
|
|
||||||
/* ─────────────────────────────────────────────
|
|
||||||
graph_channel_extra_types table queries
|
|
||||||
─────────────────────────────────────────────
|
|
||||||
*/
|
|
||||||
|
|
||||||
INSERT INTO graph_channel_extra_types (
|
|
||||||
channel_id, type, value
|
|
||||||
)
|
|
||||||
VALUES ($1, $2, $3)
|
|
||||||
`
|
|
||||||
|
|
||||||
type CreateChannelExtraTypeParams struct {
|
|
||||||
ChannelID int64
|
|
||||||
Type int64
|
|
||||||
Value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) CreateChannelExtraType(ctx context.Context, arg CreateChannelExtraTypeParams) error {
|
|
||||||
_, err := q.db.ExecContext(ctx, createChannelExtraType, arg.ChannelID, arg.Type, arg.Value)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteChannelPolicyExtraTypes = `-- name: DeleteChannelPolicyExtraTypes :exec
|
const deleteChannelPolicyExtraTypes = `-- name: DeleteChannelPolicyExtraTypes :exec
|
||||||
DELETE FROM graph_channel_policy_extra_types
|
DELETE FROM graph_channel_policy_extra_types
|
||||||
WHERE channel_policy_id = $1
|
WHERE channel_policy_id = $1
|
||||||
@@ -2327,29 +2304,6 @@ func (q *Queries) HighestSCID(ctx context.Context, version int16) ([]byte, error
|
|||||||
return scid, err
|
return scid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertChanPolicyExtraType = `-- name: InsertChanPolicyExtraType :exec
|
|
||||||
/* ─────────────────────────────────────────────
|
|
||||||
graph_channel_policy_extra_types table queries
|
|
||||||
─────────────────────────────────────────────
|
|
||||||
*/
|
|
||||||
|
|
||||||
INSERT INTO graph_channel_policy_extra_types (
|
|
||||||
channel_policy_id, type, value
|
|
||||||
)
|
|
||||||
VALUES ($1, $2, $3)
|
|
||||||
`
|
|
||||||
|
|
||||||
type InsertChanPolicyExtraTypeParams struct {
|
|
||||||
ChannelPolicyID int64
|
|
||||||
Type int64
|
|
||||||
Value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) InsertChanPolicyExtraType(ctx context.Context, arg InsertChanPolicyExtraTypeParams) error {
|
|
||||||
_, err := q.db.ExecContext(ctx, insertChanPolicyExtraType, arg.ChannelPolicyID, arg.Type, arg.Value)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
const insertChannelFeature = `-- name: InsertChannelFeature :exec
|
const insertChannelFeature = `-- name: InsertChannelFeature :exec
|
||||||
/* ─────────────────────────────────────────────
|
/* ─────────────────────────────────────────────
|
||||||
graph_channel_features table queries
|
graph_channel_features table queries
|
||||||
@@ -2360,7 +2314,9 @@ INSERT INTO graph_channel_features (
|
|||||||
channel_id, feature_bit
|
channel_id, feature_bit
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2
|
$1, $2
|
||||||
)
|
) ON CONFLICT (channel_id, feature_bit)
|
||||||
|
-- Do nothing if the channel_id and feature_bit already exist.
|
||||||
|
DO NOTHING
|
||||||
`
|
`
|
||||||
|
|
||||||
type InsertChannelFeatureParams struct {
|
type InsertChannelFeatureParams struct {
|
||||||
@@ -2373,6 +2329,72 @@ func (q *Queries) InsertChannelFeature(ctx context.Context, arg InsertChannelFea
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const insertChannelMig = `-- name: InsertChannelMig :one
|
||||||
|
INSERT INTO graph_channels (
|
||||||
|
version, scid, node_id_1, node_id_2,
|
||||||
|
outpoint, capacity, bitcoin_key_1, bitcoin_key_2,
|
||||||
|
node_1_signature, node_2_signature, bitcoin_1_signature,
|
||||||
|
bitcoin_2_signature
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
|
||||||
|
) ON CONFLICT (scid, version)
|
||||||
|
-- If a conflict occurs, we have already migrated this channel. However, we
|
||||||
|
-- still need to do an "UPDATE SET" here instead of "DO NOTHING" because
|
||||||
|
-- otherwise, the "RETURNING id" part does not work.
|
||||||
|
DO UPDATE SET
|
||||||
|
node_id_1 = EXCLUDED.node_id_1,
|
||||||
|
node_id_2 = EXCLUDED.node_id_2,
|
||||||
|
outpoint = EXCLUDED.outpoint,
|
||||||
|
capacity = EXCLUDED.capacity,
|
||||||
|
bitcoin_key_1 = EXCLUDED.bitcoin_key_1,
|
||||||
|
bitcoin_key_2 = EXCLUDED.bitcoin_key_2,
|
||||||
|
node_1_signature = EXCLUDED.node_1_signature,
|
||||||
|
node_2_signature = EXCLUDED.node_2_signature,
|
||||||
|
bitcoin_1_signature = EXCLUDED.bitcoin_1_signature,
|
||||||
|
bitcoin_2_signature = EXCLUDED.bitcoin_2_signature
|
||||||
|
RETURNING id
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertChannelMigParams struct {
|
||||||
|
Version int16
|
||||||
|
Scid []byte
|
||||||
|
NodeID1 int64
|
||||||
|
NodeID2 int64
|
||||||
|
Outpoint string
|
||||||
|
Capacity sql.NullInt64
|
||||||
|
BitcoinKey1 []byte
|
||||||
|
BitcoinKey2 []byte
|
||||||
|
Node1Signature []byte
|
||||||
|
Node2Signature []byte
|
||||||
|
Bitcoin1Signature []byte
|
||||||
|
Bitcoin2Signature []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
// for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
// we re-insert the same channel again (which would error if the normal
|
||||||
|
// CreateChannel query is used because of the uniqueness constraint on the scid
|
||||||
|
// and version columns).
|
||||||
|
func (q *Queries) InsertChannelMig(ctx context.Context, arg InsertChannelMigParams) (int64, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, insertChannelMig,
|
||||||
|
arg.Version,
|
||||||
|
arg.Scid,
|
||||||
|
arg.NodeID1,
|
||||||
|
arg.NodeID2,
|
||||||
|
arg.Outpoint,
|
||||||
|
arg.Capacity,
|
||||||
|
arg.BitcoinKey1,
|
||||||
|
arg.BitcoinKey2,
|
||||||
|
arg.Node1Signature,
|
||||||
|
arg.Node2Signature,
|
||||||
|
arg.Bitcoin1Signature,
|
||||||
|
arg.Bitcoin2Signature,
|
||||||
|
)
|
||||||
|
var id int64
|
||||||
|
err := row.Scan(&id)
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
const insertClosedChannel = `-- name: InsertClosedChannel :exec
|
const insertClosedChannel = `-- name: InsertClosedChannel :exec
|
||||||
/* ─────────────────────────────────────────────
|
/* ─────────────────────────────────────────────
|
||||||
graph_closed_scid table queries
|
graph_closed_scid table queries
|
||||||
@@ -2389,37 +2411,80 @@ func (q *Queries) InsertClosedChannel(ctx context.Context, scid []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertNodeAddress = `-- name: InsertNodeAddress :exec
|
const insertEdgePolicyMig = `-- name: InsertEdgePolicyMig :one
|
||||||
/* ─────────────────────────────────────────────
|
INSERT INTO graph_channel_policies (
|
||||||
graph_node_addresses table queries
|
version, channel_id, node_id, timelock, fee_ppm,
|
||||||
───────────────────────────────────��─────────
|
base_fee_msat, min_htlc_msat, last_update, disabled,
|
||||||
*/
|
max_htlc_msat, inbound_base_fee_msat,
|
||||||
|
inbound_fee_rate_milli_msat, message_flags, channel_flags,
|
||||||
INSERT INTO graph_node_addresses (
|
signature
|
||||||
node_id,
|
) VALUES (
|
||||||
type,
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
||||||
address,
|
)
|
||||||
position
|
ON CONFLICT (channel_id, node_id, version)
|
||||||
) VALUES (
|
-- If a conflict occurs, we have already migrated this policy. However, we
|
||||||
$1, $2, $3, $4
|
-- still need to do an "UPDATE SET" here instead of "DO NOTHING" because
|
||||||
)
|
-- otherwise, the "RETURNING id" part does not work.
|
||||||
|
DO UPDATE SET
|
||||||
|
timelock = EXCLUDED.timelock,
|
||||||
|
fee_ppm = EXCLUDED.fee_ppm,
|
||||||
|
base_fee_msat = EXCLUDED.base_fee_msat,
|
||||||
|
min_htlc_msat = EXCLUDED.min_htlc_msat,
|
||||||
|
last_update = EXCLUDED.last_update,
|
||||||
|
disabled = EXCLUDED.disabled,
|
||||||
|
max_htlc_msat = EXCLUDED.max_htlc_msat,
|
||||||
|
inbound_base_fee_msat = EXCLUDED.inbound_base_fee_msat,
|
||||||
|
inbound_fee_rate_milli_msat = EXCLUDED.inbound_fee_rate_milli_msat,
|
||||||
|
message_flags = EXCLUDED.message_flags,
|
||||||
|
channel_flags = EXCLUDED.channel_flags,
|
||||||
|
signature = EXCLUDED.signature
|
||||||
|
RETURNING id
|
||||||
`
|
`
|
||||||
|
|
||||||
type InsertNodeAddressParams struct {
|
type InsertEdgePolicyMigParams struct {
|
||||||
NodeID int64
|
Version int16
|
||||||
Type int16
|
ChannelID int64
|
||||||
Address string
|
NodeID int64
|
||||||
Position int32
|
Timelock int32
|
||||||
|
FeePpm int64
|
||||||
|
BaseFeeMsat int64
|
||||||
|
MinHtlcMsat int64
|
||||||
|
LastUpdate sql.NullInt64
|
||||||
|
Disabled sql.NullBool
|
||||||
|
MaxHtlcMsat sql.NullInt64
|
||||||
|
InboundBaseFeeMsat sql.NullInt64
|
||||||
|
InboundFeeRateMilliMsat sql.NullInt64
|
||||||
|
MessageFlags sql.NullInt16
|
||||||
|
ChannelFlags sql.NullInt16
|
||||||
|
Signature []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) InsertNodeAddress(ctx context.Context, arg InsertNodeAddressParams) error {
|
// NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
_, err := q.db.ExecContext(ctx, insertNodeAddress,
|
// for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
// we re-insert the same policy (which would error if the normal
|
||||||
|
// UpsertEdgePolicy query is used because of the constraint in that query that
|
||||||
|
// requires a policy update to have a newer last_update than the existing one).
|
||||||
|
func (q *Queries) InsertEdgePolicyMig(ctx context.Context, arg InsertEdgePolicyMigParams) (int64, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, insertEdgePolicyMig,
|
||||||
|
arg.Version,
|
||||||
|
arg.ChannelID,
|
||||||
arg.NodeID,
|
arg.NodeID,
|
||||||
arg.Type,
|
arg.Timelock,
|
||||||
arg.Address,
|
arg.FeePpm,
|
||||||
arg.Position,
|
arg.BaseFeeMsat,
|
||||||
|
arg.MinHtlcMsat,
|
||||||
|
arg.LastUpdate,
|
||||||
|
arg.Disabled,
|
||||||
|
arg.MaxHtlcMsat,
|
||||||
|
arg.InboundBaseFeeMsat,
|
||||||
|
arg.InboundFeeRateMilliMsat,
|
||||||
|
arg.MessageFlags,
|
||||||
|
arg.ChannelFlags,
|
||||||
|
arg.Signature,
|
||||||
)
|
)
|
||||||
return err
|
var id int64
|
||||||
|
err := row.Scan(&id)
|
||||||
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertNodeFeature = `-- name: InsertNodeFeature :exec
|
const insertNodeFeature = `-- name: InsertNodeFeature :exec
|
||||||
@@ -2432,7 +2497,9 @@ INSERT INTO graph_node_features (
|
|||||||
node_id, feature_bit
|
node_id, feature_bit
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2
|
$1, $2
|
||||||
)
|
) ON CONFLICT (node_id, feature_bit)
|
||||||
|
-- Do nothing if the feature already exists for the node.
|
||||||
|
DO NOTHING
|
||||||
`
|
`
|
||||||
|
|
||||||
type InsertNodeFeatureParams struct {
|
type InsertNodeFeatureParams struct {
|
||||||
@@ -2445,6 +2512,61 @@ func (q *Queries) InsertNodeFeature(ctx context.Context, arg InsertNodeFeaturePa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const insertNodeMig = `-- name: InsertNodeMig :one
|
||||||
|
/* ─────────────────────────────────────────────
|
||||||
|
Migration specific queries
|
||||||
|
|
||||||
|
NOTE: once sqldbv2 is in place, these queries can be contained to a package
|
||||||
|
dedicated to the migration that requires it, and so we can then remove
|
||||||
|
it from the main set of "live" queries that the code-base has access to.
|
||||||
|
────────────────────────────────────────────-
|
||||||
|
*/
|
||||||
|
|
||||||
|
INSERT INTO graph_nodes (
|
||||||
|
version, pub_key, alias, last_update, color, signature
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5, $6
|
||||||
|
)
|
||||||
|
ON CONFLICT (pub_key, version)
|
||||||
|
-- If a conflict occurs, we have already migrated this node. However, we
|
||||||
|
-- still need to do an "UPDATE SET" here instead of "DO NOTHING" because
|
||||||
|
-- otherwise, the "RETURNING id" part does not work.
|
||||||
|
DO UPDATE SET
|
||||||
|
alias = EXCLUDED.alias,
|
||||||
|
last_update = EXCLUDED.last_update,
|
||||||
|
color = EXCLUDED.color,
|
||||||
|
signature = EXCLUDED.signature
|
||||||
|
RETURNING id
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertNodeMigParams struct {
|
||||||
|
Version int16
|
||||||
|
PubKey []byte
|
||||||
|
Alias sql.NullString
|
||||||
|
LastUpdate sql.NullInt64
|
||||||
|
Color sql.NullString
|
||||||
|
Signature []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
// for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
// we re-insert the same node (which would error if the normal UpsertNode query
|
||||||
|
// is used because of the constraint in that query that requires a node update
|
||||||
|
// to have a newer last_update than the existing node).
|
||||||
|
func (q *Queries) InsertNodeMig(ctx context.Context, arg InsertNodeMigParams) (int64, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, insertNodeMig,
|
||||||
|
arg.Version,
|
||||||
|
arg.PubKey,
|
||||||
|
arg.Alias,
|
||||||
|
arg.LastUpdate,
|
||||||
|
arg.Color,
|
||||||
|
arg.Signature,
|
||||||
|
)
|
||||||
|
var id int64
|
||||||
|
err := row.Scan(&id)
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
const isClosedChannel = `-- name: IsClosedChannel :one
|
const isClosedChannel = `-- name: IsClosedChannel :one
|
||||||
SELECT EXISTS (
|
SELECT EXISTS (
|
||||||
SELECT 1
|
SELECT 1
|
||||||
@@ -3284,6 +3406,59 @@ func (q *Queries) ListNodesPaginated(ctx context.Context, arg ListNodesPaginated
|
|||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const upsertChanPolicyExtraType = `-- name: UpsertChanPolicyExtraType :exec
|
||||||
|
/* ─────────────────────────────────────────────
|
||||||
|
graph_channel_policy_extra_types table queries
|
||||||
|
─────────────────────────────────────────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
INSERT INTO graph_channel_policy_extra_types (
|
||||||
|
channel_policy_id, type, value
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
ON CONFLICT (channel_policy_id, type)
|
||||||
|
-- If a conflict occurs on channel_policy_id and type, then we update the
|
||||||
|
-- value.
|
||||||
|
DO UPDATE SET value = EXCLUDED.value
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpsertChanPolicyExtraTypeParams struct {
|
||||||
|
ChannelPolicyID int64
|
||||||
|
Type int64
|
||||||
|
Value []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpsertChanPolicyExtraType(ctx context.Context, arg UpsertChanPolicyExtraTypeParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, upsertChanPolicyExtraType, arg.ChannelPolicyID, arg.Type, arg.Value)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const upsertChannelExtraType = `-- name: UpsertChannelExtraType :exec
|
||||||
|
/* ─────────────────────────────────────────────
|
||||||
|
graph_channel_extra_types table queries
|
||||||
|
─────────────────────────────────────────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
INSERT INTO graph_channel_extra_types (
|
||||||
|
channel_id, type, value
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
ON CONFLICT (channel_id, type)
|
||||||
|
-- Update the value if a conflict occurs on channel_id and type.
|
||||||
|
DO UPDATE SET value = EXCLUDED.value
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpsertChannelExtraTypeParams struct {
|
||||||
|
ChannelID int64
|
||||||
|
Type int64
|
||||||
|
Value []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpsertChannelExtraType(ctx context.Context, arg UpsertChannelExtraTypeParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, upsertChannelExtraType, arg.ChannelID, arg.Type, arg.Value)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const upsertEdgePolicy = `-- name: UpsertEdgePolicy :one
|
const upsertEdgePolicy = `-- name: UpsertEdgePolicy :one
|
||||||
/* ─────────────────────────────────────────────
|
/* ─────────────────────────────────────────────
|
||||||
graph_channel_policies table queries
|
graph_channel_policies table queries
|
||||||
@@ -3407,6 +3582,40 @@ func (q *Queries) UpsertNode(ctx context.Context, arg UpsertNodeParams) (int64,
|
|||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const upsertNodeAddress = `-- name: UpsertNodeAddress :exec
|
||||||
|
/* ─────────────────────────────────────────────
|
||||||
|
graph_node_addresses table queries
|
||||||
|
───────────────────────────────────��─────────
|
||||||
|
*/
|
||||||
|
|
||||||
|
INSERT INTO graph_node_addresses (
|
||||||
|
node_id,
|
||||||
|
type,
|
||||||
|
address,
|
||||||
|
position
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4
|
||||||
|
) ON CONFLICT (node_id, type, position)
|
||||||
|
DO UPDATE SET address = EXCLUDED.address
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpsertNodeAddressParams struct {
|
||||||
|
NodeID int64
|
||||||
|
Type int16
|
||||||
|
Address string
|
||||||
|
Position int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpsertNodeAddress(ctx context.Context, arg UpsertNodeAddressParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, upsertNodeAddress,
|
||||||
|
arg.NodeID,
|
||||||
|
arg.Type,
|
||||||
|
arg.Address,
|
||||||
|
arg.Position,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const upsertNodeExtraType = `-- name: UpsertNodeExtraType :exec
|
const upsertNodeExtraType = `-- name: UpsertNodeExtraType :exec
|
||||||
/* ─────────────────────────────────────────────
|
/* ─────────────────────────────────────────────
|
||||||
graph_node_extra_types table queries
|
graph_node_extra_types table queries
|
||||||
|
|||||||
+21
-3
@@ -16,7 +16,6 @@ type Querier interface {
|
|||||||
ClearKVInvoiceHashIndex(ctx context.Context) error
|
ClearKVInvoiceHashIndex(ctx context.Context) error
|
||||||
CountZombieChannels(ctx context.Context, version int16) (int64, error)
|
CountZombieChannels(ctx context.Context, version int16) (int64, error)
|
||||||
CreateChannel(ctx context.Context, arg CreateChannelParams) (int64, error)
|
CreateChannel(ctx context.Context, arg CreateChannelParams) (int64, error)
|
||||||
CreateChannelExtraType(ctx context.Context, arg CreateChannelExtraTypeParams) error
|
|
||||||
DeleteCanceledInvoices(ctx context.Context) (sql.Result, error)
|
DeleteCanceledInvoices(ctx context.Context) (sql.Result, error)
|
||||||
DeleteChannelPolicyExtraTypes(ctx context.Context, channelPolicyID int64) error
|
DeleteChannelPolicyExtraTypes(ctx context.Context, channelPolicyID int64) error
|
||||||
DeleteChannels(ctx context.Context, ids []int64) error
|
DeleteChannels(ctx context.Context, ids []int64) error
|
||||||
@@ -88,17 +87,33 @@ type Querier interface {
|
|||||||
HighestSCID(ctx context.Context, version int16) ([]byte, error)
|
HighestSCID(ctx context.Context, version int16) ([]byte, error)
|
||||||
InsertAMPSubInvoice(ctx context.Context, arg InsertAMPSubInvoiceParams) error
|
InsertAMPSubInvoice(ctx context.Context, arg InsertAMPSubInvoiceParams) error
|
||||||
InsertAMPSubInvoiceHTLC(ctx context.Context, arg InsertAMPSubInvoiceHTLCParams) error
|
InsertAMPSubInvoiceHTLC(ctx context.Context, arg InsertAMPSubInvoiceHTLCParams) error
|
||||||
InsertChanPolicyExtraType(ctx context.Context, arg InsertChanPolicyExtraTypeParams) error
|
|
||||||
InsertChannelFeature(ctx context.Context, arg InsertChannelFeatureParams) error
|
InsertChannelFeature(ctx context.Context, arg InsertChannelFeatureParams) error
|
||||||
|
// NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
// for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
// we re-insert the same channel again (which would error if the normal
|
||||||
|
// CreateChannel query is used because of the uniqueness constraint on the scid
|
||||||
|
// and version columns).
|
||||||
|
InsertChannelMig(ctx context.Context, arg InsertChannelMigParams) (int64, error)
|
||||||
InsertClosedChannel(ctx context.Context, scid []byte) error
|
InsertClosedChannel(ctx context.Context, scid []byte) error
|
||||||
|
// NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
// for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
// we re-insert the same policy (which would error if the normal
|
||||||
|
// UpsertEdgePolicy query is used because of the constraint in that query that
|
||||||
|
// requires a policy update to have a newer last_update than the existing one).
|
||||||
|
InsertEdgePolicyMig(ctx context.Context, arg InsertEdgePolicyMigParams) (int64, error)
|
||||||
InsertInvoice(ctx context.Context, arg InsertInvoiceParams) (int64, error)
|
InsertInvoice(ctx context.Context, arg InsertInvoiceParams) (int64, error)
|
||||||
InsertInvoiceFeature(ctx context.Context, arg InsertInvoiceFeatureParams) error
|
InsertInvoiceFeature(ctx context.Context, arg InsertInvoiceFeatureParams) error
|
||||||
InsertInvoiceHTLC(ctx context.Context, arg InsertInvoiceHTLCParams) (int64, error)
|
InsertInvoiceHTLC(ctx context.Context, arg InsertInvoiceHTLCParams) (int64, error)
|
||||||
InsertInvoiceHTLCCustomRecord(ctx context.Context, arg InsertInvoiceHTLCCustomRecordParams) error
|
InsertInvoiceHTLCCustomRecord(ctx context.Context, arg InsertInvoiceHTLCCustomRecordParams) error
|
||||||
InsertKVInvoiceKeyAndAddIndex(ctx context.Context, arg InsertKVInvoiceKeyAndAddIndexParams) error
|
InsertKVInvoiceKeyAndAddIndex(ctx context.Context, arg InsertKVInvoiceKeyAndAddIndexParams) error
|
||||||
InsertMigratedInvoice(ctx context.Context, arg InsertMigratedInvoiceParams) (int64, error)
|
InsertMigratedInvoice(ctx context.Context, arg InsertMigratedInvoiceParams) (int64, error)
|
||||||
InsertNodeAddress(ctx context.Context, arg InsertNodeAddressParams) error
|
|
||||||
InsertNodeFeature(ctx context.Context, arg InsertNodeFeatureParams) error
|
InsertNodeFeature(ctx context.Context, arg InsertNodeFeatureParams) error
|
||||||
|
// NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
// for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
// we re-insert the same node (which would error if the normal UpsertNode query
|
||||||
|
// is used because of the constraint in that query that requires a node update
|
||||||
|
// to have a newer last_update than the existing node).
|
||||||
|
InsertNodeMig(ctx context.Context, arg InsertNodeMigParams) (int64, error)
|
||||||
IsClosedChannel(ctx context.Context, scid []byte) (bool, error)
|
IsClosedChannel(ctx context.Context, scid []byte) (bool, error)
|
||||||
IsPublicV1Node(ctx context.Context, pubKey []byte) (bool, error)
|
IsPublicV1Node(ctx context.Context, pubKey []byte) (bool, error)
|
||||||
IsZombieChannel(ctx context.Context, arg IsZombieChannelParams) (bool, error)
|
IsZombieChannel(ctx context.Context, arg IsZombieChannelParams) (bool, error)
|
||||||
@@ -125,8 +140,11 @@ type Querier interface {
|
|||||||
UpdateInvoiceHTLCs(ctx context.Context, arg UpdateInvoiceHTLCsParams) error
|
UpdateInvoiceHTLCs(ctx context.Context, arg UpdateInvoiceHTLCsParams) error
|
||||||
UpdateInvoiceState(ctx context.Context, arg UpdateInvoiceStateParams) (sql.Result, error)
|
UpdateInvoiceState(ctx context.Context, arg UpdateInvoiceStateParams) (sql.Result, error)
|
||||||
UpsertAMPSubInvoice(ctx context.Context, arg UpsertAMPSubInvoiceParams) (sql.Result, error)
|
UpsertAMPSubInvoice(ctx context.Context, arg UpsertAMPSubInvoiceParams) (sql.Result, error)
|
||||||
|
UpsertChanPolicyExtraType(ctx context.Context, arg UpsertChanPolicyExtraTypeParams) error
|
||||||
|
UpsertChannelExtraType(ctx context.Context, arg UpsertChannelExtraTypeParams) error
|
||||||
UpsertEdgePolicy(ctx context.Context, arg UpsertEdgePolicyParams) (int64, error)
|
UpsertEdgePolicy(ctx context.Context, arg UpsertEdgePolicyParams) (int64, error)
|
||||||
UpsertNode(ctx context.Context, arg UpsertNodeParams) (int64, error)
|
UpsertNode(ctx context.Context, arg UpsertNodeParams) (int64, error)
|
||||||
|
UpsertNodeAddress(ctx context.Context, arg UpsertNodeAddressParams) error
|
||||||
UpsertNodeExtraType(ctx context.Context, arg UpsertNodeExtraTypeParams) error
|
UpsertNodeExtraType(ctx context.Context, arg UpsertNodeExtraTypeParams) error
|
||||||
UpsertPruneLogEntry(ctx context.Context, arg UpsertPruneLogEntryParams) error
|
UpsertPruneLogEntry(ctx context.Context, arg UpsertPruneLogEntryParams) error
|
||||||
UpsertZombieChannel(ctx context.Context, arg UpsertZombieChannelParams) error
|
UpsertZombieChannel(ctx context.Context, arg UpsertZombieChannelParams) error
|
||||||
|
|||||||
@@ -105,7 +105,9 @@ INSERT INTO graph_node_features (
|
|||||||
node_id, feature_bit
|
node_id, feature_bit
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2
|
$1, $2
|
||||||
);
|
) ON CONFLICT (node_id, feature_bit)
|
||||||
|
-- Do nothing if the feature already exists for the node.
|
||||||
|
DO NOTHING;
|
||||||
|
|
||||||
-- name: GetNodeFeatures :many
|
-- name: GetNodeFeatures :many
|
||||||
SELECT *
|
SELECT *
|
||||||
@@ -135,7 +137,7 @@ WHERE node_id = $1
|
|||||||
───────────────────────────────────��─────────
|
───────────────────────────────────��─────────
|
||||||
*/
|
*/
|
||||||
|
|
||||||
-- name: InsertNodeAddress :exec
|
-- name: UpsertNodeAddress :exec
|
||||||
INSERT INTO graph_node_addresses (
|
INSERT INTO graph_node_addresses (
|
||||||
node_id,
|
node_id,
|
||||||
type,
|
type,
|
||||||
@@ -143,7 +145,8 @@ INSERT INTO graph_node_addresses (
|
|||||||
position
|
position
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2, $3, $4
|
$1, $2, $3, $4
|
||||||
);
|
) ON CONFLICT (node_id, type, position)
|
||||||
|
DO UPDATE SET address = EXCLUDED.address;
|
||||||
|
|
||||||
-- name: GetNodeAddresses :many
|
-- name: GetNodeAddresses :many
|
||||||
SELECT type, address
|
SELECT type, address
|
||||||
@@ -735,7 +738,9 @@ INSERT INTO graph_channel_features (
|
|||||||
channel_id, feature_bit
|
channel_id, feature_bit
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1, $2
|
$1, $2
|
||||||
);
|
) ON CONFLICT (channel_id, feature_bit)
|
||||||
|
-- Do nothing if the channel_id and feature_bit already exist.
|
||||||
|
DO NOTHING;
|
||||||
|
|
||||||
-- name: GetChannelFeaturesBatch :many
|
-- name: GetChannelFeaturesBatch :many
|
||||||
SELECT
|
SELECT
|
||||||
@@ -750,11 +755,14 @@ ORDER BY channel_id, feature_bit;
|
|||||||
─────────────────────────────────────────────
|
─────────────────────────────────────────────
|
||||||
*/
|
*/
|
||||||
|
|
||||||
-- name: CreateChannelExtraType :exec
|
-- name: UpsertChannelExtraType :exec
|
||||||
INSERT INTO graph_channel_extra_types (
|
INSERT INTO graph_channel_extra_types (
|
||||||
channel_id, type, value
|
channel_id, type, value
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3);
|
VALUES ($1, $2, $3)
|
||||||
|
ON CONFLICT (channel_id, type)
|
||||||
|
-- Update the value if a conflict occurs on channel_id and type.
|
||||||
|
DO UPDATE SET value = EXCLUDED.value;
|
||||||
|
|
||||||
-- name: GetChannelExtrasBatch :many
|
-- name: GetChannelExtrasBatch :many
|
||||||
SELECT
|
SELECT
|
||||||
@@ -861,11 +869,15 @@ WHERE c.scid = @scid
|
|||||||
─────────────────────────────────────────────
|
─────────────────────────────────────────────
|
||||||
*/
|
*/
|
||||||
|
|
||||||
-- name: InsertChanPolicyExtraType :exec
|
-- name: UpsertChanPolicyExtraType :exec
|
||||||
INSERT INTO graph_channel_policy_extra_types (
|
INSERT INTO graph_channel_policy_extra_types (
|
||||||
channel_policy_id, type, value
|
channel_policy_id, type, value
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3);
|
VALUES ($1, $2, $3)
|
||||||
|
ON CONFLICT (channel_policy_id, type)
|
||||||
|
-- If a conflict occurs on channel_policy_id and type, then we update the
|
||||||
|
-- value.
|
||||||
|
DO UPDATE SET value = EXCLUDED.value;
|
||||||
|
|
||||||
-- name: GetChannelPolicyExtraTypesBatch :many
|
-- name: GetChannelPolicyExtraTypesBatch :many
|
||||||
SELECT
|
SELECT
|
||||||
@@ -995,3 +1007,98 @@ SELECT EXISTS (
|
|||||||
SELECT scid
|
SELECT scid
|
||||||
FROM graph_closed_scids
|
FROM graph_closed_scids
|
||||||
WHERE scid IN (sqlc.slice('scids')/*SLICE:scids*/);
|
WHERE scid IN (sqlc.slice('scids')/*SLICE:scids*/);
|
||||||
|
|
||||||
|
/* ─────────────────────────────────────────────
|
||||||
|
Migration specific queries
|
||||||
|
|
||||||
|
NOTE: once sqldbv2 is in place, these queries can be contained to a package
|
||||||
|
dedicated to the migration that requires it, and so we can then remove
|
||||||
|
it from the main set of "live" queries that the code-base has access to.
|
||||||
|
────────────────────────────────────────────-
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
-- for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
-- we re-insert the same node (which would error if the normal UpsertNode query
|
||||||
|
-- is used because of the constraint in that query that requires a node update
|
||||||
|
-- to have a newer last_update than the existing node).
|
||||||
|
-- name: InsertNodeMig :one
|
||||||
|
INSERT INTO graph_nodes (
|
||||||
|
version, pub_key, alias, last_update, color, signature
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5, $6
|
||||||
|
)
|
||||||
|
ON CONFLICT (pub_key, version)
|
||||||
|
-- If a conflict occurs, we have already migrated this node. However, we
|
||||||
|
-- still need to do an "UPDATE SET" here instead of "DO NOTHING" because
|
||||||
|
-- otherwise, the "RETURNING id" part does not work.
|
||||||
|
DO UPDATE SET
|
||||||
|
alias = EXCLUDED.alias,
|
||||||
|
last_update = EXCLUDED.last_update,
|
||||||
|
color = EXCLUDED.color,
|
||||||
|
signature = EXCLUDED.signature
|
||||||
|
RETURNING id;
|
||||||
|
|
||||||
|
-- NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
-- for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
-- we re-insert the same channel again (which would error if the normal
|
||||||
|
-- CreateChannel query is used because of the uniqueness constraint on the scid
|
||||||
|
-- and version columns).
|
||||||
|
-- name: InsertChannelMig :one
|
||||||
|
INSERT INTO graph_channels (
|
||||||
|
version, scid, node_id_1, node_id_2,
|
||||||
|
outpoint, capacity, bitcoin_key_1, bitcoin_key_2,
|
||||||
|
node_1_signature, node_2_signature, bitcoin_1_signature,
|
||||||
|
bitcoin_2_signature
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
|
||||||
|
) ON CONFLICT (scid, version)
|
||||||
|
-- If a conflict occurs, we have already migrated this channel. However, we
|
||||||
|
-- still need to do an "UPDATE SET" here instead of "DO NOTHING" because
|
||||||
|
-- otherwise, the "RETURNING id" part does not work.
|
||||||
|
DO UPDATE SET
|
||||||
|
node_id_1 = EXCLUDED.node_id_1,
|
||||||
|
node_id_2 = EXCLUDED.node_id_2,
|
||||||
|
outpoint = EXCLUDED.outpoint,
|
||||||
|
capacity = EXCLUDED.capacity,
|
||||||
|
bitcoin_key_1 = EXCLUDED.bitcoin_key_1,
|
||||||
|
bitcoin_key_2 = EXCLUDED.bitcoin_key_2,
|
||||||
|
node_1_signature = EXCLUDED.node_1_signature,
|
||||||
|
node_2_signature = EXCLUDED.node_2_signature,
|
||||||
|
bitcoin_1_signature = EXCLUDED.bitcoin_1_signature,
|
||||||
|
bitcoin_2_signature = EXCLUDED.bitcoin_2_signature
|
||||||
|
RETURNING id;
|
||||||
|
|
||||||
|
-- NOTE: This query is only meant to be used by the graph SQL migration since
|
||||||
|
-- for that migration, in order to be retry-safe, we don't want to error out if
|
||||||
|
-- we re-insert the same policy (which would error if the normal
|
||||||
|
-- UpsertEdgePolicy query is used because of the constraint in that query that
|
||||||
|
-- requires a policy update to have a newer last_update than the existing one).
|
||||||
|
-- name: InsertEdgePolicyMig :one
|
||||||
|
INSERT INTO graph_channel_policies (
|
||||||
|
version, channel_id, node_id, timelock, fee_ppm,
|
||||||
|
base_fee_msat, min_htlc_msat, last_update, disabled,
|
||||||
|
max_htlc_msat, inbound_base_fee_msat,
|
||||||
|
inbound_fee_rate_milli_msat, message_flags, channel_flags,
|
||||||
|
signature
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
||||||
|
)
|
||||||
|
ON CONFLICT (channel_id, node_id, version)
|
||||||
|
-- If a conflict occurs, we have already migrated this policy. However, we
|
||||||
|
-- still need to do an "UPDATE SET" here instead of "DO NOTHING" because
|
||||||
|
-- otherwise, the "RETURNING id" part does not work.
|
||||||
|
DO UPDATE SET
|
||||||
|
timelock = EXCLUDED.timelock,
|
||||||
|
fee_ppm = EXCLUDED.fee_ppm,
|
||||||
|
base_fee_msat = EXCLUDED.base_fee_msat,
|
||||||
|
min_htlc_msat = EXCLUDED.min_htlc_msat,
|
||||||
|
last_update = EXCLUDED.last_update,
|
||||||
|
disabled = EXCLUDED.disabled,
|
||||||
|
max_htlc_msat = EXCLUDED.max_htlc_msat,
|
||||||
|
inbound_base_fee_msat = EXCLUDED.inbound_base_fee_msat,
|
||||||
|
inbound_fee_rate_milli_msat = EXCLUDED.inbound_fee_rate_milli_msat,
|
||||||
|
message_flags = EXCLUDED.message_flags,
|
||||||
|
channel_flags = EXCLUDED.channel_flags,
|
||||||
|
signature = EXCLUDED.signature
|
||||||
|
RETURNING id;
|
||||||
Reference in new issue
Block a user