Merge pull request #9869 from ellemouton/graphSQL8-channels-schema

sqldb+graph/db: add channel tables and implement some channel CRUD
This commit is contained in:
Oliver Gugger authored and GitHub committed 2025-06-02 17:18:04 +02:00
commit e9692f8ccd
9 files changed
+604 -20

No files matched your search

+11 -13
View File
@@ -82,7 +82,6 @@ func createLightningNode(priv *btcec.PrivateKey) *models.LightningNode {
Alias: "kek" + hex.EncodeToString(pub),
Features: testFeatures,
Addresses: testAddrs,
ExtraOpaqueData: make([]byte, 0),
}
copy(n.PubKeyBytes[:], priv.PubKey().SerializeCompressed())
@@ -262,7 +261,7 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
func TestPartialNode(t *testing.T) {
t.Parallel()
graph := MakeTestGraph(t)
graph := MakeTestGraphNew(t)
// To insert a partial node, we need to add a channel edge that has
// node keys for nodes we are not yet aware
@@ -1862,7 +1861,7 @@ func TestGraphPruning(t *testing.T) {
func TestHighestChanID(t *testing.T) {
t.Parallel()
graph := MakeTestGraph(t)
graph := MakeTestGraphNew(t)
// If we don't yet have any channels in the database, then we should
// get a channel ID of zero if we ask for the highest channel ID.
@@ -3333,34 +3332,33 @@ func TestPruneGraphNodes(t *testing.T) {
func TestAddChannelEdgeShellNodes(t *testing.T) {
t.Parallel()
graph := MakeTestGraph(t)
graph := MakeTestGraphNew(t)
// To start, we'll create two nodes, and only add one of them to the
// channel graph.
node1 := createTestVertex(t)
if err := graph.AddLightningNode(node1); err != nil {
t.Fatalf("unable to add node: %v", err)
}
require.NoError(t, graph.SetSourceNode(node1))
node2 := createTestVertex(t)
// We'll now create an edge between the two nodes, as a result, node2
// should be inserted into the database as a shell node.
edgeInfo, _ := createEdge(100, 0, 0, 0, node1, node2)
if err := graph.AddChannelEdge(&edgeInfo); err != nil {
t.Fatalf("unable to add edge: %v", err)
}
require.NoError(t, graph.AddChannelEdge(&edgeInfo))
// Ensure that node1 was inserted as a full node, while node2 only has
// a shell node present.
node1, err := graph.FetchLightningNode(node1.PubKeyBytes)
require.NoError(t, err, "unable to fetch node1")
if !node1.HaveNodeAnnouncement {
t.Fatalf("have shell announcement for node1, shouldn't")
}
require.True(t, node1.HaveNodeAnnouncement)
node2, err = graph.FetchLightningNode(node2.PubKeyBytes)
require.NoError(t, err, "unable to fetch node2")
require.False(t, node2.HaveNodeAnnouncement)
// Show that attempting to add the channel again will result in an
// error.
err = graph.AddChannelEdge(&edgeInfo)
require.ErrorIs(t, err, ErrEdgeAlreadyExist)
}
// TestNodePruningUpdateIndexDeletion tests that once a node has been removed
+5 -1
View File
@@ -4122,7 +4122,7 @@ func deserializeLightningNode(r io.Reader) (models.LightningNode, error) {
// We'll try and see if there are any opaque bytes left, if not, then
// we'll ignore the EOF error and return the node as is.
node.ExtraOpaqueData, err = wire.ReadVarBytes(
extraBytes, err := wire.ReadVarBytes(
r, 0, MaxAllowedExtraOpaqueBytes, "blob",
)
switch {
@@ -4132,6 +4132,10 @@ func deserializeLightningNode(r io.Reader) (models.LightningNode, error) {
return models.LightningNode{}, err
}
if len(extraBytes) > 0 {
node.ExtraOpaqueData = extraBytes
}
return node, nil
}
+238 -4
View File
@@ -69,6 +69,16 @@ type SQLQueries interface {
*/
AddSourceNode(ctx context.Context, nodeID int64) error
GetSourceNodesByVersion(ctx context.Context, version int16) ([]sqlc.GetSourceNodesByVersionRow, error)
/*
Channel queries.
*/
CreateChannel(ctx context.Context, arg sqlc.CreateChannelParams) (int64, error)
GetChannelBySCID(ctx context.Context, arg sqlc.GetChannelBySCIDParams) (sqlc.Channel, error)
HighestSCID(ctx context.Context, version int16) ([]byte, error)
CreateChannelExtraType(ctx context.Context, arg sqlc.CreateChannelExtraTypeParams) error
InsertChannelFeature(ctx context.Context, arg sqlc.InsertChannelFeatureParams) error
}
// BatchedSQLQueries is a version of SQLQueries that's capable of batched
@@ -455,6 +465,83 @@ func (s *SQLStore) NodeUpdatesInHorizon(startTime,
return nodes, nil
}
// AddChannelEdge adds a new (undirected, blank) edge to the graph database. An
// undirected edge from the two target nodes are created. The information stored
// denotes the static attributes of the channel, such as the channelID, the keys
// involved in creation of the channel, and the set of features that the channel
// supports. The chanPoint and chanID are used to uniquely identify the edge
// globally within the database.
//
// NOTE: part of the V1Store interface.
func (s *SQLStore) AddChannelEdge(edge *models.ChannelEdgeInfo,
opts ...batch.SchedulerOption) error {
ctx := context.TODO()
var alreadyExists bool
r := &batch.Request[SQLQueries]{
Opts: batch.NewSchedulerOptions(opts...),
Reset: func() {
alreadyExists = false
},
Do: func(tx SQLQueries) error {
err := insertChannel(ctx, tx, edge)
// Silence ErrEdgeAlreadyExist so that the batch can
// succeed, but propagate the error via local state.
if errors.Is(err, ErrEdgeAlreadyExist) {
alreadyExists = true
return nil
}
return err
},
OnCommit: func(err error) error {
switch {
case err != nil:
return err
case alreadyExists:
return ErrEdgeAlreadyExist
default:
s.rejectCache.remove(edge.ChannelID)
s.chanCache.remove(edge.ChannelID)
return nil
}
},
}
return s.chanScheduler.Execute(ctx, r)
}
// HighestChanID returns the "highest" known channel ID in the channel graph.
// This represents the "newest" channel from the PoV of the chain. This method
// can be used by peers to quickly determine if their graphs are in sync.
//
// NOTE: This is part of the V1Store interface.
func (s *SQLStore) HighestChanID() (uint64, error) {
ctx := context.TODO()
var highestChanID uint64
err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
chanID, err := db.HighestSCID(ctx, int16(ProtocolV1))
if errors.Is(err, sql.ErrNoRows) {
return nil
} else if err != nil {
return fmt.Errorf("unable to fetch highest chan ID: %w",
err)
}
highestChanID = byteOrder.Uint64(chanID)
return nil
}, sqldb.NoOpReset)
if err != nil {
return 0, fmt.Errorf("unable to fetch highest chan ID: %w", err)
}
return highestChanID, nil
}
// getNodeByPubKey attempts to look up a target node by its public key.
func getNodeByPubKey(ctx context.Context, db SQLQueries,
pubKey route.Vertex) (int64, *models.LightningNode, error) {
@@ -494,10 +581,9 @@ func buildNode(ctx context.Context, db SQLQueries, dbNode *sqlc.Node) (
copy(pub[:], dbNode.PubKey)
node := &models.LightningNode{
PubKeyBytes: pub,
Features: lnwire.EmptyFeatureVector(),
LastUpdate: time.Unix(0, 0),
ExtraOpaqueData: make([]byte, 0),
PubKeyBytes: pub,
Features: lnwire.EmptyFeatureVector(),
LastUpdate: time.Unix(0, 0),
}
if len(dbNode.Signature) == 0 {
@@ -1023,3 +1109,151 @@ func marshalExtraOpaqueData(data []byte) (map[uint64][]byte, error) {
return records, nil
}
// insertChannel inserts a new channel record into the database.
func insertChannel(ctx context.Context, db SQLQueries,
edge *models.ChannelEdgeInfo) error {
var chanIDB [8]byte
byteOrder.PutUint64(chanIDB[:], edge.ChannelID)
// Make sure that the channel doesn't already exist. We do this
// explicitly instead of relying on catching a unique constraint error
// because relying on SQL to throw that error would abort the entire
// batch of transactions.
_, err := db.GetChannelBySCID(
ctx, sqlc.GetChannelBySCIDParams{
Scid: chanIDB[:],
Version: int16(ProtocolV1),
},
)
if err == nil {
return ErrEdgeAlreadyExist
} else if !errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("unable to fetch channel: %w", err)
}
// Make sure that at least a "shell" entry for each node is present in
// the nodes table.
node1DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey1Bytes)
if err != nil {
return fmt.Errorf("unable to create shell node: %w", err)
}
node2DBID, err := maybeCreateShellNode(ctx, db, edge.NodeKey2Bytes)
if err != nil {
return 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.CreateChannelParams{
Version: int16(ProtocolV1),
Scid: chanIDB[:],
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.CreateChannel(ctx, createParams)
if err != nil {
return err
}
// Insert any channel features.
if len(edge.Features) != 0 {
chanFeatures := lnwire.NewRawFeatureVector()
err := chanFeatures.Decode(bytes.NewReader(edge.Features))
if err != nil {
return err
}
fv := lnwire.NewFeatureVector(chanFeatures, lnwire.Features)
for feature := range fv.Features() {
err = db.InsertChannelFeature(
ctx, sqlc.InsertChannelFeatureParams{
ChannelID: dbChanID,
FeatureBit: int32(feature),
},
)
if err != nil {
return 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 fmt.Errorf("unable to marshal extra opaque data: %w",
err)
}
for tlvType, value := range extra {
err := db.CreateChannelExtraType(
ctx, sqlc.CreateChannelExtraTypeParams{
ChannelID: dbChanID,
Type: int64(tlvType),
Value: value,
},
)
if err != nil {
return fmt.Errorf("unable to upsert channel(%d) extra "+
"signed field(%v): %w", edge.ChannelID,
tlvType, err)
}
}
return nil
}
// maybeCreateShellNode checks if a shell node entry exists for the
// given public key. If it does not exist, then a new shell node entry is
// created. The ID of the node is returned. A shell node only has a protocol
// version and public key persisted.
func maybeCreateShellNode(ctx context.Context, db SQLQueries,
pubKey route.Vertex) (int64, error) {
dbNode, err := db.GetNodeByPubKey(
ctx, sqlc.GetNodeByPubKeyParams{
PubKey: pubKey[:],
Version: int16(ProtocolV1),
},
)
// The node exists. Return the ID.
if err == nil {
return dbNode.ID, nil
} else if !errors.Is(err, sql.ErrNoRows) {
return 0, err
}
// Otherwise, the node does not exist, so we create a shell entry for
// it.
id, err := db.UpsertNode(ctx, sqlc.UpsertNodeParams{
Version: int16(ProtocolV1),
PubKey: pubKey[:],
})
if err != nil {
return 0, fmt.Errorf("unable to create shell node: %w", err)
}
return id, nil
}
+144
View File
@@ -26,6 +26,81 @@ func (q *Queries) AddSourceNode(ctx context.Context, nodeID int64) error {
return err
}
const createChannel = `-- name: CreateChannel :one
/* ─────────────────────────────────────────────
channels table queries
─────────────────────────────────────────────
*/
INSERT INTO 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
)
RETURNING id
`
type CreateChannelParams 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
}
func (q *Queries) CreateChannel(ctx context.Context, arg CreateChannelParams) (int64, error) {
row := q.db.QueryRowContext(ctx, createChannel,
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 createChannelExtraType = `-- name: CreateChannelExtraType :exec
/* ─────────────────────────────────────────────
channel_extra_types table queries
─────────────────────────────────────────────
*/
INSERT INTO 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 deleteExtraNodeType = `-- name: DeleteExtraNodeType :exec
DELETE FROM node_extra_types
WHERE node_id = $1
@@ -83,6 +158,37 @@ func (q *Queries) DeleteNodeFeature(ctx context.Context, arg DeleteNodeFeaturePa
return err
}
const getChannelBySCID = `-- name: GetChannelBySCID :one
SELECT id, 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 FROM channels
WHERE scid = $1 AND version = $2
`
type GetChannelBySCIDParams struct {
Scid []byte
Version int16
}
func (q *Queries) GetChannelBySCID(ctx context.Context, arg GetChannelBySCIDParams) (Channel, error) {
row := q.db.QueryRowContext(ctx, getChannelBySCID, arg.Scid, arg.Version)
var i Channel
err := row.Scan(
&i.ID,
&i.Version,
&i.Scid,
&i.NodeID1,
&i.NodeID2,
&i.Outpoint,
&i.Capacity,
&i.BitcoinKey1,
&i.BitcoinKey2,
&i.Node1Signature,
&i.Node2Signature,
&i.Bitcoin1Signature,
&i.Bitcoin2Signature,
)
return i, err
}
const getExtraNodeTypes = `-- name: GetExtraNodeTypes :many
SELECT node_id, type, value
FROM node_extra_types
@@ -323,6 +429,44 @@ func (q *Queries) GetSourceNodesByVersion(ctx context.Context, version int16) ([
return items, nil
}
const highestSCID = `-- name: HighestSCID :one
SELECT scid
FROM channels
WHERE version = $1
ORDER BY scid DESC
LIMIT 1
`
func (q *Queries) HighestSCID(ctx context.Context, version int16) ([]byte, error) {
row := q.db.QueryRowContext(ctx, highestSCID, version)
var scid []byte
err := row.Scan(&scid)
return scid, err
}
const insertChannelFeature = `-- name: InsertChannelFeature :exec
/* ─────────────────────────────────────────────
channel_features table queries
─────────────────────────────────────────────
*/
INSERT INTO channel_features (
channel_id, feature_bit
) VALUES (
$1, $2
)
`
type InsertChannelFeatureParams struct {
ChannelID int64
FeatureBit int32
}
func (q *Queries) InsertChannelFeature(ctx context.Context, arg InsertChannelFeatureParams) error {
_, err := q.db.ExecContext(ctx, insertChannelFeature, arg.ChannelID, arg.FeatureBit)
return err
}
const insertNodeAddress = `-- name: InsertNodeAddress :exec
/* ─────────────────────────────────────────────
node_addresses table queries
+10 -1
View File
@@ -4,10 +4,19 @@ DROP INDEX IF EXISTS node_extra_types_unique;
DROP INDEX IF EXISTS node_features_unique;
DROP INDEX IF EXISTS node_addresses_unique;
DROP INDEX IF EXISTS source_nodes_unique;
DROP INDEX IF EXISTS channels_node_id_1_idx;
DROP INDEX IF EXISTS channels_node_id_2_idx;
DROP INDEX IF EXISTS channels_unique;
DROP INDEX IF EXISTS channels_version_outpoint_idx;
DROP INDEX IF EXISTS channel_features_unique;
DROP INDEX IF EXISTS channel_extra_types_unique;
-- Drop tables in order of reverse dependencies.
DROP TABLE IF EXISTS source_nodes;
DROP TABLE IF EXISTS node_addresses;
DROP TABLE IF EXISTS node_features;
DROP TABLE IF EXISTS node_extra_types;
DROP TABLE IF EXISTS nodes;
DROP TABLE IF EXISTS nodes;
DROP TABLE IF EXISTS channels;
DROP TABLE IF EXISTS channel_features;
DROP TABLE IF EXISTS channel_extra_types;
+114 -1
View File
@@ -94,4 +94,117 @@ CREATE TABLE IF NOT EXISTS source_nodes (
);
CREATE UNIQUE INDEX IF NOT EXISTS source_nodes_unique ON source_nodes (
node_id
);
);
/* ─────────────────────────────────────────────
channel data tables
─────────────────────────────────────────────
*/
-- channels stores all teh channels that we are aware of in the graph.
CREATE TABLE IF NOT EXISTS channels (
-- The db ID of the channel.
id INTEGER PRIMARY KEY,
-- The protocol version that this node was gossiped on.
version SMALLINT NOT NULL,
-- The channel id (short channel id) of the channel.
scid BLOB NOT NULL,
-- A reference to a node in the nodes table for the node_1 node in
-- the channel announcement.
node_id_1 BIGINT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
-- A reference to a node in the nodes table for the node_2 node in
-- the channel announcement.
node_id_2 BIGINT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
-- The outpoint of the funding transaction. We chose to store this
-- in a string format for the sake of readability and user queries on
-- outpoint.
outpoint TEXT NOT NULL,
-- The capacity of the channel in millisatoshis. This is nullable since
-- (for the v1 protocol at least), the capacity is not necessarily known as
-- it is not gossiped in the channel announcement.
capacity BIGINT,
-- bitcoin_key_1 is the public key owned by node_1 that is used to create
-- a funding transaction. It is nullable since future protocol version may
-- not make use of this field.
bitcoin_key_1 BLOB,
-- bitcoin_key_2 is the public key owned by node_2 that is used to create
-- the funding transaction. It is nullable since future protocol version may
-- not make use of this field.
bitcoin_key_2 BLOB,
-- node_1_signature is the signature of the serialised channel announcement
-- using the node_1 public key. It is nullable since future protocol
-- versions may not make use of this field _and_ because for this node's own
-- channels, the signature will only be known after the initial record
-- creation.
node_1_signature BLOB,
-- node_2_signature is the signature of the serialised channel announcement
-- using the node_2 public key. It is nullable since future protocol
-- versions may not make use of this field _and_ because for this node's own
-- channels, the signature will only be known after the initial record
-- creation.
node_2_signature BLOB,
-- bitcoin_1_signature is the signature of the serialised channel
-- announcement using bitcion_key_1. It is nullable since future protocol
-- versions may not make use of this field _and_ because for this node's
-- own channels, the signature will only be known after the initial record
-- creation.
bitcoin_1_signature BLOB,
-- bitcoin_2_signature is the signature of the serialised channel
-- announcement using bitcion_key_2. It is nullable since future protocol
-- versions may not make use of this field _and_ because for this node's
-- own channels, the signature will only be known after the initial record
-- creation.
bitcoin_2_signature BLOB
);
-- We'll want to lookup all the channels owned by a node, so we create
-- indexes on the node_id_1 and node_id_2 columns.
CREATE INDEX IF NOT EXISTS channels_node_id_1_idx ON channels(node_id_1);
CREATE INDEX IF NOT EXISTS channels_node_id_2_idx ON channels(node_id_2);
-- A channel (identified by a short channel id) can only have one active
-- channel announcement per protocol version. We also order the index by
-- scid in descending order so that we have an idea of the latest channel
-- announcement we know of.
CREATE UNIQUE INDEX IF NOT EXISTS channels_unique ON channels(version, scid DESC);
CREATE INDEX IF NOT EXISTS channels_version_outpoint_idx ON channels(version, outpoint);
-- channel_features contains the feature bits of a channel.
CREATE TABLE IF NOT EXISTS channel_features (
-- The channel id this feature belongs to.
channel_id BIGINT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
-- The feature bit value.
feature_bit INTEGER NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS channel_features_unique ON channel_features (
channel_id, feature_bit
);
-- channel_extra_types stores any extra TLV fields covered by a channels
-- announcement that we do not have an explicit column for in the channels
-- table.
CREATE TABLE IF NOT EXISTS channel_extra_types (
-- The channel id this TLV field belongs to.
channel_id BIGINT NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
-- The Type field.
type BIGINT NOT NULL,
-- The value field.
value BLOB
);
CREATE UNIQUE INDEX IF NOT EXISTS channel_extra_types_unique ON channel_extra_types (
type, channel_id
);
+27
View File
@@ -28,6 +28,33 @@ type AmpSubInvoiceHtlc struct {
Preimage []byte
}
type Channel struct {
ID int64
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
}
type ChannelExtraType struct {
ChannelID int64
Type int64
Value []byte
}
type ChannelFeature struct {
ChannelID int64
FeatureBit int32
}
type Invoice struct {
ID int64
Hash []byte
+5
View File
@@ -13,6 +13,8 @@ import (
type Querier interface {
AddSourceNode(ctx context.Context, nodeID int64) error
ClearKVInvoiceHashIndex(ctx context.Context) error
CreateChannel(ctx context.Context, arg CreateChannelParams) (int64, error)
CreateChannelExtraType(ctx context.Context, arg CreateChannelExtraTypeParams) error
DeleteCanceledInvoices(ctx context.Context) (sql.Result, error)
DeleteExtraNodeType(ctx context.Context, arg DeleteExtraNodeTypeParams) error
DeleteInvoice(ctx context.Context, arg DeleteInvoiceParams) (sql.Result, error)
@@ -24,6 +26,7 @@ type Querier interface {
FetchSettledAMPSubInvoices(ctx context.Context, arg FetchSettledAMPSubInvoicesParams) ([]FetchSettledAMPSubInvoicesRow, error)
FilterInvoices(ctx context.Context, arg FilterInvoicesParams) ([]Invoice, error)
GetAMPInvoiceID(ctx context.Context, setID []byte) (int64, error)
GetChannelBySCID(ctx context.Context, arg GetChannelBySCIDParams) (Channel, error)
GetDatabaseVersion(ctx context.Context) (int32, error)
GetExtraNodeTypes(ctx context.Context, nodeID int64) ([]NodeExtraType, error)
// This method may return more than one invoice if filter using multiple fields
@@ -43,8 +46,10 @@ type Querier interface {
GetNodeFeaturesByPubKey(ctx context.Context, arg GetNodeFeaturesByPubKeyParams) ([]int32, error)
GetNodesByLastUpdateRange(ctx context.Context, arg GetNodesByLastUpdateRangeParams) ([]Node, error)
GetSourceNodesByVersion(ctx context.Context, version int16) ([]GetSourceNodesByVersionRow, error)
HighestSCID(ctx context.Context, version int16) ([]byte, error)
InsertAMPSubInvoice(ctx context.Context, arg InsertAMPSubInvoiceParams) error
InsertAMPSubInvoiceHTLC(ctx context.Context, arg InsertAMPSubInvoiceHTLCParams) error
InsertChannelFeature(ctx context.Context, arg InsertChannelFeatureParams) error
InsertInvoice(ctx context.Context, arg InsertInvoiceParams) (int64, error)
InsertInvoiceFeature(ctx context.Context, arg InsertInvoiceFeatureParams) error
InsertInvoiceHTLC(ctx context.Context, arg InsertInvoiceHTLCParams) (int64, error)
+50
View File
@@ -132,3 +132,53 @@ SELECT sn.node_id, n.pub_key
FROM source_nodes sn
JOIN nodes n ON sn.node_id = n.id
WHERE n.version = $1;
/* ─────────────────────────────────────────────
channels table queries
─────────────────────────────────────────────
*/
-- name: CreateChannel :one
INSERT INTO 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
)
RETURNING id;
-- name: GetChannelBySCID :one
SELECT * FROM channels
WHERE scid = $1 AND version = $2;
-- name: HighestSCID :one
SELECT scid
FROM channels
WHERE version = $1
ORDER BY scid DESC
LIMIT 1;
/* ─────────────────────────────────────────────
channel_features table queries
─────────────────────────────────────────────
*/
-- name: InsertChannelFeature :exec
INSERT INTO channel_features (
channel_id, feature_bit
) VALUES (
$1, $2
);
/* ─────────────────────────────────────────────
channel_extra_types table queries
─────────────────────────────────────────────
*/
-- name: CreateChannelExtraType :exec
INSERT INTO channel_extra_types (
channel_id, type, value
)
VALUES ($1, $2, $3);