mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-25 13:12:11 +02:00
161 lines
4.6 KiB
Go
161 lines
4.6 KiB
Go
package itest
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"net"
|
|
|
|
"github.com/lightningnetwork/lnd"
|
|
graphdb "github.com/lightningnetwork/lnd/graph/db"
|
|
"github.com/lightningnetwork/lnd/lntest"
|
|
"github.com/lightningnetwork/lnd/lntest/node"
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
|
"github.com/lightningnetwork/lnd/sqldb"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// testGraphMigration tests that the graph migration from the old KV store to
|
|
// the new native SQL store works as expected.
|
|
func testGraphMigration(ht *lntest.HarnessTest) {
|
|
if !lnd.RunTestSQLMigration {
|
|
ht.Skip("not running with test_native_sql tag")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
alice := ht.NewNodeWithCoins("Alice", nil)
|
|
|
|
// Make sure we run the test with SQLite or Postgres.
|
|
if alice.Cfg.DBBackend != node.BackendSqlite &&
|
|
alice.Cfg.DBBackend != node.BackendPostgres {
|
|
|
|
ht.Skip("node not running with SQLite or Postgres")
|
|
}
|
|
|
|
// Skip the test if the node is already running with native SQL.
|
|
if alice.Cfg.NativeSQL {
|
|
ht.Skip("node already running with native SQL")
|
|
}
|
|
|
|
// Spin up a mini network and then connect Alice to it.
|
|
chans, nodes := ht.CreateSimpleNetwork(
|
|
[][]string{nil, nil, nil, nil},
|
|
lntest.OpenChannelParams{Amt: chanAmt},
|
|
)
|
|
|
|
// The expected number of nodes in the graph will include those spun up
|
|
// above plus Alice.
|
|
expNumNodes := len(nodes) + 1
|
|
expNumChans := len(chans)
|
|
require.Equal(ht, 5, expNumNodes)
|
|
require.Equal(ht, 3, expNumChans)
|
|
|
|
// Connect Alice to one of the nodes. Alice should now perform a graph
|
|
// sync with the node.
|
|
ht.EnsureConnected(alice, nodes[0])
|
|
|
|
// Wait for Alice to have a full view of the graph.
|
|
ht.AssertNumEdges(alice, expNumChans, false)
|
|
|
|
// Now stop Alice so we can open the DB for examination.
|
|
require.NoError(ht, alice.Stop())
|
|
|
|
// Open the KV store channel graph DB.
|
|
db, err := graphdb.NewKVStore(openKVBackend(ht, alice))
|
|
require.NoError(ht, err)
|
|
|
|
// assertDBState is a helper function that asserts the state of the
|
|
// graph DB.
|
|
assertDBState := func(db graphdb.V1Store) {
|
|
var (
|
|
numNodes int
|
|
edges = make(map[uint64]bool)
|
|
)
|
|
err := db.ForEachNodeCached(ctx, false, func(_ context.Context,
|
|
_ route.Vertex, _ []net.Addr,
|
|
chans map[uint64]*graphdb.DirectedChannel) error {
|
|
|
|
numNodes++
|
|
|
|
// For each node, also count the number of edges.
|
|
for _, ch := range chans {
|
|
edges[ch.ChannelID] = true
|
|
}
|
|
|
|
return nil
|
|
}, func() {
|
|
clear(edges)
|
|
numNodes = 0
|
|
})
|
|
require.NoError(ht, err)
|
|
require.Equal(ht, expNumNodes, numNodes)
|
|
require.Equal(ht, expNumChans, len(edges))
|
|
}
|
|
assertDBState(db)
|
|
|
|
alice.SetExtraArgs([]string{"--db.use-native-sql"})
|
|
|
|
// Now run the migration flow three times to ensure that each run is
|
|
// idempotent.
|
|
for i := 0; i < 3; i++ {
|
|
// Start Alice with the native SQL flag set. This will trigger
|
|
// the migration to run.
|
|
require.NoError(ht, alice.Start(ht.Context()))
|
|
|
|
// At this point the migration should have completed and the
|
|
// node should be running with native SQL. Now we'll stop Alice
|
|
// again so we can safely examine the database.
|
|
require.NoError(ht, alice.Stop())
|
|
|
|
// Now we'll open the database with the native SQL backend and
|
|
// fetch the graph data again to ensure that it was migrated
|
|
// correctly.
|
|
sqlGraphDB := openNativeSQLGraphDB(ht, alice)
|
|
assertDBState(sqlGraphDB)
|
|
}
|
|
|
|
// Now restart Alice without the --db.use-native-sql flag so we can
|
|
// check that the KV tombstone was set and that Alice will fail to
|
|
// start.
|
|
// NOTE: this is the same tombstone used for the graph migration. Only
|
|
// one tombstone is needed since we just need one to represent the fact
|
|
// that the switch to native SQL has been made.
|
|
require.NoError(ht, alice.Stop())
|
|
alice.SetExtraArgs(nil)
|
|
|
|
// Alice should now fail to start due to the tombstone being set.
|
|
require.NoError(ht, alice.StartLndCmd(ht.Context()))
|
|
require.ErrorContains(ht, alice.WaitForProcessExit(), "exit status 1")
|
|
|
|
// Start Alice again so the test can complete.
|
|
alice.SetExtraArgs([]string{"--db.use-native-sql"})
|
|
require.NoError(ht, alice.Start(ht.Context()))
|
|
}
|
|
|
|
func openNativeSQLGraphDB(ht *lntest.HarnessTest,
|
|
hn *node.HarnessNode) graphdb.V1Store {
|
|
|
|
db := openNativeSQLDB(ht, hn)
|
|
|
|
executor := sqldb.NewTransactionExecutor(
|
|
db, func(tx *sql.Tx) graphdb.SQLQueries {
|
|
return db.WithTx(tx)
|
|
},
|
|
)
|
|
|
|
queryCfg := sqldb.DefaultSQLiteConfig()
|
|
if hn.Cfg.DBBackend != node.BackendSqlite {
|
|
queryCfg = sqldb.DefaultPostgresConfig()
|
|
}
|
|
|
|
store, err := graphdb.NewSQLStore(
|
|
&graphdb.SQLStoreConfig{
|
|
ChainHash: *ht.Miner().ActiveNet.GenesisHash,
|
|
QueryCfg: queryCfg,
|
|
},
|
|
executor,
|
|
)
|
|
require.NoError(ht, err)
|
|
|
|
return store
|
|
}
|