forked from bitcoinjs/bitcoinjs-lib
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
274 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ coverage | |
node_modules | ||
.nyc_output | ||
npm-debug.log | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// Bitcoin Gold (BTG) block header has differences compared to Bitcoin block headers | ||
// https://github.com/BTCGPU/BTCGPU/wiki/Technical-Spec | ||
|
||
var Buffer = require('safe-buffer').Buffer | ||
var varuint = require('varuint-bitcoin') | ||
|
||
var Transaction = require('./transaction') | ||
var Block = require('./block') | ||
|
||
function BlockGold () { | ||
this.version = 1 | ||
this.prevHash = null | ||
this.merkleRoot = null | ||
this.height = 0 | ||
this.reserved = null | ||
this.timestamp = 0 | ||
this.bits = 0 | ||
this.nonce = null | ||
this.solutionLength = 0 | ||
this.solution = null | ||
this.transactions = [] | ||
} | ||
|
||
BlockGold.prototype = Object.create(Block.prototype) | ||
|
||
BlockGold.fromBuffer = function (buffer) { | ||
if (buffer.length < 140) throw new Error('Buffer too small (< 140 bytes)') | ||
|
||
var offset = 0 | ||
function readSlice (n) { | ||
offset += n | ||
return buffer.slice(offset - n, offset) | ||
} | ||
|
||
function readUInt32 () { | ||
var i = buffer.readUInt32LE(offset) | ||
offset += 4 | ||
return i | ||
} | ||
|
||
function readInt32 () { | ||
var i = buffer.readInt32LE(offset) | ||
offset += 4 | ||
return i | ||
} | ||
|
||
function readVarInt () { | ||
var vi = varuint.decode(buffer, offset) | ||
offset += varuint.decode.bytes | ||
return vi | ||
} | ||
|
||
var block = new BlockGold() | ||
block.version = readInt32() | ||
block.prevHash = readSlice(32) | ||
block.merkleRoot = readSlice(32) | ||
block.height = readUInt32() | ||
block.reserved = readSlice(28) | ||
block.timestamp = readUInt32() | ||
block.bits = readUInt32() | ||
block.nonce = readSlice(32) | ||
block.solutionLength = readVarInt() | ||
block.solution = readSlice(block.solutionLength) | ||
|
||
if(buffer.length == offset) { | ||
return block; | ||
} | ||
|
||
function readTransaction () { | ||
var tx = Transaction.fromBuffer(buffer.slice(offset), true) | ||
offset += tx.byteLength() | ||
return tx | ||
} | ||
|
||
var nTransactions = readVarInt() | ||
block.transactions = [] | ||
|
||
for (var i = 0; i < nTransactions; ++i) { | ||
var tx = readTransaction() | ||
block.transactions.push(tx) | ||
} | ||
|
||
return block | ||
} | ||
|
||
BlockGold.prototype.byteLength = function (headersOnly) { | ||
// Solution can have different size, for regtest/testnet is arround 140-170, for mainnet 1400-1500 | ||
var headerSize = 140 + varuint.encodingLength(this.solutionLength) + this.solution.length | ||
if (headersOnly || !this.transactions) return headerSize | ||
|
||
return headerSize + varuint.encodingLength(this.transactions.length) + this.transactions.reduce(function (a, x) { | ||
return a + x.byteLength() | ||
}, 0) | ||
} | ||
|
||
BlockGold.fromHex = function (hex) { | ||
return BlockGold.fromBuffer(Buffer.from(hex, 'hex')) | ||
} | ||
|
||
// TODO: buffer, offset compatibility | ||
BlockGold.prototype.toBuffer = function (headersOnly) { | ||
var buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)) | ||
|
||
var offset = 0 | ||
function writeSlice (slice) { | ||
slice.copy(buffer, offset) | ||
offset += slice.length | ||
} | ||
|
||
function writeInt32 (i) { | ||
buffer.writeInt32LE(i, offset) | ||
offset += 4 | ||
} | ||
function writeUInt32 (i) { | ||
buffer.writeUInt32LE(i, offset) | ||
offset += 4 | ||
} | ||
|
||
writeInt32(this.version) | ||
writeSlice(this.prevHash) | ||
writeSlice(this.merkleRoot) | ||
writeInt32(this.height) | ||
writeSlice(this.reserved) | ||
writeUInt32(this.timestamp) | ||
writeUInt32(this.bits) | ||
writeSlice(this.nonce) | ||
varuint.encode(this.solutionLength, buffer, offset) | ||
offset += varuint.encode.bytes | ||
writeSlice(this.solution) | ||
|
||
if (headersOnly || !this.transactions) return buffer | ||
|
||
varuint.encode(this.transactions.length, buffer, offset) | ||
offset += varuint.encode.bytes | ||
|
||
this.transactions.forEach(function (tx) { | ||
var txSize = tx.byteLength() // TODO: extract from toBuffer? | ||
tx.toBuffer(buffer, offset) | ||
offset += txSize | ||
}) | ||
|
||
return buffer | ||
} | ||
|
||
BlockGold.prototype.toHex = function (headersOnly) { | ||
return this.toBuffer(headersOnly).toString('hex') | ||
} | ||
|
||
module.exports = BlockGold |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* global describe, it, beforeEach */ | ||
|
||
var assert = require('assert') | ||
var BlockGold = require('../src/block_gold') | ||
|
||
var fixtures = require('./fixtures/block_gold') | ||
|
||
describe('BlockGold', function () { | ||
var bufferToLittleEndian = function(buffer) { | ||
return buffer.toString('hex').match(/.{2}/g).reverse().join(""); | ||
} | ||
|
||
describe('fromBuffer/fromHex', function () { | ||
fixtures.valid.forEach(function (f) { | ||
it('imports ' + f.description, function () { | ||
var block = BlockGold.fromHex(f.hex) | ||
|
||
assert.strictEqual(block.version, f.version) | ||
assert.strictEqual(bufferToLittleEndian(block.prevHash), f.previousblockhash) | ||
assert.strictEqual(bufferToLittleEndian(block.merkleRoot), f.merkleroot) | ||
assert.strictEqual(block.height, f.height) | ||
assert.strictEqual(block.timestamp, f.time) | ||
assert.strictEqual(block.bits.toString(16), f.bits) | ||
assert.strictEqual(bufferToLittleEndian(block.nonce), f.nonce) | ||
assert.strictEqual(block.solution.toString('hex'), f.solution) | ||
assert.strictEqual(block.transactions.length, f.tx !== undefined ? f.tx.length : 0) | ||
}) | ||
}) | ||
|
||
fixtures.invalid.forEach(function (f) { | ||
it('throws on ' + f.exception, function () { | ||
assert.throws(function () { | ||
BlockGold.fromHex(f.hex) | ||
}, new RegExp(f.exception)) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('toBuffer/toHex', function () { | ||
fixtures.valid.forEach(function (f) { | ||
var block | ||
|
||
beforeEach(function () { | ||
block = BlockGold.fromHex(f.hex) | ||
}) | ||
|
||
it('exports ' + f.description, function () { | ||
var size = block.byteLength(true) | ||
assert.strictEqual(block.toHex(true), f.hex.slice(0, size * 2)) | ||
assert.strictEqual(block.toHex(), f.hex) | ||
}) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
{ | ||
"valid": [ | ||
{ | ||
"description": "Block after fork", | ||
"hash": "3b4489c87ee1ef257c2d2466aa6f5ac5dd6b5366daa4eeab558d48d8b09726c6", | ||
"confirmations": 1, | ||
"strippedsize": 1653, | ||
"size": 1689, | ||
"weight": 6648, | ||
"height": 2642, | ||
"version": 536870912, | ||
"versionHex": "20000000", | ||
"merkleroot": "75c336fe3deaa1cd3489a565d82515ad2e357bd8b7570d343059fbd67f944925", | ||
"tx": [ | ||
"3df0fe004bf7edeee53b880fa067886d799e7c33a5fcf0a292e3e510cfd1b755", | ||
"7d9aa686aabc37e19e1430c3ceb264b2b1ba7fcc65de6eb149c902187d201dbf" | ||
], | ||
"time": 1521884416, | ||
"mediantime": 1521884100, | ||
"nonceUint32": 3752984584, | ||
"nonce": "00000cf3b5bff6d1c7e873105c2557ca719319b07578452c6f697bf7dfb20008", | ||
"bits": "207fffff", | ||
"difficulty": 1, | ||
"chainwork": "00000000000000000000000000000000000000000000000000000000000014a6", | ||
"previousblockhash": "57754aa42cbc3bdd14641cce8c706be52f805c00318e46260de465c90520f327", | ||
"solution": "015e17d74197a1a5770fbd0db7249592b7830f12235c54747a19882740193d578f8a1181", | ||
"hex": "0000002027f32005c965e40d26468e31005c802fe56b708cce1c6414dd3bbc2ca44a75572549947fd6fb5930340d57b7d87b352ead1525d865a58934cda1ea3dfe36c375520a000000000000000000000000000000000000000000000000000000000000001db65affff7f200800b2dff77b696f2c457875b0199371ca57255c1073e8c7d1f6bfb5f30c000024015e17d74197a1a5770fbd0db7249592b7830f12235c54747a19882740193d578f8a118102020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502520a0101ffffffff0212fd000000000000232103707b1a27beefbe73af0ae987cf619aea035986086b359b67c3995f055ff46cf3ac0000000000000000266a24aa21a9edcf889e29fd0c274f50036881e4d7996f362caa1a751ae7b1cd93428a774485a20120000000000000000000000000000000000000000000000000000000000000000000000000020000000b3603cf17b3daba99f8212a49e745fe24fbe0694fb849775d96bad9a88eae7f4200000000494830450221009a423285612ce32196d0f41561def11e4d323d4944ff37e48f5fcc2b92dd31b002204ab16e67b7fae0b2bd19c5e4c8d60d8a909c725379ee1359c1a6b18b49835fc141feffffff458c691b57d73f1d6b70b146ebf6631ade07fa466b5fdc47c48ca8d05b12044a000000004847304402204b4e079c99a48af5146db5efb604b7562673db3c55cc65c15169b35c6c4a6122022059f2cdb74603ed407ea1159baab9c5c4d6d2debb51ce140023bf0aeb4d16338141feffffff86175df97b97b39464a2c7ad92a99600341d1aff0cf3a209edb645257a22d36d00000000494830450221008a1a684cbb342ae030891712cf9f47aa6b8141c413524979523b93d37c81bd82022076036843d119b2c39f60522aea5cb52706d9afb48b89660a03591597daee6d8c41feffffffaf54dd048f5f908f461c5999e341506487ece49c96e663fe31b702ce94a590e90000000049483045022100fd5144e1ddb525024861aa4121591a0fad6522ff2afc456536c00ad8dca6705c0220535932204d51463ae3c4c97af8c59b0845dfb539da8464be70ce67cf30b2caf341feffffffbe1a68dce296f3efa49a828f7e9e164234cc547703da71663f3ef64a1a7c06270000000048473044022052c4dde9d233f8149d8857f79fd3ae6315b9878a7eed9f694c968d4eecc855d50220476a17c0ef2efaee4469d6aaccc5447b1575c81d046d49929bc6e3b5f7c10bf041feffffffc0ded54f80488a1fe8dc595f54cbf96e787c994b380c041aea461c0c69d0d40e0000000049483045022100ed414e016e9dc5d569af473ef84a6fc15094c7c77e7c78c8a55dfe8a573f81c302201c04257cd23185e45578d4c4723f3018602306ad1b2bad91ae8a827f6184906b41feffffffd6f5665fa7c808d4e5f0f392b36aef52a18ad50fef2f6afa4f5ff53105235a4c00000000484730440220353e0011b8da92be6bdf9e8f84b657bb461ac5bd2aadd722253920e8dea5d6c1022051d533e36f2ddb63d4c4d8d2a56f81f32749b3d32076897bb97ff1a67a0b6fad41feffffffe9c7dc8a6eaad9aac5862e599e8c92c4955dabba7efb671f791377615dcdc4820000000048473044022100ca3398a3e21b15933f40edb5fa9eb1a1cfc6893bc04cd42abb4d418b4f1c82b8021f34b5d49e561fa53c850042622848d5db862a1f9663d75e92df5ba2e4d139d641feffffffea82d857ef36e4b9fee80dfdf8485539f829509ea157b83457d2587638af57300000000049483045022100ae501b0f8cd4ce2fb71cb4da168954f53e84cc6bf1f0e48c8f3d0b21344507e302206df3b2d05746caf1f194ac6909f41bf84fc9639ce8a4278f71a45dbae814c18341fefffffff12964d7dfa345e9fee8a973fc7e8cbd12e3ebd0233d45d139f0acb5def8b4720000000049483045022100dadf4be7dda52121261a547835ad03f9eb1ad1ae9a05bc3cfad8eddfcc67e31d0220120736f756e8f83573c282dfb2fea8c508480845110d31787e0b88a931a29e1541fefffffff314481de58fe4fc1035ced966ea1a67d8aa28fed9935326806d8c0da003d4460000000049483045022100a8778ce1b991e1c836b829db383d47f97a5a0184b624829ab3f11b4d505ccde9022046e20276fa80f886865703c50f071c4de56abc5bdb0368cebcff90e9ef5a20b241feffffff02c0833842000000001976a914c76cf02db3e9d93a94081980ea890e15f13cc56e88acaec60f00000000001976a9148b85fdd722cd20970f1d36d40a6f95d3a7c4776688ac510a0000" | ||
}, | ||
{ | ||
"description": "Headers only", | ||
"hash": "5e121efd987c4bff5ac88da58cdacbda2b29d0215b33df2628b974dccc0a9742", | ||
"confirmations": 1, | ||
"height": 2155, | ||
"version": 536870912, | ||
"versionHex": "20000000", | ||
"merkleroot": "546c2616daaf1474589815fc9f3dafda08211b6744f9565d5019aad26ff494af", | ||
"time": 1522052700, | ||
"mediantime": 1521730196, | ||
"nonceUint32": 4, | ||
"nonce": "0000000000000000000000000000000000000000000000000000000000000004", | ||
"solution": "", | ||
"bits": "207fffff", | ||
"difficulty": 4.656542373906925e-10, | ||
"chainwork": "00000000000000000000000000000000000000000000000000000000000010d8", | ||
"previousblockhash": "4e491178c5ad6d86c39ffe03bcb367a73158a7b3373e708c6257dfb39a47c366", | ||
"hex": "0000002066c3479ab3df57628c703e37b3a75831a767b3bc03fe9fc3866dadc57811494eaf94f46fd2aa19505d56f944671b2108daaf3d9ffc1598587414afda16266c546b080000000000000000000000000000000000000000000000000000000000005caeb85affff7f2004000000000000000000000000000000000000000000000000000000000000000000" | ||
} | ||
], | ||
"invalid": [ | ||
{ | ||
"exception": "Buffer too small \\(< 140 bytes\\)", | ||
"hex": "020000003385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf08000000000000cf52f0eb" | ||
} | ||
] | ||
} | ||
|