Skip to content

Commit 13bf6a5

Browse files
committed
graph/db+sqldb: implement HasChannelEdge and ChannelID
And run `TestEdgeInfoUpdates` against our SQL backends.
1 parent 4fad4a7 commit 13bf6a5

File tree

5 files changed

+220
-1
lines changed

5 files changed

+220
-1
lines changed

graph/db/graph_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ func TestEdgeInfoUpdates(t *testing.T) {
812812
t.Parallel()
813813
ctx := context.Background()
814814

815-
graph := MakeTestGraph(t)
815+
graph := MakeTestGraphNew(t)
816816

817817
// We'd like to test the update of edges inserted into the database, so
818818
// we create two vertexes to connect.

graph/db/sql_store.go

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ type SQLQueries interface {
9797
GetChannelsByPolicyLastUpdateRange(ctx context.Context, arg sqlc.GetChannelsByPolicyLastUpdateRangeParams) ([]sqlc.GetChannelsByPolicyLastUpdateRangeRow, error)
9898
GetChannelByOutpointWithPolicies(ctx context.Context, arg sqlc.GetChannelByOutpointWithPoliciesParams) (sqlc.GetChannelByOutpointWithPoliciesRow, error)
9999
GetPublicV1ChannelsBySCID(ctx context.Context, arg sqlc.GetPublicV1ChannelsBySCIDParams) ([]sqlc.Channel, error)
100+
GetSCIDByOutpoint(ctx context.Context, arg sqlc.GetSCIDByOutpointParams) ([]byte, error)
100101
DeleteChannel(ctx context.Context, id int64) error
101102

102103
CreateChannelExtraType(ctx context.Context, arg sqlc.CreateChannelExtraTypeParams) error
@@ -1833,6 +1834,162 @@ func (s *SQLStore) FetchChannelEdgesByOutpoint(op *wire.OutPoint) (
18331834
return edge, policy1, policy2, nil
18341835
}
18351836

1837+
// HasChannelEdge returns true if the database knows of a channel edge with the
1838+
// passed channel ID, and false otherwise. If an edge with that ID is found
1839+
// within the graph, then two time stamps representing the last time the edge
1840+
// was updated for both directed edges are returned along with the boolean. If
1841+
// it is not found, then the zombie index is checked and its result is returned
1842+
// as the second boolean.
1843+
//
1844+
// NOTE: part of the V1Store interface.
1845+
func (s *SQLStore) HasChannelEdge(chanID uint64) (time.Time, time.Time, bool,
1846+
bool, error) {
1847+
1848+
ctx := context.TODO()
1849+
1850+
var (
1851+
exists bool
1852+
isZombie bool
1853+
node1LastUpdate time.Time
1854+
node2LastUpdate time.Time
1855+
)
1856+
1857+
// We'll query the cache with the shared lock held to allow multiple
1858+
// readers to access values in the cache concurrently if they exist.
1859+
s.cacheMu.RLock()
1860+
if entry, ok := s.rejectCache.get(chanID); ok {
1861+
s.cacheMu.RUnlock()
1862+
node1LastUpdate = time.Unix(entry.upd1Time, 0)
1863+
node2LastUpdate = time.Unix(entry.upd2Time, 0)
1864+
exists, isZombie = entry.flags.unpack()
1865+
1866+
return node1LastUpdate, node2LastUpdate, exists, isZombie, nil
1867+
}
1868+
s.cacheMu.RUnlock()
1869+
1870+
s.cacheMu.Lock()
1871+
defer s.cacheMu.Unlock()
1872+
1873+
// The item was not found with the shared lock, so we'll acquire the
1874+
// exclusive lock and check the cache again in case another method added
1875+
// the entry to the cache while no lock was held.
1876+
if entry, ok := s.rejectCache.get(chanID); ok {
1877+
node1LastUpdate = time.Unix(entry.upd1Time, 0)
1878+
node2LastUpdate = time.Unix(entry.upd2Time, 0)
1879+
exists, isZombie = entry.flags.unpack()
1880+
1881+
return node1LastUpdate, node2LastUpdate, exists, isZombie, nil
1882+
}
1883+
1884+
err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
1885+
var chanIDB [8]byte
1886+
byteOrder.PutUint64(chanIDB[:], chanID)
1887+
1888+
channel, err := db.GetChannelBySCID(
1889+
ctx, sqlc.GetChannelBySCIDParams{
1890+
Scid: chanIDB[:],
1891+
Version: int16(ProtocolV1),
1892+
},
1893+
)
1894+
if errors.Is(err, sql.ErrNoRows) {
1895+
// Check if it is a zombie channel.
1896+
isZombie, err = db.IsZombieChannel(
1897+
ctx, sqlc.IsZombieChannelParams{
1898+
Scid: chanIDB[:],
1899+
Version: int16(ProtocolV1),
1900+
},
1901+
)
1902+
if err != nil {
1903+
return fmt.Errorf("could not check if channel "+
1904+
"is zombie: %w", err)
1905+
}
1906+
1907+
return nil
1908+
} else if err != nil {
1909+
return fmt.Errorf("unable to fetch channel: %w", err)
1910+
}
1911+
1912+
exists = true
1913+
1914+
policy1, err := db.GetChannelPolicyByChannelAndNode(
1915+
ctx, sqlc.GetChannelPolicyByChannelAndNodeParams{
1916+
Version: int16(ProtocolV1),
1917+
ChannelID: channel.ID,
1918+
NodeID: channel.NodeID1,
1919+
},
1920+
)
1921+
if err != nil && !errors.Is(err, sql.ErrNoRows) {
1922+
return fmt.Errorf("unable to fetch channel policy: %w",
1923+
err)
1924+
} else if err == nil {
1925+
node1LastUpdate = time.Unix(policy1.LastUpdate.Int64, 0)
1926+
}
1927+
1928+
policy2, err := db.GetChannelPolicyByChannelAndNode(
1929+
ctx, sqlc.GetChannelPolicyByChannelAndNodeParams{
1930+
Version: int16(ProtocolV1),
1931+
ChannelID: channel.ID,
1932+
NodeID: channel.NodeID2,
1933+
},
1934+
)
1935+
if err != nil && !errors.Is(err, sql.ErrNoRows) {
1936+
return fmt.Errorf("unable to fetch channel policy: %w",
1937+
err)
1938+
} else if err == nil {
1939+
node2LastUpdate = time.Unix(policy2.LastUpdate.Int64, 0)
1940+
}
1941+
1942+
return nil
1943+
}, sqldb.NoOpReset)
1944+
if err != nil {
1945+
return time.Time{}, time.Time{}, false, false,
1946+
fmt.Errorf("unable to fetch channel: %w", err)
1947+
}
1948+
1949+
s.rejectCache.insert(chanID, rejectCacheEntry{
1950+
upd1Time: node1LastUpdate.Unix(),
1951+
upd2Time: node2LastUpdate.Unix(),
1952+
flags: packRejectFlags(exists, isZombie),
1953+
})
1954+
1955+
return node1LastUpdate, node2LastUpdate, exists, isZombie, nil
1956+
}
1957+
1958+
// ChannelID attempt to lookup the 8-byte compact channel ID which maps to the
1959+
// passed channel point (outpoint). If the passed channel doesn't exist within
1960+
// the database, then ErrEdgeNotFound is returned.
1961+
//
1962+
// NOTE: part of the V1Store interface.
1963+
func (s *SQLStore) ChannelID(chanPoint *wire.OutPoint) (uint64, error) {
1964+
var (
1965+
ctx = context.TODO()
1966+
channelID uint64
1967+
)
1968+
err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
1969+
chanID, err := db.GetSCIDByOutpoint(
1970+
ctx, sqlc.GetSCIDByOutpointParams{
1971+
Outpoint: chanPoint.String(),
1972+
Version: int16(ProtocolV1),
1973+
},
1974+
)
1975+
if errors.Is(err, sql.ErrNoRows) {
1976+
return ErrEdgeNotFound
1977+
} else if err != nil {
1978+
return fmt.Errorf("unable to fetch channel ID: %w",
1979+
err)
1980+
}
1981+
1982+
channelID = byteOrder.Uint64(chanID)
1983+
1984+
return nil
1985+
}, sqldb.NoOpReset)
1986+
if err != nil {
1987+
return 0, fmt.Errorf("unable to fetch channel ID: %w", err)
1988+
}
1989+
1990+
return channelID, nil
1991+
}
1992+
18361993
// forEachNodeDirectedChannel iterates through all channels of a given
18371994
// node, executing the passed callback on the directed edge representing the
18381995
// channel and its incoming policy. If the node is not found, no error is
@@ -3234,6 +3391,46 @@ func extractChannelPolicies(row any) (*sqlc.ChannelPolicy, *sqlc.ChannelPolicy,
32343391

32353392
var policy1, policy2 *sqlc.ChannelPolicy
32363393
switch r := row.(type) {
3394+
case sqlc.GetChannelByOutpointWithPoliciesRow:
3395+
if r.Policy1ID.Valid {
3396+
policy1 = &sqlc.ChannelPolicy{
3397+
ID: r.Policy1ID.Int64,
3398+
Version: r.Policy1Version.Int16,
3399+
ChannelID: r.Channel.ID,
3400+
NodeID: r.Policy1NodeID.Int64,
3401+
Timelock: r.Policy1Timelock.Int32,
3402+
FeePpm: r.Policy1FeePpm.Int64,
3403+
BaseFeeMsat: r.Policy1BaseFeeMsat.Int64,
3404+
MinHtlcMsat: r.Policy1MinHtlcMsat.Int64,
3405+
MaxHtlcMsat: r.Policy1MaxHtlcMsat,
3406+
LastUpdate: r.Policy1LastUpdate,
3407+
InboundBaseFeeMsat: r.Policy1InboundBaseFeeMsat,
3408+
InboundFeeRateMilliMsat: r.Policy1InboundFeeRateMilliMsat,
3409+
Disabled: r.Policy1Disabled,
3410+
Signature: r.Policy1Signature,
3411+
}
3412+
}
3413+
if r.Policy2ID.Valid {
3414+
policy2 = &sqlc.ChannelPolicy{
3415+
ID: r.Policy2ID.Int64,
3416+
Version: r.Policy2Version.Int16,
3417+
ChannelID: r.Channel.ID,
3418+
NodeID: r.Policy2NodeID.Int64,
3419+
Timelock: r.Policy2Timelock.Int32,
3420+
FeePpm: r.Policy2FeePpm.Int64,
3421+
BaseFeeMsat: r.Policy2BaseFeeMsat.Int64,
3422+
MinHtlcMsat: r.Policy2MinHtlcMsat.Int64,
3423+
MaxHtlcMsat: r.Policy2MaxHtlcMsat,
3424+
LastUpdate: r.Policy2LastUpdate,
3425+
InboundBaseFeeMsat: r.Policy2InboundBaseFeeMsat,
3426+
InboundFeeRateMilliMsat: r.Policy2InboundFeeRateMilliMsat,
3427+
Disabled: r.Policy2Disabled,
3428+
Signature: r.Policy2Signature,
3429+
}
3430+
}
3431+
3432+
return policy1, policy2, nil
3433+
32373434
case sqlc.GetChannelBySCIDWithPoliciesRow:
32383435
if r.Policy1ID.Valid {
32393436
policy1 = &sqlc.ChannelPolicy{

sqldb/sqlc/graph.sql.go

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqldb/sqlc/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqldb/sqlc/queries/graph.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ SELECT
206206
FROM channel_extra_types cet
207207
WHERE cet.channel_id = $1;
208208

209+
-- name: GetSCIDByOutpoint :one
210+
SELECT scid from channels
211+
WHERE outpoint = $1 AND version = $2;
212+
209213
-- name: GetChannelsByPolicyLastUpdateRange :many
210214
SELECT
211215
sqlc.embed(c),

0 commit comments

Comments
 (0)