@opcat-labs/opcat 1.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 (138) hide show
  1. package/.mocharc.yaml +3 -0
  2. package/index.d.ts +1541 -0
  3. package/index.js +74 -0
  4. package/lib/address.js +478 -0
  5. package/lib/block/block.js +277 -0
  6. package/lib/block/blockheader.js +295 -0
  7. package/lib/block/index.js +4 -0
  8. package/lib/block/merkleblock.js +323 -0
  9. package/lib/bn.js +3423 -0
  10. package/lib/crypto/bn.js +278 -0
  11. package/lib/crypto/ecdsa.js +339 -0
  12. package/lib/crypto/hash.browser.js +171 -0
  13. package/lib/crypto/hash.js +2 -0
  14. package/lib/crypto/hash.node.js +171 -0
  15. package/lib/crypto/point.js +221 -0
  16. package/lib/crypto/random.browser.js +28 -0
  17. package/lib/crypto/random.js +2 -0
  18. package/lib/crypto/random.node.js +11 -0
  19. package/lib/crypto/signature.js +325 -0
  20. package/lib/encoding/base58.js +111 -0
  21. package/lib/encoding/base58check.js +121 -0
  22. package/lib/encoding/bufferreader.js +212 -0
  23. package/lib/encoding/bufferwriter.js +140 -0
  24. package/lib/encoding/decode-asm.js +24 -0
  25. package/lib/encoding/decode-hex.js +32 -0
  26. package/lib/encoding/decode-script-chunks.js +43 -0
  27. package/lib/encoding/encode-hex.js +284 -0
  28. package/lib/encoding/is-hex.js +7 -0
  29. package/lib/encoding/varint.js +75 -0
  30. package/lib/errors/index.js +54 -0
  31. package/lib/errors/spec.js +314 -0
  32. package/lib/hash-cache.js +50 -0
  33. package/lib/hdprivatekey.js +678 -0
  34. package/lib/hdpublickey.js +525 -0
  35. package/lib/message/message.js +191 -0
  36. package/lib/mnemonic/mnemonic.js +303 -0
  37. package/lib/mnemonic/pbkdf2.browser.js +68 -0
  38. package/lib/mnemonic/pbkdf2.js +2 -0
  39. package/lib/mnemonic/pbkdf2.node.js +68 -0
  40. package/lib/mnemonic/words/chinese.js +2054 -0
  41. package/lib/mnemonic/words/english.js +2054 -0
  42. package/lib/mnemonic/words/french.js +2054 -0
  43. package/lib/mnemonic/words/index.js +8 -0
  44. package/lib/mnemonic/words/italian.js +2054 -0
  45. package/lib/mnemonic/words/japanese.js +2054 -0
  46. package/lib/mnemonic/words/spanish.js +2054 -0
  47. package/lib/networks.js +379 -0
  48. package/lib/opcode.js +255 -0
  49. package/lib/privatekey.js +374 -0
  50. package/lib/publickey.js +386 -0
  51. package/lib/script/index.js +5 -0
  52. package/lib/script/interpreter.js +1834 -0
  53. package/lib/script/script.js +1074 -0
  54. package/lib/script/stack.js +109 -0
  55. package/lib/script/write-i32-le.js +17 -0
  56. package/lib/script/write-push-data.js +35 -0
  57. package/lib/script/write-u16-le.js +12 -0
  58. package/lib/script/write-u32-le.js +16 -0
  59. package/lib/script/write-u64-le.js +24 -0
  60. package/lib/script/write-u8-le.js +8 -0
  61. package/lib/script/write-varint.js +46 -0
  62. package/lib/transaction/index.js +7 -0
  63. package/lib/transaction/input/index.js +5 -0
  64. package/lib/transaction/input/input.js +354 -0
  65. package/lib/transaction/input/multisig.js +242 -0
  66. package/lib/transaction/input/publickey.js +100 -0
  67. package/lib/transaction/input/publickeyhash.js +118 -0
  68. package/lib/transaction/output.js +231 -0
  69. package/lib/transaction/sighash.js +167 -0
  70. package/lib/transaction/signature.js +97 -0
  71. package/lib/transaction/transaction.js +1639 -0
  72. package/lib/transaction/unspentoutput.js +113 -0
  73. package/lib/util/_.js +47 -0
  74. package/lib/util/js.js +90 -0
  75. package/lib/util/preconditions.js +33 -0
  76. package/package.json +26 -0
  77. package/test/address.js +509 -0
  78. package/test/block/block.js +251 -0
  79. package/test/block/blockheader.js +275 -0
  80. package/test/block/merklebloack.js +211 -0
  81. package/test/crypto/bn.js +177 -0
  82. package/test/crypto/ecdsa.js +391 -0
  83. package/test/crypto/hash.browser.js +135 -0
  84. package/test/crypto/hash.js +136 -0
  85. package/test/crypto/point.js +224 -0
  86. package/test/crypto/random.js +32 -0
  87. package/test/crypto/signature.js +409 -0
  88. package/test/data/bip69.json +215 -0
  89. package/test/data/bitcoind/base58_keys_invalid.json +52 -0
  90. package/test/data/bitcoind/base58_keys_valid.json +335 -0
  91. package/test/data/bitcoind/blocks.json +22 -0
  92. package/test/data/bitcoind/script_tests.json +3822 -0
  93. package/test/data/bitcoind/sig_canonical.json +7 -0
  94. package/test/data/bitcoind/sig_noncanonical.json +36 -0
  95. package/test/data/bitcoind/tx_invalid.json +445 -0
  96. package/test/data/bitcoind/tx_valid.json +44 -0
  97. package/test/data/blk86756-testnet.dat +0 -0
  98. package/test/data/blk86756-testnet.js +14 -0
  99. package/test/data/blk86756-testnet.json +684 -0
  100. package/test/data/block.hex +1 -0
  101. package/test/data/ecdsa.json +230 -0
  102. package/test/data/merkleblocks.js +488 -0
  103. package/test/data/messages.json +22 -0
  104. package/test/data/sighash.json +12 -0
  105. package/test/data/tx_creation.json +95 -0
  106. package/test/encoding/base58.js +131 -0
  107. package/test/encoding/base58check.js +136 -0
  108. package/test/encoding/bufferreader.js +337 -0
  109. package/test/encoding/bufferwriter.js +172 -0
  110. package/test/encoding/varint.js +104 -0
  111. package/test/hashCache.js +67 -0
  112. package/test/hdkeys.js +445 -0
  113. package/test/hdprivatekey.js +332 -0
  114. package/test/hdpublickey.js +304 -0
  115. package/test/index.js +16 -0
  116. package/test/message/message.js +204 -0
  117. package/test/mnemonic/data/fixtures.json +300 -0
  118. package/test/mnemonic/mnemonic.js +259 -0
  119. package/test/mnemonic/mocha.opts +1 -0
  120. package/test/mnemonic/pbkdf2.test.js +59 -0
  121. package/test/networks.js +159 -0
  122. package/test/opcode.js +161 -0
  123. package/test/privatekey.js +439 -0
  124. package/test/publickey.js +554 -0
  125. package/test/script/interpreter.js +734 -0
  126. package/test/script/script.js +1437 -0
  127. package/test/transaction/deserialize.js +34 -0
  128. package/test/transaction/input/input.js +90 -0
  129. package/test/transaction/input/multisig.js +90 -0
  130. package/test/transaction/input/publickey.js +68 -0
  131. package/test/transaction/input/publickeyhash.js +51 -0
  132. package/test/transaction/output.js +185 -0
  133. package/test/transaction/sighash.js +65 -0
  134. package/test/transaction/signature.js +114 -0
  135. package/test/transaction/transaction.js +1109 -0
  136. package/test/transaction/unspentoutput.js +110 -0
  137. package/test/util/js.js +76 -0
  138. package/test/util/preconditions.js +79 -0
@@ -0,0 +1,242 @@
1
+ 'use strict';
2
+
3
+ var _ = require('../../util/_');
4
+ var inherits = require('inherits');
5
+ var Input = require('./input');
6
+ var Output = require('../output');
7
+ var $ = require('../../util/preconditions');
8
+
9
+ var Script = require('../../script');
10
+ var Signature = require('../../crypto/signature');
11
+ var Sighash = require('../sighash');
12
+ var TransactionSignature = require('../signature');
13
+ var PublicKey = require('../../publickey');
14
+ var Varint = require('../../encoding/varint');
15
+
16
+ /**
17
+ * @constructor
18
+ */
19
+ function MultiSigInput(input, pubkeys, threshold, signatures) {
20
+ Input.apply(this, arguments);
21
+ var self = this;
22
+ pubkeys = pubkeys || input.publicKeys;
23
+ threshold = threshold || input.threshold;
24
+ signatures = signatures || input.signatures;
25
+ this.publicKeys = pubkeys
26
+ .map((k) => k.toString('hex'))
27
+ .sort()
28
+ .map((k) => new PublicKey(k));
29
+ $.checkState(
30
+ Script.buildMultisigOut(this.publicKeys, threshold).equals(this.output.script),
31
+ "Provided public keys don't match to the provided output script",
32
+ );
33
+ this.publicKeyIndex = {};
34
+ _.each(this.publicKeys, function (publicKey, index) {
35
+ self.publicKeyIndex[publicKey.toString()] = index;
36
+ });
37
+ this.threshold = threshold;
38
+ // Empty array of signatures
39
+ this.signatures = signatures
40
+ ? this._deserializeSignatures(signatures)
41
+ : new Array(this.publicKeys.length);
42
+ }
43
+ inherits(MultiSigInput, Input);
44
+
45
+ MultiSigInput.prototype.toObject = function () {
46
+ var obj = Input.prototype.toObject.apply(this, arguments);
47
+ obj.threshold = this.threshold;
48
+ obj.publicKeys = _.map(this.publicKeys, function (publicKey) {
49
+ return publicKey.toString();
50
+ });
51
+ obj.signatures = this._serializeSignatures();
52
+ return obj;
53
+ };
54
+
55
+ MultiSigInput.prototype._deserializeSignatures = function (signatures) {
56
+ return _.map(signatures, function (signature) {
57
+ if (!signature) {
58
+ return undefined;
59
+ }
60
+ return new TransactionSignature(signature);
61
+ });
62
+ };
63
+
64
+ MultiSigInput.prototype._serializeSignatures = function () {
65
+ return _.map(this.signatures, function (signature) {
66
+ if (!signature) {
67
+ return undefined;
68
+ }
69
+ return signature.toObject();
70
+ });
71
+ };
72
+
73
+ MultiSigInput.prototype.getSignatures = function (transaction, privateKey, index, sigtype) {
74
+ $.checkState(this.output instanceof Output);
75
+ sigtype = sigtype || Signature.SIGHASH_ALL;
76
+
77
+ var self = this;
78
+ var results = [];
79
+ _.each(this.publicKeys, function (publicKey) {
80
+ if (publicKey.toString() === privateKey.publicKey.toString()) {
81
+ results.push(
82
+ new TransactionSignature({
83
+ publicKey: privateKey.publicKey,
84
+ prevTxId: self.prevTxId,
85
+ outputIndex: self.outputIndex,
86
+ inputIndex: index,
87
+ signature: Sighash.sign(
88
+ transaction,
89
+ privateKey,
90
+ sigtype,
91
+ index,
92
+ ),
93
+ sigtype: sigtype,
94
+ }),
95
+ );
96
+ }
97
+ });
98
+
99
+ return results;
100
+ };
101
+
102
+ MultiSigInput.prototype.addSignature = function (transaction, signature) {
103
+ $.checkState(!this.isFullySigned(), 'All needed signatures have already been added');
104
+ $.checkArgument(
105
+ !_.isUndefined(this.publicKeyIndex[signature.publicKey.toString()]),
106
+ 'Signature has no matching public key',
107
+ );
108
+ $.checkState(this.isValidSignature(transaction, signature));
109
+ this.signatures[this.publicKeyIndex[signature.publicKey.toString()]] = signature;
110
+ this._updateScript();
111
+ return this;
112
+ };
113
+
114
+ MultiSigInput.prototype._updateScript = function () {
115
+ this.setScript(Script.buildMultisigIn(this.publicKeys, this.threshold, this._createSignatures()));
116
+ return this;
117
+ };
118
+
119
+ MultiSigInput.prototype._createSignatures = function () {
120
+ return _.map(
121
+ _.filter(this.signatures, function (signature) {
122
+ return !_.isUndefined(signature);
123
+ }),
124
+ function (signature) {
125
+ return Buffer.concat([signature.signature.toDER(), Buffer.from([signature.sigtype & 0xff])]);
126
+ },
127
+ );
128
+ };
129
+
130
+ MultiSigInput.prototype.clearSignatures = function () {
131
+ this.signatures = new Array(this.publicKeys.length);
132
+ this._updateScript();
133
+ };
134
+
135
+ MultiSigInput.prototype.isFullySigned = function () {
136
+ return this.countSignatures() === this.threshold;
137
+ };
138
+
139
+ MultiSigInput.prototype.countMissingSignatures = function () {
140
+ return this.threshold - this.countSignatures();
141
+ };
142
+
143
+ MultiSigInput.prototype.countSignatures = function () {
144
+ return _.reduce(
145
+ this.signatures,
146
+ function (sum, signature) {
147
+ return sum + !!signature;
148
+ },
149
+ 0,
150
+ );
151
+ };
152
+
153
+ MultiSigInput.prototype.publicKeysWithoutSignature = function () {
154
+ var self = this;
155
+ return _.filter(this.publicKeys, function (publicKey) {
156
+ return !self.signatures[self.publicKeyIndex[publicKey.toString()]];
157
+ });
158
+ };
159
+
160
+ MultiSigInput.prototype.isValidSignature = function (transaction, signature) {
161
+ // FIXME: Refactor signature so this is not necessary
162
+ signature.signature.nhashtype = signature.sigtype;
163
+ return Sighash.verify(
164
+ transaction,
165
+ signature.signature,
166
+ signature.publicKey,
167
+ signature.inputIndex,
168
+ this.output.script,
169
+ this.output.satoshisBN,
170
+ );
171
+ };
172
+
173
+ /**
174
+ *
175
+ * @param {Buffer[]} signatures
176
+ * @param {PublicKey[]} publicKeys
177
+ * @param {Transaction} transaction
178
+ * @param {Integer} inputIndex
179
+ * @param {Input} input
180
+ * @returns {TransactionSignature[]}
181
+ */
182
+ MultiSigInput.normalizeSignatures = function (
183
+ transaction,
184
+ input,
185
+ inputIndex,
186
+ signatures,
187
+ publicKeys,
188
+ ) {
189
+ return publicKeys.map(function (pubKey) {
190
+ var signatureMatch = null;
191
+ signatures = signatures.filter(function (signatureBuffer) {
192
+ if (signatureMatch) {
193
+ return true;
194
+ }
195
+
196
+ var signature = new TransactionSignature({
197
+ signature: Signature.fromTxFormat(signatureBuffer),
198
+ publicKey: pubKey,
199
+ prevTxId: input.prevTxId,
200
+ outputIndex: input.outputIndex,
201
+ inputIndex: inputIndex,
202
+ sigtype: Signature.SIGHASH_ALL,
203
+ });
204
+
205
+ signature.signature.nhashtype = signature.sigtype;
206
+ var isMatch = Sighash.verify(
207
+ transaction,
208
+ signature.signature,
209
+ signature.publicKey,
210
+ signature.inputIndex,
211
+ );
212
+
213
+ if (isMatch) {
214
+ signatureMatch = signature;
215
+ return false;
216
+ }
217
+
218
+ return true;
219
+ });
220
+
221
+ return signatureMatch || null;
222
+ });
223
+ };
224
+
225
+ // 32 txid
226
+ // 4 output index
227
+ // --- script ---
228
+ // ??? script size (VARINT)
229
+ // 1 OP_0
230
+ // --- signature list ---
231
+ // 1 signature size (OP_PUSHDATA)
232
+ // <=72 signature (DER + SIGHASH type)
233
+ //
234
+ // 4 sequence number
235
+ MultiSigInput.SIGNATURE_SIZE = 73;
236
+
237
+ MultiSigInput.prototype._estimateSize = function () {
238
+ var scriptSize = 1 + this.threshold * MultiSigInput.SIGNATURE_SIZE;
239
+ return Input.BASE_SIZE + Varint(scriptSize).toBuffer().length + scriptSize;
240
+ };
241
+
242
+ module.exports = MultiSigInput;
@@ -0,0 +1,100 @@
1
+ 'use strict';
2
+
3
+ var inherits = require('inherits');
4
+
5
+ var $ = require('../../util/preconditions');
6
+
7
+ var Input = require('./input');
8
+ var Output = require('../output');
9
+ var Sighash = require('../sighash');
10
+ var Script = require('../../script');
11
+ var Signature = require('../../crypto/signature');
12
+ var TransactionSignature = require('../signature');
13
+
14
+ /**
15
+ * Represents a special kind of input of PayToPublicKey kind.
16
+ * @constructor
17
+ */
18
+ function PublicKeyInput() {
19
+ Input.apply(this, arguments);
20
+ }
21
+ inherits(PublicKeyInput, Input);
22
+
23
+ /**
24
+ * @param {Transaction} transaction - the transaction to be signed
25
+ * @param {PrivateKey} privateKey - the private key with which to sign the transaction
26
+ * @param {number} index - the index of the input in the transaction input vector
27
+ * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL
28
+ * @return {Array} of objects that can be
29
+ */
30
+ PublicKeyInput.prototype.getSignatures = function (transaction, privateKey, index, sigtype) {
31
+ $.checkState(this.output instanceof Output);
32
+ sigtype = sigtype || Signature.SIGHASH_ALL;
33
+ var publicKey = privateKey.toPublicKey();
34
+ if (publicKey.toString() === this.output.script.getPublicKey().toString('hex')) {
35
+ return [
36
+ new TransactionSignature({
37
+ publicKey: publicKey,
38
+ prevTxId: this.prevTxId,
39
+ outputIndex: this.outputIndex,
40
+ inputIndex: index,
41
+ signature: Sighash.sign(
42
+ transaction,
43
+ privateKey,
44
+ sigtype,
45
+ index,
46
+ ),
47
+ sigtype: sigtype,
48
+ }),
49
+ ];
50
+ }
51
+ return [];
52
+ };
53
+
54
+ /**
55
+ * Add the provided signature
56
+ *
57
+ * @param {Object} signature
58
+ * @param {PublicKey} signature.publicKey
59
+ * @param {Signature} signature.signature
60
+ * @param {number=} signature.sigtype
61
+ * @return {PublicKeyInput} this, for chaining
62
+ */
63
+ PublicKeyInput.prototype.addSignature = function (transaction, signature) {
64
+ $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid');
65
+ this.setScript(Script.buildPublicKeyIn(signature.signature.toDER(), signature.sigtype));
66
+ return this;
67
+ };
68
+
69
+ /**
70
+ * Clear the input's signature
71
+ * @return {PublicKeyHashInput} this, for chaining
72
+ */
73
+ PublicKeyInput.prototype.clearSignatures = function () {
74
+ this.setScript(Script.empty());
75
+ return this;
76
+ };
77
+
78
+ /**
79
+ * Query whether the input is signed
80
+ * @return {boolean}
81
+ */
82
+ PublicKeyInput.prototype.isFullySigned = function () {
83
+ return this.script.isPublicKeyIn();
84
+ };
85
+
86
+ // 32 txid
87
+ // 4 output index
88
+ // ---
89
+ // 1 script size (VARINT)
90
+ // 1 signature size (OP_PUSHDATA)
91
+ // <=72 signature (DER + SIGHASH type)
92
+ // ---
93
+ // 4 sequence number
94
+ PublicKeyInput.SCRIPT_MAX_SIZE = 74;
95
+
96
+ PublicKeyInput.prototype._estimateSize = function () {
97
+ return Input.BASE_SIZE + PublicKeyInput.SCRIPT_MAX_SIZE;
98
+ };
99
+
100
+ module.exports = PublicKeyInput;
@@ -0,0 +1,118 @@
1
+ 'use strict';
2
+
3
+ var inherits = require('inherits');
4
+
5
+ var $ = require('../../util/preconditions');
6
+
7
+ var Hash = require('../../crypto/hash');
8
+ var Input = require('./input');
9
+ var Output = require('../output');
10
+ var Sighash = require('../sighash');
11
+ var Script = require('../../script');
12
+ var Signature = require('../../crypto/signature');
13
+ var TransactionSignature = require('../signature');
14
+
15
+ /**
16
+ * Represents a special kind of input of PayToPublicKeyHash kind.
17
+ * @constructor
18
+ */
19
+ function PublicKeyHashInput() {
20
+ Input.apply(this, arguments);
21
+ }
22
+ inherits(PublicKeyHashInput, Input);
23
+
24
+ /**
25
+ * @param {Transaction} transaction - the transaction to be signed
26
+ * @param {PrivateKey} privateKey - the private key with which to sign the transaction
27
+ * @param {number} index - the index of the input in the transaction input vector
28
+ * @param {number=} sigtype - the type of signature, defaults to Signature.SIGHASH_ALL
29
+ * @param {Buffer=} hashData - the precalculated hash of the public key associated with the privateKey provided
30
+ * @return {Array} of objects that can be
31
+ */
32
+ PublicKeyHashInput.prototype.getSignatures = function (
33
+ transaction,
34
+ privateKey,
35
+ index,
36
+ sigtype,
37
+ hashData,
38
+ ) {
39
+ $.checkState(this.output instanceof Output);
40
+ hashData = hashData || Hash.sha256ripemd160(privateKey.publicKey.toBuffer());
41
+ sigtype = sigtype || Signature.SIGHASH_ALL;
42
+
43
+ if (hashData.equals(this.output.script.getPublicKeyHash())) {
44
+ return [
45
+ new TransactionSignature({
46
+ publicKey: privateKey.publicKey,
47
+ prevTxId: this.prevTxId,
48
+ outputIndex: this.outputIndex,
49
+ inputIndex: index,
50
+ signature: Sighash.sign(
51
+ transaction,
52
+ privateKey,
53
+ sigtype,
54
+ index,
55
+ ),
56
+ sigtype: sigtype,
57
+ }),
58
+ ];
59
+ }
60
+ return [];
61
+ };
62
+
63
+ /**
64
+ * Add the provided signature
65
+ *
66
+ * @param {Object} signature
67
+ * @param {PublicKey} signature.publicKey
68
+ * @param {Signature} signature.signature
69
+ * @param {number=} signature.sigtype
70
+ * @return {PublicKeyHashInput} this, for chaining
71
+ */
72
+ PublicKeyHashInput.prototype.addSignature = function (transaction, signature) {
73
+ $.checkState(this.isValidSignature(transaction, signature), 'Signature is invalid');
74
+
75
+ this.setScript(
76
+ Script.buildPublicKeyHashIn(
77
+ signature.publicKey,
78
+ signature.signature.toDER(),
79
+ signature.sigtype,
80
+ ),
81
+ );
82
+ return this;
83
+ };
84
+
85
+ /**
86
+ * Clear the input's signature
87
+ * @return {PublicKeyHashInput} this, for chaining
88
+ */
89
+ PublicKeyHashInput.prototype.clearSignatures = function () {
90
+ this.setScript(Script.empty());
91
+ return this;
92
+ };
93
+
94
+ /**
95
+ * Query whether the input is signed
96
+ * @return {boolean}
97
+ */
98
+ PublicKeyHashInput.prototype.isFullySigned = function () {
99
+ return this.script.isPublicKeyHashIn();
100
+ };
101
+
102
+ // 32 txid
103
+ // 4 output index
104
+ // --- script ---
105
+ // 1 script size (VARINT)
106
+ // 1 signature size (OP_PUSHDATA)
107
+ // <=72 signature (DER + SIGHASH type)
108
+ // 1 public key size (OP_PUSHDATA)
109
+ // 65 uncompressed public key
110
+ //
111
+ // 4 sequence number
112
+ PublicKeyHashInput.SCRIPT_MAX_SIZE = 140;
113
+
114
+ PublicKeyHashInput.prototype._estimateSize = function () {
115
+ return Input.BASE_SIZE + PublicKeyHashInput.SCRIPT_MAX_SIZE;
116
+ };
117
+
118
+ module.exports = PublicKeyHashInput;
@@ -0,0 +1,231 @@
1
+ 'use strict';
2
+
3
+ var _ = require('../util/_');
4
+ var BN = require('../crypto/bn');
5
+ var JSUtil = require('../util/js');
6
+ var BufferWriter = require('../encoding/bufferwriter');
7
+ var Varint = require('../encoding/varint');
8
+ var Script = require('../script');
9
+ var $ = require('../util/preconditions');
10
+ var errors = require('../errors');
11
+ var Hash = require('../crypto/hash')
12
+
13
+ var MAX_SAFE_INTEGER = 0x1fffffffffffff;
14
+
15
+ function Output(args) {
16
+ if (!(this instanceof Output)) {
17
+ return new Output(args);
18
+ }
19
+ if (_.isObject(args)) {
20
+ this.satoshis = args.satoshis;
21
+ if (Buffer.isBuffer(args.script)) {
22
+ this.setScriptFromBuffer(args.script);
23
+ } else {
24
+ var script;
25
+ if (_.isString(args.script) && JSUtil.isHexa(args.script)) {
26
+ script = Buffer.from(args.script, 'hex');
27
+ } else {
28
+ script = args.script;
29
+ }
30
+ this.setScript(script);
31
+ }
32
+ this.setData(args.data)
33
+ } else {
34
+ throw new TypeError('Unrecognized argument for Output');
35
+ }
36
+ }
37
+
38
+ Object.defineProperty(Output.prototype, 'script', {
39
+ configurable: false,
40
+ enumerable: true,
41
+ get: function () {
42
+ return this._script;
43
+ },
44
+ });
45
+
46
+ Object.defineProperty(Output.prototype, 'data', {
47
+ configurable: false,
48
+ enumerable: true,
49
+ get: function () {
50
+ return this._data;
51
+ },
52
+ });
53
+
54
+ Object.defineProperty(Output.prototype, 'satoshis', {
55
+ configurable: false,
56
+ enumerable: true,
57
+ get: function () {
58
+ return this._satoshis;
59
+ },
60
+ set: function (num) {
61
+ if (num instanceof BN) {
62
+ this._satoshisBN = num;
63
+ this._satoshis = num.toNumber();
64
+ } else if (_.isString(num)) {
65
+ this._satoshis = parseInt(num);
66
+ this._satoshisBN = BN.fromNumber(this._satoshis);
67
+ } else {
68
+ $.checkArgument(JSUtil.isNaturalNumber(num), 'Output satoshis is not a natural number');
69
+ this._satoshisBN = BN.fromNumber(num);
70
+ this._satoshis = num;
71
+ }
72
+ $.checkState(JSUtil.isNaturalNumber(this._satoshis), 'Output satoshis is not a natural number');
73
+ },
74
+ });
75
+
76
+ Output.prototype.invalidSatoshis = function () {
77
+ if (this._satoshis > MAX_SAFE_INTEGER) {
78
+ return 'transaction txout satoshis greater than max safe integer';
79
+ }
80
+ if (this._satoshis !== this._satoshisBN.toNumber()) {
81
+ return 'transaction txout satoshis has corrupted value';
82
+ }
83
+ if (this._satoshis < 0) {
84
+ return 'transaction txout negative';
85
+ }
86
+ return false;
87
+ };
88
+
89
+ Object.defineProperty(Output.prototype, 'satoshisBN', {
90
+ configurable: false,
91
+ enumerable: true,
92
+ get: function () {
93
+ return this._satoshisBN;
94
+ },
95
+ set: function (num) {
96
+ this._satoshisBN = num;
97
+ this._satoshis = num.toNumber();
98
+ $.checkState(JSUtil.isNaturalNumber(this._satoshis), 'Output satoshis is not a natural number');
99
+ },
100
+ });
101
+
102
+ Output.prototype.toObject = Output.prototype.toJSON = function toObject() {
103
+ var obj = {
104
+ satoshis: this.satoshis,
105
+ };
106
+ obj.script = this._script.toBuffer().toString('hex');
107
+ obj.data = this._data.toString('hex')
108
+ return obj;
109
+ };
110
+
111
+ Output.prototype.setData = function (data) {
112
+ if (!data) {
113
+ this._data = Buffer.from([])
114
+ return;
115
+ }
116
+ if (Buffer.isBuffer(data)) {
117
+ this._data = data
118
+ } else if (_.isString(data) && JSUtil.isHexa(data)) {
119
+ this._data = Buffer.from(data, 'hex')
120
+ } else {
121
+ throw new TypeError('Invalid argument type: data for output.setData')
122
+ }
123
+ }
124
+
125
+ Output.fromObject = function (data) {
126
+ return new Output(data);
127
+ };
128
+
129
+ Output.prototype.setScriptFromBuffer = function (buffer) {
130
+ try {
131
+ this._script = Script.fromBuffer(buffer);
132
+ this._script._isOutput = true;
133
+ } catch (e) {
134
+ if (e instanceof errors.Script.InvalidBuffer) {
135
+ this._script = null;
136
+ } else {
137
+ throw e;
138
+ }
139
+ }
140
+ };
141
+
142
+ Output.prototype.setScript = function (script) {
143
+ if (script instanceof Script) {
144
+ this._script = script;
145
+ this._script._isOutput = true;
146
+ } else if (_.isString(script)) {
147
+ this._script = Script.fromString(script);
148
+ this._script._isOutput = true;
149
+ } else if (Buffer.isBuffer(script)) {
150
+ this.setScriptFromBuffer(script);
151
+ } else {
152
+ throw new TypeError('Invalid argument type: script');
153
+ }
154
+ return this;
155
+ };
156
+
157
+ Output.prototype.inspect = function () {
158
+ var scriptStr;
159
+ if (this.script) {
160
+ scriptStr = this.script.inspect();
161
+ }
162
+ return '<Output (' + this.satoshis + ' sats) ' + scriptStr + '>';
163
+ };
164
+
165
+ Output.fromBufferReader = function (br) {
166
+ var obj = {}
167
+ obj.satoshis = br.readUInt64LEBN()
168
+ var scriptSize = br.readVarintNum()
169
+ if (scriptSize !== 0) {
170
+ if (br.remaining() < scriptSize) {
171
+ throw new TypeError('Unrecognized Output')
172
+ }
173
+ obj.script = br.read(scriptSize)
174
+ } else {
175
+ obj.script = Buffer.from([])
176
+ }
177
+ var dataSize = br.readVarintNum()
178
+ if (dataSize !== 0) {
179
+ if (br.remaining() < dataSize) {
180
+ throw new TypeError('Unrecognized Output')
181
+ }
182
+ obj.data = br.read(dataSize)
183
+ } else {
184
+ obj.data = Buffer.from([])
185
+ }
186
+ return new Output(obj)
187
+ }
188
+
189
+ Output.prototype.toBufferWriter = function (hashScriptPubkey, writer) {
190
+ $.checkArgument(typeof hashScriptPubkey === 'boolean', 'hashScriptSig should be boolean')
191
+ if (!writer) {
192
+ writer = new BufferWriter();
193
+ }
194
+ writer.writeUInt64LEBN(this._satoshisBN);
195
+ var script = this._script.toBuffer();
196
+ var data = this._data
197
+ if(hashScriptPubkey) {
198
+ writer.write(Hash.sha256(script))
199
+ writer.write(Hash.sha256(data))
200
+ } else {
201
+ writer.writeVarintNum(script.length);
202
+ writer.write(script);
203
+ writer.writeVarintNum(data.length)
204
+ writer.write(data)
205
+ }
206
+
207
+
208
+ return writer
209
+ };
210
+
211
+ // 8 value
212
+ // ??? script size (VARINT)
213
+ // ??? script
214
+ /**
215
+ * Calculates the total size of the output in bytes.
216
+ * Includes the script size, data size, and their respective varint sizes,
217
+ * plus a fixed 8-byte overhead.
218
+ * @returns {number} The total output size in bytes.
219
+ */
220
+ Output.prototype.getSize = function () {
221
+ var scriptSize = this.script.toBuffer().length;
222
+ var dataSize = this.data.length
223
+ var varintSize = Varint(scriptSize).toBuffer().length + Varint(dataSize).toBuffer().length
224
+ return 8 + varintSize + scriptSize + dataSize
225
+ };
226
+
227
+ Output.prototype.clone = function () {
228
+ return Output.fromObject(this.toObject());
229
+ }
230
+
231
+ module.exports = Output;