chain: refactor coinview.

This commit is contained in:
Christopher Jeffrey 2016-12-07 03:24:10 -08:00
parent 9e4db47792
commit 8b99b5103b
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 129 additions and 113 deletions

View File

@ -848,6 +848,34 @@ ChainDB.prototype.hasCoins = function hasCoins(hash) {
return this.db.has(layout.c(hash));
};
/**
* Get coin viewpoint.
* @param {TX} tx
* @returns {Promise} - Returns {@link CoinView}.
*/
ChainDB.prototype.getCoinView = co(function* getCoinView(tx, callback) {
var view = new CoinView();
var prevout = tx.getPrevout();
var i, prev, coins;
for (i = 0; i < prevout.length; i++) {
prev = prevout[i];
coins = yield this.getCoins(prev);
if (!coins) {
coins = new Coins();
coins.hash = prev.hash;
view.add(coins);
continue;
}
view.add(coins);
}
return view;
});
/**
* Get coins necessary to be resurrected during a reorg.
* @param {Hash} hash

View File

@ -90,20 +90,39 @@ Coins.fromOptions = function fromOptions(options) {
};
/**
* Add a single output to the collection.
* Add a single entry to the collection.
* @param {Number} index
* @param {Output} output
* @param {CoinEntry} entry
*/
Coins.prototype.add = function add(index, output) {
assert(!output.script.isUnspendable());
Coins.prototype.add = function add(index, entry) {
while (this.outputs.length <= index)
this.outputs.push(null);
assert(!this.outputs[index]);
this.outputs[index] = CoinEntry.fromOutput(output);
this.outputs[index] = entry;
};
/**
* Add a single output to the collection.
* @param {Number} index
* @param {Output} output
*/
Coins.prototype.addOutput = function addOutput(index, output) {
assert(!output.script.isUnspendable());
this.add(index, CoinEntry.fromOutput(output));
};
/**
* Add a single coin to the collection.
* @param {Coin} coin
*/
Coins.prototype.addCoin = function addCoin(coin) {
assert(!coin.script.isUnspendable());
this.add(coin.index, CoinEntry.fromCoin(coin));
};
/**
@ -132,6 +151,21 @@ Coins.prototype.get = function get(index) {
return this.outputs[index];
};
/**
* Get an output.
* @param {Number} index
* @returns {Output}
*/
Coins.prototype.getOutput = function getOutput(index) {
var entry = this.get(index);
if (!entry)
return;
return entry.toOutput();
};
/**
* Get a coin.
* @param {Number} index
@ -426,6 +460,7 @@ Coins.fromRaw = function fromRaw(data, hash) {
* Inject properties from tx.
* @private
* @param {TX} tx
* @param {Number} height
*/
Coins.prototype.fromTX = function fromTX(tx, height) {
@ -457,6 +492,7 @@ Coins.prototype.fromTX = function fromTX(tx, height) {
/**
* Instantiate a coins object from a transaction.
* @param {TX} tx
* @param {Number} height
* @returns {Coins}
*/
@ -586,7 +622,7 @@ CoinEntry.fromReader = function fromReader(br) {
};
/**
* Instantiate compressed coin from coin.
* Instantiate compressed coin from output.
* @param {Output} output
* @returns {CoinEntry}
*/
@ -597,6 +633,21 @@ CoinEntry.fromOutput = function fromOutput(output) {
return entry;
};
/**
* Instantiate compressed coin from coin.
* @param {Coin} coin
* @returns {CoinEntry}
*/
CoinEntry.fromCoin = function fromCoin(coin) {
var entry = new CoinEntry();
var output = new Output();
output.value = coin.value;
output.script = coin.script;
entry.output = output;
return entry;
};
/*
* Expose
*/

View File

@ -26,12 +26,22 @@ function CoinView() {
this.undo = new UndoCoins();
}
/**
* Get coins.
* @param {Hash} hash
* @returns {Coins} coins
*/
CoinView.prototype.get = function get(hash) {
return this.unspent[hash];
};
/**
* Add coins to the collection.
* @param {Coins} coins
*/
CoinView.prototype.addCoins = function addCoins(coins) {
CoinView.prototype.add = function add(coins) {
this.unspent[coins.hash] = coins;
return coins;
};
@ -39,76 +49,24 @@ CoinView.prototype.addCoins = function addCoins(coins) {
/**
* Add a tx to the collection.
* @param {TX} tx
* @param {Number} height
*/
CoinView.prototype.addTX = function addTX(tx, height) {
var coins = Coins.fromTX(tx, height);
return this.addCoins(coins);
return this.add(coins);
};
/**
* Remove a tx from the collection.
* @param {TX} tx
* @param {Number} height
*/
CoinView.prototype.removeTX = function removeTX(tx, height) {
var coins = Coins.fromTX(tx, height);
coins.outputs.length = 0;
return this.addCoins(coins);
};
/**
* Get a coin.
* @param {Hash} hash
* @param {Number} index
* @returns {Coin}
*/
CoinView.prototype.get = function get(hash, index) {
var coins = this.unspent[hash];
var entry;
if (!coins)
return;
entry = coins.get(index);
if (!entry)
return;
return entry.toCoin(coins, index);
};
/**
* Test whether the collection has a coin.
* @param {Hash} hash
* @param {Number} index
* @returns {Boolean}
*/
CoinView.prototype.has = function has(hash, index) {
var coins = this.unspent[hash];
if (!coins)
return false;
return coins.has(index);
};
/**
* Remove a coin and return it.
* @param {Hash} hash
* @param {Number} index
* @returns {Coin}
*/
CoinView.prototype.spend = function spend(hash, index) {
var coins = this.unspent[hash];
if (!coins)
return null;
return this.spendFrom(coins, index);
return this.add(coins);
};
/**
@ -158,31 +116,6 @@ CoinView.prototype.getCoins = co(function* getCoins(db, hash) {
return coins;
});
/**
* Test whether all inputs are available.
* @param {ChainDB} db
* @param {TX} tx
* @returns {Boolean} True if all inputs are available.
*/
CoinView.prototype.hasInputs = co(function* hasInputs(db, tx) {
var i, input, prevout, coins;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
prevout = input.prevout;
coins = yield this.getCoins(db, prevout.hash);
if (!coins)
return false;
if (!coins.has(prevout.index))
return false;
}
return true;
});
/**
* Read all input coins into unspent map.
* @param {ChainDB} db
@ -198,28 +131,6 @@ CoinView.prototype.ensureInputs = co(function* ensureInputs(db, tx) {
}
});
/**
* Spend coins for transaction.
* @param {TX} tx
* @returns {Boolean}
*/
CoinView.prototype.spendCoins = function spendCoins(tx) {
var i, input, prevout;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
prevout = input.prevout;
input.coin = this.spend(prevout.hash, prevout.index);
if (!input.coin)
return false;
}
return true;
};
/**
* Spend coins for transaction.
* @param {TX} tx

View File

@ -148,7 +148,7 @@ UndoCoins.prototype.apply = function apply(view, outpoint) {
assert(coins);
}
coins.add(index, undo.toOutput());
coins.addOutput(index, undo.toOutput());
assert(coins.has(index));

View File

@ -1574,6 +1574,32 @@ Mempool.prototype.fillAllCoins = co(function* fillAllCoins(tx) {
return found;
});
/**
* Get coin viewpoint.
* @param {TX} tx
* @returns {Promise} - Returns {@link CoinView}.
*/
Mempool.prototype.getCoinView = co(function* getCoinView(tx) {
var view = yield this.chain.db.getCoinView(tx);
var entries = view.toArray();
var i, coins, entry;
for (i = 0; i < entries.length; i++) {
coins = entries[i];
if (!coins.isEmpty())
continue;
entry = this.getEntry(coins.hash);
if (!entry)
continue;
view.addTX(entry.tx, entry.height);
}
});
/**
* Get a snapshot of all transaction hashes in the mempool. Used
* for generating INV packets in response to MEMPOOL packets.

View File

@ -152,7 +152,7 @@ var reserializeCoins = co(function* reserializeCoins() {
output.value = coin.value;
if (!output.script.isUnspendable())
coins.add(coin.index, output);
coins.addOutput(coin.index, output);
}
coins.cleanup();