diff --git a/migrate/walletdb3to4.js b/migrate/walletdb3to4.js new file mode 100644 index 00000000..1d320e5a --- /dev/null +++ b/migrate/walletdb3to4.js @@ -0,0 +1,122 @@ +var assert = require('assert'); +var bcoin = require('../'); +var constants = require('../lib/protocol/constants'); +var WalletDB = require('../lib/wallet/walletdb'); +var TXDB = require('../lib/wallet/txdb'); +var BufferWriter = require('../lib/utils/writer'); +var utils = require('../lib/utils/utils'); +var co = bcoin.co; +var layout = WalletDB.layout; +var tlayout = TXDB.layout; +var file = process.argv[2]; +var db, batch; + +assert(typeof file === 'string', 'Please pass in a database path.'); + +file = file.replace(/\.ldb\/?$/, ''); + +db = bcoin.ldb({ + location: file, + db: 'leveldb', + compression: true, + cacheSize: 16 << 20, + writeBufferSize: 8 << 20, + createIfMissing: false, + bufferKeys: true +}); + +var updateVersion = co(function* updateVersion() { + var bak = process.env.HOME + '/walletdb-bak-' + Date.now() + '.ldb'; + var data, ver; + + console.log('Checking version.'); + + data = yield db.get('V'); + assert(data, 'No version.'); + + ver = data.readUInt32LE(0, true); + + if (ver !== 3) + throw Error('DB is version ' + ver + '.'); + + console.log('Backing up DB to: %s.', bak); + + yield db.backup(bak); + + ver = new Buffer(4); + ver.writeUInt32LE(4, 0, true); + batch.put('V', ver); +}); + +var updateState = co(function* updateState(wid) { + var total = 0; + var unconfirmed = 0; + var confirmed = 0; + var txs = 0; + var coins = 0; + var p, keys; + + keys = yield db.keys({ + gte: tlayout.prefix(wid, tlayout.t(constants.NULL_HASH)), + lte: tlayout.prefix(wid, tlayout.t(constants.HIGH_HASH)) + }); + + txs += keys.length; + + yield db.range({ + gte: tlayout.prefix(wid, tlayout.c(constants.NULL_HASH, 0x00000000)), + lte: tlayout.prefix(wid, tlayout.c(constants.HIGH_HASH, 0xffffffff)), + parse: function(key, data) { + var height = data.readUInt32LE(4, true); + var value = utils.read64N(data, 8); + + total += value; + + if (height === 0x7fffffff) + unconfirmed += value; + else + confirmed += value; + + coins += 1; + } + }); + + p = new BufferWriter(); + p.writeU64(txs); + p.writeU64(coins); + p.writeU64(unconfirmed); + p.writeU64(confirmed); + + batch.put(tlayout.prefix(wid, tlayout.R), p.render()); +}); + +var updateStates = co(function* updateStates() { + var i, wallets, wid; + + wallets = yield db.keys({ + gte: layout.w(0), + lte: layout.w(0xffffffff), + parse: layout.pre + }); + + console.log('Updating states...'); + + for (i = 0; i < wallets.length; i++) { + wid = wallets[i]; + yield updateState(wid); + } + + console.log('Updated %d states.', wallets.length); +}); + +co.spawn(function* () { + yield db.open(); + batch = db.batch(); + console.log('Opened %s.', file); + yield updateVersion(); + yield updateStates(); + yield batch.write(); +}).then(function() { + console.log('Migration complete.'); + process.exit(0); +});