@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,277 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('../util/_');
|
|
4
|
+
var BlockHeader = require('./blockheader');
|
|
5
|
+
var BN = require('../crypto/bn');
|
|
6
|
+
var BufferReader = require('../encoding/bufferreader');
|
|
7
|
+
var BufferWriter = require('../encoding/bufferwriter');
|
|
8
|
+
var Hash = require('../crypto/hash');
|
|
9
|
+
var Transaction = require('../transaction');
|
|
10
|
+
var $ = require('../util/preconditions');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Instantiate a Block from a Buffer, JSON object, or Object with
|
|
14
|
+
* the properties of the Block
|
|
15
|
+
*
|
|
16
|
+
* @param {*} - A Buffer, JSON string, or Object
|
|
17
|
+
* @returns {Block}
|
|
18
|
+
* @constructor
|
|
19
|
+
*/
|
|
20
|
+
function Block(arg) {
|
|
21
|
+
if (!(this instanceof Block)) {
|
|
22
|
+
return new Block(arg);
|
|
23
|
+
}
|
|
24
|
+
_.extend(this, Block._from(arg));
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Block.MAX_BLOCK_SIZE = 128000000;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {*} - A Buffer, JSON string or Object
|
|
32
|
+
* @returns {Object} - An object representing block data
|
|
33
|
+
* @throws {TypeError} - If the argument was not recognized
|
|
34
|
+
* @private
|
|
35
|
+
*/
|
|
36
|
+
Block._from = function _from(arg) {
|
|
37
|
+
var info = {};
|
|
38
|
+
if (Buffer.isBuffer(arg)) {
|
|
39
|
+
info = Block._fromBufferReader(BufferReader(arg));
|
|
40
|
+
} else if (_.isObject(arg)) {
|
|
41
|
+
info = Block._fromObject(arg);
|
|
42
|
+
} else {
|
|
43
|
+
throw new TypeError('Unrecognized argument for Block');
|
|
44
|
+
}
|
|
45
|
+
return info;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {Object} - A plain JavaScript object
|
|
50
|
+
* @returns {Object} - An object representing block data
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
Block._fromObject = function _fromObject(data) {
|
|
54
|
+
var transactions = [];
|
|
55
|
+
data.transactions.forEach(function (tx) {
|
|
56
|
+
if (tx instanceof Transaction) {
|
|
57
|
+
transactions.push(tx);
|
|
58
|
+
} else {
|
|
59
|
+
transactions.push(Transaction().fromObject(tx));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
var info = {
|
|
63
|
+
header: BlockHeader.fromObject(data.header),
|
|
64
|
+
transactions: transactions,
|
|
65
|
+
};
|
|
66
|
+
return info;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {Object} - A plain JavaScript object
|
|
71
|
+
* @returns {Block} - An instance of block
|
|
72
|
+
*/
|
|
73
|
+
Block.fromObject = function fromObject(obj) {
|
|
74
|
+
var info = Block._fromObject(obj);
|
|
75
|
+
return new Block(info);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {BufferReader} - Block data
|
|
80
|
+
* @returns {Object} - An object representing the block data
|
|
81
|
+
* @private
|
|
82
|
+
*/
|
|
83
|
+
Block._fromBufferReader = function _fromBufferReader(br) {
|
|
84
|
+
var info = {};
|
|
85
|
+
$.checkState(!br.finished(), 'No block data received');
|
|
86
|
+
info.header = BlockHeader.fromBufferReader(br);
|
|
87
|
+
var transactions = br.readVarintNum();
|
|
88
|
+
info.transactions = [];
|
|
89
|
+
for (var i = 0; i < transactions; i++) {
|
|
90
|
+
info.transactions.push(Transaction().fromBufferReader(br));
|
|
91
|
+
}
|
|
92
|
+
return info;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @param {BufferReader} - A buffer reader of the block
|
|
97
|
+
* @returns {Block} - An instance of block
|
|
98
|
+
*/
|
|
99
|
+
Block.fromBufferReader = function fromBufferReader(br) {
|
|
100
|
+
$.checkArgument(br, 'br is required');
|
|
101
|
+
var info = Block._fromBufferReader(br);
|
|
102
|
+
return new Block(info);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param {Buffer} - A buffer of the block
|
|
107
|
+
* @returns {Block} - An instance of block
|
|
108
|
+
*/
|
|
109
|
+
Block.fromBuffer = function fromBuffer(buf) {
|
|
110
|
+
return Block.fromBufferReader(new BufferReader(buf));
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @param {string} - str - A hex encoded string of the block
|
|
115
|
+
* @returns {Block} - A hex encoded string of the block
|
|
116
|
+
*/
|
|
117
|
+
Block.fromString = function fromString(str) {
|
|
118
|
+
var buf = Buffer.from(str, 'hex');
|
|
119
|
+
return Block.fromBuffer(buf);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {Binary} - Raw block binary data or buffer
|
|
124
|
+
* @returns {Block} - An instance of block
|
|
125
|
+
*/
|
|
126
|
+
Block.fromRawBlock = function fromRawBlock(data) {
|
|
127
|
+
if (!Buffer.isBuffer(data)) {
|
|
128
|
+
data = Buffer.from(data, 'binary');
|
|
129
|
+
}
|
|
130
|
+
var br = BufferReader(data);
|
|
131
|
+
br.pos = Block.Values.START_OF_BLOCK;
|
|
132
|
+
var info = Block._fromBufferReader(br);
|
|
133
|
+
return new Block(info);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @returns {Object} - A plain object with the block properties
|
|
138
|
+
*/
|
|
139
|
+
Block.prototype.toObject = Block.prototype.toJSON = function toObject() {
|
|
140
|
+
var transactions = [];
|
|
141
|
+
this.transactions.forEach(function (tx) {
|
|
142
|
+
transactions.push(tx.toObject());
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
header: this.header.toObject(),
|
|
146
|
+
transactions: transactions,
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @returns {Buffer} - A buffer of the block
|
|
152
|
+
*/
|
|
153
|
+
Block.prototype.toBuffer = function toBuffer() {
|
|
154
|
+
return this.toBufferWriter().concat();
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @returns {string} - A hex encoded string of the block
|
|
159
|
+
*/
|
|
160
|
+
Block.prototype.toString = function toString() {
|
|
161
|
+
return this.toBuffer().toString('hex');
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @param {BufferWriter} - An existing instance of BufferWriter
|
|
166
|
+
* @returns {BufferWriter} - An instance of BufferWriter representation of the Block
|
|
167
|
+
*/
|
|
168
|
+
Block.prototype.toBufferWriter = function toBufferWriter(bw) {
|
|
169
|
+
if (!bw) {
|
|
170
|
+
bw = new BufferWriter();
|
|
171
|
+
}
|
|
172
|
+
bw.write(this.header.toBuffer());
|
|
173
|
+
bw.writeVarintNum(this.transactions.length);
|
|
174
|
+
for (var i = 0; i < this.transactions.length; i++) {
|
|
175
|
+
this.transactions[i].toBufferWriter(false, bw);
|
|
176
|
+
}
|
|
177
|
+
return bw;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Will iterate through each transaction and return an array of hashes
|
|
182
|
+
* @returns {Array} - An array with transaction hashes
|
|
183
|
+
*/
|
|
184
|
+
Block.prototype.getTransactionHashes = function getTransactionHashes() {
|
|
185
|
+
var hashes = [];
|
|
186
|
+
if (this.transactions.length === 0) {
|
|
187
|
+
return [Block.Values.NULL_HASH];
|
|
188
|
+
}
|
|
189
|
+
for (var t = 0; t < this.transactions.length; t++) {
|
|
190
|
+
hashes.push(this.transactions[t]._getHash());
|
|
191
|
+
}
|
|
192
|
+
return hashes;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Will build a merkle tree of all the transactions, ultimately arriving at
|
|
197
|
+
* a single point, the merkle root.
|
|
198
|
+
* @link https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees
|
|
199
|
+
* @returns {Array} - An array with each level of the tree after the other.
|
|
200
|
+
*/
|
|
201
|
+
Block.prototype.getMerkleTree = function getMerkleTree() {
|
|
202
|
+
var tree = this.getTransactionHashes();
|
|
203
|
+
|
|
204
|
+
var j = 0;
|
|
205
|
+
for (var size = this.transactions.length; size > 1; size = Math.floor((size + 1) / 2)) {
|
|
206
|
+
for (var i = 0; i < size; i += 2) {
|
|
207
|
+
var i2 = Math.min(i + 1, size - 1);
|
|
208
|
+
var buf = Buffer.concat([tree[j + i], tree[j + i2]]);
|
|
209
|
+
tree.push(Hash.sha256sha256(buf));
|
|
210
|
+
}
|
|
211
|
+
j += size;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return tree;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Calculates the merkleRoot from the transactions.
|
|
219
|
+
* @returns {Buffer} - A buffer of the merkle root hash
|
|
220
|
+
*/
|
|
221
|
+
Block.prototype.getMerkleRoot = function getMerkleRoot() {
|
|
222
|
+
var tree = this.getMerkleTree();
|
|
223
|
+
return tree[tree.length - 1];
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Verifies that the transactions in the block match the header merkle root
|
|
228
|
+
* @returns {Boolean} - If the merkle roots match
|
|
229
|
+
*/
|
|
230
|
+
Block.prototype.validMerkleRoot = function validMerkleRoot() {
|
|
231
|
+
var h = new BN(this.header.merkleRoot.toString('hex'), 'hex');
|
|
232
|
+
var c = new BN(this.getMerkleRoot().toString('hex'), 'hex');
|
|
233
|
+
|
|
234
|
+
if (h.cmp(c) !== 0) {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return true;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @returns {Buffer} - The little endian hash buffer of the header
|
|
243
|
+
*/
|
|
244
|
+
Block.prototype._getHash = function () {
|
|
245
|
+
return this.header._getHash();
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
var idProperty = {
|
|
249
|
+
configurable: false,
|
|
250
|
+
enumerable: true,
|
|
251
|
+
/**
|
|
252
|
+
* @returns {string} - The big endian hash buffer of the header
|
|
253
|
+
*/
|
|
254
|
+
get: function () {
|
|
255
|
+
if (!this._id) {
|
|
256
|
+
this._id = this.header.id;
|
|
257
|
+
}
|
|
258
|
+
return this._id;
|
|
259
|
+
},
|
|
260
|
+
set: _.noop,
|
|
261
|
+
};
|
|
262
|
+
Object.defineProperty(Block.prototype, 'id', idProperty);
|
|
263
|
+
Object.defineProperty(Block.prototype, 'hash', idProperty);
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @returns {string} - A string formatted for the console
|
|
267
|
+
*/
|
|
268
|
+
Block.prototype.inspect = function inspect() {
|
|
269
|
+
return '<Block ' + this.id + '>';
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
Block.Values = {
|
|
273
|
+
START_OF_BLOCK: 8, // Start of block in raw block data
|
|
274
|
+
NULL_HASH: Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'),
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
module.exports = Block;
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('../util/_');
|
|
4
|
+
var BN = require('../crypto/bn');
|
|
5
|
+
var BufferReader = require('../encoding/bufferreader');
|
|
6
|
+
var BufferWriter = require('../encoding/bufferwriter');
|
|
7
|
+
var Hash = require('../crypto/hash');
|
|
8
|
+
var $ = require('../util/preconditions');
|
|
9
|
+
|
|
10
|
+
var GENESIS_BITS = 0x1d00ffff;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Instantiate a BlockHeader from a Buffer, JSON object, or Object with
|
|
14
|
+
* the properties of the BlockHeader
|
|
15
|
+
*
|
|
16
|
+
* @param {*} - A Buffer, JSON string, or Object
|
|
17
|
+
* @returns {BlockHeader} - An instance of block header
|
|
18
|
+
* @constructor
|
|
19
|
+
*/
|
|
20
|
+
var BlockHeader = function BlockHeader(arg) {
|
|
21
|
+
if (!(this instanceof BlockHeader)) {
|
|
22
|
+
return new BlockHeader(arg);
|
|
23
|
+
}
|
|
24
|
+
var info = BlockHeader._from(arg);
|
|
25
|
+
this.version = info.version;
|
|
26
|
+
this.prevHash = info.prevHash;
|
|
27
|
+
this.merkleRoot = info.merkleRoot;
|
|
28
|
+
this.time = info.time;
|
|
29
|
+
this.timestamp = info.time;
|
|
30
|
+
this.bits = info.bits;
|
|
31
|
+
this.nonce = info.nonce;
|
|
32
|
+
|
|
33
|
+
if (info.hash) {
|
|
34
|
+
$.checkState(
|
|
35
|
+
this.hash === info.hash,
|
|
36
|
+
'Argument object hash property does not match block hash.',
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return this;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {*} - A Buffer, JSON string or Object
|
|
45
|
+
* @returns {Object} - An object representing block header data
|
|
46
|
+
* @throws {TypeError} - If the argument was not recognized
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
BlockHeader._from = function _from(arg) {
|
|
50
|
+
var info = {};
|
|
51
|
+
if (Buffer.isBuffer(arg)) {
|
|
52
|
+
info = BlockHeader._fromBufferReader(BufferReader(arg));
|
|
53
|
+
} else if (_.isObject(arg)) {
|
|
54
|
+
info = BlockHeader._fromObject(arg);
|
|
55
|
+
} else {
|
|
56
|
+
throw new TypeError('Unrecognized argument for BlockHeader');
|
|
57
|
+
}
|
|
58
|
+
return info;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {Object} - A JSON string
|
|
63
|
+
* @returns {Object} - An object representing block header data
|
|
64
|
+
* @private
|
|
65
|
+
*/
|
|
66
|
+
BlockHeader._fromObject = function _fromObject(data) {
|
|
67
|
+
$.checkArgument(data, 'data is required');
|
|
68
|
+
var prevHash = data.prevHash;
|
|
69
|
+
var merkleRoot = data.merkleRoot;
|
|
70
|
+
if (_.isString(data.prevHash)) {
|
|
71
|
+
prevHash = Buffer.from(data.prevHash, 'hex').reverse();
|
|
72
|
+
}
|
|
73
|
+
if (_.isString(data.merkleRoot)) {
|
|
74
|
+
merkleRoot = Buffer.from(data.merkleRoot, 'hex').reverse();
|
|
75
|
+
}
|
|
76
|
+
var info = {
|
|
77
|
+
hash: data.hash,
|
|
78
|
+
version: data.version,
|
|
79
|
+
prevHash: prevHash,
|
|
80
|
+
merkleRoot: merkleRoot,
|
|
81
|
+
time: data.time,
|
|
82
|
+
timestamp: data.time,
|
|
83
|
+
bits: data.bits,
|
|
84
|
+
nonce: data.nonce,
|
|
85
|
+
};
|
|
86
|
+
return info;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {Object} - A plain JavaScript object
|
|
91
|
+
* @returns {BlockHeader} - An instance of block header
|
|
92
|
+
*/
|
|
93
|
+
BlockHeader.fromObject = function fromObject(obj) {
|
|
94
|
+
var info = BlockHeader._fromObject(obj);
|
|
95
|
+
return new BlockHeader(info);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param {Binary} - Raw block binary data or buffer
|
|
100
|
+
* @returns {BlockHeader} - An instance of block header
|
|
101
|
+
*/
|
|
102
|
+
BlockHeader.fromRawBlock = function fromRawBlock(data) {
|
|
103
|
+
if (!Buffer.isBuffer(data)) {
|
|
104
|
+
data = Buffer.from(data, 'binary');
|
|
105
|
+
}
|
|
106
|
+
var br = BufferReader(data);
|
|
107
|
+
br.pos = BlockHeader.Constants.START_OF_HEADER;
|
|
108
|
+
var info = BlockHeader._fromBufferReader(br);
|
|
109
|
+
return new BlockHeader(info);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @param {Buffer} - A buffer of the block header
|
|
114
|
+
* @returns {BlockHeader} - An instance of block header
|
|
115
|
+
*/
|
|
116
|
+
BlockHeader.fromBuffer = function fromBuffer(buf) {
|
|
117
|
+
var info = BlockHeader._fromBufferReader(BufferReader(buf));
|
|
118
|
+
return new BlockHeader(info);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @param {string} - A hex encoded buffer of the block header
|
|
123
|
+
* @returns {BlockHeader} - An instance of block header
|
|
124
|
+
*/
|
|
125
|
+
BlockHeader.fromString = function fromString(str) {
|
|
126
|
+
var buf = Buffer.from(str, 'hex');
|
|
127
|
+
return BlockHeader.fromBuffer(buf);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {BufferReader} - A BufferReader of the block header
|
|
132
|
+
* @returns {Object} - An object representing block header data
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
BlockHeader._fromBufferReader = function _fromBufferReader(br) {
|
|
136
|
+
var info = {};
|
|
137
|
+
info.version = br.readInt32LE();
|
|
138
|
+
info.prevHash = br.read(32);
|
|
139
|
+
info.merkleRoot = br.read(32);
|
|
140
|
+
info.time = br.readUInt32LE();
|
|
141
|
+
info.bits = br.readUInt32LE();
|
|
142
|
+
info.nonce = br.readUInt32LE();
|
|
143
|
+
return info;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @param {BufferReader} - A BufferReader of the block header
|
|
148
|
+
* @returns {BlockHeader} - An instance of block header
|
|
149
|
+
*/
|
|
150
|
+
BlockHeader.fromBufferReader = function fromBufferReader(br) {
|
|
151
|
+
var info = BlockHeader._fromBufferReader(br);
|
|
152
|
+
return new BlockHeader(info);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @returns {Object} - A plain object of the BlockHeader
|
|
157
|
+
*/
|
|
158
|
+
BlockHeader.prototype.toObject = BlockHeader.prototype.toJSON = function toObject() {
|
|
159
|
+
return {
|
|
160
|
+
hash: this.hash,
|
|
161
|
+
version: this.version,
|
|
162
|
+
prevHash: Buffer.from(this.prevHash).reverse().toString('hex'),
|
|
163
|
+
merkleRoot: Buffer.from(this.merkleRoot).reverse().toString('hex'),
|
|
164
|
+
time: this.time,
|
|
165
|
+
bits: this.bits,
|
|
166
|
+
nonce: this.nonce,
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @returns {Buffer} - A Buffer of the BlockHeader
|
|
172
|
+
*/
|
|
173
|
+
BlockHeader.prototype.toBuffer = function toBuffer() {
|
|
174
|
+
return this.toBufferWriter().concat();
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @returns {string} - A hex encoded string of the BlockHeader
|
|
179
|
+
*/
|
|
180
|
+
BlockHeader.prototype.toString = function toString() {
|
|
181
|
+
return this.toBuffer().toString('hex');
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param {BufferWriter} - An existing instance BufferWriter
|
|
186
|
+
* @returns {BufferWriter} - An instance of BufferWriter representation of the BlockHeader
|
|
187
|
+
*/
|
|
188
|
+
BlockHeader.prototype.toBufferWriter = function toBufferWriter(bw) {
|
|
189
|
+
if (!bw) {
|
|
190
|
+
bw = new BufferWriter();
|
|
191
|
+
}
|
|
192
|
+
bw.writeInt32LE(this.version);
|
|
193
|
+
bw.write(this.prevHash);
|
|
194
|
+
bw.write(this.merkleRoot);
|
|
195
|
+
bw.writeUInt32LE(this.time);
|
|
196
|
+
bw.writeUInt32LE(this.bits);
|
|
197
|
+
bw.writeUInt32LE(this.nonce);
|
|
198
|
+
return bw;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Returns the target difficulty for this block
|
|
203
|
+
* @param {Number} bits
|
|
204
|
+
* @returns {BN} An instance of BN with the decoded difficulty bits
|
|
205
|
+
*/
|
|
206
|
+
BlockHeader.prototype.getTargetDifficulty = function getTargetDifficulty(bits) {
|
|
207
|
+
bits = bits || this.bits;
|
|
208
|
+
|
|
209
|
+
var target = new BN(bits & 0xffffff);
|
|
210
|
+
var mov = 8 * ((bits >>> 24) - 3);
|
|
211
|
+
while (mov-- > 0) {
|
|
212
|
+
target = target.mul(new BN(2));
|
|
213
|
+
}
|
|
214
|
+
return target;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @link https://en.bitcoin.it/wiki/Difficulty
|
|
219
|
+
* @return {Number}
|
|
220
|
+
*/
|
|
221
|
+
BlockHeader.prototype.getDifficulty = function getDifficulty() {
|
|
222
|
+
var difficulty1TargetBN = this.getTargetDifficulty(GENESIS_BITS).mul(new BN(Math.pow(10, 8)));
|
|
223
|
+
var currentTargetBN = this.getTargetDifficulty();
|
|
224
|
+
|
|
225
|
+
var difficultyString = difficulty1TargetBN.div(currentTargetBN).toString(10);
|
|
226
|
+
var decimalPos = difficultyString.length - 8;
|
|
227
|
+
difficultyString =
|
|
228
|
+
difficultyString.slice(0, decimalPos) + '.' + difficultyString.slice(decimalPos);
|
|
229
|
+
|
|
230
|
+
return parseFloat(difficultyString);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @returns {Buffer} - The little endian hash buffer of the header
|
|
235
|
+
*/
|
|
236
|
+
BlockHeader.prototype._getHash = function hash() {
|
|
237
|
+
var buf = this.toBuffer();
|
|
238
|
+
return Hash.sha256sha256(buf);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
var idProperty = {
|
|
242
|
+
configurable: false,
|
|
243
|
+
enumerable: true,
|
|
244
|
+
/**
|
|
245
|
+
* @returns {string} - The big endian hash buffer of the header
|
|
246
|
+
*/
|
|
247
|
+
get: function () {
|
|
248
|
+
if (!this._id) {
|
|
249
|
+
this._id = BufferReader(this._getHash()).readReverse().toString('hex');
|
|
250
|
+
}
|
|
251
|
+
return this._id;
|
|
252
|
+
},
|
|
253
|
+
set: _.noop,
|
|
254
|
+
};
|
|
255
|
+
Object.defineProperty(BlockHeader.prototype, 'id', idProperty);
|
|
256
|
+
Object.defineProperty(BlockHeader.prototype, 'hash', idProperty);
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @returns {Boolean} - If timestamp is not too far in the future
|
|
260
|
+
*/
|
|
261
|
+
BlockHeader.prototype.validTimestamp = function validTimestamp() {
|
|
262
|
+
var currentTime = Math.round(new Date().getTime() / 1000);
|
|
263
|
+
if (this.time > currentTime + BlockHeader.Constants.MAX_TIME_OFFSET) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
return true;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @returns {Boolean} - If the proof-of-work hash satisfies the target difficulty
|
|
271
|
+
*/
|
|
272
|
+
BlockHeader.prototype.validProofOfWork = function validProofOfWork() {
|
|
273
|
+
var pow = new BN(this.id, 'hex');
|
|
274
|
+
var target = this.getTargetDifficulty();
|
|
275
|
+
|
|
276
|
+
if (pow.cmp(target) > 0) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
return true;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @returns {string} - A string formatted for the console
|
|
284
|
+
*/
|
|
285
|
+
BlockHeader.prototype.inspect = function inspect() {
|
|
286
|
+
return '<BlockHeader ' + this.id + '>';
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
BlockHeader.Constants = {
|
|
290
|
+
START_OF_HEADER: 8, // Start buffer position in raw block data
|
|
291
|
+
MAX_TIME_OFFSET: 2 * 60 * 60, // The max a timestamp can be in the future
|
|
292
|
+
LARGEST_HASH: new BN('10000000000000000000000000000000000000000000000000000000000000000', 'hex'),
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
module.exports = BlockHeader;
|