fcoin/lib/bcoin/chainblock.js
Christopher Jeffrey 78e9be11c3 switch to buffers.
2016-02-22 20:37:15 -08:00

158 lines
3.9 KiB
JavaScript

/**
* chainblock.js - chainblock object for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* https://github.com/indutny/bcoin
*/
var EventEmitter = require('events').EventEmitter;
var bcoin = require('../bcoin');
var bn = require('bn.js');
var constants = bcoin.protocol.constants;
var network = bcoin.protocol.network;
var utils = bcoin.utils;
var assert = utils.assert;
var fs = bcoin.fs;
/**
* ChainBlock
*/
function ChainBlock(chain, data) {
if (!(this instanceof ChainBlock))
return new ChainBlock(chain, data);
this.chain = chain;
this.hash = data.hash;
this.version = data.version;
this.prevBlock = data.prevBlock;
this.merkleRoot = data.merkleRoot;
this.ts = data.ts;
this.bits = data.bits;
this.nonce = data.nonce;
this.height = data.height;
this.chainwork = data.chainwork || this.getChainwork();
}
ChainBlock.BLOCK_SIZE = 112;
ChainBlock.prototype.__defineGetter__('prev', function() {
return this.chain.db.getSync(this.height - 1);
});
ChainBlock.prototype.__defineGetter__('next', function() {
return this.chain.db.getSync(this.height + 1);
});
ChainBlock.prototype.getProof = function getProof() {
var target = utils.fromCompact(this.bits);
if (target.isNeg() || target.cmpn(0) === 0)
return new bn(0);
return new bn(1).ushln(256).div(target.addn(1));
};
ChainBlock.prototype.getChainwork = function getChainwork() {
var prev;
// Workaround for genesis block
// being added _in_ chaindb.
if (!this.chain.db)
return this.getProof();
prev = this.prev;
return (prev ? prev.chainwork : new bn(0)).add(this.getProof());
};
ChainBlock.prototype.isGenesis = function isGenesis() {
return this.hash === network.genesis.hash;
};
ChainBlock.prototype.getMedianTime = function getMedianTime() {
var entry = this;
var median = [];
var timeSpan = constants.block.medianTimespan;
var i;
for (i = 0; i < timeSpan && entry; i++, entry = entry.prev)
median.push(entry.ts);
median = median.sort();
return median[median.length / 2 | 0];
};
ChainBlock.prototype.isOutdated = function isOutdated(version) {
return this.isSuperMajority(version, network.block.majorityRejectOutdated);
};
ChainBlock.prototype.isUpgraded = function isUpgraded(version) {
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade);
};
ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required) {
var entry = this;
var found = 0;
var majorityWindow = network.block.majorityWindow;
var i;
for (i = 0; i < majorityWindow && found < required && entry; i++) {
if (entry.version >= version)
found++;
entry = entry.prev;
}
return found >= required;
};
ChainBlock.prototype.toJSON = function toJSON() {
return {
hash: this.hash,
version: this.version,
prevBlock: this.prevBlock,
merkleRoot: this.merkleRoot,
ts: this.ts,
bits: this.bits,
nonce: this.nonce,
height: this.height
};
};
ChainBlock.fromJSON = function fromJSON(chain, json) {
return new ChainBlock(chain, json);
};
ChainBlock.prototype.toRaw = function toRaw() {
var res = new Buffer(ChainBlock.BLOCK_SIZE);
utils.write32(res, this.version, 0);
utils.copy(new Buffer(this.prevBlock, 'hex'), res, 4);
utils.copy(new Buffer(this.merkleRoot, 'hex'), res, 36);
utils.writeU32(res, this.ts, 68);
utils.writeU32(res, this.bits, 72);
utils.writeU32(res, this.nonce, 76);
utils.copy(new Buffer(this.chainwork.toArray('be', 32)), res, 80);
return res;
};
ChainBlock.fromRaw = function fromRaw(chain, height, p) {
return new ChainBlock(chain, {
height: height,
hash: utils.toHex(utils.dsha256(p.slice(0, 80))),
version: utils.read32(p, 0),
prevBlock: utils.toHex(p.slice(4, 36)),
merkleRoot: utils.toHex(p.slice(36, 68)),
ts: utils.readU32(p, 68),
bits: utils.readU32(p, 72),
nonce: utils.readU32(p, 76),
chainwork: new bn(p.slice(80, 112), 'be')
});
};
/**
* Expose
*/
module.exports = ChainBlock;