UNPKG

hsd

Version:
258 lines (207 loc) 4.96 kB
/*! * coinentry.js - coin entry object for hsd * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License). * https://github.com/handshake-org/hsd */ 'use strict'; const assert = require('bsert'); const bio = require('bufio'); const Coin = require('../primitives/coin'); const Output = require('../primitives/output'); const compress = require('./compress'); const {encoding} = bio; /** @typedef {import('../types').BufioWriter} BufioWriter */ /** @typedef {import('../primitives/outpoint')} Outpoint */ /** @typedef {import('../primitives/tx')} TX */ /* * Constants */ const NUM_FLAGS = 1; const MAX_HEIGHT = ((1 << (32 - NUM_FLAGS)) >>> 0) - 1; /** * Coin Entry * Represents an unspent output. * @alias module:coins.CoinEntry * @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 */ class CoinEntry extends bio.Struct { /** * Create a coin entry. * @constructor */ constructor() { super(); 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} */ toOutput() { return this.output; } /** * Convert coin entry to a coin. * @param {Outpoint} prevout * @returns {Coin} */ toCoin(prevout) { const coin = new Coin(); coin.version = this.version; coin.height = this.height; coin.coinbase = this.coinbase; coin.value = this.output.value; coin.address = this.output.address; coin.covenant = this.output.covenant; coin.hash = prevout.hash; coin.index = prevout.index; return coin; } /** * Inject properties from TX. * @param {Output} output */ fromOutput(output) { this.output = output; return this; } /** * Instantiate a coin from a TX * @param {Output} output * @returns {CoinEntry} */ static fromOutput(output) { return new this().fromOutput(output); } /** * Inject properties from Coin. * @param {Coin} coin */ fromCoin(coin) { this.version = coin.version; this.height = coin.height; this.coinbase = coin.coinbase; this.output.value = coin.value; this.output.address = coin.address; this.output.covenant = coin.covenant; return this; } /** * Instantiate a coin from a TX * @param {Coin} coin * @returns {CoinEntry} */ static fromCoin(coin) { return new this().fromCoin(coin); } /** * Inject properties from TX. * @param {TX} tx * @param {Number} index * @param {Number} height */ 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. * @param {Number} height * @returns {CoinEntry} */ static fromTX(tx, index, height) { return new this().fromTX(tx, index, height); } /** * Calculate size of coin. * @returns {Number} */ getSize() { if (this.raw) return this.raw.length; let size = 0; size += encoding.sizeVarint(this.version); size += 4; size += compress.size(this.output); return size; } /** * Write the coin to a buffer writer. * @param {BufioWriter} bw * @returns {BufioWriter} */ write(bw) { if (this.raw) { bw.writeBytes(this.raw); return bw; } let height = this.height; let field = 0; if (this.coinbase) field |= 1; if (height === -1) height = MAX_HEIGHT; field |= height << NUM_FLAGS; bw.writeVarint(this.version); bw.writeU32(field); compress.pack(this.output, bw); return bw; } /** * Serialize the coin. * @returns {Buffer} */ encode() { if (!this.raw) this.raw = super.encode(); return this.raw; } /** * Inject properties from serialized buffer writer. * @param {bio.BufferReader} br */ read(br) { const version = br.readVarint(); const field = br.readU32(); let height = field >>> NUM_FLAGS; if (height === MAX_HEIGHT) height = -1; this.version = version; this.coinbase = (field & 1) !== 0; this.height = height; compress.unpack(this.output, br); return this; } /** * Inject properties from serialized data. * @param {Buffer} data */ decode(data) { super.decode(data); this.raw = data; return this; } } /* * Expose */ module.exports = CoinEntry;