github.com/decred/dcrlnd@v0.7.6/channeldb/dcrdb.go (about)

     1  package channeldb
     2  
     3  import (
     4  	dcrmigration01 "github.com/decred/dcrlnd/channeldb/dcrmigrations/migration01"
     5  	dcrmigration02 "github.com/decred/dcrlnd/channeldb/dcrmigrations/migration02"
     6  	"github.com/decred/dcrlnd/kvdb"
     7  )
     8  
     9  var (
    10  	dcrMetaBucket = []byte("dcrlnd_metadata")
    11  )
    12  
    13  var (
    14  	// dcrDbVersions are the decred-only migrations.
    15  	dcrDbVersions = []version{
    16  		{number: 1, migration: dcrmigration01.FixMigration20},
    17  		{number: 2, migration: dcrmigration02.RemoveFutureTimestampFromPeers},
    18  	}
    19  )
    20  
    21  // latestDcrDbVersion returns the latest version of the decred-specific db
    22  // migrations.
    23  func latestDcrDbVersion() uint32 {
    24  	return dcrDbVersions[len(dcrDbVersions)-1].number
    25  }
    26  
    27  // applyDecredMigations applies the decred-only migrations.
    28  func (d *DB) applyDecredMigations(tx kvdb.RwTx, dbVersion uint32) error {
    29  	latestVersion := dcrDbVersions[len(dcrDbVersions)-1].number
    30  	log.Infof("Checking for decred-specicic migrations latest_version=%d, "+
    31  		"db_version=%d", latestVersion, dbVersion)
    32  
    33  	if latestVersion < dbVersion {
    34  		log.Errorf("Refusing to revert from decred db_version=%d to "+
    35  			"lower version=%d", dbVersion, latestVersion)
    36  		return ErrDBReversion
    37  	}
    38  
    39  	if latestVersion == dbVersion {
    40  		// Nothing to do.
    41  		return nil
    42  	}
    43  
    44  	log.Infof("Performing decred-specific database schema migration")
    45  
    46  	metaBucket := tx.ReadWriteBucket(dcrMetaBucket)
    47  	for _, mig := range dcrDbVersions {
    48  		if mig.migration == nil {
    49  			continue
    50  		}
    51  		if mig.number <= dbVersion {
    52  			continue
    53  		}
    54  
    55  		log.Infof("Applying migration #%d", mig.number)
    56  
    57  		if err := mig.migration(tx); err != nil {
    58  			log.Infof("Unable to apply migration #%d",
    59  				mig.number)
    60  			return err
    61  		}
    62  
    63  		// Save the new db version.
    64  		dbVersion = mig.number
    65  		err := metaBucket.Put(dbVersionKey, byteOrder.AppendUint32(nil, dbVersion))
    66  		if err != nil {
    67  			return err
    68  		}
    69  	}
    70  
    71  	// Stop if running in dry-run mode.
    72  	if d.dryRun {
    73  		return ErrDryRunMigrationOK
    74  	}
    75  
    76  	return nil
    77  }
    78  
    79  // syncDcrlndDBVersions performs the dcrlnd-specific db upgrades.
    80  func (d *DB) syncDcrlndDBVersions(tx kvdb.RwTx) error {
    81  	// Read dcr-specific version.
    82  	var dbVersion uint32
    83  	bucket := tx.ReadWriteBucket(dcrMetaBucket)
    84  	if bucket == nil {
    85  		// Filled meta bucket but empty dcr-specific meta bucket.
    86  		// Create dcr one.
    87  		var err error
    88  		bucket, err = tx.CreateTopLevelBucket(dcrMetaBucket)
    89  		if err != nil {
    90  			return err
    91  		}
    92  
    93  		// If the global meta bucket is empty, it's a new db.
    94  		if tx.ReadBucket(metaBucket) == nil {
    95  			dbVersion = latestDcrDbVersion()
    96  		}
    97  
    98  		// dbVersion == 0.
    99  		bucket.Put(dbVersionKey, byteOrder.AppendUint32(nil, dbVersion))
   100  	} else {
   101  		v := bucket.Get(dbVersionKey)
   102  		if v != nil {
   103  			dbVersion = byteOrder.Uint32(v)
   104  		}
   105  	}
   106  
   107  	// Apply dcr-specific migrations.
   108  	return d.applyDecredMigations(tx, dbVersion)
   109  }
   110  
   111  // initDcrlndFeatures initializes features that are specific to dcrlnd.
   112  func (d *DB) initDcrlndFeatures() error {
   113  	return kvdb.Update(d, func(tx kvdb.RwTx) error {
   114  		if err := d.syncDcrlndDBVersions(tx); err != nil {
   115  			return err
   116  		}
   117  
   118  		// If the inflight payments index bucket doesn't exist,
   119  		// initialize it.
   120  		indexBucket := tx.ReadWriteBucket(paymentsInflightIndexBucket)
   121  		if indexBucket == nil {
   122  			return recreatePaymentsInflightIndex(tx)
   123  		}
   124  
   125  		return nil
   126  	}, func() {})
   127  }
   128  
   129  // LocalOpenChanIDs returns a map of channel IDs of all open channels in the
   130  // local DB.
   131  func (d *DB) LocalOpenChanIDs() (map[uint64]struct{}, error) {
   132  	// Note: this is less efficient than it could be, because it iterates
   133  	// through the entire list of channels and then discards all that just
   134  	// to extract the channel id. In the future, decode that field directly.
   135  	openChans, err := d.ChannelStateDB().FetchAllOpenChannels()
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	res := make(map[uint64]struct{}, len(openChans))
   141  	for _, c := range openChans {
   142  		res[c.ShortChanID().ToUint64()] = struct{}{}
   143  	}
   144  	return res, nil
   145  }