Merge pull request #1673 from cfromknecht/prevent-db-reversions

channeldb: fail Open on db reversion
This commit is contained in:
Olaoluwa Osuntokun 2018-08-07 15:47:02 -07:00 committed by GitHub
commit 8379bbaa9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 3 deletions

@ -663,12 +663,24 @@ func (d *DB) syncVersions(versions []version) error {
}
}
// If the current database version matches the latest version number,
// then we don't need to perform any migrations.
latestVersion := getLatestDBVersion(versions)
log.Infof("Checking for schema update: latest_version=%v, "+
"db_version=%v", latestVersion, meta.DbVersionNumber)
if meta.DbVersionNumber == latestVersion {
switch {
// If the database reports a higher version that we are aware of, the
// user is probably trying to revert to a prior version of lnd. We fail
// here to prevent reversions and unintended corruption.
case meta.DbVersionNumber > latestVersion:
log.Errorf("Refusing to revert from db_version=%d to "+
"lower version=%d", meta.DbVersionNumber,
latestVersion)
return ErrDBReversion
// If the current database version matches the latest version number,
// then we don't need to perform any migrations.
case meta.DbVersionNumber == latestVersion:
return nil
}

@ -7,6 +7,10 @@ var (
// created.
ErrNoChanDBExists = fmt.Errorf("channel db has not yet been created")
// ErrDBReversion is returned when detecting an attempt to revert to a
// prior database version.
ErrDBReversion = fmt.Errorf("channel db cannot revert to prior version")
// ErrLinkNodesNotFound is returned when node info bucket hasn't been
// created.
ErrLinkNodesNotFound = fmt.Errorf("no link nodes exist")

@ -2,6 +2,7 @@ package channeldb
import (
"bytes"
"io/ioutil"
"testing"
"github.com/coreos/bbolt"
@ -380,3 +381,43 @@ func TestMigrationWithoutErrors(t *testing.T) {
migrationWithoutErrors,
false)
}
// TestMigrationReversion tests after performing a migration to a higher
// database version, opening the database with a lower latest db version returns
// ErrDBReversion.
func TestMigrationReversion(t *testing.T) {
t.Parallel()
tempDirName, err := ioutil.TempDir("", "channeldb")
if err != nil {
t.Fatalf("unable to create temp dir: %v", err)
}
cdb, err := Open(tempDirName)
if err != nil {
t.Fatalf("unable to open channeldb: %v", err)
}
// Update the database metadata to point to one more than the highest
// known version.
err = cdb.Update(func(tx *bolt.Tx) error {
newMeta := &Meta{
DbVersionNumber: getLatestDBVersion(dbVersions) + 1,
}
return putMeta(newMeta, tx)
})
// Close the database. Even if we succeeded, our next step is to reopen.
cdb.Close()
if err != nil {
t.Fatalf("unable to increase db version: %v", err)
}
_, err = Open(tempDirName)
if err != ErrDBReversion {
t.Fatalf("unexpected error when opening channeldb, "+
"want: %v, got: %v", ErrDBReversion, err)
}
}