fcoin/lib/coins/coins.js

222 lines
3.9 KiB
JavaScript

/*!
* coins.js - coins object for bcoin
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
const assert = require('assert');
const CoinEntry = require('./coinentry');
/**
* Represents the outputs for a single transaction.
* @alias module:coins.Coins
* @constructor
* @property {Map[]} outputs - Coins.
*/
function Coins() {
if (!(this instanceof Coins))
return new Coins();
this.outputs = new Map();
}
/**
* Add a single entry to the collection.
* @param {Number} index
* @param {CoinEntry} coin
* @returns {CoinEntry}
*/
Coins.prototype.add = function add(index, coin) {
assert((index >>> 0) === index);
assert(coin);
this.outputs.set(index, coin);
return coin;
};
/**
* Add a single output to the collection.
* @param {Number} index
* @param {Output} output
* @returns {CoinEntry}
*/
Coins.prototype.addOutput = function addOutput(index, output) {
return this.add(index, CoinEntry.fromOutput(output));
};
/**
* Add an output to the collection by output index.
* @param {TX} tx
* @param {Number} index
* @param {Number} height
* @returns {CoinEntry}
*/
Coins.prototype.addIndex = function addIndex(tx, index, height) {
return this.add(index, CoinEntry.fromTX(tx, index, height));
};
/**
* Add a single coin to the collection.
* @param {Coin} coin
* @returns {CoinEntry}
*/
Coins.prototype.addCoin = function addCoin(coin) {
return this.add(coin.index, CoinEntry.fromCoin(coin));
};
/**
* Test whether the collection has a coin.
* @param {Number} index
* @returns {Boolean}
*/
Coins.prototype.has = function has(index) {
return this.outputs.has(index);
};
/**
* Test whether the collection has an unspent coin.
* @param {Number} index
* @returns {Boolean}
*/
Coins.prototype.isUnspent = function isUnspent(index) {
const coin = this.outputs.get(index);
if (!coin || coin.spent)
return false;
return true;
};
/**
* Get a coin entry.
* @param {Number} index
* @returns {CoinEntry|null}
*/
Coins.prototype.get = function get(index) {
return this.outputs.get(index) || null;
};
/**
* Get an output.
* @param {Number} index
* @returns {Output|null}
*/
Coins.prototype.getOutput = function getOutput(index) {
const coin = this.outputs.get(index);
if (!coin)
return null;
return coin.output;
};
/**
* Get a coin.
* @param {Outpoint} prevout
* @returns {Coin|null}
*/
Coins.prototype.getCoin = function getCoin(prevout) {
const coin = this.outputs.get(prevout.index);
if (!coin)
return null;
return coin.toCoin(prevout);
};
/**
* Spend a coin entry and return it.
* @param {Number} index
* @returns {CoinEntry|null}
*/
Coins.prototype.spend = function spend(index) {
const coin = this.get(index);
if (!coin || coin.spent)
return null;
coin.spent = true;
return coin;
};
/**
* Remove a coin entry and return it.
* @param {Number} index
* @returns {CoinEntry|null}
*/
Coins.prototype.remove = function remove(index) {
const coin = this.get(index);
if (!coin)
return null;
this.outputs.delete(index);
return coin;
};
/**
* Test whether the coins are fully spent.
* @returns {Boolean}
*/
Coins.prototype.isEmpty = function isEmpty() {
return this.outputs.size === 0;
};
/**
* Inject properties from tx.
* @private
* @param {TX} tx
* @param {Number} height
* @returns {Coins}
*/
Coins.prototype.fromTX = function fromTX(tx, height) {
assert(typeof height === 'number');
for (let i = 0; i < tx.outputs.length; i++) {
const output = tx.outputs[i];
if (output.script.isUnspendable())
continue;
const entry = CoinEntry.fromTX(tx, i, height);
this.outputs.set(i, entry);
}
return this;
};
/**
* Instantiate a coins object from a transaction.
* @param {TX} tx
* @param {Number} height
* @returns {Coins}
*/
Coins.fromTX = function fromTX(tx, height) {
return new Coins().fromTX(tx, height);
};
/*
* Expose
*/
module.exports = Coins;