209 lines
3.6 KiB
JavaScript
209 lines
3.6 KiB
JavaScript
/*!
|
|
* coinview.js - coinview object for bcoin
|
|
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
|
|
* https://github.com/bcoin-org/bcoin
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var co = require('../utils/co');
|
|
var Coins = require('./coins');
|
|
var UndoCoins = require('./undocoins');
|
|
|
|
/**
|
|
* A collections of {@link Coins} objects.
|
|
* @exports CoinView
|
|
* @constructor
|
|
* @param {Object} coins - A hash-to-coins map.
|
|
* @property {Object} coins
|
|
*/
|
|
|
|
function CoinView() {
|
|
if (!(this instanceof CoinView))
|
|
return new CoinView();
|
|
|
|
this.unspent = {};
|
|
this.undo = new UndoCoins();
|
|
}
|
|
|
|
/**
|
|
* Get coins.
|
|
* @param {Hash} hash
|
|
* @returns {Coins} coins
|
|
*/
|
|
|
|
CoinView.prototype.get = function get(hash) {
|
|
return this.unspent[hash];
|
|
};
|
|
|
|
/**
|
|
* Test whether the view has an entry.
|
|
* @param {Hash} hash
|
|
* @returns {Boolean}
|
|
*/
|
|
|
|
CoinView.prototype.has = function has(hash) {
|
|
return this.unspent[hash] != null;
|
|
};
|
|
|
|
/**
|
|
* Add coins to the collection.
|
|
* @param {Coins} coins
|
|
*/
|
|
|
|
CoinView.prototype.add = function add(coins) {
|
|
this.unspent[coins.hash] = coins;
|
|
return 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.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.add(coins);
|
|
};
|
|
|
|
/**
|
|
* Remove a coin and return it.
|
|
* @param {Coins} coins
|
|
* @param {Number} index
|
|
* @returns {Coin}
|
|
*/
|
|
|
|
CoinView.prototype.spendFrom = function spendFrom(coins, index) {
|
|
var entry = coins.spend(index);
|
|
var undo;
|
|
|
|
if (!entry)
|
|
return null;
|
|
|
|
this.undo.push(entry);
|
|
|
|
if (coins.isEmpty()) {
|
|
undo = this.undo.top();
|
|
undo.height = coins.height;
|
|
undo.coinbase = coins.coinbase;
|
|
undo.version = coins.version;
|
|
}
|
|
|
|
return entry.toCoin(coins, index);
|
|
};
|
|
|
|
/**
|
|
* Get a single coin.
|
|
* @param {Hash} hash
|
|
* @param {Number} index
|
|
* @returns {Coin}
|
|
*/
|
|
|
|
CoinView.prototype.getCoin = function getCoin(hash, index) {
|
|
var coins = this.get(hash);
|
|
|
|
if (!coins)
|
|
return;
|
|
|
|
return coins.getCoin(index);
|
|
};
|
|
|
|
/**
|
|
* Retrieve coins from database.
|
|
* @param {TX} tx
|
|
* @returns {Promise}
|
|
*/
|
|
|
|
CoinView.prototype.getCoins = co(function* getCoins(db, hash) {
|
|
var coins = this.unspent[hash];
|
|
|
|
if (!coins) {
|
|
coins = yield db.getCoins(hash);
|
|
|
|
if (!coins)
|
|
return;
|
|
|
|
this.unspent[hash] = coins;
|
|
}
|
|
|
|
return coins;
|
|
});
|
|
|
|
/**
|
|
* Read all input coins into unspent map.
|
|
* @param {ChainDB} db
|
|
* @param {TX} tx
|
|
*/
|
|
|
|
CoinView.prototype.ensureInputs = co(function* ensureInputs(db, tx) {
|
|
var i, input;
|
|
|
|
for (i = 0; i < tx.inputs.length; i++) {
|
|
input = tx.inputs[i];
|
|
yield this.getCoins(db, input.prevout.hash);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Spend coins for transaction.
|
|
* @param {TX} tx
|
|
* @returns {Boolean}
|
|
*/
|
|
|
|
CoinView.prototype.spendInputs = co(function* spendInputs(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;
|
|
|
|
input.coin = this.spendFrom(coins, prevout.index);
|
|
|
|
if (!input.coin)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
/**
|
|
* Convert collection to an array.
|
|
* @returns {Coins[]}
|
|
*/
|
|
|
|
CoinView.prototype.toArray = function toArray() {
|
|
var keys = Object.keys(this.unspent);
|
|
var out = [];
|
|
var i, hash;
|
|
|
|
for (i = 0; i < keys.length; i++) {
|
|
hash = keys[i];
|
|
out.push(this.unspent[hash]);
|
|
}
|
|
|
|
return out;
|
|
};
|
|
|
|
/*
|
|
* Expose
|
|
*/
|
|
|
|
module.exports = CoinView;
|