channeldb: remove graph db from channeldb

Now that the channel.DB no longer uses the ChannelGraph pointer, we can
completely remove it as a member of channeldb.DB.
This commit is contained in:
Elle Mouton 2024-10-22 14:51:32 +02:00
parent 2c083bc017
commit b86980ec40
No known key found for this signature in database
GPG key ID: D7D916376026F177
9 changed files with 100 additions and 134 deletions

View file

@ -8,7 +8,8 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/channeldb"
graphdb "github.com/lightningnetwork/lnd/graph/db"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/stretchr/testify/require"
)
@ -24,17 +25,21 @@ type testGraph interface {
}
func newDiskChanGraph(t *testing.T) (testGraph, error) {
// Next, create channeldb for the first time.
cdb, err := channeldb.Open(t.TempDir())
if err != nil {
return nil, err
}
t.Cleanup(func() {
require.NoError(t, cdb.Close())
backend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: t.TempDir(),
DBFileName: "graph.db",
NoFreelistSync: true,
AutoCompact: false,
AutoCompactMinAge: kvdb.DefaultBoltAutoCompactMinAge,
DBTimeout: kvdb.DefaultDBTimeout,
})
require.NoError(t, err)
graphDB, err := graphdb.NewChannelGraph(backend)
require.NoError(t, err)
return &databaseChannelGraph{
db: cdb.ChannelGraph(),
db: graphDB,
}, nil
}

View file

@ -335,7 +335,6 @@ type DB struct {
channelStateDB *ChannelStateDB
dbPath string
graph *graphdb.ChannelGraph
clock clock.Clock
dryRun bool
keepFailedPaymentAttempts bool
@ -362,22 +361,18 @@ func Open(dbPath string, modifiers ...OptionModifier) (*DB, error) {
return nil, err
}
graphDB, err := graphdb.NewChannelGraph(backend)
if err != nil {
return nil, err
}
db, err := CreateWithBackend(backend, graphDB, modifiers...)
db, err := CreateWithBackend(backend, modifiers...)
if err == nil {
db.dbPath = dbPath
}
return db, err
}
// CreateWithBackend creates channeldb instance using the passed kvdb.Backend.
// Any necessary schemas migrations due to updates will take place as necessary.
func CreateWithBackend(backend kvdb.Backend, graph *graphdb.ChannelGraph,
modifiers ...OptionModifier) (*DB, error) {
func CreateWithBackend(backend kvdb.Backend, modifiers ...OptionModifier) (*DB,
error) {
opts := DefaultOptions()
for _, modifier := range modifiers {
@ -403,7 +398,6 @@ func CreateWithBackend(backend kvdb.Backend, graph *graphdb.ChannelGraph,
keepFailedPaymentAttempts: opts.keepFailedPaymentAttempts,
storeFinalHtlcResolutions: opts.storeFinalHtlcResolutions,
noRevLogAmtData: opts.NoRevLogAmtData,
graph: graph,
}
// Set the parent pointer (only used in tests).
@ -1612,11 +1606,6 @@ func (d *DB) applyOptionalVersions(cfg OptionalMiragtionConfig) error {
return nil
}
// ChannelGraph returns the current instance of the directed channel graph.
func (d *DB) ChannelGraph() *graphdb.ChannelGraph {
return d.graph
}
// ChannelStateDB returns the sub database that is concerned with the channel
// state.
func (d *DB) ChannelStateDB() *ChannelStateDB {
@ -1832,13 +1821,7 @@ func MakeTestDB(t *testing.T, modifiers ...OptionModifier) (*DB, error) {
return nil, err
}
graphDB, err := graphdb.NewChannelGraph(backend)
if err != nil {
backendCleanup()
return nil, err
}
cdb, err := CreateWithBackend(backend, graphDB, modifiers...)
cdb, err := CreateWithBackend(backend, modifiers...)
if err != nil {
backendCleanup()
return nil, err

View file

@ -51,10 +51,7 @@ func TestOpenWithCreate(t *testing.T) {
require.NoError(t, err, "unable to get test db backend")
t.Cleanup(cleanup)
graphDB, err := graphdb.NewChannelGraph(backend)
require.NoError(t, err)
cdb, err := CreateWithBackend(backend, graphDB)
cdb, err := CreateWithBackend(backend)
require.NoError(t, err, "unable to create channeldb")
if err := cdb.Close(); err != nil {
t.Fatalf("unable to close channeldb: %v", err)
@ -90,10 +87,7 @@ func TestWipe(t *testing.T) {
require.NoError(t, err, "unable to get test db backend")
t.Cleanup(cleanup)
graphDB, err := graphdb.NewChannelGraph(backend)
require.NoError(t, err)
fullDB, err := CreateWithBackend(backend, graphDB)
fullDB, err := CreateWithBackend(backend)
require.NoError(t, err, "unable to create channeldb")
defer fullDB.Close()
@ -194,7 +188,8 @@ func TestMultiSourceAddrsForNode(t *testing.T) {
fullDB, err := MakeTestDB(t)
require.NoError(t, err, "unable to make test database")
graph := fullDB.ChannelGraph()
graph, err := graphdb.MakeTestGraph(t)
require.NoError(t, err)
// We'll make a test vertex to insert into the database, as the source
// node, but this node will only have half the number of addresses it

View file

@ -25,10 +25,9 @@ func applyMigration(t *testing.T, beforeMigration, afterMigration func(d *DB),
// Create a test node that will be our source node.
testNode := createTestVertex(t)
graph := cdb.ChannelGraph()
if err := graph.SetSourceNode(testNode); err != nil {
t.Fatal(err)
}
graph, err := graphdb.MakeTestGraph(t)
require.NoError(t, err)
require.NoError(t, graph.SetSourceNode(testNode))
// beforeMigration usually used for populating the database
// with test data.
@ -423,10 +422,7 @@ func TestMigrationReversion(t *testing.T) {
backend, cleanup, err := kvdb.GetTestBackend(tempDirName, "cdb")
require.NoError(t, err, "unable to get test db backend")
graphDB, err := graphdb.NewChannelGraph(backend)
require.NoError(t, err)
cdb, err := CreateWithBackend(backend, graphDB)
cdb, err := CreateWithBackend(backend)
if err != nil {
cleanup()
t.Fatalf("unable to open channeldb: %v", err)
@ -452,10 +448,7 @@ func TestMigrationReversion(t *testing.T) {
require.NoError(t, err, "unable to get test db backend")
t.Cleanup(cleanup)
graphDB, err = graphdb.NewChannelGraph(backend)
require.NoError(t, err)
_, err = CreateWithBackend(backend, graphDB)
_, err = CreateWithBackend(backend)
if err != ErrDBReversion {
t.Fatalf("unexpected error when opening channeldb, "+
"want: %v, got: %v", ErrDBReversion, err)
@ -683,11 +676,8 @@ func TestMarkerAndTombstone(t *testing.T) {
err = db.View(EnsureNoTombstone, func() {})
require.ErrorContains(t, err, string(tombstoneText))
graphDB, err := graphdb.NewChannelGraph(db.Backend)
require.NoError(t, err)
// Now that the DB has a tombstone, we should no longer be able to open
// it once we close it.
_, err = CreateWithBackend(db.Backend, graphDB)
_, err = CreateWithBackend(db.Backend)
require.ErrorContains(t, err, string(tombstoneText))
}

View file

@ -901,18 +901,10 @@ func (d *RPCSignerWalletImpl) BuildChainControl(
type DatabaseInstances struct {
// GraphDB is the database that stores the channel graph used for path
// finding.
//
// NOTE/TODO: This currently _needs_ to be the same instance as the
// ChanStateDB below until the separation of the two databases is fully
// complete!
GraphDB *channeldb.DB
GraphDB *graphdb.ChannelGraph
// ChanStateDB is the database that stores all of our node's channel
// state.
//
// NOTE/TODO: This currently _needs_ to be the same instance as the
// GraphDB above until the separation of the two databases is fully
// complete!
ChanStateDB *channeldb.DB
// HeightHintDB is the database that stores height hints for spends.
@ -1040,7 +1032,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
)
}
graphDB, err := graphdb.NewChannelGraph(
dbs.GraphDB, err = graphdb.NewChannelGraph(
databaseBackends.GraphDB, graphDBOptions...,
)
if err != nil {
@ -1066,8 +1058,8 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
// Otherwise, we'll open two instances, one for the state we only need
// locally, and the other for things we want to ensure are replicated.
dbs.GraphDB, err = channeldb.CreateWithBackend(
databaseBackends.ChanStateDB, graphDB, dbOptions...,
dbs.ChanStateDB, err = channeldb.CreateWithBackend(
databaseBackends.ChanStateDB, dbOptions...,
)
switch {
// Give the DB a chance to dry run the migration. Since we know that
@ -1085,27 +1077,14 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
return nil, nil, err
}
// For now, we don't _actually_ split the graph and channel state DBs on
// the code level. Since they both are based upon the *channeldb.DB
// struct it will require more refactoring to fully separate them. With
// the full remote mode we at least know for now that they both point to
// the same DB backend (and also namespace within that) so we only need
// to apply any migration once.
//
// TODO(guggero): Once the full separation of anything graph related
// from the channeldb.DB is complete, the decorated instance of the
// channel state DB should be created here individually instead of just
// using the same struct (and DB backend) instance.
dbs.ChanStateDB = dbs.GraphDB
// Instantiate a native SQL invoice store if the flag is set.
if d.cfg.DB.UseNativeSQL {
// KV invoice db resides in the same database as the graph and
// channel state DB. Let's query the database to see if we have
// any invoices there. If we do, we won't allow the user to
// start lnd with native SQL enabled, as we don't currently
// migrate the invoices to the new database schema.
invoiceSlice, err := dbs.GraphDB.QueryInvoices(
// KV invoice db resides in the same database as the channel
// state DB. Let's query the database to see if we have any
// invoices there. If we do, we won't allow the user to start
// lnd with native SQL enabled, as we don't currently migrate
// the invoices to the new database schema.
invoiceSlice, err := dbs.ChanStateDB.QueryInvoices(
ctx, invoices.InvoiceQuery{
NumMaxInvoices: 1,
},
@ -1139,7 +1118,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
executor, clock.NewDefaultClock(),
)
} else {
dbs.InvoiceDB = dbs.GraphDB
dbs.InvoiceDB = dbs.ChanStateDB
}
// Wrap the watchtower client DB and make sure we clean up.

View file

@ -12,6 +12,7 @@ import (
"net"
"sort"
"sync"
"testing"
"time"
"github.com/btcsuite/btcd/btcec/v2"
@ -4775,3 +4776,31 @@ func deserializeChanEdgePolicyRaw(r io.Reader) (*models.ChannelEdgePolicy,
return edge, nil
}
// MakeTestGraph creates a new instance of the ChannelGraph for testing purposes.
func MakeTestGraph(t testing.TB, modifiers ...OptionModifier) (*ChannelGraph, error) {
opts := DefaultOptions()
for _, modifier := range modifiers {
modifier(opts)
}
// Next, create channelgraph for the first time.
backend, backendCleanup, err := kvdb.GetTestBackend(t.TempDir(), "cgr")
if err != nil {
backendCleanup()
return nil, err
}
graph, err := NewChannelGraph(backend)
if err != nil {
backendCleanup()
return nil, err
}
t.Cleanup(func() {
_ = backend.Close()
backendCleanup()
})
return graph, nil
}

View file

@ -65,34 +65,6 @@ var (
}
)
// MakeTestGraph creates a new instance of the ChannelGraph for testing purposes.
func MakeTestGraph(t testing.TB, modifiers ...OptionModifier) (*ChannelGraph, error) {
opts := DefaultOptions()
for _, modifier := range modifiers {
modifier(opts)
}
// Next, create channelgraph for the first time.
backend, backendCleanup, err := kvdb.GetTestBackend(t.TempDir(), "cgr")
if err != nil {
backendCleanup()
return nil, err
}
graph, err := NewChannelGraph(backend)
if err != nil {
backendCleanup()
return nil, err
}
t.Cleanup(func() {
_ = backend.Close()
backendCleanup()
})
return graph, nil
}
func createLightningNode(db kvdb.Backend, priv *btcec.PrivateKey) (*LightningNode, error) {
updateTime := prand.Int63()

View file

@ -19,9 +19,11 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channelnotifier"
"github.com/lightningnetwork/lnd/fn"
graphdb "github.com/lightningnetwork/lnd/graph/db"
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lntest/channels"
"github.com/lightningnetwork/lnd/lntest/mock"
"github.com/lightningnetwork/lnd/lntypes"
@ -607,10 +609,25 @@ func createTestPeer(t *testing.T) *peerTestCtx {
const chanActiveTimeout = time.Minute
dbAlice, err := channeldb.Open(t.TempDir())
dbPath := t.TempDir()
graphBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: dbPath,
DBFileName: "graph.db",
NoFreelistSync: true,
AutoCompact: false,
AutoCompactMinAge: kvdb.DefaultBoltAutoCompactMinAge,
DBTimeout: kvdb.DefaultDBTimeout,
})
require.NoError(t, err)
dbAliceGraph, err := graphdb.NewChannelGraph(graphBackend)
require.NoError(t, err)
dbAliceChannel, err := channeldb.Open(dbPath)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, dbAlice.Close())
require.NoError(t, dbAliceChannel.Close())
})
nodeSignerAlice := netann.NewNodeSigner(aliceKeySigner)
@ -620,8 +637,8 @@ func createTestPeer(t *testing.T) *peerTestCtx {
ChanStatusSampleInterval: 30 * time.Second,
ChanEnableTimeout: chanActiveTimeout,
ChanDisableTimeout: 2 * time.Minute,
DB: dbAlice.ChannelStateDB(),
Graph: dbAlice.ChannelGraph(),
DB: dbAliceChannel.ChannelStateDB(),
Graph: dbAliceGraph,
MessageSigner: nodeSignerAlice,
OurPubKey: aliceKeyPub,
OurKeyLoc: testKeyLoc,
@ -663,7 +680,7 @@ func createTestPeer(t *testing.T) *peerTestCtx {
mockSwitch := &mockMessageSwitch{}
// TODO(yy): change ChannelNotifier to be an interface.
channelNotifier := channelnotifier.New(dbAlice.ChannelStateDB())
channelNotifier := channelnotifier.New(dbAliceChannel.ChannelStateDB())
require.NoError(t, channelNotifier.Start())
t.Cleanup(func() {
require.NoError(t, channelNotifier.Stop(),
@ -707,7 +724,7 @@ func createTestPeer(t *testing.T) *peerTestCtx {
Switch: mockSwitch,
ChanActiveTimeout: chanActiveTimeout,
InterceptSwitch: interceptableSwitch,
ChannelDB: dbAlice.ChannelStateDB(),
ChannelDB: dbAliceChannel.ChannelStateDB(),
FeeEstimator: estimator,
Wallet: wallet,
ChainNotifier: notifier,
@ -749,7 +766,7 @@ func createTestPeer(t *testing.T) *peerTestCtx {
mockSwitch: mockSwitch,
peer: alicePeer,
notifier: notifier,
db: dbAlice,
db: dbAliceChannel,
privKey: aliceKeyPriv,
mockConn: mockConn,
customChan: receivedCustomChan,

View file

@ -612,7 +612,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
s := &server{
cfg: cfg,
implCfg: implCfg,
graphDB: dbs.GraphDB.ChannelGraph(),
graphDB: dbs.GraphDB,
chanStateDB: dbs.ChanStateDB.ChannelStateDB(),
addrSource: addrSource,
miscDB: dbs.ChanStateDB,
@ -766,7 +766,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
IsChannelActive: s.htlcSwitch.HasActiveLink,
ApplyChannelUpdate: s.applyChannelUpdate,
DB: s.chanStateDB,
Graph: dbs.GraphDB.ChannelGraph(),
Graph: dbs.GraphDB,
}
chanStatusMgr, err := netann.NewChanStatusManager(chanStatusMgrCfg)
@ -856,10 +856,6 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
selfAddrs := make([]net.Addr, 0, len(externalIPs))
selfAddrs = append(selfAddrs, externalIPs...)
// As the graph can be obtained at anytime from the network, we won't
// replicate it, and instead it'll only be stored locally.
chanGraph := dbs.GraphDB.ChannelGraph()
// We'll now reconstruct a node announcement based on our current
// configuration so we can send it out as a sort of heart beat within
// the network.
@ -918,7 +914,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
// Finally, we'll update the representation on disk, and update our
// cached in-memory version as well.
if err := chanGraph.SetSourceNode(selfNode); err != nil {
if err := dbs.GraphDB.SetSourceNode(selfNode); err != nil {
return nil, fmt.Errorf("can't set self node: %w", err)
}
s.currentNodeAnn = nodeAnn
@ -1018,13 +1014,13 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
MinProbability: routingConfig.MinRouteProbability,
}
sourceNode, err := chanGraph.SourceNode()
sourceNode, err := dbs.GraphDB.SourceNode()
if err != nil {
return nil, fmt.Errorf("error getting source node: %w", err)
}
paymentSessionSource := &routing.SessionSource{
GraphSessionFactory: graphsession.NewGraphSessionFactory(
chanGraph,
dbs.GraphDB,
),
SourceNode: sourceNode,
MissionControl: s.defaultMC,
@ -1041,7 +1037,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
s.graphBuilder, err = graph.NewBuilder(&graph.Config{
SelfNode: selfNode.PubKeyBytes,
Graph: chanGraph,
Graph: dbs.GraphDB,
Chain: cc.ChainIO,
ChainView: cc.ChainView,
Notifier: cc.ChainNotifier,
@ -1058,7 +1054,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
s.chanRouter, err = routing.New(routing.Config{
SelfNode: selfNode.PubKeyBytes,
RoutingGraph: graphsession.NewRoutingGraph(chanGraph),
RoutingGraph: graphsession.NewRoutingGraph(dbs.GraphDB),
Chain: cc.ChainIO,
Payer: s.htlcSwitch,
Control: s.controlTower,