Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added upgrade path for used -> active migration
Browse files Browse the repository at this point in the history
tuxcanfly committed Apr 7, 2015
1 parent b208534 commit be38bef
Showing 2 changed files with 101 additions and 25 deletions.
6 changes: 4 additions & 2 deletions waddrmgr/address.go
Original file line number Diff line number Diff line change
@@ -189,7 +189,8 @@ func (a *managedAddress) Compressed() bool {
return a.compressed
}

// Active returns true if the backing address is active
// Active returns true if the backing address is active i.e if it has not been
// used in any transaction.
//
// This is part of the ManagedAddress interface implementation.
func (a *managedAddress) Active() bool {
@@ -455,7 +456,8 @@ func (a *scriptAddress) Compressed() bool {
return false
}

// Active returns true if the backing address is active
// Active returns true if the backing address is active i.e if it has not been
// used in any transaction.
//
// This is part of the ManagedAddress interface implementation.
func (a *scriptAddress) Active() bool {
120 changes: 97 additions & 23 deletions waddrmgr/db.go
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ import (

const (
// LatestMgrVersion is the most recent manager version.
LatestMgrVersion = 3
LatestMgrVersion = 4
)

var (
@@ -209,7 +209,7 @@ var (
acctNumAcctsName = []byte("numaccts")

// Active addresses (active bucket)
activeAddrBucket = []byte("activeaddrs")
activeAddrBucketName = []byte("activeaddrs")
)

// uint32ToBytes converts a 32 bit unsigned integer into a 4-byte slice in
@@ -982,9 +982,33 @@ func serializeScriptAddress(encryptedHash, encryptedScript []byte) []byte {
return rawData
}

// putAddressActive flags the provided address hash as active.
func putAddressActive(tx walletdb.Tx, addrHash []byte) error {
bucket := tx.RootBucket().Bucket(activeAddrBucketName)
err := bucket.Put(addrHash[:], nullVal)
if err != nil {
str := fmt.Sprintf("failed to mark active address %x", addrHash)
return managerError(ErrDatabase, str, err)
}
return nil
}

// markAddressInactive flags the provided address hash as inactive.
func markAddressInactive(tx walletdb.Tx, addressID []byte) error {
bucket := tx.RootBucket().Bucket(activeAddrBucketName)

addrHash := fastsha256.Sum256(addressID)
err := bucket.Delete(addrHash[:])
if err != nil {
str := fmt.Sprintf("failed to mark address inactive %x", addressID)
return managerError(ErrDatabase, str, err)
}
return nil
}

// fetchAddressActive returns true if the provided address hash was flagged as active.
func fetchAddressActive(tx walletdb.Tx, addrHash []byte) bool {
bucket := tx.RootBucket().Bucket(activeAddrBucket)
bucket := tx.RootBucket().Bucket(activeAddrBucketName)

val := bucket.Get(addrHash[:])
if val != nil {
@@ -1026,19 +1050,6 @@ func fetchAddressByHash(tx walletdb.Tx, addrHash []byte) (interface{}, error) {
return nil, managerError(ErrDatabase, str, nil)
}

// markAddressInactive flags the provided address id as inactive in the database.
func markAddressInactive(tx walletdb.Tx, addressID []byte) error {
bucket := tx.RootBucket().Bucket(activeAddrBucket)

addrHash := fastsha256.Sum256(addressID)
err := bucket.Delete(addrHash[:])
if err != nil {
str := fmt.Sprintf("failed to mark address inactive %x", addressID)
return managerError(ErrDatabase, str, err)
}
return nil
}

// fetchAddress loads address information for the provided address id from the
// database. The returned value is one of the address rows for the specific
// address type. The caller should use type assertions to ascertain the type.
@@ -1063,11 +1074,10 @@ func putAddress(tx walletdb.Tx, addressID []byte, row *dbAddressRow) error {
str := fmt.Sprintf("failed to store address %x", addressID)
return managerError(ErrDatabase, str, err)
}
bucket = tx.RootBucket().Bucket(activeAddrBucket)
err = bucket.Put(addrHash[:], nullVal)
// Mark address as active
err = putAddressActive(tx, addressID)
if err != nil {
str := fmt.Sprintf("failed to mark active address %x", addressID)
return managerError(ErrDatabase, str, err)
return err
}
// Update address account index
return putAddressAccountIndex(tx, row.account, addrHash[:])
@@ -1224,7 +1234,7 @@ func forEachAccountAddress(tx walletdb.Tx, account uint32, fn func(rowInterface

// forEachActiveAddress iterates through each active address in the database.
func forEachActiveAddress(tx walletdb.Tx, fn func(rowInterface interface{}) error) error {
bucket := tx.RootBucket().Bucket(addrBucketName)
bucket := tx.RootBucket().Bucket(activeAddrBucketName)

err := bucket.ForEach(func(k, v []byte) error {
// Skip buckets.
@@ -1573,7 +1583,7 @@ func createManagerNS(namespace walletdb.Namespace) error {
}

// activeAddrBucket bucket was added after manager version 1 release
_, err = rootBucket.CreateBucket(activeAddrBucket)
_, err = rootBucket.CreateBucket(activeAddrBucketName)
if err != nil {
str := "failed to create used addresses bucket"
return managerError(ErrDatabase, str, err)
@@ -1631,7 +1641,7 @@ func upgradeToVersion2(namespace walletdb.Namespace) error {
currentMgrVersion := uint32(2)
rootBucket := tx.RootBucket()

_, err := rootBucket.CreateBucket(activeAddrBucket)
_, err := rootBucket.CreateBucket(activeAddrBucketName)
if err != nil {
str := "failed to create active addresses bucket"
return managerError(ErrDatabase, str, err)
@@ -1649,6 +1659,60 @@ func upgradeToVersion2(namespace walletdb.Namespace) error {
return nil
}

// upgradeToVersion4 upgrades the database from version 3 to version 4
// usedAddrBucket was converted to activeAddrBucket
func upgradeToVersion4(namespace walletdb.Namespace) error {
err := namespace.Update(func(tx walletdb.Tx) error {
rootBucket := tx.RootBucket()
usedAddrBucketName := []byte("usedaddrs")
addrBucket := rootBucket.Bucket(addrBucketName)
usedAddrBucket := rootBucket.Bucket(usedAddrBucketName)

activeAddrBucket, err := rootBucket.CreateBucket(activeAddrBucketName)
if err != nil {
str := "failed to create active addresses bucket"
return managerError(ErrDatabase, str, err)
}

err = addrBucket.ForEach(func(k, v []byte) error {
// Skip buckets.
if v == nil {
return nil
}

// For each unused address, insert the key into the active bucket.
if usedAddrBucket.Get(k) != nil {
err := activeAddrBucket.Put(k, nullVal)
if err != nil {
str := fmt.Sprintf("failed to mark active address %x", k)
return managerError(ErrDatabase, str, err)
}
}
return nil
})
if err != nil {
return err
}

err = rootBucket.DeleteBucket(usedAddrBucketName)
if err != nil {
str := "failed to delete used addresses bucket"
return managerError(ErrDatabase, str, err)
}

if err := putManagerVersion(tx, 4); err != nil {
return err
}

return err

})
if err != nil {
return maybeConvertDbError(err)
}
return nil
}

// upgradeManager upgrades the data in the provided manager namespace to newer
// versions as neeeded.
func upgradeManager(namespace walletdb.Namespace, pubPassPhrase []byte, config *Options) error {
@@ -1726,6 +1790,16 @@ func upgradeManager(namespace walletdb.Namespace, pubPassPhrase []byte, config *
version = 3
}

if version < 4 {
// Upgrade from version 3 to 4.
if err := upgradeToVersion4(namespace); err != nil {
return err
}

// The manager is now at version 4.
version = 4
}

// Ensure the manager is upraded to the latest version. This check is
// to intentionally cause a failure if the manager version is updated
// without writing code to handle the upgrade.

0 comments on commit be38bef

Please sign in to comment.