@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.
- package/.mocharc.yaml +3 -0
- package/index.d.ts +1541 -0
- package/index.js +74 -0
- package/lib/address.js +478 -0
- package/lib/block/block.js +277 -0
- package/lib/block/blockheader.js +295 -0
- package/lib/block/index.js +4 -0
- package/lib/block/merkleblock.js +323 -0
- package/lib/bn.js +3423 -0
- package/lib/crypto/bn.js +278 -0
- package/lib/crypto/ecdsa.js +339 -0
- package/lib/crypto/hash.browser.js +171 -0
- package/lib/crypto/hash.js +2 -0
- package/lib/crypto/hash.node.js +171 -0
- package/lib/crypto/point.js +221 -0
- package/lib/crypto/random.browser.js +28 -0
- package/lib/crypto/random.js +2 -0
- package/lib/crypto/random.node.js +11 -0
- package/lib/crypto/signature.js +325 -0
- package/lib/encoding/base58.js +111 -0
- package/lib/encoding/base58check.js +121 -0
- package/lib/encoding/bufferreader.js +212 -0
- package/lib/encoding/bufferwriter.js +140 -0
- package/lib/encoding/decode-asm.js +24 -0
- package/lib/encoding/decode-hex.js +32 -0
- package/lib/encoding/decode-script-chunks.js +43 -0
- package/lib/encoding/encode-hex.js +284 -0
- package/lib/encoding/is-hex.js +7 -0
- package/lib/encoding/varint.js +75 -0
- package/lib/errors/index.js +54 -0
- package/lib/errors/spec.js +314 -0
- package/lib/hash-cache.js +50 -0
- package/lib/hdprivatekey.js +678 -0
- package/lib/hdpublickey.js +525 -0
- package/lib/message/message.js +191 -0
- package/lib/mnemonic/mnemonic.js +303 -0
- package/lib/mnemonic/pbkdf2.browser.js +68 -0
- package/lib/mnemonic/pbkdf2.js +2 -0
- package/lib/mnemonic/pbkdf2.node.js +68 -0
- package/lib/mnemonic/words/chinese.js +2054 -0
- package/lib/mnemonic/words/english.js +2054 -0
- package/lib/mnemonic/words/french.js +2054 -0
- package/lib/mnemonic/words/index.js +8 -0
- package/lib/mnemonic/words/italian.js +2054 -0
- package/lib/mnemonic/words/japanese.js +2054 -0
- package/lib/mnemonic/words/spanish.js +2054 -0
- package/lib/networks.js +379 -0
- package/lib/opcode.js +255 -0
- package/lib/privatekey.js +374 -0
- package/lib/publickey.js +386 -0
- package/lib/script/index.js +5 -0
- package/lib/script/interpreter.js +1834 -0
- package/lib/script/script.js +1074 -0
- package/lib/script/stack.js +109 -0
- package/lib/script/write-i32-le.js +17 -0
- package/lib/script/write-push-data.js +35 -0
- package/lib/script/write-u16-le.js +12 -0
- package/lib/script/write-u32-le.js +16 -0
- package/lib/script/write-u64-le.js +24 -0
- package/lib/script/write-u8-le.js +8 -0
- package/lib/script/write-varint.js +46 -0
- package/lib/transaction/index.js +7 -0
- package/lib/transaction/input/index.js +5 -0
- package/lib/transaction/input/input.js +354 -0
- package/lib/transaction/input/multisig.js +242 -0
- package/lib/transaction/input/publickey.js +100 -0
- package/lib/transaction/input/publickeyhash.js +118 -0
- package/lib/transaction/output.js +231 -0
- package/lib/transaction/sighash.js +167 -0
- package/lib/transaction/signature.js +97 -0
- package/lib/transaction/transaction.js +1639 -0
- package/lib/transaction/unspentoutput.js +113 -0
- package/lib/util/_.js +47 -0
- package/lib/util/js.js +90 -0
- package/lib/util/preconditions.js +33 -0
- package/package.json +26 -0
- package/test/address.js +509 -0
- package/test/block/block.js +251 -0
- package/test/block/blockheader.js +275 -0
- package/test/block/merklebloack.js +211 -0
- package/test/crypto/bn.js +177 -0
- package/test/crypto/ecdsa.js +391 -0
- package/test/crypto/hash.browser.js +135 -0
- package/test/crypto/hash.js +136 -0
- package/test/crypto/point.js +224 -0
- package/test/crypto/random.js +32 -0
- package/test/crypto/signature.js +409 -0
- package/test/data/bip69.json +215 -0
- package/test/data/bitcoind/base58_keys_invalid.json +52 -0
- package/test/data/bitcoind/base58_keys_valid.json +335 -0
- package/test/data/bitcoind/blocks.json +22 -0
- package/test/data/bitcoind/script_tests.json +3822 -0
- package/test/data/bitcoind/sig_canonical.json +7 -0
- package/test/data/bitcoind/sig_noncanonical.json +36 -0
- package/test/data/bitcoind/tx_invalid.json +445 -0
- package/test/data/bitcoind/tx_valid.json +44 -0
- package/test/data/blk86756-testnet.dat +0 -0
- package/test/data/blk86756-testnet.js +14 -0
- package/test/data/blk86756-testnet.json +684 -0
- package/test/data/block.hex +1 -0
- package/test/data/ecdsa.json +230 -0
- package/test/data/merkleblocks.js +488 -0
- package/test/data/messages.json +22 -0
- package/test/data/sighash.json +12 -0
- package/test/data/tx_creation.json +95 -0
- package/test/encoding/base58.js +131 -0
- package/test/encoding/base58check.js +136 -0
- package/test/encoding/bufferreader.js +337 -0
- package/test/encoding/bufferwriter.js +172 -0
- package/test/encoding/varint.js +104 -0
- package/test/hashCache.js +67 -0
- package/test/hdkeys.js +445 -0
- package/test/hdprivatekey.js +332 -0
- package/test/hdpublickey.js +304 -0
- package/test/index.js +16 -0
- package/test/message/message.js +204 -0
- package/test/mnemonic/data/fixtures.json +300 -0
- package/test/mnemonic/mnemonic.js +259 -0
- package/test/mnemonic/mocha.opts +1 -0
- package/test/mnemonic/pbkdf2.test.js +59 -0
- package/test/networks.js +159 -0
- package/test/opcode.js +161 -0
- package/test/privatekey.js +439 -0
- package/test/publickey.js +554 -0
- package/test/script/interpreter.js +734 -0
- package/test/script/script.js +1437 -0
- package/test/transaction/deserialize.js +34 -0
- package/test/transaction/input/input.js +90 -0
- package/test/transaction/input/multisig.js +90 -0
- package/test/transaction/input/publickey.js +68 -0
- package/test/transaction/input/publickeyhash.js +51 -0
- package/test/transaction/output.js +185 -0
- package/test/transaction/sighash.js +65 -0
- package/test/transaction/signature.js +114 -0
- package/test/transaction/transaction.js +1109 -0
- package/test/transaction/unspentoutput.js +110 -0
- package/test/util/js.js +76 -0
- 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;
|