parent
5074e3100d
commit
0e31719d13
@ -92,8 +92,8 @@ function ChainDB(chain, options) {
|
||||
// Average number of outputs per tx: 2.2
|
||||
// Average size of outputs per tx: 74b
|
||||
// Average number of txs: 2300
|
||||
// Key size: 66b (* 2)
|
||||
this.coinWindow = ((165 * 1024 + 2300 * 4) + (2300 * 66 * 2)) * 5;
|
||||
// Key size: 68b (* 2)
|
||||
this.coinWindow = ((165 * 1024 + 5000 * 9) + (5000 * 68 * 2)) * 5;
|
||||
|
||||
this.coinCache = new bcoin.lru(this.coinWindow);
|
||||
this.cacheHash = new bcoin.lru(this.cacheWindow, 1);
|
||||
@ -782,7 +782,7 @@ ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) {
|
||||
ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
var self = this;
|
||||
var undo = new BufferWriter();
|
||||
var i, j, tx, input, output, key, addresses, address, hash, view, coins, raw;
|
||||
var i, j, tx, input, output, key, addresses, address, hash, coin;
|
||||
|
||||
if (this.options.spv) {
|
||||
self.emit('add block', block);
|
||||
@ -830,38 +830,31 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
batch.del('C/' + address + '/' + key);
|
||||
}
|
||||
|
||||
batch.del('c/' + key);
|
||||
|
||||
Framer.coin(input.coin, false, undo);
|
||||
|
||||
block.view.spend(input.prevout.hash, input.prevout.index);
|
||||
self.coinCache.remove(key);
|
||||
}
|
||||
|
||||
for (j = 0; j < tx.outputs.length; j++) {
|
||||
output = tx.outputs[j];
|
||||
key = hash + '/' + j;
|
||||
|
||||
if (output.script.isUnspendable())
|
||||
continue;
|
||||
|
||||
coin = bcoin.coin.fromTX(tx, j).toRaw();
|
||||
|
||||
if (self.options.indexAddress) {
|
||||
address = output.getHash();
|
||||
if (address)
|
||||
batch.put('C/' + address + '/' + key, DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
block.view.add(tx.toCoins());
|
||||
}
|
||||
batch.put('c/' + key, coin);
|
||||
|
||||
view = block.view.toArray();
|
||||
|
||||
for (i = 0; i < view.length; i++) {
|
||||
coins = view[i];
|
||||
if (coins.count() === 0) {
|
||||
batch.del('c/' + coins.hash);
|
||||
self.coinCache.remove(coins.hash);
|
||||
} else {
|
||||
raw = coins.toRaw();
|
||||
batch.put('c/' + coins.hash, raw);
|
||||
self.coinCache.set(coins.hash, raw);
|
||||
self.coinCache.set(key, coin);
|
||||
}
|
||||
}
|
||||
|
||||
@ -887,7 +880,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) {
|
||||
|
||||
ChainDB.prototype.disconnectBlock = function disconnectBlock(block, batch, callback) {
|
||||
var self = this;
|
||||
var i, j, tx, input, output, key, addresses, address, hash, view, coins, raw;
|
||||
var i, j, tx, input, output, key, addresses, address, hash, coin;
|
||||
|
||||
if (this.options.spv)
|
||||
return utils.nextTick(callback);
|
||||
@ -929,10 +922,12 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(block, batch, callb
|
||||
batch.put('C/' + address + '/' + key, DUMMY);
|
||||
}
|
||||
|
||||
block.view.addCoin(input.coin);
|
||||
}
|
||||
coin = input.coin.toRaw();
|
||||
|
||||
block.view.add(tx.toCoins());
|
||||
batch.put('c/' + key, coin);
|
||||
|
||||
self.coinCache.set(key, coin);
|
||||
}
|
||||
|
||||
for (j = 0; j < tx.outputs.length; j++) {
|
||||
output = tx.outputs[j];
|
||||
@ -947,21 +942,9 @@ ChainDB.prototype.disconnectBlock = function disconnectBlock(block, batch, callb
|
||||
batch.del('C/' + address + '/' + key);
|
||||
}
|
||||
|
||||
block.view.spend(hash, j);
|
||||
}
|
||||
}
|
||||
batch.del('c/' + key);
|
||||
|
||||
view = block.view.toArray();
|
||||
|
||||
for (i = 0; i < view.length; i++) {
|
||||
coins = view[i];
|
||||
if (coins.count() === 0) {
|
||||
batch.del('c/' + coins.hash);
|
||||
self.coinCache.remove(coins.hash);
|
||||
} else {
|
||||
raw = coins.toRaw();
|
||||
batch.put('c/' + coins.hash, raw);
|
||||
self.coinCache.set(coins.hash, raw);
|
||||
self.coinCache.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1065,62 +1048,29 @@ ChainDB.prototype.fillHistory = function fillHistory(tx, callback) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
var self = this;
|
||||
var key = hash + '/' + index;
|
||||
var coin;
|
||||
|
||||
this.getCoins(hash, true, function(err, coins) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!coins)
|
||||
return callback();
|
||||
|
||||
try {
|
||||
coin = bcoin.coins.parseCoin(coins, hash, index);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
return callback(null, coin);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get coins (unspents only).
|
||||
* @param {Hash} hash
|
||||
* @param {Function} callback - Returns [Error, {@link Coins}].
|
||||
*/
|
||||
|
||||
ChainDB.prototype.getCoins = function getCoins(hash, raw, callback) {
|
||||
var self = this;
|
||||
var coins;
|
||||
|
||||
if (!callback) {
|
||||
callback = raw;
|
||||
raw = false;
|
||||
}
|
||||
|
||||
coins = this.coinCache.get(hash);
|
||||
|
||||
if (coins) {
|
||||
coin = this.coinCache.get(key);
|
||||
if (coin) {
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (raw)
|
||||
return callback(null, coins);
|
||||
|
||||
try {
|
||||
coins = bcoin.coins.fromRaw(coins, hash);
|
||||
coin = bcoin.coin.fromRaw(coin);
|
||||
coin.hash = hash;
|
||||
coin.index = index;
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
return callback(null, coins);
|
||||
return callback(null, coin);
|
||||
}
|
||||
|
||||
this.db.fetch('c/' + hash, function(data) {
|
||||
self.coinCache.set(hash, data);
|
||||
if (raw)
|
||||
return data;
|
||||
return bcoin.coins.fromRaw(data, hash);
|
||||
this.db.fetch('c/' + key, function(data) {
|
||||
var coin = bcoin.coin.fromRaw(data);
|
||||
coin.hash = hash;
|
||||
coin.index = index;
|
||||
self.coinCache.set(key, data);
|
||||
return coin;
|
||||
}, callback);
|
||||
};
|
||||
|
||||
@ -1178,32 +1128,27 @@ ChainDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, call
|
||||
|
||||
utils.forEachSerial(addresses, function(address, next) {
|
||||
address = bcoin.address.getHash(address);
|
||||
|
||||
if (!address)
|
||||
return next();
|
||||
|
||||
self.db.iterate({
|
||||
self.db.lookup({
|
||||
gte: 'C/' + address,
|
||||
lte: 'C/' + address + '~',
|
||||
transform: function(key) {
|
||||
key = key.split('/');
|
||||
return [key[2], +key[3]];
|
||||
return 'c/' + key[2] + '/' + key[3];
|
||||
},
|
||||
parse: function(data, key) {
|
||||
var coin = bcoin.coin.fromRaw(data);
|
||||
var hash = key.split('/');
|
||||
coin.hash = hash[1];
|
||||
coin.index = +hash[2];
|
||||
return coin;
|
||||
}
|
||||
}, function(err, keys) {
|
||||
}, function(err, coin) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
utils.forEachSerial(keys, function(key, next) {
|
||||
self.getCoin(key[0], key[1], function(err, coin) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (coin)
|
||||
coins.push(coin);
|
||||
|
||||
return next();
|
||||
});
|
||||
}, next);
|
||||
coins = coins.concat(coin);
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
@ -1339,21 +1284,9 @@ ChainDB.prototype._ensureHistory = function _ensureHistory(hash, callback) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.fillBlock = function fillBlock(block, callback) {
|
||||
var self = this;
|
||||
var view = new bcoin.coinview();
|
||||
var coins, spent, i, tx, hash, j, input, key;
|
||||
|
||||
utils.forEachSerial(block.getPrevout(), function(prevout, next) {
|
||||
self.getCoins(prevout, function(err, coins) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (coins)
|
||||
view.add(coins);
|
||||
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
return this.fillCoins(block.txs, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -1364,8 +1297,6 @@ ChainDB.prototype.fillBlock = function fillBlock(block, callback) {
|
||||
tx = block.txs[i];
|
||||
hash = tx.hash('hex');
|
||||
|
||||
view.fill(tx);
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
key = input.prevout.hash + '/' + input.prevout.index;
|
||||
@ -1387,8 +1318,6 @@ ChainDB.prototype.fillBlock = function fillBlock(block, callback) {
|
||||
coins[hash + '/' + j] = bcoin.coin.fromTX(tx, j);
|
||||
}
|
||||
|
||||
block.view = view;
|
||||
|
||||
return callback(null, block);
|
||||
});
|
||||
};
|
||||
@ -1421,36 +1350,30 @@ ChainDB.prototype.getUndoCoins = function getUndoCoins(hash, callback) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.fillHistoryBlock = function fillHistoryBlock(block, callback) {
|
||||
var self = this;
|
||||
var i, j, k, tx, input;
|
||||
|
||||
return this.fillBlock(block, function(err) {
|
||||
return this.getUndoCoins(block.hash('hex'), function(err, coins) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return self.getUndoCoins(block.hash('hex'), function(err, coins) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (!coins)
|
||||
return callback(null, block);
|
||||
|
||||
for (i = 0, k = 0; i < block.txs.length; i++) {
|
||||
tx = block.txs[i];
|
||||
|
||||
if (tx.isCoinbase())
|
||||
continue;
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
input.coin = coins[k++];
|
||||
input.coin.hash = input.prevout.hash;
|
||||
input.coin.index = input.prevout.index;
|
||||
}
|
||||
}
|
||||
|
||||
if (!coins)
|
||||
return callback(null, block);
|
||||
});
|
||||
|
||||
for (i = 0, k = 0; i < block.txs.length; i++) {
|
||||
tx = block.txs[i];
|
||||
|
||||
if (tx.isCoinbase())
|
||||
continue;
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
input = tx.inputs[j];
|
||||
input.coin = coins[k++];
|
||||
input.coin.hash = input.prevout.hash;
|
||||
input.coin.index = input.prevout.index;
|
||||
}
|
||||
}
|
||||
|
||||
return callback(null, block);
|
||||
});
|
||||
};
|
||||
|
||||
@ -1504,13 +1427,32 @@ ChainDB.prototype.isUnspentTX = function isUnspentTX(hash, callback) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.isSpentTX = function isSpentTX(hash, callback) {
|
||||
var iter;
|
||||
|
||||
if (hash.hash)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
this.getCoins(hash, function(err, coins) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback(null, !coins);
|
||||
iter = this.db.iterator({
|
||||
gte: 'c/' + hash,
|
||||
lte: 'c/' + hash + '~',
|
||||
keys: true,
|
||||
values: false,
|
||||
fillCache: false,
|
||||
keyAsBuffer: false
|
||||
});
|
||||
|
||||
iter.next(function(err, key, value) {
|
||||
if (err) {
|
||||
return iter.end(function() {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
iter.end(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback(null, key === undefined);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user