4 changed files with 353 additions and 0 deletions
@ -0,0 +1,176 @@ |
|||
'use strict'; |
|||
var _ = require('lodash'); |
|||
var BlockHeader = require('../blockheader'); |
|||
var BufferUtil = require('../util/buffer'); |
|||
var BufferReader = require('../encoding/bufferreader'); |
|||
var BufferWriter = require('../encoding/bufferwriter'); |
|||
var JSUtil = require('../util/js'); |
|||
var $ = require('../util/preconditions'); |
|||
|
|||
/** |
|||
* Instantiate a MerkleBlock from a Buffer, JSON object, or Object with |
|||
* the properties of the Block |
|||
* |
|||
* @param {*} - A Buffer, JSON string, or Object representing a MerkleBlock |
|||
* @returns {MerkleBlock} |
|||
* @constructor |
|||
*/ |
|||
function MerkleBlock(arg) { |
|||
if (!(this instanceof MerkleBlock)) { |
|||
return new MerkleBlock(arg); |
|||
} |
|||
|
|||
var info = {}; |
|||
if (BufferUtil.isBuffer(arg)) { |
|||
info = MerkleBlock._fromBufferReader(BufferReader(arg)); |
|||
} else if (JSUtil.isValidJSON(arg)) { |
|||
info = MerkleBlock._fromJSON(arg); |
|||
} else if (_.isObject(arg)) { |
|||
var header; |
|||
if(arg.header instanceof BlockHeader) { |
|||
header = arg.header |
|||
} else { |
|||
header = BlockHeader.fromJSON(JSON.stringify(arg.header)); |
|||
} |
|||
info = { |
|||
/** |
|||
* @name MerkleBlock#header |
|||
* @type {BlockHeader} |
|||
*/ |
|||
header: header, |
|||
/** |
|||
* @name MerkleBlock#numTransactions |
|||
* @type {Number} |
|||
*/ |
|||
numTransactions: arg.numTransactions, |
|||
/** |
|||
* @name MerkleBlock#hashes |
|||
* @type {String[]} |
|||
*/ |
|||
hashes: arg.hashes, |
|||
/** |
|||
* @name MerkleBlock#flags |
|||
* @type {Number[]} |
|||
*/ |
|||
flags: arg.flags |
|||
}; |
|||
} else { |
|||
throw new TypeError('Unrecognized argument for Block'); |
|||
} |
|||
_.extend(this,info); |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* @param {Buffer} - MerkleBlock data in a Buffer object |
|||
* @returns {MerkleBlock} - A MerkleBlock object |
|||
*/ |
|||
MerkleBlock.fromBuffer = function fromBuffer(buf) { |
|||
return MerkleBlock.fromBufferReader(BufferReader(buf)); |
|||
} |
|||
|
|||
/** |
|||
* @param {BufferReader} - MerkleBlock data in a BufferReader object |
|||
* @returns {MerkleBlock} - A MerkleBlock object |
|||
*/ |
|||
MerkleBlock.fromBufferReader = function fromBufferReader(br) { |
|||
return new MerkleBlock(MerkleBlock._fromBufferReader(br)); |
|||
} |
|||
|
|||
/** |
|||
* @param {String|Object} - A JSON String or Object |
|||
* @returns {MerkleBlock} - A MerkleBlock object |
|||
*/ |
|||
MerkleBlock.fromJSON = function fromJSON(buf) { |
|||
return new MerkleBlock(MerkleBlock._fromJSON(buf)); |
|||
} |
|||
|
|||
/** |
|||
* @returns {Buffer} - A buffer of the block |
|||
*/ |
|||
MerkleBlock.prototype.toBuffer = function toBuffer() { |
|||
return this.toBufferWriter().concat(); |
|||
}; |
|||
|
|||
/** |
|||
* @param {BufferWriter} - An existing instance of BufferWriter |
|||
* @returns {BufferWriter} - An instance of BufferWriter representation of the MerkleBlock |
|||
*/ |
|||
MerkleBlock.prototype.toBufferWriter = function toBufferWriter(bw) { |
|||
if (!bw) { |
|||
bw = new BufferWriter(); |
|||
} |
|||
bw.write(this.header.toBuffer()); |
|||
bw.writeUInt32LE(this.numTransactions); |
|||
bw.writeVarintNum(this.hashes.length); |
|||
for (var i = 0; i < this.hashes.length; i++) { |
|||
bw.write(new Buffer(this.hashes[i], 'hex')); |
|||
} |
|||
bw.writeVarintNum(this.flags.length); |
|||
for (var i = 0; i < this.flags.length; i++) { |
|||
bw.writeUInt8(this.flags[i]); |
|||
} |
|||
return bw; |
|||
}; |
|||
|
|||
/** |
|||
* @returns {Object} - A plain object with the MerkleBlock properties |
|||
*/ |
|||
MerkleBlock.prototype.toObject = function toObject() { |
|||
return { |
|||
header: this.header.toObject(), |
|||
numTransactions: this.numTransactions, |
|||
hashes: this.hashes, |
|||
flags: this.flags |
|||
}; |
|||
}; |
|||
|
|||
/** |
|||
* @returns {String} - A JSON string of a MerkleBlock |
|||
*/ |
|||
MerkleBlock.prototype.toJSON = function toJSON() { |
|||
return JSON.stringify(this.toObject()); |
|||
}; |
|||
|
|||
/** |
|||
* @param {Buffer} - MerkleBlock data |
|||
* @returns {Object} - An Object representing merkleblock data |
|||
* @private |
|||
*/ |
|||
MerkleBlock._fromBufferReader = function _fromBufferReader(br) { |
|||
$.checkState(!br.finished(), 'No merkleblock data received'); |
|||
var info = {}; |
|||
info.header = BlockHeader.fromBufferReader(br); |
|||
info.numTransactions = br.readUInt32LE(); |
|||
var numHashes = br.readVarintNum(); |
|||
info.hashes = []; |
|||
for (var i = 0; i < numHashes; i++) { |
|||
info.hashes.push(br.read(32).toString('hex')); |
|||
} |
|||
var numFlags = br.readVarintNum(); |
|||
info.flags = []; |
|||
for (var i = 0; i < numFlags; i++) { |
|||
info.flags.push(br.readUInt8()); |
|||
} |
|||
return info; |
|||
}; |
|||
|
|||
/** |
|||
* @param {String|Object} - A JSON or String Object |
|||
* @returns {Object} - An Object representing merkleblock data |
|||
* @private |
|||
*/ |
|||
MerkleBlock._fromJSON = function _fromJSON(data) { |
|||
if (JSUtil.isValidJSON(data)) { |
|||
data = JSON.parse(data); |
|||
} |
|||
var info = { |
|||
header: BlockHeader.fromJSON(data.header), |
|||
numTransactions: data.numTransactions, |
|||
hashes: data.hashes, |
|||
flags: data.flags, |
|||
}; |
|||
return info; |
|||
}; |
|||
|
|||
module.exports = MerkleBlock; |
@ -0,0 +1,44 @@ |
|||
'use strict'; |
|||
|
|||
module.exports = { |
|||
HEX: [ |
|||
// Mainnet Block 100015
|
|||
"01000000" + // Version
|
|||
"82bb869cf3a793432a66e826e05a6fc37469f8efb7421dc88067010000000000" + // prevHash
|
|||
"7f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d97287" + // MerkleRoot
|
|||
"76381b4d" + // Time
|
|||
"4c86041b" + // Bits
|
|||
"554b8529" + // Nonce
|
|||
"07000000" + // Transaction Count
|
|||
"04" + // Hash Count
|
|||
"3612262624047ee87660be1a707519a443b1c1ce3d248cbfc6c15870f6c5daa2" + // Hash1
|
|||
"019f5b01d4195ecbc9398fbf3c3b1fa9bb3183301d7a1fb3bd174fcfa40a2b65" + // Hash2
|
|||
"41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068" + // Hash3
|
|||
"20d2a7bc994987302e5b1ac80fc425fe25f8b63169ea78e68fbaaefa59379bbf" + // Hash4
|
|||
"01" + // Num Flag Bytes
|
|||
"1d" // Flags
|
|||
], |
|||
JSON: [ |
|||
{ // Mainnet Block 100015
|
|||
header: { |
|||
version: 1, |
|||
prevHash: "82bb869cf3a793432a66e826e05a6fc37469f8efb7421dc88067010000000000", |
|||
merkleRoot: "7f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d97287", |
|||
time: 1293629558, |
|||
bits: 453281356, |
|||
nonce: 151839121 |
|||
}, |
|||
numTransactions: 7, |
|||
hashes: [ |
|||
"3612262624047ee87660be1a707519a443b1c1ce3d248cbfc6c15870f6c5daa2", |
|||
"019f5b01d4195ecbc9398fbf3c3b1fa9bb3183301d7a1fb3bd174fcfa40a2b65", |
|||
"41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068", |
|||
"20d2a7bc994987302e5b1ac80fc425fe25f8b63169ea78e68fbaaefa59379bbf" |
|||
], |
|||
flags: [ 29 ] |
|||
} |
|||
|
|||
|
|||
|
|||
] |
|||
}; |
@ -0,0 +1,132 @@ |
|||
'use strict'; |
|||
|
|||
var bitcore = require('..'), |
|||
BufferUtil = bitcore.util.buffer, |
|||
MerkleBlock = bitcore.MerkleBlock, |
|||
BlockHeader = bitcore.BlockHeader, |
|||
BufferReader = bitcore.encoding.BufferReader, |
|||
BufferWriter = bitcore.encoding.BufferWriter, |
|||
data = require('./data/merkleblocks.js'); |
|||
|
|||
describe('MerkleBlock', function() { |
|||
var blockhex = data.HEX[0]; |
|||
var blockbuf = new Buffer(blockhex,'hex'); |
|||
var blockJSON = JSON.stringify(data.JSON[0]); |
|||
var blockObject = JSON.parse(JSON.stringify(data.JSON[0])); |
|||
|
|||
describe('#constructor', function() { |
|||
it('should make a new merkleblock from buffer', function() { |
|||
var b = MerkleBlock(blockbuf); |
|||
b.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
it('should make a new merkleblock from object', function() { |
|||
var b = MerkleBlock(blockObject); |
|||
b.toObject().should.deep.equal(blockObject); |
|||
}); |
|||
|
|||
it('should make a new merkleblock from JSON', function() { |
|||
var b = MerkleBlock(blockJSON); |
|||
b.toJSON().should.equal(blockJSON); |
|||
}); |
|||
|
|||
it('should not make an empty block', function() { |
|||
(function() { |
|||
return new MerkleBlock(); |
|||
}).should.throw('Unrecognized argument for Block'); |
|||
}); |
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should set these known values', function() { |
|||
var block = MerkleBlock.fromJSON(blockJSON); |
|||
should.exist(block.header); |
|||
should.exist(block.numTransactions); |
|||
should.exist(block.hashes); |
|||
should.exist(block.flags); |
|||
}); |
|||
|
|||
it('should set these known values', function() { |
|||
var block = MerkleBlock(blockJSON); |
|||
should.exist(block.header); |
|||
should.exist(block.numTransactions); |
|||
should.exist(block.hashes); |
|||
should.exist(block.flags); |
|||
}); |
|||
|
|||
it('accepts an object as argument', function() { |
|||
var block = MerkleBlock(blockbuf); |
|||
MerkleBlock.fromJSON(block.toObject()).should.exist(); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should recover these known values', function() { |
|||
var block = MerkleBlock.fromJSON(blockJSON); |
|||
var b = JSON.parse(block.toJSON()); |
|||
should.exist(block.header); |
|||
should.exist(block.numTransactions); |
|||
should.exist(block.hashes); |
|||
should.exist(block.flags); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
// TODO
|
|||
//describe('#fromString/#toString', function() {
|
|||
|
|||
//it('should output/input a block hex string', function() {
|
|||
//var b = MerkleBlock.fromString(blockhex);
|
|||
//b.toString().should.equal(blockhex);
|
|||
//});
|
|||
|
|||
//});
|
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should make a block from this known buffer', function() { |
|||
var block = MerkleBlock.fromBuffer(blockbuf); |
|||
block.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBufferReader', function() { |
|||
|
|||
it('should make a block from this known buffer', function() { |
|||
var block = MerkleBlock.fromBufferReader(BufferReader(blockbuf)); |
|||
block.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should recover a block from this known buffer', function() { |
|||
var block = MerkleBlock.fromBuffer(blockbuf); |
|||
block.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBufferWriter', function() { |
|||
|
|||
it('should recover a block from this known buffer', function() { |
|||
var block = MerkleBlock.fromBuffer(blockbuf); |
|||
block.toBufferWriter().concat().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
it('doesn\'t create a bufferWriter if one provided', function() { |
|||
var writer = new BufferWriter(); |
|||
var block = MerkleBlock.fromBuffer(blockbuf); |
|||
block.toBufferWriter(writer).should.equal(writer); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
}); |
|||
|
Loading…
Reference in new issue