Merge pull request #772 from braydonf/docs/block

Block: Updated documentation, and changed to use consistent naming.
This commit is contained in:
Manuel Aráoz 2014-12-17 11:58:22 -03:00
commit 9f51b1b4ce
6 changed files with 103 additions and 122 deletions

View File

@ -1,30 +1,55 @@
# Block
A Block instance represents the information on a block in the bitcoin network. Instantiating it is not a cheap operation, as the tree of transactions needs to be created or verified. There's a (BlockHeader)[https://github.com/bitpay/bitcore/tree/master/lib/blockheader.js] interface that is easier on the javascript VM.
Given a hexa or base64 string representation of the serialization of a block with its transactions, you can instantiate a Block instance. It will calculate and check the merkle root hash (if enough data is provided), but transactions won't necessarily be valid spends, and this class won't validate them. A binary representation as a `Buffer` instance is also valid input for a Block's constructor.
A Block instance represents the information on a block in the bitcoin network. Given a hexa or base64 string representation of the serialization of a block with its transactions, you can instantiate a Block instance. Methods are provided to calculate and check the merkle root hash (if enough data is provided), but transactions won't necessarily be valid spends, and this class won't validate them. A binary representation as a `Buffer` instance is also valid input for a Block's constructor.
```javascript
assert(Block.isValidHeader(data);
assert(Block.isValidBlock(data);
// instantiate a new block instance
var block = new Block(hexaEncodedBlock);
assert(block.id && block.hash && block.id === block.hash);
assert(block.version === Block.CurrentVersion);
assert(block.prevHash);
assert(block.timestamp);
assert(block.nonce);
// will verify that the correspending block transactions match the header
assert(block.validMerkleRoot());
// blocks have several properties
assert(block.magicnum);
assert(block.size);
assert(block.transactions[0] instanceof Transaction);
assert(block.header); // an instance of block header, more info below
assert(block.txs); // an array of transactions, more info below
```
## Navigating through transactions
For detailed technical information about a block please visit [Blocks](https://en.bitcoin.it/wiki/Blocks#Block_structure) on the Bitcoin Wiki.
The set of transactions in a block can be explored by iterating on the block's
`transactions` member.
## Block Header
Each instance of Block has a BlockHeader *(which can be instantiated seperately)*. The header has validation methods, to verify that the block.
```javascript
for (var transaction in block.transactions) {
// ...
// will verify that the nonce demonstrates enough proof of work
assert(block.header.validProofOfWork());
// will verify that timestamp is not too far in the future
assert(block.header.validTimestamp());
// each header has the following properties
assert(block.header.version);
assert(block.header.prevHash);
assert(block.header.merkleRoot);
assert(block.header.time);
assert(block.header.bits);
assert(block.header.nonce);
```
For more information about the specific properties of a block header please visit the [Block hashing algorithm](https://en.bitcoin.it/wiki/Block_hashing_algorithm) page on the Bitcoin Wiki.
## Transactions
The set of transactions in a block is an array of instances of [Transaction](Transaction.md) and can be explored by iterating on the block's `transactions` member.
```javascript
for (var i in block.txs) {
var transaction = block.txs[i];
}
```

View File

@ -25,7 +25,6 @@ function Block(arg) {
return new Block(arg);
}
_.extend(this, Block._from(arg));
this._setupProperties();
return this;
}
@ -52,15 +51,15 @@ Block._from = function _from(arg) {
*/
magicnum: arg.magicnum,
/**
* @name Block#blocksize
* @name Block#size
* @type number
*/
blocksize: arg.blocksize,
size: arg.size,
/**
* @name Block#blockheader
* @name Block#header
* @type {BlockHeader}
*/
blockheader: arg.blockheader,
header: arg.header,
txsvi: arg.txsvi,
/**
* @name Block#txs
@ -74,46 +73,6 @@ Block._from = function _from(arg) {
return info;
};
/**
* Internal function that sets up a some properties from blockheader for
* easier access
*/
Block.prototype._setupProperties = function() {
/**
* @name Block#version
* @type {number}
*/
Object.defineProperty(this, 'version', {
configurable: false,
value: this.blockheader.version
});
/**
* @name Block#timestamp
* @type {number}
*/
Object.defineProperty(this, 'timestamp', {
configurable: false,
value: this.blockheader.timestamp
});
/**
* @name Block#nonce
* @type {number}
*/
Object.defineProperty(this, 'nonce', {
configurable: false,
value: this.blockheader.nonce
});
/**
* Amount of bytes of the serialized block
* @name Block#size
* @type {number}
*/
Object.defineProperty(this, 'size', {
configurable: false,
value: this.blockheader.size
});
};
/**
* @param {String|Object} - A JSON string or object
* @returns {Object} - An object representing block data
@ -129,8 +88,8 @@ Block._fromJSON = function _fromJSON(data) {
});
var info = {
magicnum: data.magicnum,
blocksize: data.blocksize,
blockheader: BlockHeader.fromJSON(data.blockheader),
size: data.size,
header: BlockHeader.fromJSON(data.header),
txsvi: Varint().fromString(data.txsvi),
txs: txs
};
@ -154,8 +113,8 @@ Block.fromJSON = function fromJSON(json) {
Block._fromBufferReader = function _fromBufferReader(br) {
var info = {};
info.magicnum = br.readUInt32LE();
info.blocksize = br.readUInt32LE();
info.blockheader = BlockHeader.fromBufferReader(br);
info.size = br.readUInt32LE();
info.header = BlockHeader.fromBufferReader(br);
info.txsvi = Varint(br.readVarintBuf());
var txslen = info.txsvi.toNumber();
info.txs = [];
@ -214,8 +173,8 @@ Block.prototype.toObject = function toObject() {
});
return {
magicnum: this.magicnum,
blocksize: this.blocksize,
blockheader: this.blockheader.toObject(),
size: this.size,
header: this.header.toObject(),
txsvi: this.txsvi.toString(),
txs: txs
};
@ -251,8 +210,8 @@ Block.prototype.toBufferWriter = function toBufferWriter(bw) {
bw = new BufferWriter();
}
bw.writeUInt32LE(this.magicnum);
bw.writeUInt32LE(this.blocksize);
bw.write(this.blockheader.toBuffer());
bw.writeUInt32LE(this.size);
bw.write(this.header.toBuffer());
bw.write(this.txsvi.buf);
var txslen = this.txsvi.toNumber();
for (var i = 0; i < txslen; i++) {
@ -309,12 +268,12 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() {
};
/**
* Verifies that the transactions in the block match the blockheader merkle root
* Verifies that the transactions in the block match the header merkle root
* @returns {Boolean} - If the merkle roots match
*/
Block.prototype.validMerkleRoot = function validMerkleRoot() {
var h = new BN(this.blockheader.merklerootbuf.toString('hex'), 'hex');
var h = new BN(this.header.merkleRoot.toString('hex'), 'hex');
var c = new BN(this.getMerkleRoot().toString('hex'), 'hex');
if (h.cmp(c) !== 0) {
@ -328,7 +287,7 @@ Block.prototype.validMerkleRoot = function validMerkleRoot() {
* @returns {Buffer} - The little endian hash buffer of the header
*/
Block.prototype._getHash = function() {
return this.blockheader._getHash();
return this.header._getHash();
};
var idProperty = {
@ -339,7 +298,7 @@ var idProperty = {
*/
get: function() {
if (!this._id) {
this._id = this.blockheader.id;
this._id = this.header.id;
}
return this._id;
},

View File

@ -39,11 +39,9 @@ BlockHeader._from = function _from(arg) {
} else if (_.isObject(arg)) {
info = {
version: arg.version,
prevblockidbuf: arg.prevblockidbuf,
prevHash: arg.prevblockidbuf,
merklerootbuf: arg.merklerootbuf,
prevHash: arg.prevHash,
merkleRoot: arg.merkleRoot,
time: arg.time,
timestamp: arg.time,
bits: arg.bits,
nonce: arg.nonce
};
@ -64,9 +62,8 @@ BlockHeader._fromJSON = function _fromJSON(data) {
}
var info = {
version: data.version,
prevblockidbuf: new Buffer(data.prevblockidbuf, 'hex'),
prevHash: new Buffer(data.prevblockidbuf, 'hex'),
merklerootbuf: new Buffer(data.merklerootbuf, 'hex'),
prevHash: new Buffer(data.prevHash, 'hex'),
merkleRoot: new Buffer(data.merkleRoot, 'hex'),
time: data.time,
timestamp: data.time,
bits: data.bits,
@ -124,8 +121,8 @@ BlockHeader.fromString = function fromString(str) {
BlockHeader._fromBufferReader = function _fromBufferReader(br) {
var info = {
version: br.readUInt32LE(),
prevblockidbuf: br.read(32),
merklerootbuf: br.read(32),
prevHash: br.read(32),
merkleRoot: br.read(32),
time: br.readUInt32LE(),
bits: br.readUInt32LE(),
nonce: br.readUInt32LE()
@ -148,8 +145,8 @@ BlockHeader.fromBufferReader = function fromBufferReader(br) {
BlockHeader.prototype.toObject = function toObject() {
return {
version: this.version,
prevblockidbuf: this.prevblockidbuf.toString('hex'),
merklerootbuf: this.merklerootbuf.toString('hex'),
prevHash: this.prevHash.toString('hex'),
merkleRoot: this.merkleRoot.toString('hex'),
time: this.time,
bits: this.bits,
nonce: this.nonce
@ -186,8 +183,8 @@ BlockHeader.prototype.toBufferWriter = function toBufferWriter(bw) {
bw = new BufferWriter();
}
bw.writeUInt32LE(this.version);
bw.write(this.prevblockidbuf);
bw.write(this.merklerootbuf);
bw.write(this.prevHash);
bw.write(this.merkleRoot);
bw.writeUInt32LE(this.time);
bw.writeUInt32LE(this.bits);
bw.writeUInt32LE(this.nonce);

View File

@ -22,7 +22,7 @@ describe('Block', function() {
var magicnum = data.magicnum;
var blockhex = data.blockhex;
var blockbuf = new Buffer(blockhex, 'hex');
var blocksize = data.blocksize;
var size = data.blocksize;
var bh = BlockHeader.fromBuffer(new Buffer(data.blockheaderhex, 'hex'));
var txsvi = Varint().fromNumber(data.txsvi);
var txs = [];
@ -51,15 +51,15 @@ describe('Block', function() {
it('should set these known values', function() {
var b = new Block({
magicnum: magicnum,
blocksize: blocksize,
blockheader: bh,
size: size,
header: bh,
txsvi: txsvi,
txs: txs
});
should.exist(b.magicnum);
should.exist(b.blocksize);
should.exist(b.size);
should.exist(b.txsvi);
should.exist(b.blockheader);
should.exist(b.header);
should.exist(b.txs);
});
@ -69,14 +69,14 @@ describe('Block', function() {
it('should instantiate from a raw block binary', function() {
var x = Block.fromRawBlock(dataRawBlockBinary);
x.blockheader.version.should.equal(2);
BN(x.blockheader.bits).toString('hex').should.equal('1c3fffc0');
x.header.version.should.equal(2);
BN(x.header.bits).toString('hex').should.equal('1c3fffc0');
});
it('should instantiate from raw block buffer', function() {
var x = Block.fromRawBlock(dataRawBlockBuffer);
x.blockheader.version.should.equal(2);
BN(x.blockheader.bits).toString('hex').should.equal('1c3fffc0');
x.header.version.should.equal(2);
BN(x.header.bits).toString('hex').should.equal('1c3fffc0');
});
});
@ -86,8 +86,8 @@ describe('Block', function() {
it('should set these known values', function() {
var block = Block.fromJSON(json);
should.exist(block.magicnum);
should.exist(block.blocksize);
should.exist(block.blockheader);
should.exist(block.size);
should.exist(block.header);
should.exist(block.txsvi);
should.exist(block.txs);
});
@ -96,8 +96,8 @@ describe('Block', function() {
var block = Block(json);
should.exist(block.magicnum);
should.exist(block.blocksize);
should.exist(block.blockheader);
should.exist(block.size);
should.exist(block.header);
should.exist(block.txsvi);
should.exist(block.txs);
});
@ -110,8 +110,8 @@ describe('Block', function() {
var block = Block.fromJSON(json);
var b = JSON.parse(block.toJSON());
should.exist(b.magicnum);
should.exist(b.blocksize);
should.exist(b.blockheader);
should.exist(b.size);
should.exist(b.header);
should.exist(b.txsvi);
should.exist(b.txs);
});

View File

@ -23,8 +23,8 @@ describe('BlockHeader', function() {
var nonce = data.nonce;
var bh = new BlockHeader({
version: version,
prevblockidbuf: prevblockidbuf,
merklerootbuf: merklerootbuf,
prevHash: prevblockidbuf,
merkleRoot: merklerootbuf,
time: time,
bits: bits,
nonce: nonce
@ -47,15 +47,15 @@ describe('BlockHeader', function() {
it('should set all the variables', function() {
var bh = new BlockHeader({
version: version,
prevblockidbuf: prevblockidbuf,
merklerootbuf: merklerootbuf,
prevHash: prevblockidbuf,
merkleRoot: merklerootbuf,
time: time,
bits: bits,
nonce: nonce
});
should.exist(bh.version);
should.exist(bh.prevblockidbuf);
should.exist(bh.merklerootbuf);
should.exist(bh.prevHash);
should.exist(bh.merkleRoot);
should.exist(bh.time);
should.exist(bh.bits);
should.exist(bh.nonce);
@ -68,15 +68,15 @@ describe('BlockHeader', function() {
it('should set all the variables', function() {
var bh = BlockHeader.fromJSON({
version: version,
prevblockidbuf: prevblockidbuf.toString('hex'),
merklerootbuf: merklerootbuf.toString('hex'),
prevHash: prevblockidbuf.toString('hex'),
merkleRoot: merklerootbuf.toString('hex'),
time: time,
bits: bits,
nonce: nonce
});
should.exist(bh.version);
should.exist(bh.prevblockidbuf);
should.exist(bh.merklerootbuf);
should.exist(bh.prevHash);
should.exist(bh.merkleRoot);
should.exist(bh.time);
should.exist(bh.bits);
should.exist(bh.nonce);
@ -89,8 +89,8 @@ describe('BlockHeader', function() {
it('should set all the variables', function() {
var json = JSON.parse(bh.toJSON());
should.exist(json.version);
should.exist(json.prevblockidbuf);
should.exist(json.merklerootbuf);
should.exist(json.prevHash);
should.exist(json.merkleRoot);
should.exist(json.time);
should.exist(json.bits);
should.exist(json.nonce);
@ -104,8 +104,8 @@ describe('BlockHeader', function() {
var jsonString = JSON.stringify({
version: version,
prevblockidbuf: prevblockidbuf,
merklerootbuf: merklerootbuf,
prevHash: prevblockidbuf,
merkleRoot: merklerootbuf,
time: time,
bits: bits,
nonce: nonce
@ -113,8 +113,8 @@ describe('BlockHeader', function() {
var json = new BlockHeader(jsonString);
should.exist(json.version);
should.exist(json.prevblockidbuf);
should.exist(json.merklerootbuf);
should.exist(json.prevHash);
should.exist(json.merkleRoot);
should.exist(json.time);
should.exist(json.bits);
should.exist(json.nonce);

View File

@ -1,10 +1,10 @@
{
"magicnum": 118034699,
"blocksize": 8003,
"blockheader": {
"size": 8003,
"header": {
"version": 2,
"prevblockidbuf": "4baaa9507c3b27908397ea7bc177a998e9f4fe38b9d5130be7b5353c00000000",
"merklerootbuf": "97fc4c97868288e984ff9f246f2c38510f5c37a3d5b41aae7004b01e2dd5e658",
"prevHash": "4baaa9507c3b27908397ea7bc177a998e9f4fe38b9d5130be7b5353c00000000",
"merkleRoot": "97fc4c97868288e984ff9f246f2c38510f5c37a3d5b41aae7004b01e2dd5e658",
"time": 1371410638,
"bits": 473956288,
"nonce": 3594009557
@ -597,4 +597,4 @@
}],
"nlocktime": 0
}]
}
}