meta_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. package channeldb
  2. import (
  3. "bytes"
  4. "testing"
  5. "github.com/btcsuite/btcwallet/walletdb"
  6. "github.com/go-errors/errors"
  7. "github.com/lightningnetwork/lnd/kvdb"
  8. "github.com/stretchr/testify/require"
  9. )
  10. // applyMigration is a helper test function that encapsulates the general steps
  11. // which are needed to properly check the result of applying migration function.
  12. func applyMigration(t *testing.T, beforeMigration, afterMigration func(d *DB),
  13. migrationFunc migration, shouldFail bool, dryRun bool) {
  14. cdb, err := MakeTestDB(t)
  15. if err != nil {
  16. t.Fatal(err)
  17. }
  18. cdb.dryRun = dryRun
  19. // Create a test node that will be our source node.
  20. testNode, err := createTestVertex(cdb)
  21. if err != nil {
  22. t.Fatal(err)
  23. }
  24. graph := cdb.ChannelGraph()
  25. if err := graph.SetSourceNode(testNode); err != nil {
  26. t.Fatal(err)
  27. }
  28. // beforeMigration usually used for populating the database
  29. // with test data.
  30. beforeMigration(cdb)
  31. // Create test meta info with zero database version and put it on disk.
  32. // Than creating the version list pretending that new version was added.
  33. meta := &Meta{DbVersionNumber: 0}
  34. if err := cdb.PutMeta(meta); err != nil {
  35. t.Fatalf("unable to store meta data: %v", err)
  36. }
  37. versions := []mandatoryVersion{
  38. {
  39. number: 0,
  40. migration: nil,
  41. },
  42. {
  43. number: 1,
  44. migration: migrationFunc,
  45. },
  46. }
  47. defer func() {
  48. if r := recover(); r != nil {
  49. if dryRun && r != ErrDryRunMigrationOK {
  50. t.Fatalf("expected dry run migration OK")
  51. }
  52. err = errors.New(r)
  53. }
  54. if err == nil && shouldFail {
  55. t.Fatal("error wasn't received on migration stage")
  56. } else if err != nil && !shouldFail {
  57. t.Fatalf("error was received on migration stage: %v", err)
  58. }
  59. // afterMigration usually used for checking the database state and
  60. // throwing the error if something went wrong.
  61. afterMigration(cdb)
  62. }()
  63. // Sync with the latest version - applying migration function.
  64. err = cdb.syncVersions(versions)
  65. if err != nil {
  66. log.Error(err)
  67. }
  68. }
  69. // TestVersionFetchPut checks the propernces of fetch/put methods
  70. // and also initialization of meta data in case if don't have any in
  71. // database.
  72. func TestVersionFetchPut(t *testing.T) {
  73. t.Parallel()
  74. db, err := MakeTestDB(t)
  75. if err != nil {
  76. t.Fatal(err)
  77. }
  78. meta, err := db.FetchMeta()
  79. if err != nil {
  80. t.Fatal(err)
  81. }
  82. if meta.DbVersionNumber != getLatestDBVersion(dbVersions) {
  83. t.Fatal("initialization of meta information wasn't performed")
  84. }
  85. newVersion := getLatestDBVersion(dbVersions) + 1
  86. meta.DbVersionNumber = newVersion
  87. if err := db.PutMeta(meta); err != nil {
  88. t.Fatalf("update of meta failed %v", err)
  89. }
  90. meta, err = db.FetchMeta()
  91. if err != nil {
  92. t.Fatal(err)
  93. }
  94. if meta.DbVersionNumber != newVersion {
  95. t.Fatal("update of meta information wasn't performed")
  96. }
  97. }
  98. // TestOrderOfMigrations checks that migrations are applied in proper order.
  99. func TestOrderOfMigrations(t *testing.T) {
  100. t.Parallel()
  101. appliedMigration := -1
  102. versions := []mandatoryVersion{
  103. {0, nil},
  104. {1, nil},
  105. {2, func(tx kvdb.RwTx) error {
  106. appliedMigration = 2
  107. return nil
  108. }},
  109. {3, func(tx kvdb.RwTx) error {
  110. appliedMigration = 3
  111. return nil
  112. }},
  113. }
  114. // Retrieve the migration that should be applied to db, as far as
  115. // current version is 1, we skip zero and first versions.
  116. migrations, _ := getMigrationsToApply(versions, 1)
  117. if len(migrations) != 2 {
  118. t.Fatal("incorrect number of migrations to apply")
  119. }
  120. // Apply first migration.
  121. migrations[0](nil)
  122. // Check that first migration corresponds to the second version.
  123. if appliedMigration != 2 {
  124. t.Fatal("incorrect order of applying migrations")
  125. }
  126. // Apply second migration.
  127. migrations[1](nil)
  128. // Check that second migration corresponds to the third version.
  129. if appliedMigration != 3 {
  130. t.Fatal("incorrect order of applying migrations")
  131. }
  132. }
  133. // TestGlobalVersionList checks that there is no mistake in global version list
  134. // in terms of version ordering.
  135. func TestGlobalVersionList(t *testing.T) {
  136. t.Parallel()
  137. if dbVersions == nil {
  138. t.Fatal("can't find versions list")
  139. }
  140. if len(dbVersions) == 0 {
  141. t.Fatal("db versions list is empty")
  142. }
  143. prev := dbVersions[0].number
  144. for i := 1; i < len(dbVersions); i++ {
  145. version := dbVersions[i].number
  146. if version == prev {
  147. t.Fatal("duplicates db versions")
  148. }
  149. if version < prev {
  150. t.Fatal("order of db versions is wrong")
  151. }
  152. prev = version
  153. }
  154. }
  155. // TestMigrationWithPanic asserts that if migration logic panics, we will return
  156. // to the original state unaltered.
  157. func TestMigrationWithPanic(t *testing.T) {
  158. t.Parallel()
  159. bucketPrefix := []byte("somebucket")
  160. keyPrefix := []byte("someprefix")
  161. beforeMigration := []byte("beforemigration")
  162. afterMigration := []byte("aftermigration")
  163. beforeMigrationFunc := func(d *DB) {
  164. // Insert data in database and in order then make sure that the
  165. // key isn't changes in case of panic or fail.
  166. err := kvdb.Update(d, func(tx kvdb.RwTx) error {
  167. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  168. if err != nil {
  169. return err
  170. }
  171. return bucket.Put(keyPrefix, beforeMigration)
  172. }, func() {})
  173. if err != nil {
  174. t.Fatalf("unable to insert: %v", err)
  175. }
  176. }
  177. // Create migration function which changes the initially created data and
  178. // throw the panic, in this case we pretending that something goes.
  179. migrationWithPanic := func(tx kvdb.RwTx) error {
  180. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  181. if err != nil {
  182. return err
  183. }
  184. bucket.Put(keyPrefix, afterMigration)
  185. panic("panic!")
  186. }
  187. // Check that version of database and data wasn't changed.
  188. afterMigrationFunc := func(d *DB) {
  189. meta, err := d.FetchMeta()
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. if meta.DbVersionNumber != 0 {
  194. t.Fatal("migration panicked but version is changed")
  195. }
  196. err = kvdb.Update(d, func(tx kvdb.RwTx) error {
  197. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  198. if err != nil {
  199. return err
  200. }
  201. value := bucket.Get(keyPrefix)
  202. if !bytes.Equal(value, beforeMigration) {
  203. return errors.New("migration failed but data is " +
  204. "changed")
  205. }
  206. return nil
  207. }, func() {})
  208. if err != nil {
  209. t.Fatal(err)
  210. }
  211. }
  212. applyMigration(t,
  213. beforeMigrationFunc,
  214. afterMigrationFunc,
  215. migrationWithPanic,
  216. true,
  217. false)
  218. }
  219. // TestMigrationWithFatal asserts that migrations which fail do not modify the
  220. // database.
  221. func TestMigrationWithFatal(t *testing.T) {
  222. t.Parallel()
  223. bucketPrefix := []byte("somebucket")
  224. keyPrefix := []byte("someprefix")
  225. beforeMigration := []byte("beforemigration")
  226. afterMigration := []byte("aftermigration")
  227. beforeMigrationFunc := func(d *DB) {
  228. err := kvdb.Update(d, func(tx kvdb.RwTx) error {
  229. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  230. if err != nil {
  231. return err
  232. }
  233. return bucket.Put(keyPrefix, beforeMigration)
  234. }, func() {})
  235. if err != nil {
  236. t.Fatalf("unable to insert pre migration key: %v", err)
  237. }
  238. }
  239. // Create migration function which changes the initially created data and
  240. // return the error, in this case we pretending that something goes
  241. // wrong.
  242. migrationWithFatal := func(tx kvdb.RwTx) error {
  243. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  244. if err != nil {
  245. return err
  246. }
  247. bucket.Put(keyPrefix, afterMigration)
  248. return errors.New("some error")
  249. }
  250. // Check that version of database and initial data wasn't changed.
  251. afterMigrationFunc := func(d *DB) {
  252. meta, err := d.FetchMeta()
  253. if err != nil {
  254. t.Fatal(err)
  255. }
  256. if meta.DbVersionNumber != 0 {
  257. t.Fatal("migration failed but version is changed")
  258. }
  259. err = kvdb.Update(d, func(tx kvdb.RwTx) error {
  260. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  261. if err != nil {
  262. return err
  263. }
  264. value := bucket.Get(keyPrefix)
  265. if !bytes.Equal(value, beforeMigration) {
  266. return errors.New("migration failed but data is " +
  267. "changed")
  268. }
  269. return nil
  270. }, func() {})
  271. if err != nil {
  272. t.Fatal(err)
  273. }
  274. }
  275. applyMigration(t,
  276. beforeMigrationFunc,
  277. afterMigrationFunc,
  278. migrationWithFatal,
  279. true,
  280. false)
  281. }
  282. // TestMigrationWithoutErrors asserts that a successful migration has its
  283. // changes applied to the database.
  284. func TestMigrationWithoutErrors(t *testing.T) {
  285. t.Parallel()
  286. bucketPrefix := []byte("somebucket")
  287. keyPrefix := []byte("someprefix")
  288. beforeMigration := []byte("beforemigration")
  289. afterMigration := []byte("aftermigration")
  290. // Populate database with initial data.
  291. beforeMigrationFunc := func(d *DB) {
  292. err := kvdb.Update(d, func(tx kvdb.RwTx) error {
  293. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  294. if err != nil {
  295. return err
  296. }
  297. return bucket.Put(keyPrefix, beforeMigration)
  298. }, func() {})
  299. if err != nil {
  300. t.Fatalf("unable to update db pre migration: %v", err)
  301. }
  302. }
  303. // Create migration function which changes the initially created data.
  304. migrationWithoutErrors := func(tx kvdb.RwTx) error {
  305. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  306. if err != nil {
  307. return err
  308. }
  309. bucket.Put(keyPrefix, afterMigration)
  310. return nil
  311. }
  312. // Check that version of database and data was properly changed.
  313. afterMigrationFunc := func(d *DB) {
  314. meta, err := d.FetchMeta()
  315. if err != nil {
  316. t.Fatal(err)
  317. }
  318. if meta.DbVersionNumber != 1 {
  319. t.Fatal("version number isn't changed after " +
  320. "successfully applied migration")
  321. }
  322. err = kvdb.Update(d, func(tx kvdb.RwTx) error {
  323. bucket, err := tx.CreateTopLevelBucket(bucketPrefix)
  324. if err != nil {
  325. return err
  326. }
  327. value := bucket.Get(keyPrefix)
  328. if !bytes.Equal(value, afterMigration) {
  329. return errors.New("migration wasn't applied " +
  330. "properly")
  331. }
  332. return nil
  333. }, func() {})
  334. if err != nil {
  335. t.Fatal(err)
  336. }
  337. }
  338. applyMigration(t,
  339. beforeMigrationFunc,
  340. afterMigrationFunc,
  341. migrationWithoutErrors,
  342. false,
  343. false)
  344. }
  345. // TestMigrationReversion tests after performing a migration to a higher
  346. // database version, opening the database with a lower latest db version returns
  347. // ErrDBReversion.
  348. func TestMigrationReversion(t *testing.T) {
  349. t.Parallel()
  350. tempDirName := t.TempDir()
  351. backend, cleanup, err := kvdb.GetTestBackend(tempDirName, "cdb")
  352. require.NoError(t, err, "unable to get test db backend")
  353. cdb, err := CreateWithBackend(backend)
  354. if err != nil {
  355. cleanup()
  356. t.Fatalf("unable to open channeldb: %v", err)
  357. }
  358. // Update the database metadata to point to one more than the highest
  359. // known version.
  360. err = kvdb.Update(cdb, func(tx kvdb.RwTx) error {
  361. newMeta := &Meta{
  362. DbVersionNumber: getLatestDBVersion(dbVersions) + 1,
  363. }
  364. return putMeta(newMeta, tx)
  365. }, func() {})
  366. // Close the database. Even if we succeeded, our next step is to reopen.
  367. cdb.Close()
  368. cleanup()
  369. require.NoError(t, err, "unable to increase db version")
  370. backend, cleanup, err = kvdb.GetTestBackend(tempDirName, "cdb")
  371. require.NoError(t, err, "unable to get test db backend")
  372. t.Cleanup(cleanup)
  373. _, err = CreateWithBackend(backend)
  374. if err != ErrDBReversion {
  375. t.Fatalf("unexpected error when opening channeldb, "+
  376. "want: %v, got: %v", ErrDBReversion, err)
  377. }
  378. }
  379. // TestMigrationDryRun ensures that opening the database in dry run migration
  380. // mode will fail and not commit the migration.
  381. func TestMigrationDryRun(t *testing.T) {
  382. t.Parallel()
  383. // Nothing to do, will inspect version number.
  384. beforeMigrationFunc := func(d *DB) {}
  385. // Check that version of database version is not modified.
  386. afterMigrationFunc := func(d *DB) {
  387. err := kvdb.View(d, func(tx kvdb.RTx) error {
  388. meta, err := d.FetchMeta()
  389. if err != nil {
  390. t.Fatal(err)
  391. }
  392. if meta.DbVersionNumber != 0 {
  393. t.Fatal("dry run migration was not aborted")
  394. }
  395. return nil
  396. }, func() {})
  397. if err != nil {
  398. t.Fatalf("unable to apply after func: %v", err)
  399. }
  400. }
  401. applyMigration(t,
  402. beforeMigrationFunc,
  403. afterMigrationFunc,
  404. func(kvdb.RwTx) error { return nil },
  405. true,
  406. true)
  407. }
  408. // TestOptionalMeta checks the basic read and write for the optional meta.
  409. func TestOptionalMeta(t *testing.T) {
  410. t.Parallel()
  411. db, err := MakeTestDB(t)
  412. require.NoError(t, err)
  413. // Test read an empty optional meta.
  414. om, err := db.fetchOptionalMeta()
  415. require.NoError(t, err, "error getting optional meta")
  416. require.Empty(t, om.Versions, "expected empty versions")
  417. // Test write an optional meta.
  418. om = &OptionalMeta{
  419. Versions: map[uint64]string{
  420. 0: optionalVersions[0].name,
  421. },
  422. }
  423. err = db.putOptionalMeta(om)
  424. require.NoError(t, err, "error putting optional meta")
  425. om1, err := db.fetchOptionalMeta()
  426. require.NoError(t, err, "error getting optional meta")
  427. require.Equal(t, om, om1, "unexpected empty versions")
  428. require.Equal(t, "0: prune revocation log", om.String())
  429. }
  430. // TestApplyOptionalVersions checks that the optional migration is applied as
  431. // expected based on the config.
  432. func TestApplyOptionalVersions(t *testing.T) {
  433. t.Parallel()
  434. db, err := MakeTestDB(t)
  435. require.NoError(t, err)
  436. // Overwrite the migration function so we can count how many times the
  437. // migration has happened.
  438. migrateCount := 0
  439. optionalVersions[0].migration = func(_ kvdb.Backend,
  440. _ MigrationConfig) error {
  441. migrateCount++
  442. return nil
  443. }
  444. // Test that when the flag is false, no migration happens.
  445. cfg := OptionalMiragtionConfig{}
  446. err = db.applyOptionalVersions(cfg)
  447. require.NoError(t, err, "failed to apply optional migration")
  448. require.Equal(t, 0, migrateCount, "expected no migration")
  449. // Check the optional meta is not updated.
  450. om, err := db.fetchOptionalMeta()
  451. require.NoError(t, err, "error getting optional meta")
  452. require.Empty(t, om.Versions, "expected empty versions")
  453. // Test that when specified, the optional migration is applied.
  454. cfg.PruneRevocationLog = true
  455. err = db.applyOptionalVersions(cfg)
  456. require.NoError(t, err, "failed to apply optional migration")
  457. require.Equal(t, 1, migrateCount, "expected migration")
  458. // Fetch the updated optional meta.
  459. om, err = db.fetchOptionalMeta()
  460. require.NoError(t, err, "error getting optional meta")
  461. // Verify that the optional meta is updated as expected.
  462. omExpected := &OptionalMeta{
  463. Versions: map[uint64]string{
  464. 0: optionalVersions[0].name,
  465. },
  466. }
  467. require.Equal(t, omExpected, om, "unexpected empty versions")
  468. // Test that though specified, the optional migration is not run since
  469. // it's already been applied.
  470. cfg.PruneRevocationLog = true
  471. err = db.applyOptionalVersions(cfg)
  472. require.NoError(t, err, "failed to apply optional migration")
  473. require.Equal(t, 1, migrateCount, "expected no migration")
  474. }
  475. // TestFetchMeta tests that the FetchMeta returns the latest DB version for a
  476. // freshly created DB instance.
  477. func TestFetchMeta(t *testing.T) {
  478. t.Parallel()
  479. db, err := MakeTestDB(t)
  480. require.NoError(t, err)
  481. meta := &Meta{}
  482. err = db.View(func(tx walletdb.ReadTx) error {
  483. return FetchMeta(meta, tx)
  484. }, func() {
  485. meta = &Meta{}
  486. })
  487. require.NoError(t, err)
  488. require.Equal(t, LatestDBVersion(), meta.DbVersionNumber)
  489. }
  490. // TestMarkerAndTombstone tests that markers like a tombstone can be added to a
  491. // DB.
  492. func TestMarkerAndTombstone(t *testing.T) {
  493. t.Parallel()
  494. db, err := MakeTestDB(t)
  495. require.NoError(t, err)
  496. // Test that a generic marker is not present in a fresh DB.
  497. var marker []byte
  498. err = db.View(func(tx walletdb.ReadTx) error {
  499. var err error
  500. marker, err = CheckMarkerPresent(tx, []byte("foo"))
  501. return err
  502. }, func() {
  503. marker = nil
  504. })
  505. require.ErrorIs(t, err, ErrMarkerNotPresent)
  506. require.Nil(t, marker)
  507. // Only adding the marker bucket should not be enough to be counted as
  508. // a marker, we explicitly also want the value to be set.
  509. err = db.Update(func(tx walletdb.ReadWriteTx) error {
  510. _, err := tx.CreateTopLevelBucket([]byte("foo"))
  511. return err
  512. }, func() {})
  513. require.NoError(t, err)
  514. err = db.View(func(tx walletdb.ReadTx) error {
  515. var err error
  516. marker, err = CheckMarkerPresent(tx, []byte("foo"))
  517. return err
  518. }, func() {
  519. marker = nil
  520. })
  521. require.ErrorIs(t, err, ErrMarkerNotPresent)
  522. require.Nil(t, marker)
  523. // Test that a tombstone marker is not present in a fresh DB.
  524. err = db.View(EnsureNoTombstone, func() {})
  525. require.NoError(t, err)
  526. // Add a generic marker now and assert that it can be read.
  527. err = db.Update(func(tx walletdb.ReadWriteTx) error {
  528. return AddMarker(tx, []byte("foo"), []byte("bar"))
  529. }, func() {})
  530. require.NoError(t, err)
  531. err = db.View(func(tx walletdb.ReadTx) error {
  532. var err error
  533. marker, err = CheckMarkerPresent(tx, []byte("foo"))
  534. return err
  535. }, func() {
  536. marker = nil
  537. })
  538. require.NoError(t, err)
  539. require.Equal(t, []byte("bar"), marker)
  540. // A tombstone should still not be present.
  541. err = db.View(EnsureNoTombstone, func() {})
  542. require.NoError(t, err)
  543. // Finally, add a tombstone.
  544. tombstoneText := []byte("RIP test DB")
  545. err = db.Update(func(tx walletdb.ReadWriteTx) error {
  546. return AddMarker(tx, TombstoneKey, tombstoneText)
  547. }, func() {})
  548. require.NoError(t, err)
  549. // We can read it as a normal marker.
  550. err = db.View(func(tx walletdb.ReadTx) error {
  551. var err error
  552. marker, err = CheckMarkerPresent(tx, TombstoneKey)
  553. return err
  554. }, func() {
  555. marker = nil
  556. })
  557. require.NoError(t, err)
  558. require.Equal(t, tombstoneText, marker)
  559. // But also as a tombstone, and now we should get an error that the DB
  560. // cannot be used anymore.
  561. err = db.View(EnsureNoTombstone, func() {})
  562. require.ErrorContains(t, err, string(tombstoneText))
  563. // Now that the DB has a tombstone, we should no longer be able to open
  564. // it once we close it.
  565. _, err = CreateWithBackend(db.Backend)
  566. require.ErrorContains(t, err, string(tombstoneText))
  567. }