smartledger-bsv 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +36 -0
  2. package/README.md +305 -0
  3. package/SECURITY.md +75 -0
  4. package/bsv-ecies.min.js +12 -0
  5. package/bsv-message.min.js +10 -0
  6. package/bsv-mnemonic.min.js +12 -0
  7. package/bsv.d.ts +440 -0
  8. package/bsv.min.js +37 -0
  9. package/ecies/index.js +1 -0
  10. package/index.js +101 -0
  11. package/lib/address.js +526 -0
  12. package/lib/block/block.js +277 -0
  13. package/lib/block/blockheader.js +294 -0
  14. package/lib/block/index.js +4 -0
  15. package/lib/block/merkleblock.js +316 -0
  16. package/lib/crypto/bn.js +278 -0
  17. package/lib/crypto/ecdsa.js +330 -0
  18. package/lib/crypto/elliptic-fixed.js +74 -0
  19. package/lib/crypto/hash.browser.js +171 -0
  20. package/lib/crypto/hash.js +2 -0
  21. package/lib/crypto/hash.node.js +171 -0
  22. package/lib/crypto/point.js +217 -0
  23. package/lib/crypto/random.js +37 -0
  24. package/lib/crypto/signature.js +410 -0
  25. package/lib/crypto/smartledger_verify.js +109 -0
  26. package/lib/ecies/bitcore-ecies.js +163 -0
  27. package/lib/ecies/electrum-ecies.js +175 -0
  28. package/lib/ecies/errors.js +16 -0
  29. package/lib/ecies/index.js +1 -0
  30. package/lib/encoding/base58.js +108 -0
  31. package/lib/encoding/base58check.js +112 -0
  32. package/lib/encoding/bufferreader.js +200 -0
  33. package/lib/encoding/bufferwriter.js +150 -0
  34. package/lib/encoding/varint.js +71 -0
  35. package/lib/errors/index.js +57 -0
  36. package/lib/errors/spec.js +184 -0
  37. package/lib/hdprivatekey.js +655 -0
  38. package/lib/hdpublickey.js +509 -0
  39. package/lib/message/index.js +4 -0
  40. package/lib/message/message.js +181 -0
  41. package/lib/mnemonic/errors.js +18 -0
  42. package/lib/mnemonic/index.js +4 -0
  43. package/lib/mnemonic/mnemonic.js +304 -0
  44. package/lib/mnemonic/pbkdf2.js +68 -0
  45. package/lib/mnemonic/words/chinese.js +5 -0
  46. package/lib/mnemonic/words/english.js +5 -0
  47. package/lib/mnemonic/words/french.js +5 -0
  48. package/lib/mnemonic/words/index.js +8 -0
  49. package/lib/mnemonic/words/italian.js +5 -0
  50. package/lib/mnemonic/words/japanese.js +5 -0
  51. package/lib/mnemonic/words/spanish.js +5 -0
  52. package/lib/networks.js +392 -0
  53. package/lib/opcode.js +248 -0
  54. package/lib/privatekey.js +373 -0
  55. package/lib/publickey.js +387 -0
  56. package/lib/script/index.js +3 -0
  57. package/lib/script/interpreter.js +1807 -0
  58. package/lib/script/script.js +1153 -0
  59. package/lib/transaction/index.js +7 -0
  60. package/lib/transaction/input/index.js +6 -0
  61. package/lib/transaction/input/input.js +202 -0
  62. package/lib/transaction/input/multisig.js +220 -0
  63. package/lib/transaction/input/multisigscripthash.js +189 -0
  64. package/lib/transaction/input/publickey.js +96 -0
  65. package/lib/transaction/input/publickeyhash.js +103 -0
  66. package/lib/transaction/output.js +192 -0
  67. package/lib/transaction/sighash.js +288 -0
  68. package/lib/transaction/signature.js +88 -0
  69. package/lib/transaction/transaction.js +1208 -0
  70. package/lib/transaction/unspentoutput.js +97 -0
  71. package/lib/util/_.js +44 -0
  72. package/lib/util/js.js +91 -0
  73. package/lib/util/preconditions.js +34 -0
  74. package/message/index.js +1 -0
  75. package/mnemonic/index.js +1 -0
  76. package/package.json +86 -0
@@ -0,0 +1,1208 @@
1
+ 'use strict'
2
+
3
+ var _ = require('../util/_')
4
+ var $ = require('../util/preconditions')
5
+ var buffer = require('buffer')
6
+
7
+ var errors = require('../errors')
8
+ var JSUtil = require('../util/js')
9
+ var BufferReader = require('../encoding/bufferreader')
10
+ var BufferWriter = require('../encoding/bufferwriter')
11
+ var Varint = require('../encoding/varint')
12
+ var Hash = require('../crypto/hash')
13
+ var Signature = require('../crypto/signature')
14
+ var Sighash = require('./sighash')
15
+
16
+ var Address = require('../address')
17
+ var UnspentOutput = require('./unspentoutput')
18
+ var Input = require('./input')
19
+ var PublicKeyHashInput = Input.PublicKeyHash
20
+ var PublicKeyInput = Input.PublicKey
21
+ var MultiSigScriptHashInput = Input.MultiSigScriptHash
22
+ var MultiSigInput = Input.MultiSig
23
+ var Output = require('./output')
24
+ var Script = require('../script')
25
+ var PrivateKey = require('../privatekey')
26
+ var BN = require('../crypto/bn')
27
+
28
+ /**
29
+ * Represents a transaction, a set of inputs and outputs to change ownership of tokens
30
+ *
31
+ * @param {*} serialized
32
+ * @constructor
33
+ */
34
+ function Transaction (serialized) {
35
+ if (!(this instanceof Transaction)) {
36
+ return new Transaction(serialized)
37
+ }
38
+ this.inputs = []
39
+ this.outputs = []
40
+ this._inputAmount = undefined
41
+ this._outputAmount = undefined
42
+
43
+ if (serialized) {
44
+ if (serialized instanceof Transaction) {
45
+ return Transaction.shallowCopy(serialized)
46
+ } else if (JSUtil.isHexa(serialized)) {
47
+ this.fromString(serialized)
48
+ } else if (Buffer.isBuffer(serialized)) {
49
+ this.fromBuffer(serialized)
50
+ } else if (_.isObject(serialized)) {
51
+ this.fromObject(serialized)
52
+ } else {
53
+ throw new errors.InvalidArgument('Must provide an object or string to deserialize a transaction')
54
+ }
55
+ } else {
56
+ this._newTransaction()
57
+ }
58
+ }
59
+
60
+ var CURRENT_VERSION = 1
61
+ var DEFAULT_NLOCKTIME = 0
62
+ var MAX_BLOCK_SIZE = 1000000
63
+
64
+ // Minimum amount for an output for it not to be considered a dust output
65
+ Transaction.DUST_AMOUNT = 546
66
+
67
+ // Margin of error to allow fees in the vecinity of the expected value but doesn't allow a big difference
68
+ Transaction.FEE_SECURITY_MARGIN = 150
69
+
70
+ // max amount of satoshis in circulation
71
+ Transaction.MAX_MONEY = 21000000 * 1e8
72
+
73
+ // nlocktime limit to be considered block height rather than a timestamp
74
+ Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT = 5e8
75
+
76
+ // Max value for an unsigned 32 bit value
77
+ Transaction.NLOCKTIME_MAX_VALUE = 4294967295
78
+
79
+ // Value used for fee estimation (satoshis per kilobyte)
80
+ Transaction.FEE_PER_KB = 500
81
+
82
+ // Safe upper bound for change address script size in bytes
83
+ Transaction.CHANGE_OUTPUT_MAX_SIZE = 20 + 4 + 34 + 4
84
+
85
+ /* Constructors and Serialization */
86
+
87
+ /**
88
+ * Create a 'shallow' copy of the transaction, by serializing and deserializing
89
+ * it dropping any additional information that inputs and outputs may have hold
90
+ *
91
+ * @param {Transaction} transaction
92
+ * @return {Transaction}
93
+ */
94
+ Transaction.shallowCopy = function (transaction) {
95
+ var copy = new Transaction(transaction.toBuffer())
96
+ return copy
97
+ }
98
+
99
+ var hashProperty = {
100
+ configurable: false,
101
+ enumerable: true,
102
+ get: function () {
103
+ this._hash = new BufferReader(this._getHash()).readReverse().toString('hex')
104
+ return this._hash
105
+ }
106
+ }
107
+ Object.defineProperty(Transaction.prototype, 'hash', hashProperty)
108
+ Object.defineProperty(Transaction.prototype, 'id', hashProperty)
109
+
110
+ var ioProperty = {
111
+ configurable: false,
112
+ enumerable: true,
113
+ get: function () {
114
+ return this._getInputAmount()
115
+ }
116
+ }
117
+ Object.defineProperty(Transaction.prototype, 'inputAmount', ioProperty)
118
+ ioProperty.get = function () {
119
+ return this._getOutputAmount()
120
+ }
121
+ Object.defineProperty(Transaction.prototype, 'outputAmount', ioProperty)
122
+
123
+ /**
124
+ * Retrieve the little endian hash of the transaction (used for serialization)
125
+ * @return {Buffer}
126
+ */
127
+ Transaction.prototype._getHash = function () {
128
+ return Hash.sha256sha256(this.toBuffer())
129
+ }
130
+
131
+ /**
132
+ * Retrieve a hexa string that can be used with bitcoind's CLI interface
133
+ * (decoderawtransaction, sendrawtransaction)
134
+ *
135
+ * @param {Object|boolean=} unsafe if true, skip all tests. if it's an object,
136
+ * it's expected to contain a set of flags to skip certain tests:
137
+ * * `disableAll`: disable all checks
138
+ * * `disableLargeFees`: disable checking for fees that are too large
139
+ * * `disableIsFullySigned`: disable checking if all inputs are fully signed
140
+ * * `disableDustOutputs`: disable checking if there are no outputs that are dust amounts
141
+ * * `disableMoreOutputThanInput`: disable checking if the transaction spends more bitcoins than the sum of the input amounts
142
+ * @return {string}
143
+ */
144
+ Transaction.prototype.serialize = function (unsafe) {
145
+ if (unsafe === true || (unsafe && unsafe.disableAll)) {
146
+ return this.uncheckedSerialize()
147
+ } else {
148
+ return this.checkedSerialize(unsafe)
149
+ }
150
+ }
151
+
152
+ Transaction.prototype.uncheckedSerialize = Transaction.prototype.toString = function () {
153
+ return this.toBuffer().toString('hex')
154
+ }
155
+
156
+ /**
157
+ * Retrieve a hexa string that can be used with bitcoind's CLI interface
158
+ * (decoderawtransaction, sendrawtransaction)
159
+ *
160
+ * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize}
161
+ * @return {string}
162
+ */
163
+ Transaction.prototype.checkedSerialize = function (opts) {
164
+ var serializationError = this.getSerializationError(opts)
165
+ if (serializationError) {
166
+ serializationError.message += ' - For more information please see: ' +
167
+ 'https://bsv.io/api/lib/transaction#serialization-checks'
168
+ throw serializationError
169
+ }
170
+ return this.uncheckedSerialize()
171
+ }
172
+
173
+ Transaction.prototype.invalidSatoshis = function () {
174
+ var invalid = false
175
+ for (var i = 0; i < this.outputs.length; i++) {
176
+ if (this.outputs[i].invalidSatoshis()) {
177
+ invalid = true
178
+ }
179
+ }
180
+ return invalid
181
+ }
182
+
183
+ /**
184
+ * Retrieve a possible error that could appear when trying to serialize and
185
+ * broadcast this transaction.
186
+ *
187
+ * @param {Object} opts allows to skip certain tests. {@see Transaction#serialize}
188
+ * @return {bsv.Error}
189
+ */
190
+ Transaction.prototype.getSerializationError = function (opts) {
191
+ opts = opts || {}
192
+
193
+ if (this.invalidSatoshis()) {
194
+ return new errors.Transaction.InvalidSatoshis()
195
+ }
196
+
197
+ var unspent = this._getUnspentValue()
198
+ var unspentError
199
+ if (unspent < 0) {
200
+ if (!opts.disableMoreOutputThanInput) {
201
+ unspentError = new errors.Transaction.InvalidOutputAmountSum()
202
+ }
203
+ } else {
204
+ unspentError = this._hasFeeError(opts, unspent)
205
+ }
206
+
207
+ return unspentError ||
208
+ this._hasDustOutputs(opts) ||
209
+ this._isMissingSignatures(opts)
210
+ }
211
+
212
+ Transaction.prototype._hasFeeError = function (opts, unspent) {
213
+ if (!_.isUndefined(this._fee) && this._fee !== unspent) {
214
+ return new errors.Transaction.FeeError.Different(
215
+ 'Unspent value is ' + unspent + ' but specified fee is ' + this._fee
216
+ )
217
+ }
218
+
219
+ if (!opts.disableLargeFees) {
220
+ var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee())
221
+ if (unspent > maximumFee) {
222
+ if (this._missingChange()) {
223
+ return new errors.Transaction.ChangeAddressMissing(
224
+ 'Fee is too large and no change address was provided'
225
+ )
226
+ }
227
+ return new errors.Transaction.FeeError.TooLarge(
228
+ 'expected less than ' + maximumFee + ' but got ' + unspent
229
+ )
230
+ }
231
+ }
232
+ }
233
+
234
+ Transaction.prototype._missingChange = function () {
235
+ return !this._changeScript
236
+ }
237
+
238
+ Transaction.prototype._hasDustOutputs = function (opts) {
239
+ if (opts.disableDustOutputs) {
240
+ return
241
+ }
242
+ var index, output
243
+ for (index in this.outputs) {
244
+ output = this.outputs[index]
245
+ if (output.satoshis < Transaction.DUST_AMOUNT && !output.script.isDataOut() && !output.script.isSafeDataOut()) {
246
+ return new errors.Transaction.DustOutputs()
247
+ }
248
+ }
249
+ }
250
+
251
+ Transaction.prototype._isMissingSignatures = function (opts) {
252
+ if (opts.disableIsFullySigned) {
253
+ return
254
+ }
255
+ if (!this.isFullySigned()) {
256
+ return new errors.Transaction.MissingSignatures()
257
+ }
258
+ }
259
+
260
+ Transaction.prototype.inspect = function () {
261
+ return '<Transaction: ' + this.uncheckedSerialize() + '>'
262
+ }
263
+
264
+ Transaction.prototype.toBuffer = function () {
265
+ var writer = new BufferWriter()
266
+ return this.toBufferWriter(writer).toBuffer()
267
+ }
268
+
269
+ Transaction.prototype.toBufferWriter = function (writer) {
270
+ writer.writeInt32LE(this.version)
271
+ writer.writeVarintNum(this.inputs.length)
272
+ _.each(this.inputs, function (input) {
273
+ input.toBufferWriter(writer)
274
+ })
275
+ writer.writeVarintNum(this.outputs.length)
276
+ _.each(this.outputs, function (output) {
277
+ output.toBufferWriter(writer)
278
+ })
279
+ writer.writeUInt32LE(this.nLockTime)
280
+ return writer
281
+ }
282
+
283
+ Transaction.prototype.fromBuffer = function (buffer) {
284
+ var reader = new BufferReader(buffer)
285
+ return this.fromBufferReader(reader)
286
+ }
287
+
288
+ Transaction.prototype.fromBufferReader = function (reader) {
289
+ $.checkArgument(!reader.finished(), 'No transaction data received')
290
+ var i, sizeTxIns, sizeTxOuts
291
+
292
+ this.version = reader.readInt32LE()
293
+ sizeTxIns = reader.readVarintNum()
294
+ for (i = 0; i < sizeTxIns; i++) {
295
+ var input = Input.fromBufferReader(reader)
296
+ this.inputs.push(input)
297
+ }
298
+ sizeTxOuts = reader.readVarintNum()
299
+ for (i = 0; i < sizeTxOuts; i++) {
300
+ this.outputs.push(Output.fromBufferReader(reader))
301
+ }
302
+ this.nLockTime = reader.readUInt32LE()
303
+ return this
304
+ }
305
+
306
+ Transaction.prototype.toObject = Transaction.prototype.toJSON = function toObject () {
307
+ var inputs = []
308
+ this.inputs.forEach(function (input) {
309
+ inputs.push(input.toObject())
310
+ })
311
+ var outputs = []
312
+ this.outputs.forEach(function (output) {
313
+ outputs.push(output.toObject())
314
+ })
315
+ var obj = {
316
+ hash: this.hash,
317
+ version: this.version,
318
+ inputs: inputs,
319
+ outputs: outputs,
320
+ nLockTime: this.nLockTime
321
+ }
322
+ if (this._changeScript) {
323
+ obj.changeScript = this._changeScript.toString()
324
+ }
325
+ if (!_.isUndefined(this._changeIndex)) {
326
+ obj.changeIndex = this._changeIndex
327
+ }
328
+ if (!_.isUndefined(this._fee)) {
329
+ obj.fee = this._fee
330
+ }
331
+ return obj
332
+ }
333
+
334
+ Transaction.prototype.fromObject = function fromObject (arg) {
335
+ $.checkArgument(_.isObject(arg) || arg instanceof Transaction)
336
+ var self = this
337
+ var transaction
338
+ if (arg instanceof Transaction) {
339
+ transaction = transaction.toObject()
340
+ } else {
341
+ transaction = arg
342
+ }
343
+ _.each(transaction.inputs, function (input) {
344
+ if (!input.output || !input.output.script) {
345
+ self.uncheckedAddInput(new Input(input))
346
+ return
347
+ }
348
+ var script = new Script(input.output.script)
349
+ var txin
350
+ if (script.isPublicKeyHashOut()) {
351
+ txin = new Input.PublicKeyHash(input)
352
+ } else if (script.isScriptHashOut() && input.publicKeys && input.threshold) {
353
+ txin = new Input.MultiSigScriptHash(
354
+ input, input.publicKeys, input.threshold, input.signatures
355
+ )
356
+ } else if (script.isPublicKeyOut()) {
357
+ txin = new Input.PublicKey(input)
358
+ } else {
359
+ throw new errors.Transaction.Input.UnsupportedScript(input.output.script)
360
+ }
361
+ self.addInput(txin)
362
+ })
363
+ _.each(transaction.outputs, function (output) {
364
+ self.addOutput(new Output(output))
365
+ })
366
+ if (transaction.changeIndex) {
367
+ this._changeIndex = transaction.changeIndex
368
+ }
369
+ if (transaction.changeScript) {
370
+ this._changeScript = new Script(transaction.changeScript)
371
+ }
372
+ if (transaction.fee) {
373
+ this._fee = transaction.fee
374
+ }
375
+ this.nLockTime = transaction.nLockTime
376
+ this.version = transaction.version
377
+ this._checkConsistency(arg)
378
+ return this
379
+ }
380
+
381
+ Transaction.prototype._checkConsistency = function (arg) {
382
+ if (!_.isUndefined(this._changeIndex)) {
383
+ $.checkState(this._changeScript, 'Change script is expected.')
384
+ $.checkState(this.outputs[this._changeIndex], 'Change index points to undefined output.')
385
+ $.checkState(this.outputs[this._changeIndex].script.toString() ===
386
+ this._changeScript.toString(), 'Change output has an unexpected script.')
387
+ }
388
+ if (arg && arg.hash) {
389
+ $.checkState(arg.hash === this.hash, 'Hash in object does not match transaction hash.')
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Sets nLockTime so that transaction is not valid until the desired date(a
395
+ * timestamp in seconds since UNIX epoch is also accepted)
396
+ *
397
+ * @param {Date | Number} time
398
+ * @return {Transaction} this
399
+ */
400
+ Transaction.prototype.lockUntilDate = function (time) {
401
+ $.checkArgument(time)
402
+ if (_.isNumber(time) && time < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
403
+ throw new errors.Transaction.LockTimeTooEarly()
404
+ }
405
+ if (_.isDate(time)) {
406
+ time = time.getTime() / 1000
407
+ }
408
+
409
+ for (var i = 0; i < this.inputs.length; i++) {
410
+ if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) {
411
+ this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER
412
+ }
413
+ }
414
+
415
+ this.nLockTime = time
416
+ return this
417
+ }
418
+
419
+ /**
420
+ * Sets nLockTime so that transaction is not valid until the desired block
421
+ * height.
422
+ *
423
+ * @param {Number} height
424
+ * @return {Transaction} this
425
+ */
426
+ Transaction.prototype.lockUntilBlockHeight = function (height) {
427
+ $.checkArgument(_.isNumber(height))
428
+ if (height >= Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
429
+ throw new errors.Transaction.BlockHeightTooHigh()
430
+ }
431
+ if (height < 0) {
432
+ throw new errors.Transaction.NLockTimeOutOfRange()
433
+ }
434
+
435
+ for (var i = 0; i < this.inputs.length; i++) {
436
+ if (this.inputs[i].sequenceNumber === Input.DEFAULT_SEQNUMBER) {
437
+ this.inputs[i].sequenceNumber = Input.DEFAULT_LOCKTIME_SEQNUMBER
438
+ }
439
+ }
440
+
441
+ this.nLockTime = height
442
+ return this
443
+ }
444
+
445
+ /**
446
+ * Returns a semantic version of the transaction's nLockTime.
447
+ * @return {Number|Date}
448
+ * If nLockTime is 0, it returns null,
449
+ * if it is < 500000000, it returns a block height (number)
450
+ * else it returns a Date object.
451
+ */
452
+ Transaction.prototype.getLockTime = function () {
453
+ if (!this.nLockTime) {
454
+ return null
455
+ }
456
+ if (this.nLockTime < Transaction.NLOCKTIME_BLOCKHEIGHT_LIMIT) {
457
+ return this.nLockTime
458
+ }
459
+ return new Date(1000 * this.nLockTime)
460
+ }
461
+
462
+ Transaction.prototype.fromString = function (string) {
463
+ this.fromBuffer(buffer.Buffer.from(string, 'hex'))
464
+ }
465
+
466
+ Transaction.prototype._newTransaction = function () {
467
+ this.version = CURRENT_VERSION
468
+ this.nLockTime = DEFAULT_NLOCKTIME
469
+ }
470
+
471
+ /* Transaction creation interface */
472
+
473
+ /**
474
+ * @typedef {Object} Transaction~fromObject
475
+ * @property {string} prevTxId
476
+ * @property {number} outputIndex
477
+ * @property {(Buffer|string|Script)} script
478
+ * @property {number} satoshis
479
+ */
480
+
481
+ /**
482
+ * Add an input to this transaction. This is a high level interface
483
+ * to add an input, for more control, use @{link Transaction#addInput}.
484
+ *
485
+ * Can receive, as output information, the output of bitcoind's `listunspent` command,
486
+ * and a slightly fancier format recognized by bsv:
487
+ *
488
+ * ```
489
+ * {
490
+ * address: 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1',
491
+ * txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
492
+ * outputIndex: 0,
493
+ * script: Script.empty(),
494
+ * satoshis: 1020000
495
+ * }
496
+ * ```
497
+ * Where `address` can be either a string or a bsv Address object. The
498
+ * same is true for `script`, which can be a string or a bsv Script.
499
+ *
500
+ * Beware that this resets all the signatures for inputs (in further versions,
501
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
502
+ *
503
+ * @example
504
+ * ```javascript
505
+ * var transaction = new Transaction();
506
+ *
507
+ * // From a pay to public key hash output from bitcoind's listunspent
508
+ * transaction.from({'txid': '0000...', vout: 0, amount: 0.1, scriptPubKey: 'OP_DUP ...'});
509
+ *
510
+ * // From a pay to public key hash output
511
+ * transaction.from({'txId': '0000...', outputIndex: 0, satoshis: 1000, script: 'OP_DUP ...'});
512
+ *
513
+ * // From a multisig P2SH output
514
+ * transaction.from({'txId': '0000...', inputIndex: 0, satoshis: 1000, script: '... OP_HASH'},
515
+ * ['03000...', '02000...'], 2);
516
+ * ```
517
+ *
518
+ * @param {(Array.<Transaction~fromObject>|Transaction~fromObject)} utxo
519
+ * @param {Array=} pubkeys
520
+ * @param {number=} threshold
521
+ */
522
+ Transaction.prototype.from = function (utxo, pubkeys, threshold) {
523
+ if (_.isArray(utxo)) {
524
+ var self = this
525
+ _.each(utxo, function (utxo) {
526
+ self.from(utxo, pubkeys, threshold)
527
+ })
528
+ return this
529
+ }
530
+ var exists = _.some(this.inputs, function (input) {
531
+ // TODO: Maybe prevTxId should be a string? Or defined as read only property?
532
+ return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex
533
+ })
534
+ if (exists) {
535
+ return this
536
+ }
537
+ if (pubkeys && threshold) {
538
+ this._fromMultisigUtxo(utxo, pubkeys, threshold)
539
+ } else {
540
+ this._fromNonP2SH(utxo)
541
+ }
542
+ return this
543
+ }
544
+
545
+ Transaction.prototype._fromNonP2SH = function (utxo) {
546
+ var Clazz
547
+ utxo = new UnspentOutput(utxo)
548
+ if (utxo.script.isPublicKeyHashOut()) {
549
+ Clazz = PublicKeyHashInput
550
+ } else if (utxo.script.isPublicKeyOut()) {
551
+ Clazz = PublicKeyInput
552
+ } else {
553
+ Clazz = Input
554
+ }
555
+ this.addInput(new Clazz({
556
+ output: new Output({
557
+ script: utxo.script,
558
+ satoshis: utxo.satoshis
559
+ }),
560
+ prevTxId: utxo.txId,
561
+ outputIndex: utxo.outputIndex,
562
+ script: Script.empty()
563
+ }))
564
+ }
565
+
566
+ Transaction.prototype._fromMultisigUtxo = function (utxo, pubkeys, threshold) {
567
+ $.checkArgument(threshold <= pubkeys.length,
568
+ 'Number of required signatures must be greater than the number of public keys')
569
+ var Clazz
570
+ utxo = new UnspentOutput(utxo)
571
+ if (utxo.script.isMultisigOut()) {
572
+ Clazz = MultiSigInput
573
+ } else if (utxo.script.isScriptHashOut()) {
574
+ Clazz = MultiSigScriptHashInput
575
+ } else {
576
+ throw new Error('@TODO')
577
+ }
578
+ this.addInput(new Clazz({
579
+ output: new Output({
580
+ script: utxo.script,
581
+ satoshis: utxo.satoshis
582
+ }),
583
+ prevTxId: utxo.txId,
584
+ outputIndex: utxo.outputIndex,
585
+ script: Script.empty()
586
+ }, pubkeys, threshold))
587
+ }
588
+
589
+ /**
590
+ * Add an input to this transaction. The input must be an instance of the `Input` class.
591
+ * It should have information about the Output that it's spending, but if it's not already
592
+ * set, two additional parameters, `outputScript` and `satoshis` can be provided.
593
+ *
594
+ * @param {Input} input
595
+ * @param {String|Script} outputScript
596
+ * @param {number} satoshis
597
+ * @return Transaction this, for chaining
598
+ */
599
+ Transaction.prototype.addInput = function (input, outputScript, satoshis) {
600
+ $.checkArgumentType(input, Input, 'input')
601
+ if (!input.output && (_.isUndefined(outputScript) || _.isUndefined(satoshis))) {
602
+ throw new errors.Transaction.NeedMoreInfo('Need information about the UTXO script and satoshis')
603
+ }
604
+ if (!input.output && outputScript && !_.isUndefined(satoshis)) {
605
+ outputScript = outputScript instanceof Script ? outputScript : new Script(outputScript)
606
+ $.checkArgumentType(satoshis, 'number', 'satoshis')
607
+ input.output = new Output({
608
+ script: outputScript,
609
+ satoshis: satoshis
610
+ })
611
+ }
612
+ return this.uncheckedAddInput(input)
613
+ }
614
+
615
+ /**
616
+ * Add an input to this transaction, without checking that the input has information about
617
+ * the output that it's spending.
618
+ *
619
+ * @param {Input} input
620
+ * @return Transaction this, for chaining
621
+ */
622
+ Transaction.prototype.uncheckedAddInput = function (input) {
623
+ $.checkArgumentType(input, Input, 'input')
624
+ this.inputs.push(input)
625
+ this._inputAmount = undefined
626
+ this._updateChangeOutput()
627
+ return this
628
+ }
629
+
630
+ /**
631
+ * Returns true if the transaction has enough info on all inputs to be correctly validated
632
+ *
633
+ * @return {boolean}
634
+ */
635
+ Transaction.prototype.hasAllUtxoInfo = function () {
636
+ return _.every(this.inputs.map(function (input) {
637
+ return !!input.output
638
+ }))
639
+ }
640
+
641
+ /**
642
+ * Manually set the fee for this transaction. Beware that this resets all the signatures
643
+ * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not
644
+ * be reset).
645
+ *
646
+ * @param {number} amount satoshis to be sent
647
+ * @return {Transaction} this, for chaining
648
+ */
649
+ Transaction.prototype.fee = function (amount) {
650
+ $.checkArgument(_.isNumber(amount), 'amount must be a number')
651
+ this._fee = amount
652
+ this._updateChangeOutput()
653
+ return this
654
+ }
655
+
656
+ /**
657
+ * Manually set the fee per KB for this transaction. Beware that this resets all the signatures
658
+ * for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not
659
+ * be reset).
660
+ *
661
+ * @param {number} amount satoshis per KB to be sent
662
+ * @return {Transaction} this, for chaining
663
+ */
664
+ Transaction.prototype.feePerKb = function (amount) {
665
+ $.checkArgument(_.isNumber(amount), 'amount must be a number')
666
+ this._feePerKb = amount
667
+ this._updateChangeOutput()
668
+ return this
669
+ }
670
+
671
+ /* Output management */
672
+
673
+ /**
674
+ * Set the change address for this transaction
675
+ *
676
+ * Beware that this resets all the signatures for inputs (in further versions,
677
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
678
+ *
679
+ * @param {Address} address An address for change to be sent to.
680
+ * @return {Transaction} this, for chaining
681
+ */
682
+ Transaction.prototype.change = function (address) {
683
+ $.checkArgument(address, 'address is required')
684
+ this._changeScript = Script.fromAddress(address)
685
+ this._updateChangeOutput()
686
+ return this
687
+ }
688
+
689
+ /**
690
+ * @return {Output} change output, if it exists
691
+ */
692
+ Transaction.prototype.getChangeOutput = function () {
693
+ if (!_.isUndefined(this._changeIndex)) {
694
+ return this.outputs[this._changeIndex]
695
+ }
696
+ return null
697
+ }
698
+
699
+ /**
700
+ * @typedef {Object} Transaction~toObject
701
+ * @property {(string|Address)} address
702
+ * @property {number} satoshis
703
+ */
704
+
705
+ /**
706
+ * Add an output to the transaction.
707
+ *
708
+ * Beware that this resets all the signatures for inputs (in further versions,
709
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
710
+ *
711
+ * @param {(string|Address|Array.<Transaction~toObject>)} address
712
+ * @param {number} amount in satoshis
713
+ * @return {Transaction} this, for chaining
714
+ */
715
+ Transaction.prototype.to = function (address, amount) {
716
+ if (_.isArray(address)) {
717
+ var self = this
718
+ _.each(address, function (to) {
719
+ self.to(to.address, to.satoshis)
720
+ })
721
+ return this
722
+ }
723
+
724
+ $.checkArgument(
725
+ JSUtil.isNaturalNumber(amount),
726
+ 'Amount is expected to be a positive integer'
727
+ )
728
+ this.addOutput(new Output({
729
+ script: Script(new Address(address)),
730
+ satoshis: amount
731
+ }))
732
+ return this
733
+ }
734
+
735
+ /**
736
+ * Add an OP_RETURN output to the transaction.
737
+ *
738
+ * Beware that this resets all the signatures for inputs (in further versions,
739
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
740
+ *
741
+ * @param {Buffer|string} value the data to be stored in the OP_RETURN output.
742
+ * In case of a string, the UTF-8 representation will be stored
743
+ * @return {Transaction} this, for chaining
744
+ */
745
+ Transaction.prototype.addData = function (value) {
746
+ this.addOutput(new Output({
747
+ script: Script.buildDataOut(value),
748
+ satoshis: 0
749
+ }))
750
+ return this
751
+ }
752
+
753
+ /**
754
+ * Add an OP_FALSE | OP_RETURN output to the transaction.
755
+ *
756
+ * Beware that this resets all the signatures for inputs (in further versions,
757
+ * SIGHASH_SINGLE or SIGHASH_NONE signatures will not be reset).
758
+ *
759
+ * @param {Buffer|string} value the data to be stored in the OP_RETURN output.
760
+ * In case of a string, the UTF-8 representation will be stored
761
+ * @return {Transaction} this, for chaining
762
+ */
763
+ Transaction.prototype.addSafeData = function (value) {
764
+ this.addOutput(new Output({
765
+ script: Script.buildSafeDataOut(value),
766
+ satoshis: 0
767
+ }))
768
+ return this
769
+ }
770
+
771
+ /**
772
+ * Add an output to the transaction.
773
+ *
774
+ * @param {Output} output the output to add.
775
+ * @return {Transaction} this, for chaining
776
+ */
777
+ Transaction.prototype.addOutput = function (output) {
778
+ $.checkArgumentType(output, Output, 'output')
779
+ this._addOutput(output)
780
+ this._updateChangeOutput()
781
+ return this
782
+ }
783
+
784
+ /**
785
+ * Remove all outputs from the transaction.
786
+ *
787
+ * @return {Transaction} this, for chaining
788
+ */
789
+ Transaction.prototype.clearOutputs = function () {
790
+ this.outputs = []
791
+ this._clearSignatures()
792
+ this._outputAmount = undefined
793
+ this._changeIndex = undefined
794
+ this._updateChangeOutput()
795
+ return this
796
+ }
797
+
798
+ Transaction.prototype._addOutput = function (output) {
799
+ this.outputs.push(output)
800
+ this._outputAmount = undefined
801
+ }
802
+
803
+ /**
804
+ * Calculates or gets the total output amount in satoshis
805
+ *
806
+ * @return {Number} the transaction total output amount
807
+ */
808
+ Transaction.prototype._getOutputAmount = function () {
809
+ if (_.isUndefined(this._outputAmount)) {
810
+ var self = this
811
+ this._outputAmount = 0
812
+ _.each(this.outputs, function (output) {
813
+ self._outputAmount += output.satoshis
814
+ })
815
+ }
816
+ return this._outputAmount
817
+ }
818
+
819
+ /**
820
+ * Calculates or gets the total input amount in satoshis
821
+ *
822
+ * @return {Number} the transaction total input amount
823
+ */
824
+ Transaction.prototype._getInputAmount = function () {
825
+ if (_.isUndefined(this._inputAmount)) {
826
+ var self = this
827
+ this._inputAmount = 0
828
+ _.each(this.inputs, function (input) {
829
+ if (_.isUndefined(input.output)) {
830
+ throw new errors.Transaction.Input.MissingPreviousOutput()
831
+ }
832
+ self._inputAmount += input.output.satoshis
833
+ })
834
+ }
835
+ return this._inputAmount
836
+ }
837
+
838
+ Transaction.prototype._updateChangeOutput = function () {
839
+ if (!this._changeScript) {
840
+ return
841
+ }
842
+ this._clearSignatures()
843
+ if (!_.isUndefined(this._changeIndex)) {
844
+ this._removeOutput(this._changeIndex)
845
+ }
846
+ this._changeIndex = this.outputs.length
847
+ this._addOutput(new Output({
848
+ script: this._changeScript,
849
+ satoshis: 0
850
+ }))
851
+ var available = this._getUnspentValue()
852
+ var fee = this.getFee()
853
+ var changeAmount = available - fee
854
+ this._removeOutput(this._changeIndex)
855
+ this._changeIndex = undefined
856
+ if (changeAmount >= Transaction.DUST_AMOUNT) {
857
+ this._changeIndex = this.outputs.length
858
+ this._addOutput(new Output({
859
+ script: this._changeScript,
860
+ satoshis: changeAmount
861
+ }))
862
+ }
863
+ }
864
+ /**
865
+ * Calculates the fee of the transaction.
866
+ *
867
+ * If there's a fixed fee set, return that.
868
+ *
869
+ * If there is no change output set, the fee is the
870
+ * total value of the outputs minus inputs. Note that
871
+ * a serialized transaction only specifies the value
872
+ * of its outputs. (The value of inputs are recorded
873
+ * in the previous transaction outputs being spent.)
874
+ * This method therefore raises a "MissingPreviousOutput"
875
+ * error when called on a serialized transaction.
876
+ *
877
+ * If there's no fee set and no change address,
878
+ * estimate the fee based on size.
879
+ *
880
+ * @return {Number} fee of this transaction in satoshis
881
+ */
882
+ Transaction.prototype.getFee = function () {
883
+ if (this.isCoinbase()) {
884
+ return 0
885
+ }
886
+ if (!_.isUndefined(this._fee)) {
887
+ return this._fee
888
+ }
889
+ // if no change output is set, fees should equal all the unspent amount
890
+ if (!this._changeScript) {
891
+ return this._getUnspentValue()
892
+ }
893
+ return this._estimateFee()
894
+ }
895
+
896
+ /**
897
+ * Estimates fee from serialized transaction size in bytes.
898
+ */
899
+ Transaction.prototype._estimateFee = function () {
900
+ var estimatedSize = this._estimateSize()
901
+ return Math.ceil(estimatedSize / 1000 * (this._feePerKb || Transaction.FEE_PER_KB))
902
+ }
903
+
904
+ Transaction.prototype._getUnspentValue = function () {
905
+ return this._getInputAmount() - this._getOutputAmount()
906
+ }
907
+
908
+ Transaction.prototype._clearSignatures = function () {
909
+ _.each(this.inputs, function (input) {
910
+ input.clearSignatures()
911
+ })
912
+ }
913
+
914
+ // 4 version
915
+ // ??? num inputs (VARINT)
916
+ // --- input list ---
917
+ //
918
+ // ??? num outputs (VARINT)
919
+ // --- output list ---
920
+ // 8 value
921
+ // ??? script size (VARINT)
922
+ // ??? script
923
+ //
924
+ // 4 locktime
925
+ Transaction.prototype._estimateSize = function () {
926
+ var result = 4 + 4 // size of version + size of locktime
927
+ result += Varint(this.inputs.length).toBuffer().length
928
+ result += Varint(this.outputs.length).toBuffer().length
929
+ _.each(this.inputs, function (input) {
930
+ result += input._estimateSize()
931
+ })
932
+ _.each(this.outputs, function (output) {
933
+ result += output.getSize()
934
+ })
935
+ return result
936
+ }
937
+
938
+ Transaction.prototype._removeOutput = function (index) {
939
+ var output = this.outputs[index]
940
+ this.outputs = _.without(this.outputs, output)
941
+ this._outputAmount = undefined
942
+ }
943
+
944
+ Transaction.prototype.removeOutput = function (index) {
945
+ this._removeOutput(index)
946
+ this._updateChangeOutput()
947
+ }
948
+
949
+ /**
950
+ * Sort a transaction's inputs and outputs according to BIP69
951
+ *
952
+ * @see {https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki}
953
+ * @return {Transaction} this
954
+ */
955
+ Transaction.prototype.sort = function () {
956
+ this.sortInputs(function (inputs) {
957
+ var copy = Array.prototype.concat.apply([], inputs)
958
+ copy.sort(function (first, second) {
959
+ return first.prevTxId.compare(second.prevTxId) ||
960
+ first.outputIndex - second.outputIndex
961
+ })
962
+ return copy
963
+ })
964
+ this.sortOutputs(function (outputs) {
965
+ var copy = Array.prototype.concat.apply([], outputs)
966
+ copy.sort(function (first, second) {
967
+ return first.satoshis - second.satoshis ||
968
+ first.script.toBuffer().compare(second.script.toBuffer())
969
+ })
970
+ return copy
971
+ })
972
+ return this
973
+ }
974
+
975
+ /**
976
+ * Randomize this transaction's outputs ordering. The shuffling algorithm is a
977
+ * version of the Fisher-Yates shuffle.
978
+ *
979
+ * @return {Transaction} this
980
+ */
981
+ Transaction.prototype.shuffleOutputs = function () {
982
+ return this.sortOutputs(_.shuffle)
983
+ }
984
+
985
+ /**
986
+ * Sort this transaction's outputs, according to a given sorting function that
987
+ * takes an array as argument and returns a new array, with the same elements
988
+ * but with a different order. The argument function MUST NOT modify the order
989
+ * of the original array
990
+ *
991
+ * @param {Function} sortingFunction
992
+ * @return {Transaction} this
993
+ */
994
+ Transaction.prototype.sortOutputs = function (sortingFunction) {
995
+ var outs = sortingFunction(this.outputs)
996
+ return this._newOutputOrder(outs)
997
+ }
998
+
999
+ /**
1000
+ * Sort this transaction's inputs, according to a given sorting function that
1001
+ * takes an array as argument and returns a new array, with the same elements
1002
+ * but with a different order.
1003
+ *
1004
+ * @param {Function} sortingFunction
1005
+ * @return {Transaction} this
1006
+ */
1007
+ Transaction.prototype.sortInputs = function (sortingFunction) {
1008
+ this.inputs = sortingFunction(this.inputs)
1009
+ this._clearSignatures()
1010
+ return this
1011
+ }
1012
+
1013
+ Transaction.prototype._newOutputOrder = function (newOutputs) {
1014
+ var isInvalidSorting = (this.outputs.length !== newOutputs.length ||
1015
+ _.difference(this.outputs, newOutputs).length !== 0)
1016
+ if (isInvalidSorting) {
1017
+ throw new errors.Transaction.InvalidSorting()
1018
+ }
1019
+
1020
+ if (!_.isUndefined(this._changeIndex)) {
1021
+ var changeOutput = this.outputs[this._changeIndex]
1022
+ this._changeIndex = newOutputs.indexOf(changeOutput)
1023
+ }
1024
+
1025
+ this.outputs = newOutputs
1026
+ return this
1027
+ }
1028
+
1029
+ Transaction.prototype.removeInput = function (txId, outputIndex) {
1030
+ var index
1031
+ if (!outputIndex && _.isNumber(txId)) {
1032
+ index = txId
1033
+ } else {
1034
+ index = _.findIndex(this.inputs, function (input) {
1035
+ return input.prevTxId.toString('hex') === txId && input.outputIndex === outputIndex
1036
+ })
1037
+ }
1038
+ if (index < 0 || index >= this.inputs.length) {
1039
+ throw new errors.Transaction.InvalidIndex(index, this.inputs.length)
1040
+ }
1041
+ var input = this.inputs[index]
1042
+ this.inputs = _.without(this.inputs, input)
1043
+ this._inputAmount = undefined
1044
+ this._updateChangeOutput()
1045
+ }
1046
+
1047
+ /* Signature handling */
1048
+
1049
+ /**
1050
+ * Sign the transaction using one or more private keys.
1051
+ *
1052
+ * It tries to sign each input, verifying that the signature will be valid
1053
+ * (matches a public key).
1054
+ *
1055
+ * @param {Array|String|PrivateKey} privateKey
1056
+ * @param {number} sigtype
1057
+ * @return {Transaction} this, for chaining
1058
+ */
1059
+ Transaction.prototype.sign = function (privateKey, sigtype) {
1060
+ $.checkState(this.hasAllUtxoInfo(), 'Not all utxo information is available to sign the transaction.')
1061
+ var self = this
1062
+ if (_.isArray(privateKey)) {
1063
+ _.each(privateKey, function (privateKey) {
1064
+ self.sign(privateKey, sigtype)
1065
+ })
1066
+ return this
1067
+ }
1068
+ _.each(this.getSignatures(privateKey, sigtype), function (signature) {
1069
+ self.applySignature(signature)
1070
+ })
1071
+ return this
1072
+ }
1073
+
1074
+ Transaction.prototype.getSignatures = function (privKey, sigtype) {
1075
+ privKey = new PrivateKey(privKey)
1076
+ // By default, signs using ALL|FORKID
1077
+ sigtype = sigtype || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
1078
+ var transaction = this
1079
+ var results = []
1080
+ var hashData = Hash.sha256ripemd160(privKey.publicKey.toBuffer())
1081
+ _.each(this.inputs, function forEachInput (input, index) {
1082
+ _.each(input.getSignatures(transaction, privKey, index, sigtype, hashData), function (signature) {
1083
+ results.push(signature)
1084
+ })
1085
+ })
1086
+ return results
1087
+ }
1088
+
1089
+ /**
1090
+ * Add a signature to the transaction
1091
+ *
1092
+ * @param {Object} signature
1093
+ * @param {number} signature.inputIndex
1094
+ * @param {number} signature.sigtype
1095
+ * @param {PublicKey} signature.publicKey
1096
+ * @param {Signature} signature.signature
1097
+ * @return {Transaction} this, for chaining
1098
+ */
1099
+ Transaction.prototype.applySignature = function (signature) {
1100
+ this.inputs[signature.inputIndex].addSignature(this, signature)
1101
+ return this
1102
+ }
1103
+
1104
+ Transaction.prototype.isFullySigned = function () {
1105
+ _.each(this.inputs, function (input) {
1106
+ if (input.isFullySigned === Input.prototype.isFullySigned) {
1107
+ throw new errors.Transaction.UnableToVerifySignature(
1108
+ 'Unrecognized script kind, or not enough information to execute script.' +
1109
+ 'This usually happens when creating a transaction from a serialized transaction'
1110
+ )
1111
+ }
1112
+ })
1113
+ return _.every(_.map(this.inputs, function (input) {
1114
+ return input.isFullySigned()
1115
+ }))
1116
+ }
1117
+
1118
+ Transaction.prototype.isValidSignature = function (signature) {
1119
+ var self = this
1120
+ if (this.inputs[signature.inputIndex].isValidSignature === Input.prototype.isValidSignature) {
1121
+ throw new errors.Transaction.UnableToVerifySignature(
1122
+ 'Unrecognized script kind, or not enough information to execute script.' +
1123
+ 'This usually happens when creating a transaction from a serialized transaction'
1124
+ )
1125
+ }
1126
+ return this.inputs[signature.inputIndex].isValidSignature(self, signature)
1127
+ }
1128
+
1129
+ /**
1130
+ * @returns {bool} whether the signature is valid for this transaction input
1131
+ */
1132
+ Transaction.prototype.verifySignature = function (sig, pubkey, nin, subscript, satoshisBN, flags) {
1133
+ return Sighash.verify(this, sig, pubkey, nin, subscript, satoshisBN, flags)
1134
+ }
1135
+
1136
+ /**
1137
+ * Check that a transaction passes basic sanity tests. If not, return a string
1138
+ * describing the error. This function contains the same logic as
1139
+ * CheckTransaction in bitcoin core.
1140
+ */
1141
+ Transaction.prototype.verify = function () {
1142
+ // Basic checks that don't depend on any context
1143
+ if (this.inputs.length === 0) {
1144
+ return 'transaction txins empty'
1145
+ }
1146
+
1147
+ if (this.outputs.length === 0) {
1148
+ return 'transaction txouts empty'
1149
+ }
1150
+
1151
+ // Check for negative or overflow output values
1152
+ var valueoutbn = new BN(0)
1153
+ for (var i = 0; i < this.outputs.length; i++) {
1154
+ var txout = this.outputs[i]
1155
+
1156
+ if (txout.invalidSatoshis()) {
1157
+ return 'transaction txout ' + i + ' satoshis is invalid'
1158
+ }
1159
+ if (txout._satoshisBN.gt(new BN(Transaction.MAX_MONEY, 10))) {
1160
+ return 'transaction txout ' + i + ' greater than MAX_MONEY'
1161
+ }
1162
+ valueoutbn = valueoutbn.add(txout._satoshisBN)
1163
+ if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) {
1164
+ return 'transaction txout ' + i + ' total output greater than MAX_MONEY'
1165
+ }
1166
+ }
1167
+
1168
+ // Size limits
1169
+ if (this.toBuffer().length > MAX_BLOCK_SIZE) {
1170
+ return 'transaction over the maximum block size'
1171
+ }
1172
+
1173
+ // Check for duplicate inputs
1174
+ var txinmap = {}
1175
+ for (i = 0; i < this.inputs.length; i++) {
1176
+ var txin = this.inputs[i]
1177
+
1178
+ var inputid = txin.prevTxId + ':' + txin.outputIndex
1179
+ if (!_.isUndefined(txinmap[inputid])) {
1180
+ return 'transaction input ' + i + ' duplicate input'
1181
+ }
1182
+ txinmap[inputid] = true
1183
+ }
1184
+
1185
+ var isCoinbase = this.isCoinbase()
1186
+ if (isCoinbase) {
1187
+ var buf = this.inputs[0]._scriptBuffer
1188
+ if (buf.length < 2 || buf.length > 100) {
1189
+ return 'coinbase transaction script size invalid'
1190
+ }
1191
+ } else {
1192
+ for (i = 0; i < this.inputs.length; i++) {
1193
+ if (this.inputs[i].isNull()) {
1194
+ return 'transaction input ' + i + ' has null input'
1195
+ }
1196
+ }
1197
+ }
1198
+ return true
1199
+ }
1200
+
1201
+ /**
1202
+ * Analogous to bitcoind's IsCoinBase function in transaction.h
1203
+ */
1204
+ Transaction.prototype.isCoinbase = function () {
1205
+ return (this.inputs.length === 1 && this.inputs[0].isNull())
1206
+ }
1207
+
1208
+ module.exports = Transaction