chain: refactor coinview.
This commit is contained in:
parent
9e4db47792
commit
8b99b5103b
@ -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
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user