handle forks better.
This commit is contained in:
parent
d2767e4e34
commit
b352bfbe3d
@ -329,14 +329,10 @@ Chain.prototype._preload = function _preload(callback) {
|
||||
// Create a chain entry.
|
||||
entry = new bcoin.chainblock(self, data, lastEntry);
|
||||
|
||||
// Filthy hack to avoid writing
|
||||
// redundant blocks to disk!
|
||||
if (entry.height <= chainHeight) {
|
||||
if (entry.height <= chainHeight)
|
||||
self.db.addCache(entry);
|
||||
// self.db.bloom(entry.hash, 'hex');
|
||||
} else {
|
||||
self.db.save(entry);
|
||||
}
|
||||
else
|
||||
self.db.save(entry, null, true);
|
||||
|
||||
if ((height + 1) % 50000 === 0)
|
||||
utils.debug('Received %d headers from electrum.org.', height + 1);
|
||||
@ -588,11 +584,11 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, peer,
|
||||
// and extraNonce.
|
||||
if (result) {
|
||||
utils.debug('Block is overwriting txids: %s', block.rhash);
|
||||
if (!(network.type === 'main' && (height === 91842 || height === 91880))) {
|
||||
self.emit('verify-error',
|
||||
block, 'invalid', 'bad-txns-BIP30', 100, peer);
|
||||
return next(null, false);
|
||||
}
|
||||
if (network.type === 'main' && (height === 91842 || height === 91880))
|
||||
return next(null, true);
|
||||
self.emit('verify-error',
|
||||
block, 'invalid', 'bad-txns-BIP30', 100, peer);
|
||||
return next(null, false);
|
||||
}
|
||||
|
||||
next(null, true);
|
||||
@ -867,34 +863,37 @@ Chain.prototype._reorganize = function _reorganize(entry, block, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype._addEntry = function _addEntry(entry, block, callback) {
|
||||
// Set main chain only if chainwork is higher.
|
||||
// Add the block but do _not_ connect the inputs.
|
||||
if (entry.chainwork.cmp(this.tip.chainwork) <= 0) {
|
||||
return this.db.save(entry, block, false, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, false);
|
||||
});
|
||||
}
|
||||
|
||||
// Attempt to add block to the chain index.
|
||||
return this._setBestChain(entry, block, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback(null, true);
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype._setBestChain = function _setBestChain(entry, block, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
this.lastUpdate = utils.now();
|
||||
|
||||
// Start fsyncing writes once we're no
|
||||
// longer dealing with historical data.
|
||||
if (this.isFull())
|
||||
this.db.fsync = true;
|
||||
|
||||
if (!this.tip) {
|
||||
if (entry.hash !== network.genesis.hash)
|
||||
return callback(new Error('Bad genesis block.'));
|
||||
|
||||
done();
|
||||
} else if (entry.prevBlock === this.tip.hash) {
|
||||
done();
|
||||
} else {
|
||||
self._reorganize(entry, block, done);
|
||||
}
|
||||
|
||||
function done(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.db.save(entry, block, function(err) {
|
||||
self.db.save(entry, block, true, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -909,6 +908,17 @@ Chain.prototype._setBestChain = function _setBestChain(entry, block, callback) {
|
||||
return callback();
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.tip) {
|
||||
if (entry.hash !== network.genesis.hash)
|
||||
return utils.asyncify(callback)(new Error('Bad genesis block.'));
|
||||
|
||||
done();
|
||||
} else if (entry.prevBlock === this.tip.hash) {
|
||||
done();
|
||||
} else {
|
||||
self._reorganize(entry, block, done);
|
||||
}
|
||||
};
|
||||
|
||||
Chain.prototype.reset = function reset(height, callback, force) {
|
||||
@ -1203,12 +1213,8 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
|
||||
height: height
|
||||
}, prev);
|
||||
|
||||
// Set main chain only if chainwork is higher.
|
||||
if (entry.chainwork.cmp(self.tip.chainwork) <= 0)
|
||||
return done();
|
||||
|
||||
// Attempt to add block to the chain index.
|
||||
self._setBestChain(entry, block, function(err) {
|
||||
self._addEntry(entry, block, function(err, mainChain) {
|
||||
if (err)
|
||||
return done(err);
|
||||
|
||||
@ -1217,8 +1223,10 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
|
||||
total++;
|
||||
|
||||
// Emit our block (and potentially resolved
|
||||
// orphan) so the programmer can save it.
|
||||
self.emit('block', block, entry, peer);
|
||||
// orphan) only if it is on the main chain.
|
||||
if (mainChain)
|
||||
self.emit('block', block, entry, peer);
|
||||
|
||||
if (block.hash('hex') !== initial.hash('hex'))
|
||||
self.emit('resolved', block, entry, peer);
|
||||
|
||||
|
||||
@ -56,59 +56,6 @@ function ChainDB(chain, options) {
|
||||
this._init();
|
||||
}
|
||||
|
||||
function DumbCache(size) {
|
||||
this.data = {};
|
||||
this.count = 0;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
DumbCache.prototype.set = function set(key, value) {
|
||||
key = key + '';
|
||||
|
||||
assert(value !== undefined);
|
||||
|
||||
if (this.count > this.size)
|
||||
this.reset();
|
||||
|
||||
if (this.data[key] === undefined)
|
||||
this.count++;
|
||||
|
||||
this.data[key] = value;
|
||||
};
|
||||
|
||||
DumbCache.prototype.remove = function remove(key) {
|
||||
key = key + '';
|
||||
|
||||
if (this.data[key] === undefined)
|
||||
return;
|
||||
|
||||
this.count--;
|
||||
delete this.data[key];
|
||||
};
|
||||
|
||||
DumbCache.prototype.get = function get(key) {
|
||||
key = key + '';
|
||||
return this.data[key];
|
||||
};
|
||||
|
||||
DumbCache.prototype.has = function has(key) {
|
||||
key = key + '';
|
||||
return this.data[key] !== undefined;
|
||||
};
|
||||
|
||||
DumbCache.prototype.reset = function reset() {
|
||||
this.data = {};
|
||||
this.count = 0;
|
||||
};
|
||||
|
||||
function NullCache(size) {}
|
||||
|
||||
NullCache.prototype.set = function set(key, value) {};
|
||||
NullCache.prototype.remove = function remove(key) {};
|
||||
NullCache.prototype.get = function get(key) {};
|
||||
NullCache.prototype.has = function has(key) {};
|
||||
NullCache.prototype.reset = function reset() {};
|
||||
|
||||
utils.inherits(ChainDB, EventEmitter);
|
||||
|
||||
ChainDB.prototype._init = function _init() {
|
||||
@ -162,7 +109,7 @@ ChainDB.prototype._init = function _init() {
|
||||
block = bcoin.block.fromRaw(network.genesisBlock, 'hex');
|
||||
block.height = 0;
|
||||
|
||||
self.save(genesis, block, finish);
|
||||
self.save(genesis, block, true, finish);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -206,6 +153,8 @@ ChainDB.prototype.getCache = function getCache(hash) {
|
||||
};
|
||||
|
||||
ChainDB.prototype.getHeight = function getHeight(hash, callback) {
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (hash == null || hash < 0)
|
||||
return callback(null, -1);
|
||||
|
||||
@ -231,6 +180,8 @@ ChainDB.prototype.getHeight = function getHeight(hash, callback) {
|
||||
};
|
||||
|
||||
ChainDB.prototype.getHash = function getHash(height, callback) {
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (height == null || height < 0)
|
||||
return callback(null, null);
|
||||
|
||||
@ -305,7 +256,7 @@ ChainDB.prototype.getBoth = function getBoth(block, callback) {
|
||||
var hash, height;
|
||||
|
||||
if (block == null || block < 0)
|
||||
return callback(null, null, -1);
|
||||
return utils.asyncify(callback)(null, null, -1);
|
||||
|
||||
if (typeof block === 'string')
|
||||
hash = block;
|
||||
@ -340,7 +291,7 @@ ChainDB.prototype._getEntry = function _getEntry(hash, callback) {
|
||||
var entry;
|
||||
|
||||
if (hash == null || hash < 0)
|
||||
return callback();
|
||||
return utils.nextTick(callback);
|
||||
|
||||
return this.getBoth(hash, function(err, hash, height) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
@ -369,8 +320,6 @@ ChainDB.prototype._getEntry = function _getEntry(hash, callback) {
|
||||
ChainDB.prototype.get = function get(height, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
return this._getEntry(height, function(err, entry) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -378,35 +327,52 @@ ChainDB.prototype.get = function get(height, callback) {
|
||||
if (!entry)
|
||||
return callback();
|
||||
|
||||
self.addCache(entry);
|
||||
// There's no efficient way to check whether
|
||||
// this is in the main chain or not, so
|
||||
// don't add it to the height cache.
|
||||
self.cacheHash.set(entry.hash, entry);
|
||||
|
||||
return callback(null, entry);
|
||||
});
|
||||
};
|
||||
|
||||
ChainDB.prototype.save = function save(entry, block, callback) {
|
||||
ChainDB.prototype.save = function save(entry, block, connect, callback) {
|
||||
var self = this;
|
||||
var batch, height;
|
||||
var batch, hash, height;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
assert(entry.height >= 0);
|
||||
|
||||
this.addCache(entry);
|
||||
|
||||
batch = this.db.batch();
|
||||
|
||||
hash = new Buffer(entry.hash, 'hex');
|
||||
|
||||
height = new Buffer(4);
|
||||
utils.writeU32(height, entry.height, 0);
|
||||
|
||||
batch.put('c/b/' + entry.hash, height);
|
||||
batch.put('c/c/' + entry.hash, entry.toRaw());
|
||||
batch.put('c/n/' + entry.prevBlock, new Buffer(entry.hash, 'hex'));
|
||||
batch.put('c/h/' + pad32(entry.height), new Buffer(entry.hash, 'hex'));
|
||||
batch.put('c/t', new Buffer(entry.hash, 'hex'));
|
||||
batch.put('c/n/' + entry.prevBlock, hash);
|
||||
|
||||
this.cacheHash.set(entry.hash, entry);
|
||||
|
||||
if (!connect) {
|
||||
return this.saveBlock(block, batch, false, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return batch.write(callback);
|
||||
});
|
||||
}
|
||||
|
||||
this.cacheHeight.set(entry.height, entry);
|
||||
|
||||
batch.put('c/h/' + pad32(entry.height), hash);
|
||||
batch.put('c/t', hash);
|
||||
|
||||
this.emit('add entry', entry);
|
||||
|
||||
this.saveBlock(block, batch, function(err) {
|
||||
this.saveBlock(block, batch, true, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -435,7 +401,7 @@ ChainDB.prototype.connect = function connect(block, callback) {
|
||||
var self = this;
|
||||
var batch;
|
||||
|
||||
this._get(block, function(err, entry) {
|
||||
this._ensureEntry(block, function(err, entry) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -468,7 +434,7 @@ ChainDB.prototype.disconnect = function disconnect(block, callback) {
|
||||
var self = this;
|
||||
var batch;
|
||||
|
||||
this._get(block, function(err, entry) {
|
||||
this._ensureEntry(block, function(err, entry) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -497,7 +463,7 @@ ChainDB.prototype.disconnect = function disconnect(block, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
ChainDB.prototype._get = function _get(block, callback) {
|
||||
ChainDB.prototype._ensureEntry = function _ensureEntry(block, callback) {
|
||||
if (block instanceof bcoin.chainblock)
|
||||
return callback(null, block);
|
||||
return this.get(block, callback);
|
||||
@ -571,7 +537,7 @@ ChainDB.prototype.reset = function reset(block, callback) {
|
||||
|
||||
ChainDB.prototype.has = function has(height, callback) {
|
||||
if (height == null || height < 0)
|
||||
return callback(null, false);
|
||||
return utils.asyncify(callback)(null, false);
|
||||
|
||||
return this.getBoth(height, function(err, hash, height) {
|
||||
if (err)
|
||||
@ -580,9 +546,9 @@ ChainDB.prototype.has = function has(height, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
ChainDB.prototype.saveBlock = function saveBlock(block, batch, callback) {
|
||||
ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback) {
|
||||
if (this.options.spv)
|
||||
return callback();
|
||||
return utils.nextTick(callback);
|
||||
|
||||
batch.put('b/b/' + block.hash('hex'), block.toCompact());
|
||||
|
||||
@ -590,6 +556,9 @@ ChainDB.prototype.saveBlock = function saveBlock(block, batch, callback) {
|
||||
batch.put('t/t/' + tx.hash('hex'), tx.toExtended());
|
||||
});
|
||||
|
||||
if (!connect)
|
||||
return utils.nextTick(callback);
|
||||
|
||||
this.connectBlock(block, batch, callback);
|
||||
};
|
||||
|
||||
@ -597,9 +566,9 @@ ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
|
||||
var self = this;
|
||||
|
||||
if (this.options.spv)
|
||||
return callback();
|
||||
return utils.nextTick(callback);
|
||||
|
||||
this._getTXBlock(hash, function(err, block) {
|
||||
this._ensureHistory(hash, function(err, block) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -621,10 +590,10 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
|
||||
if (this.options.spv) {
|
||||
self.emit('add block', block);
|
||||
return callback();
|
||||
return utils.nextTick(callback);
|
||||
}
|
||||
|
||||
this._getCoinBlock(block, function(err, block) {
|
||||
this._ensureBlock(block, function(err, block) {
|
||||
var height;
|
||||
|
||||
if (err)
|
||||
@ -638,6 +607,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
var uniq = {};
|
||||
|
||||
tx.inputs.forEach(function(input) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
var address;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
@ -653,18 +623,15 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
batch.put('t/a/' + address + '/' + hash, DUMMY);
|
||||
}
|
||||
|
||||
if (address) {
|
||||
batch.del(
|
||||
'u/a/' + address
|
||||
+ '/' + input.prevout.hash
|
||||
+ '/' + input.prevout.index);
|
||||
}
|
||||
if (address)
|
||||
batch.del('u/a/' + address + '/' + key);
|
||||
}
|
||||
|
||||
batch.del('u/t/' + input.prevout.hash + '/' + input.prevout.index);
|
||||
batch.del('u/t/' + key);
|
||||
});
|
||||
|
||||
tx.outputs.forEach(function(output, i) {
|
||||
var key = hash + '/' + i;
|
||||
var address;
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
@ -676,10 +643,10 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
}
|
||||
|
||||
if (address)
|
||||
batch.put('u/a/' + address + '/' + hash + '/' + i, DUMMY);
|
||||
batch.put('u/a/' + address + '/' + key, DUMMY);
|
||||
}
|
||||
|
||||
batch.put('u/t/' + hash + '/' + i, bcoin.coin(tx, i).toRaw());
|
||||
batch.put('u/t/' + key, bcoin.coin(tx, i).toRaw());
|
||||
});
|
||||
});
|
||||
|
||||
@ -693,9 +660,9 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
|
||||
var self = this;
|
||||
|
||||
if (this.options.spv)
|
||||
return callback();
|
||||
return utils.nextTick(callback);
|
||||
|
||||
this._getTXBlock(hash, function(err, block) {
|
||||
this._ensureHistory(hash, function(err, block) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -710,6 +677,7 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
|
||||
var uniq = {};
|
||||
|
||||
tx.inputs.forEach(function(input) {
|
||||
var key = input.prevout.hash + '/' + input.prevout.index;
|
||||
var address;
|
||||
|
||||
if (tx.isCoinbase())
|
||||
@ -725,21 +693,15 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
|
||||
batch.del('t/a/' + address + '/' + hash);
|
||||
}
|
||||
|
||||
if (address) {
|
||||
batch.put('u/a/' + address
|
||||
+ '/' + input.prevout.hash
|
||||
+ '/' + input.prevout.index,
|
||||
DUMMY);
|
||||
}
|
||||
if (address)
|
||||
batch.put('u/a/' + address + '/' + key, DUMMY);
|
||||
}
|
||||
|
||||
batch.put('u/t/'
|
||||
+ input.prevout.hash
|
||||
+ '/' + input.prevout.index,
|
||||
input.coin.toRaw());
|
||||
batch.put('u/t/' + key, input.coin.toRaw());
|
||||
});
|
||||
|
||||
tx.outputs.forEach(function(output, i) {
|
||||
var key = hash + '/' + i;
|
||||
var address;
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
@ -751,10 +713,10 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
|
||||
}
|
||||
|
||||
if (address)
|
||||
batch.del('u/a/' + address + '/' + hash + '/' + i);
|
||||
batch.del('u/a/' + address + '/' + key);
|
||||
}
|
||||
|
||||
batch.del('u/t/' + hash + '/' + i);
|
||||
batch.del('u/t/' + key);
|
||||
});
|
||||
});
|
||||
|
||||
@ -767,8 +729,6 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callba
|
||||
ChainDB.prototype.fillCoins = function fillCoins(tx, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (Array.isArray(tx)) {
|
||||
return utils.forEachSerial(tx, function(tx, next) {
|
||||
self.fillCoins(tx, next);
|
||||
@ -780,7 +740,7 @@ ChainDB.prototype.fillCoins = function fillCoins(tx, callback) {
|
||||
}
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return callback(null, tx);
|
||||
return utils.asyncify(callback)(null, tx);
|
||||
|
||||
utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
if (input.coin)
|
||||
@ -805,8 +765,6 @@ ChainDB.prototype.fillCoins = function fillCoins(tx, callback) {
|
||||
ChainDB.prototype.fillTX = function fillTX(tx, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (Array.isArray(tx)) {
|
||||
return utils.forEachSerial(tx, function(tx, next) {
|
||||
self.fillTX(tx, next);
|
||||
@ -818,7 +776,7 @@ ChainDB.prototype.fillTX = function fillTX(tx, callback) {
|
||||
}
|
||||
|
||||
if (tx.isCoinbase())
|
||||
return callback(null, tx);
|
||||
return utils.asyncify(callback)(null, tx);
|
||||
|
||||
if (this.prune) {
|
||||
return utils.forEachSerial(tx.inputs, function(input, next) {
|
||||
@ -935,15 +893,15 @@ ChainDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, opti
|
||||
};
|
||||
|
||||
ChainDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
var id = 'u/t/' + hash + '/' + index;
|
||||
var key = 'u/t/' + hash + '/' + index;
|
||||
var coin;
|
||||
|
||||
this.db.get(id, function(err, data) {
|
||||
if (err) {
|
||||
if (err.type === 'NotFoundError')
|
||||
return callback();
|
||||
this.db.get(key, function(err, data) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!data)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
coin = bcoin.coin.fromRaw(data);
|
||||
@ -1036,10 +994,10 @@ ChainDB.prototype.getTXByAddress = function getTXByAddress(addresses, options, c
|
||||
|
||||
ChainDB.prototype.getTX = function getTX(hash, callback) {
|
||||
var self = this;
|
||||
var id = 't/t/' + hash;
|
||||
var key = 't/t/' + hash;
|
||||
var tx;
|
||||
|
||||
this.db.get(id, function(err, data) {
|
||||
this.db.get(key, function(err, data) {
|
||||
if (err) {
|
||||
if (err.type === 'NotFoundError')
|
||||
return callback();
|
||||
@ -1097,11 +1055,11 @@ ChainDB.prototype.getFullBlock = function getFullBlock(hash, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
ChainDB.prototype._getCoinBlock = function _getCoinBlock(hash, callback) {
|
||||
ChainDB.prototype._ensureBlock = function _ensureBlock(hash, callback) {
|
||||
var self = this;
|
||||
|
||||
if (hash instanceof bcoin.block)
|
||||
return callback(null, hash);
|
||||
return utils.asyncify(callback)(null, hash);
|
||||
|
||||
return this.getBlock(hash, function(err, block) {
|
||||
if (err)
|
||||
@ -1114,11 +1072,11 @@ ChainDB.prototype._getCoinBlock = function _getCoinBlock(hash, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
ChainDB.prototype._getTXBlock = function _getTXBlock(hash, callback) {
|
||||
ChainDB.prototype._ensureHistory = function _ensureHistory(hash, callback) {
|
||||
var self = this;
|
||||
|
||||
if (hash instanceof bcoin.block)
|
||||
return callback(null, hash);
|
||||
return utils.asyncify(callback)(null, hash);
|
||||
|
||||
return this.getBlock(hash, function(err, block) {
|
||||
if (err)
|
||||
@ -1133,7 +1091,7 @@ ChainDB.prototype._getTXBlock = function _getTXBlock(hash, callback) {
|
||||
|
||||
ChainDB.prototype.fillBlock = function fillBlock(block, callback) {
|
||||
return this.fillCoins(block.txs, function(err) {
|
||||
var coins, i, tx, hash, j, input, id;
|
||||
var coins, i, tx, hash, j, input, key;
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -1146,10 +1104,10 @@ ChainDB.prototype.fillBlock = function fillBlock(block, callback) {
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
id = input.prevout.hash + '/' + input.prevout.index;
|
||||
if (!input.coin && coins[id]) {
|
||||
input.coin = coins[id];
|
||||
delete coins[id];
|
||||
key = input.prevout.hash + '/' + input.prevout.index;
|
||||
if (!input.coin && coins[key]) {
|
||||
input.coin = coins[key];
|
||||
delete coins[key];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1163,7 +1121,7 @@ ChainDB.prototype.fillBlock = function fillBlock(block, callback) {
|
||||
|
||||
ChainDB.prototype.fillTXBlock = function fillTXBlock(block, callback) {
|
||||
return this.fillTX(block.txs, function(err) {
|
||||
var coins, i, tx, hash, j, input, id;
|
||||
var coins, i, tx, hash, j, input, key;
|
||||
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -1176,10 +1134,10 @@ ChainDB.prototype.fillTXBlock = function fillTXBlock(block, callback) {
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
id = input.prevout.hash + '/' + input.prevout.index;
|
||||
if (!input.coin && coins[id]) {
|
||||
input.coin = coins[id];
|
||||
delete coins[id];
|
||||
key = input.prevout.hash + '/' + input.prevout.index;
|
||||
if (!input.coin && coins[key]) {
|
||||
input.coin = coins[key];
|
||||
delete coins[key];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1193,7 +1151,7 @@ ChainDB.prototype.fillTXBlock = function fillTXBlock(block, callback) {
|
||||
|
||||
ChainDB.prototype.getBlock = function getBlock(hash, callback) {
|
||||
var self = this;
|
||||
var id, block;
|
||||
var key, block;
|
||||
|
||||
return this.getHash(hash, function(err, hash) {
|
||||
if (err)
|
||||
@ -1202,14 +1160,14 @@ ChainDB.prototype.getBlock = function getBlock(hash, callback) {
|
||||
if (!hash)
|
||||
return callback();
|
||||
|
||||
id = 'b/b/' + hash;
|
||||
key = 'b/b/' + hash;
|
||||
|
||||
self.db.get(id, function(err, data) {
|
||||
if (err) {
|
||||
if (err.type === 'NotFoundError')
|
||||
return callback();
|
||||
self.db.get(key, function(err, data) {
|
||||
if (err && errr.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!data)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
block = bcoin.block.fromCompact(data);
|
||||
@ -1344,24 +1302,24 @@ ChainDB.prototype._pruneQueue = function _pruneQueue(block, batch, callback) {
|
||||
|
||||
hash = utils.toHex(hash);
|
||||
|
||||
self.db.get('b/b/' + hash, function(err, cblock) {
|
||||
self.db.get('b/b/' + hash, function(err, compact) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
batch.del(key);
|
||||
|
||||
if (!cblock)
|
||||
if (!compact)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
cblock = bcoin.block.fromCompact(cblock);
|
||||
compact = bcoin.block.fromCompact(compact);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
batch.del('b/b/' + hash);
|
||||
|
||||
cblock.hashes.forEach(function(hash) {
|
||||
compact.hashes.forEach(function(hash) {
|
||||
batch.del('t/t/' + hash);
|
||||
});
|
||||
|
||||
@ -1407,10 +1365,10 @@ ChainDB.prototype._pruneCoinQueue = function _pruneQueue(block, batch, callback)
|
||||
|
||||
ChainDB.prototype._getPruneCoin = function _getPruneCoin(hash, index, callback) {
|
||||
var self = this;
|
||||
var id = 'u/x/' + hash + '/' + index;
|
||||
var key = 'u/x/' + hash + '/' + index;
|
||||
var coin;
|
||||
|
||||
this.db.get(id, function(err, data) {
|
||||
this.db.get(key, function(err, data) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
@ -1429,6 +1387,59 @@ ChainDB.prototype._getPruneCoin = function _getPruneCoin(hash, index, callback)
|
||||
});
|
||||
};
|
||||
|
||||
function DumbCache(size) {
|
||||
this.data = {};
|
||||
this.count = 0;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
DumbCache.prototype.set = function set(key, value) {
|
||||
key = key + '';
|
||||
|
||||
assert(value !== undefined);
|
||||
|
||||
if (this.count > this.size)
|
||||
this.reset();
|
||||
|
||||
if (this.data[key] === undefined)
|
||||
this.count++;
|
||||
|
||||
this.data[key] = value;
|
||||
};
|
||||
|
||||
DumbCache.prototype.remove = function remove(key) {
|
||||
key = key + '';
|
||||
|
||||
if (this.data[key] === undefined)
|
||||
return;
|
||||
|
||||
this.count--;
|
||||
delete this.data[key];
|
||||
};
|
||||
|
||||
DumbCache.prototype.get = function get(key) {
|
||||
key = key + '';
|
||||
return this.data[key];
|
||||
};
|
||||
|
||||
DumbCache.prototype.has = function has(key) {
|
||||
key = key + '';
|
||||
return this.data[key] !== undefined;
|
||||
};
|
||||
|
||||
DumbCache.prototype.reset = function reset() {
|
||||
this.data = {};
|
||||
this.count = 0;
|
||||
};
|
||||
|
||||
function NullCache(size) {}
|
||||
|
||||
NullCache.prototype.set = function set(key, value) {};
|
||||
NullCache.prototype.remove = function remove(key) {};
|
||||
NullCache.prototype.get = function get(key) {};
|
||||
NullCache.prototype.has = function has(key) {};
|
||||
NullCache.prototype.reset = function reset() {};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user