@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,323 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('../util/_');
|
|
4
|
+
var BlockHeader = require('./blockheader');
|
|
5
|
+
var BufferReader = require('../encoding/bufferreader');
|
|
6
|
+
var BufferWriter = require('../encoding/bufferwriter');
|
|
7
|
+
var Hash = require('../crypto/hash');
|
|
8
|
+
var Transaction = require('../transaction');
|
|
9
|
+
var errors = require('../errors');
|
|
10
|
+
var $ = require('../util/preconditions');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Instantiate a MerkleBlock from a Buffer, JSON object, or Object with
|
|
14
|
+
* the properties of the Block
|
|
15
|
+
*
|
|
16
|
+
* @param {*} - A Buffer, JSON string, or Object representing a MerkleBlock
|
|
17
|
+
* @returns {MerkleBlock}
|
|
18
|
+
* @constructor
|
|
19
|
+
*/
|
|
20
|
+
function MerkleBlock(arg) {
|
|
21
|
+
if (!(this instanceof MerkleBlock)) {
|
|
22
|
+
return new MerkleBlock(arg);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var info = {};
|
|
26
|
+
if (Buffer.isBuffer(arg)) {
|
|
27
|
+
info = MerkleBlock._fromBufferReader(BufferReader(arg));
|
|
28
|
+
} else if (_.isObject(arg)) {
|
|
29
|
+
var header;
|
|
30
|
+
if (arg.header instanceof BlockHeader) {
|
|
31
|
+
header = arg.header;
|
|
32
|
+
} else {
|
|
33
|
+
header = BlockHeader.fromObject(arg.header);
|
|
34
|
+
}
|
|
35
|
+
info = {
|
|
36
|
+
/**
|
|
37
|
+
* @name MerkleBlock#header
|
|
38
|
+
* @type {BlockHeader}
|
|
39
|
+
*/
|
|
40
|
+
header: header,
|
|
41
|
+
/**
|
|
42
|
+
* @name MerkleBlock#numTransactions
|
|
43
|
+
* @type {Number}
|
|
44
|
+
*/
|
|
45
|
+
numTransactions: arg.numTransactions,
|
|
46
|
+
/**
|
|
47
|
+
* @name MerkleBlock#hashes
|
|
48
|
+
* @type {String[]}
|
|
49
|
+
*/
|
|
50
|
+
hashes: arg.hashes,
|
|
51
|
+
/**
|
|
52
|
+
* @name MerkleBlock#flags
|
|
53
|
+
* @type {Number[]}
|
|
54
|
+
*/
|
|
55
|
+
flags: arg.flags,
|
|
56
|
+
};
|
|
57
|
+
} else {
|
|
58
|
+
throw new TypeError('Unrecognized argument for MerkleBlock');
|
|
59
|
+
}
|
|
60
|
+
_.extend(this, info);
|
|
61
|
+
this._flagBitsUsed = 0;
|
|
62
|
+
this._hashesUsed = 0;
|
|
63
|
+
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Buffer} - MerkleBlock data in a Buffer object
|
|
69
|
+
* @returns {MerkleBlock} - A MerkleBlock object
|
|
70
|
+
*/
|
|
71
|
+
MerkleBlock.fromBuffer = function fromBuffer(buf) {
|
|
72
|
+
return MerkleBlock.fromBufferReader(BufferReader(buf));
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {BufferReader} - MerkleBlock data in a BufferReader object
|
|
77
|
+
* @returns {MerkleBlock} - A MerkleBlock object
|
|
78
|
+
*/
|
|
79
|
+
MerkleBlock.fromBufferReader = function fromBufferReader(br) {
|
|
80
|
+
return new MerkleBlock(MerkleBlock._fromBufferReader(br));
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @returns {Buffer} - A buffer of the block
|
|
85
|
+
*/
|
|
86
|
+
MerkleBlock.prototype.toBuffer = function toBuffer() {
|
|
87
|
+
return this.toBufferWriter().concat();
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {BufferWriter} - An existing instance of BufferWriter
|
|
92
|
+
* @returns {BufferWriter} - An instance of BufferWriter representation of the MerkleBlock
|
|
93
|
+
*/
|
|
94
|
+
MerkleBlock.prototype.toBufferWriter = function toBufferWriter(bw) {
|
|
95
|
+
if (!bw) {
|
|
96
|
+
bw = new BufferWriter();
|
|
97
|
+
}
|
|
98
|
+
bw.write(this.header.toBuffer());
|
|
99
|
+
bw.writeUInt32LE(this.numTransactions);
|
|
100
|
+
bw.writeVarintNum(this.hashes.length);
|
|
101
|
+
for (var i = 0; i < this.hashes.length; i++) {
|
|
102
|
+
bw.write(Buffer.from(this.hashes[i], 'hex'));
|
|
103
|
+
}
|
|
104
|
+
bw.writeVarintNum(this.flags.length);
|
|
105
|
+
for (i = 0; i < this.flags.length; i++) {
|
|
106
|
+
bw.writeUInt8(this.flags[i]);
|
|
107
|
+
}
|
|
108
|
+
return bw;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @returns {Object} - A plain object with the MerkleBlock properties
|
|
113
|
+
*/
|
|
114
|
+
MerkleBlock.prototype.toObject = MerkleBlock.prototype.toJSON = function toObject() {
|
|
115
|
+
return {
|
|
116
|
+
header: this.header.toObject(),
|
|
117
|
+
numTransactions: this.numTransactions,
|
|
118
|
+
hashes: this.hashes,
|
|
119
|
+
flags: this.flags,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Verify that the MerkleBlock is valid
|
|
125
|
+
* @returns {Boolean} - True/False whether this MerkleBlock is Valid
|
|
126
|
+
*/
|
|
127
|
+
MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
|
|
128
|
+
$.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array');
|
|
129
|
+
$.checkState(_.isArray(this.hashes), 'MerkleBlock hashes is not an array');
|
|
130
|
+
|
|
131
|
+
// Can't have more hashes than numTransactions
|
|
132
|
+
if (this.hashes.length > this.numTransactions) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Can't have more flag bits than num hashes
|
|
137
|
+
if (this.flags.length * 8 < this.hashes.length) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
var height = this._calcTreeHeight();
|
|
142
|
+
var opts = { hashesUsed: 0, flagBitsUsed: 0 };
|
|
143
|
+
var root = this._traverseMerkleTree(height, 0, opts);
|
|
144
|
+
if (opts.hashesUsed !== this.hashes.length) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
return root.equals(this.header.merkleRoot);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* WARNING: This method is deprecated. Use filteredTxsHash instead.
|
|
152
|
+
*
|
|
153
|
+
* Return a list of all the txs hash that match the filter
|
|
154
|
+
* @returns {Array} - txs hash that match the filter
|
|
155
|
+
*/
|
|
156
|
+
MerkleBlock.prototype.filterdTxsHash = function filterdTxsHash() {
|
|
157
|
+
throw new Error('filterdTxsHash has been deprecated. use filteredTxsHash.');
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Return a list of all the txs hash that match the filter
|
|
162
|
+
* @returns {Array} - txs hash that match the filter
|
|
163
|
+
*/
|
|
164
|
+
MerkleBlock.prototype.filteredTxsHash = function filteredTxsHash() {
|
|
165
|
+
$.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array');
|
|
166
|
+
$.checkState(_.isArray(this.hashes), 'MerkleBlock hashes is not an array');
|
|
167
|
+
|
|
168
|
+
// Can't have more hashes than numTransactions
|
|
169
|
+
if (this.hashes.length > this.numTransactions) {
|
|
170
|
+
throw new errors.MerkleBlock.InvalidMerkleTree();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Can't have more flag bits than num hashes
|
|
174
|
+
if (this.flags.length * 8 < this.hashes.length) {
|
|
175
|
+
throw new errors.MerkleBlock.InvalidMerkleTree();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// If there is only one hash the filter do not match any txs in the block
|
|
179
|
+
if (this.hashes.length === 1) {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
var height = this._calcTreeHeight();
|
|
184
|
+
var opts = { hashesUsed: 0, flagBitsUsed: 0 };
|
|
185
|
+
var txs = this._traverseMerkleTree(height, 0, opts, true);
|
|
186
|
+
if (opts.hashesUsed !== this.hashes.length) {
|
|
187
|
+
throw new errors.MerkleBlock.InvalidMerkleTree();
|
|
188
|
+
}
|
|
189
|
+
return txs;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Traverse a the tree in this MerkleBlock, validating it along the way
|
|
194
|
+
* Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract()
|
|
195
|
+
* @param {Number} - depth - Current height
|
|
196
|
+
* @param {Number} - pos - Current position in the tree
|
|
197
|
+
* @param {Object} - opts - Object with values that need to be mutated throughout the traversal
|
|
198
|
+
* @param {Boolean} - checkForTxs - if true return opts.txs else return the Merkle Hash
|
|
199
|
+
* @param {Number} - opts.flagBitsUsed - Number of flag bits used, should start at 0
|
|
200
|
+
* @param {Number} - opts.hashesUsed - Number of hashes used, should start at 0
|
|
201
|
+
* @param {Array} - opts.txs - Will finish populated by transactions found during traversal that match the filter
|
|
202
|
+
* @returns {Buffer|null} - Buffer containing the Merkle Hash for that height
|
|
203
|
+
* @returns {Array} - transactions found during traversal that match the filter
|
|
204
|
+
* @private
|
|
205
|
+
*/
|
|
206
|
+
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(
|
|
207
|
+
depth,
|
|
208
|
+
pos,
|
|
209
|
+
opts,
|
|
210
|
+
checkForTxs,
|
|
211
|
+
) {
|
|
212
|
+
opts = opts || {};
|
|
213
|
+
opts.txs = opts.txs || [];
|
|
214
|
+
opts.flagBitsUsed = opts.flagBitsUsed || 0;
|
|
215
|
+
opts.hashesUsed = opts.hashesUsed || 0;
|
|
216
|
+
checkForTxs = checkForTxs || false;
|
|
217
|
+
|
|
218
|
+
if (opts.flagBitsUsed > this.flags.length * 8) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
var isParentOfMatch = (this.flags[opts.flagBitsUsed >> 3] >>> (opts.flagBitsUsed++ & 7)) & 1;
|
|
222
|
+
if (depth === 0 || !isParentOfMatch) {
|
|
223
|
+
if (opts.hashesUsed >= this.hashes.length) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
var hash = this.hashes[opts.hashesUsed++];
|
|
227
|
+
if (depth === 0 && isParentOfMatch) {
|
|
228
|
+
opts.txs.push(hash);
|
|
229
|
+
}
|
|
230
|
+
return Buffer.from(hash, 'hex');
|
|
231
|
+
} else {
|
|
232
|
+
var left = this._traverseMerkleTree(depth - 1, pos * 2, opts);
|
|
233
|
+
var right = left;
|
|
234
|
+
if (pos * 2 + 1 < this._calcTreeWidth(depth - 1)) {
|
|
235
|
+
right = this._traverseMerkleTree(depth - 1, pos * 2 + 1, opts);
|
|
236
|
+
}
|
|
237
|
+
if (checkForTxs) {
|
|
238
|
+
return opts.txs;
|
|
239
|
+
} else {
|
|
240
|
+
return Hash.sha256sha256(Buffer.concat([left, right]));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/** Calculates the width of a merkle tree at a given height.
|
|
246
|
+
* Modeled after Bitcoin Core merkleblock.h CalcTreeWidth()
|
|
247
|
+
* @param {Number} - Height at which we want the tree width
|
|
248
|
+
* @returns {Number} - Width of the tree at a given height
|
|
249
|
+
* @private
|
|
250
|
+
*/
|
|
251
|
+
MerkleBlock.prototype._calcTreeWidth = function calcTreeWidth(height) {
|
|
252
|
+
return (this.numTransactions + (1 << height) - 1) >> height;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/** Calculates the height of the merkle tree in this MerkleBlock
|
|
256
|
+
* @param {Number} - Height at which we want the tree width
|
|
257
|
+
* @returns {Number} - Height of the merkle tree in this MerkleBlock
|
|
258
|
+
* @private
|
|
259
|
+
*/
|
|
260
|
+
MerkleBlock.prototype._calcTreeHeight = function calcTreeHeight() {
|
|
261
|
+
var height = 0;
|
|
262
|
+
while (this._calcTreeWidth(height) > 1) {
|
|
263
|
+
height++;
|
|
264
|
+
}
|
|
265
|
+
return height;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @param {Transaction|String} - Transaction or Transaction ID Hash
|
|
270
|
+
* @returns {Boolean} - return true/false if this MerkleBlock has the TX or not
|
|
271
|
+
* @private
|
|
272
|
+
*/
|
|
273
|
+
MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) {
|
|
274
|
+
$.checkArgument(!_.isUndefined(tx), 'tx cannot be undefined');
|
|
275
|
+
$.checkArgument(
|
|
276
|
+
tx instanceof Transaction || typeof tx === 'string',
|
|
277
|
+
'Invalid tx given, tx must be a "string" or "Transaction"',
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
var hash = tx;
|
|
281
|
+
if (tx instanceof Transaction) {
|
|
282
|
+
// We need to reverse the id hash for the lookup
|
|
283
|
+
hash = Buffer.from(tx.id, 'hex').reverse().toString('hex');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
var txs = [];
|
|
287
|
+
var height = this._calcTreeHeight();
|
|
288
|
+
this._traverseMerkleTree(height, 0, { txs: txs });
|
|
289
|
+
return txs.indexOf(hash) !== -1;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @param {Buffer} - MerkleBlock data
|
|
294
|
+
* @returns {Object} - An Object representing merkleblock data
|
|
295
|
+
* @private
|
|
296
|
+
*/
|
|
297
|
+
MerkleBlock._fromBufferReader = function _fromBufferReader(br) {
|
|
298
|
+
$.checkState(!br.finished(), 'No merkleblock data received');
|
|
299
|
+
var info = {};
|
|
300
|
+
info.header = BlockHeader.fromBufferReader(br);
|
|
301
|
+
info.numTransactions = br.readUInt32LE();
|
|
302
|
+
var numHashes = br.readVarintNum();
|
|
303
|
+
info.hashes = [];
|
|
304
|
+
for (var i = 0; i < numHashes; i++) {
|
|
305
|
+
info.hashes.push(br.read(32).toString('hex'));
|
|
306
|
+
}
|
|
307
|
+
var numFlags = br.readVarintNum();
|
|
308
|
+
info.flags = [];
|
|
309
|
+
for (i = 0; i < numFlags; i++) {
|
|
310
|
+
info.flags.push(br.readUInt8());
|
|
311
|
+
}
|
|
312
|
+
return info;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* @param {Object} - A plain JavaScript object
|
|
317
|
+
* @returns {Block} - An instance of block
|
|
318
|
+
*/
|
|
319
|
+
MerkleBlock.fromObject = function fromObject(obj) {
|
|
320
|
+
return new MerkleBlock(obj);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
module.exports = MerkleBlock;
|