drop old scanning. always rescan blockchain on boot.

This commit is contained in:
Christopher Jeffrey 2016-07-14 12:31:27 -07:00
parent 1c9c06b4f9
commit e51736728e
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
5 changed files with 60 additions and 181 deletions

View File

@ -1168,6 +1168,9 @@ ChainDB.prototype.scan = function scan(start, hashes, iter, callback) {
if (err)
return next(err);
if (!block)
return next();
self.logger.info('Scanning block %s.', utils.revHex(hash));
utils.forEachSerial(block.txs, function(tx, next) {
@ -1177,7 +1180,7 @@ ChainDB.prototype.scan = function scan(start, hashes, iter, callback) {
for (i = 0; i < hashes.length; i++) {
hash = hashes[i];
if (hashMap[hash])
return iter(tx, next);
return iter(tx, block.toHeaders(), next);
}
next();

View File

@ -258,26 +258,27 @@ Fullnode.prototype._open = function open(callback) {
this.mempool.open.bind(this.mempool),
this.miner.open.bind(this.miner),
this.pool.open.bind(this.pool),
this.walletdb.open.bind(this.walletdb),
function(next) {
self.walletdb.open(function(err) {
self.createWallet(options, function(err, wallet) {
if (err)
return next(err);
self.createWallet(options, function(err, wallet) {
if (err)
return next(err);
// Set the miner payout address if the
// programmer didn't pass one in.
if (!self.miner.address)
self.miner.address = wallet.getAddress();
// Set the miner payout address if the
// programmer didn't pass one in.
if (!self.miner.address)
self.miner.address = wallet.getAddress();
self.wallet = wallet;
self.wallet = wallet;
next();
});
next();
});
},
function(next) {
// Always rescan to make sure we didn't miss anything:
// there is no atomicity between the chaindb and walletdb.
self.walletdb.rescan(self.chain.db, next);
},
function(next) {
var i;
self.walletdb.getUnconfirmed(function(err, txs) {

View File

@ -309,6 +309,17 @@ TXDB.prototype.writeGenesis = function writeGenesis(callback) {
});
};
/**
* Get the best block hash.
* @param {Function} callback
*/
TXDB.prototype.getTip = function getTip(callback) {
this.db.fetch('R', function(data) {
return data.toString('hex');
}, callback);
};
/**
* Add a block's transactions and write the new best hash.
* @param {Block} block

View File

@ -1112,71 +1112,6 @@ Wallet.prototype.getRedeem = function getRedeem(hash, callback) {
});
};
/**
* Scan for active accounts and addresses. Used for importing a wallet.
* @param {Function} scanner - Must be a function which accepts
* a {@link Base58Address} as well as a callback and returns
* transactions by address.
* @param {Function} callback - Return [Error, Number] (total number
* of addresses allocated).
*/
Wallet.prototype.scan = function scan(maxGap, scanner, callback) {
var self = this;
var total = 0;
var index = 0;
var unlock;
if (typeof maxGap === 'function') {
callback = scanner;
scanner = maxGap;
maxGap = null;
}
unlock = this.writeLock.lock(scan, [maxGap, scanner, callback]);
if (!unlock)
return;
callback = utils.wrap(callback, unlock);
if (!this.initialized)
return callback(new Error('Wallet is not initialized.'));
self.start();
function done(err, total) {
if (err) {
self.drop();
return callback(err);
}
self.commit(function(err) {
if (err)
return callback(err);
return callback(null, total);
});
}
(function next() {
self.getAccount(index++, function(err, account) {
if (err)
return done(err);
if (!account)
return done(null, total);
account.scan(maxGap, scanner, function(err, result) {
if (err)
return done(err);
total += result;
next();
});
}, true);
})();
};
/**
* Build input scripts templates for a transaction (does not
* sign, only creates signature slots). Only builds scripts
@ -1908,13 +1843,6 @@ Account.fromOptions = function fromOptions(db, options) {
Account.MAX_LOOKAHEAD = 5;
/*
* Default address gap for scanning.
* @const {Number}
*/
Account.MAX_GAP = 20;
/**
* Attempt to intialize the account (generating
* the first addresses along with the lookahead
@ -2285,102 +2213,6 @@ Account.prototype.setDepth = function setDepth(receiveDepth, changeDepth, callba
});
};
/**
* Scan for addresses.
* @param {Function} scanner - Must be a callback which accepts
* a callback and returns transactions by address.
* @param {Function} callback - Return [Error, Number] (total number
* of addresses allocated).
*/
Account.prototype.scan = function scan(maxGap, scanner, callback) {
var self = this;
var total = 0;
if (typeof maxGap === 'function') {
callback = scanner;
scanner = maxGap;
maxGap = null;
}
if (maxGap == null)
maxGap = Account.MAX_GAP;
if (!this.initialized)
return callback(new Error('Account is not initialized.'));
function addTX(txs, calback) {
if (!Array.isArray(txs) || txs.length === 0)
return callback(null, false);
utils.forEachSerial(txs, function(tx, next) {
self.db.addTX(tx, next);
}, function(err) {
if (err)
return callback(err);
return callback(null, true);
});
}
(function chainCheck(change) {
var depth = change ? self.changeDepth : self.receiveDepth;
var index = 0;
var gap = 0;
function createAddress(callback) {
if (index === depth)
return self.createAddress(change, callback);
return callback(null, self.deriveAddress(change, index++));
}
(function next() {
createAddress(function(err, address) {
if (err)
return callback(err);
scanner(address.getAddress(), function(err, txs) {
if (err)
return callback(err);
addTX(txs, function(err, result) {
if (err)
return callback(err);
// Special case for maxGap=0
if (maxGap === 0 && index === depth) {
if (!change)
return chainCheck(true);
self.save();
return callback(null, total);
}
if (result) {
total++;
gap = 0;
return next();
}
if (++gap < Account.MAX_GAP)
return next();
if (!change) {
self.receiveDepth = Math.max(depth, self.receiveDepth - gap);
self.receiveAddress = self.deriveReceive(self.receiveDepth - 1);
return chainCheck(true);
}
self.changeDepth = Math.max(depth, self.changeDepth - gap);
self.changeAddress = self.deriveChange(self.changeDepth - 1);
return callback(null, total);
});
});
});
})();
})(false);
};
/**
* Convert the account to a more inspection-friendly object.
* @returns {Object}

View File

@ -1048,6 +1048,38 @@ WalletDB.prototype.getAddresses = function getAddresses(id, callback) {
}, callback);
};
/**
* Rescan the blockchain.
* @param {ChainDB} chaindb
* @param {Function} callback
*/
WalletDB.prototype.rescan = function rescan(chaindb, callback) {
var self = this;
this.tx.getTip(function(err, hash) {
if (err)
return callback(err);
if (!hash)
return callback(new Error('Best hash not found.'));
self.getAddresses(function(err, hashes) {
if (err)
return callback(err);
self.logger.info('Scanning for %d addresses.', hashes.length);
chaindb.scan(hash, hashes, function(tx, block, next) {
self.tx.add(tx, function(err) {
if (err)
return next(err);
self.db.put('R', block.hash(), next);
});
}, callback);
});
});
};
/**
* Get the corresponding path for an address hash.
* @param {WalletID} id