Source: coins/coinentry.js

  1. /*!
  2. * coinentry.js - coin entry object for bcoin
  3. * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
  4. * https://github.com/bcoin-org/bcoin
  5. */
  6. 'use strict';
  7. const assert = require('bsert');
  8. const bio = require('bufio');
  9. const Coin = require('../primitives/coin');
  10. const Output = require('../primitives/output');
  11. const compress = require('./compress');
  12. const {encoding} = bio;
  13. /*
  14. * Constants
  15. */
  16. const NUM_FLAGS = 1;
  17. const MAX_HEIGHT = ((1 << (32 - NUM_FLAGS)) >>> 0) - 1;
  18. /**
  19. * Coin Entry
  20. * Represents an unspent output.
  21. * @alias module:coins.CoinEntry
  22. * @property {Number} version - Transaction version.
  23. * @property {Number} height - Transaction height (-1 if unconfirmed).
  24. * @property {Boolean} coinbase - Whether the containing
  25. * transaction is a coinbase.
  26. * @property {Output} output
  27. * @property {Boolean} spent
  28. * @property {Buffer} raw
  29. */
  30. class CoinEntry {
  31. /**
  32. * Create a coin entry.
  33. * @constructor
  34. */
  35. constructor() {
  36. this.version = 1;
  37. this.height = -1;
  38. this.coinbase = false;
  39. this.output = new Output();
  40. this.spent = false;
  41. this.raw = null;
  42. }
  43. /**
  44. * Convert coin entry to an output.
  45. * @returns {Output}
  46. */
  47. toOutput() {
  48. return this.output;
  49. }
  50. /**
  51. * Convert coin entry to a coin.
  52. * @param {Outpoint} prevout
  53. * @returns {Coin}
  54. */
  55. toCoin(prevout) {
  56. const coin = new Coin();
  57. coin.version = this.version;
  58. coin.height = this.height;
  59. coin.coinbase = this.coinbase;
  60. coin.script = this.output.script;
  61. coin.value = this.output.value;
  62. coin.hash = prevout.hash;
  63. coin.index = prevout.index;
  64. return coin;
  65. }
  66. /**
  67. * Inject properties from TX.
  68. * @param {TX} tx
  69. * @param {Number} index
  70. */
  71. fromOutput(output) {
  72. this.output = output;
  73. return this;
  74. }
  75. /**
  76. * Instantiate a coin from a TX
  77. * @param {TX} tx
  78. * @param {Number} index - Output index.
  79. * @returns {CoinEntry}
  80. */
  81. static fromOutput(output) {
  82. return new this().fromOutput(output);
  83. }
  84. /**
  85. * Inject properties from TX.
  86. * @param {TX} tx
  87. * @param {Number} index
  88. */
  89. fromCoin(coin) {
  90. this.version = coin.version;
  91. this.height = coin.height;
  92. this.coinbase = coin.coinbase;
  93. this.output.script = coin.script;
  94. this.output.value = coin.value;
  95. return this;
  96. }
  97. /**
  98. * Instantiate a coin from a TX
  99. * @param {TX} tx
  100. * @param {Number} index - Output index.
  101. * @returns {CoinEntry}
  102. */
  103. static fromCoin(coin) {
  104. return new this().fromCoin(coin);
  105. }
  106. /**
  107. * Inject properties from TX.
  108. * @param {TX} tx
  109. * @param {Number} index
  110. */
  111. fromTX(tx, index, height) {
  112. assert(typeof index === 'number');
  113. assert(typeof height === 'number');
  114. assert(index >= 0 && index < tx.outputs.length);
  115. this.version = tx.version;
  116. this.height = height;
  117. this.coinbase = tx.isCoinbase();
  118. this.output = tx.outputs[index];
  119. return this;
  120. }
  121. /**
  122. * Instantiate a coin from a TX
  123. * @param {TX} tx
  124. * @param {Number} index - Output index.
  125. * @returns {CoinEntry}
  126. */
  127. static fromTX(tx, index, height) {
  128. return new this().fromTX(tx, index, height);
  129. }
  130. /**
  131. * Calculate size of coin.
  132. * @returns {Number}
  133. */
  134. getSize() {
  135. if (this.raw)
  136. return this.raw.length;
  137. let size = 0;
  138. size += encoding.sizeVarint(this.version);
  139. size += 4;
  140. size += compress.size(this.output);
  141. return size;
  142. }
  143. /**
  144. * Write the coin to a buffer writer.
  145. * @param {BufferWriter} bw
  146. */
  147. toWriter(bw) {
  148. if (this.raw) {
  149. bw.writeBytes(this.raw);
  150. return bw;
  151. }
  152. let height = this.height;
  153. let field = 0;
  154. if (this.coinbase)
  155. field |= 1;
  156. if (height === -1)
  157. height = MAX_HEIGHT;
  158. field |= height << NUM_FLAGS;
  159. bw.writeVarint(this.version);
  160. bw.writeU32(field);
  161. compress.pack(this.output, bw);
  162. return bw;
  163. }
  164. /**
  165. * Serialize the coin.
  166. * @returns {Buffer}
  167. */
  168. toRaw() {
  169. if (this.raw)
  170. return this.raw;
  171. const size = this.getSize();
  172. const bw = bio.write(size);
  173. this.toWriter(bw);
  174. this.raw = bw.render();
  175. return this.raw;
  176. }
  177. /**
  178. * Inject properties from serialized buffer writer.
  179. * @private
  180. * @param {BufferReader} br
  181. */
  182. fromReader(br) {
  183. const version = br.readVarint();
  184. const field = br.readU32();
  185. let height = field >>> NUM_FLAGS;
  186. if (height === MAX_HEIGHT)
  187. height = -1;
  188. this.version = version;
  189. this.coinbase = (field & 1) !== 0;
  190. this.height = height;
  191. compress.unpack(this.output, br);
  192. return this;
  193. }
  194. /**
  195. * Instantiate a coin from a serialized Buffer.
  196. * @param {Buffer} data
  197. * @returns {CoinEntry}
  198. */
  199. static fromReader(data) {
  200. return new this().fromReader(data);
  201. }
  202. /**
  203. * Inject properties from serialized data.
  204. * @private
  205. * @param {Buffer} data
  206. */
  207. fromRaw(data) {
  208. this.fromReader(bio.read(data));
  209. this.raw = data;
  210. return this;
  211. }
  212. /**
  213. * Instantiate a coin from a serialized Buffer.
  214. * @param {Buffer} data
  215. * @returns {CoinEntry}
  216. */
  217. static fromRaw(data) {
  218. return new this().fromRaw(data);
  219. }
  220. }
  221. /*
  222. * Expose
  223. */
  224. module.exports = CoinEntry;