/*! * coinentry.js - coin entry object for bcoin * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ 'use strict'; const assert = require('assert'); const Output = require('../primitives/output'); const BufferReader = require('../utils/reader'); const StaticWriter = require('../utils/staticwriter'); const encoding = require('../utils/encoding'); const Coin = require('../primitives/coin'); const {compress, decompress} = require('../coins/compress'); /** * Represents an unspent output. * @alias module:coins.CoinEntry * @constructor * @property {Number} version - Transaction version. * @property {Number} height - Transaction height (-1 if unconfirmed). * @property {Boolean} coinbase - Whether the containing * transaction is a coinbase. * @property {Output} output * @property {Boolean} spent * @property {Buffer} raw */ function CoinEntry() { if (!(this instanceof CoinEntry)) return new CoinEntry(); this.version = 1; this.height = -1; this.coinbase = false; this.output = new Output(); this.spent = false; this.raw = null; } /** * Convert coin entry to an output. * @returns {Output} */ CoinEntry.prototype.toOutput = function toOutput() { return this.output; }; /** * Convert coin entry to a coin. * @param {Outpoint} prevout * @returns {Coin} */ CoinEntry.prototype.toCoin = function toCoin(prevout) { let coin = new Coin(); coin.version = this.version; coin.height = this.height; coin.coinbase = this.coinbase; coin.script = this.output.script; coin.value = this.output.value; coin.hash = prevout.hash; coin.index = prevout.index; return coin; }; /** * Inject properties from TX. * @param {TX} tx * @param {Number} index */ CoinEntry.prototype.fromOutput = function fromOutput(output) { this.output = output; return this; }; /** * Instantiate a coin from a TX * @param {TX} tx * @param {Number} index - Output index. * @returns {CoinEntry} */ CoinEntry.fromOutput = function fromOutput(output) { return new CoinEntry().fromOutput(output); }; /** * Inject properties from TX. * @param {TX} tx * @param {Number} index */ CoinEntry.prototype.fromCoin = function fromCoin(coin) { this.version = coin.version; this.height = coin.height; this.coinbase = coin.coinbase; this.output.script = coin.script; this.output.value = coin.value; return this; }; /** * Instantiate a coin from a TX * @param {TX} tx * @param {Number} index - Output index. * @returns {CoinEntry} */ CoinEntry.fromCoin = function fromCoin(coin) { return new CoinEntry().fromCoin(coin); }; /** * Inject properties from TX. * @param {TX} tx * @param {Number} index */ CoinEntry.prototype.fromTX = function fromTX(tx, index, height) { assert(typeof index === 'number'); assert(typeof height === 'number'); assert(index >= 0 && index < tx.outputs.length); this.version = tx.version; this.height = height; this.coinbase = tx.isCoinbase(); this.output = tx.outputs[index]; return this; }; /** * Instantiate a coin from a TX * @param {TX} tx * @param {Number} index - Output index. * @returns {CoinEntry} */ CoinEntry.fromTX = function fromTX(tx, index, height) { return new CoinEntry().fromTX(tx, index, height); }; /** * Calculate size of coin. * @returns {Number} */ CoinEntry.prototype.getSize = function getSize() { let size; if (this.raw) return this.raw.length; size = 0; size += encoding.sizeVarint(this.version); size += 4; size += compress.size(this.output); return size; }; /** * Write the coin to a buffer writer. * @param {BufferWriter} bw */ CoinEntry.prototype.toWriter = function toWriter(bw) { let flags = 0; let height = this.height; let field; if (this.raw) { bw.writeBytes(this.raw); return bw; } // We save 29 bits for the height. // This should be good for the next 4000 years. if (height === -1) height = 0x1fffffff; if (this.coinbase) flags |= 1; field = (height * 8) | flags; bw.writeVarint(this.version); bw.writeU32(field); compress.output(this.output, bw); return bw; }; /** * Serialize the coin. * @returns {Buffer} */ CoinEntry.prototype.toRaw = function toRaw() { let size, bw; if (this.raw) return this.raw; size = this.getSize(); bw = new StaticWriter(size); this.toWriter(bw); this.raw = bw.render(); return this.raw; }; /** * Inject properties from serialized buffer writer. * @private * @param {BufferReader} br */ CoinEntry.prototype.fromReader = function fromReader(br) { let field, flags, height; this.version = br.readVarint(); field = br.readU32(); height = field / 8 | 0; flags = field & 0x07; if (height === 0x1fffffff) height = -1; this.coinbase = (flags & 1) !== 0; this.height = height; decompress.output(this.output, br); return this; }; /** * Instantiate a coin from a serialized Buffer. * @param {Buffer} data * @returns {CoinEntry} */ CoinEntry.fromReader = function fromReader(data) { return new CoinEntry().fromReader(data); }; /** * Inject properties from serialized data. * @private * @param {Buffer} data */ CoinEntry.prototype.fromRaw = function fromRaw(data) { this.fromReader(new BufferReader(data)); this.raw = data; return this; }; /** * Instantiate a coin from a serialized Buffer. * @param {Buffer} data * @returns {CoinEntry} */ CoinEntry.fromRaw = function fromRaw(data) { return new CoinEntry().fromRaw(data); }; /* * Expose */ module.exports = CoinEntry;