more chainblock refactoring.

This commit is contained in:
Christopher Jeffrey 2016-03-08 14:25:43 -08:00
parent 27214676bc
commit 9f56efe0d7
3 changed files with 97 additions and 153 deletions

View File

@ -1848,7 +1848,7 @@ Chain.prototype.getTarget = function getTarget(last, block) {
return powLimit;
i = 1;
prev = last.previous;
prev = last.ancestors;
while (prev[i]
&& last.height % network.powDiffInterval !== 0
&& last.bits === powLimit) {
@ -1861,7 +1861,7 @@ Chain.prototype.getTarget = function getTarget(last, block) {
}
// Back 2 weeks
first = last.previous[network.powDiffInterval - 1];
first = last.ancestors[network.powDiffInterval - 1];
assert(first);

View File

@ -23,6 +23,7 @@ function ChainBlock(chain, data, prev) {
return new ChainBlock(chain, data);
this.chain = chain;
this.hash = data.hash;
this.version = data.version;
this.prevBlock = data.prevBlock;
@ -32,14 +33,9 @@ function ChainBlock(chain, data, prev) {
this.nonce = data.nonce;
this.height = data.height;
this.chainwork = data.chainwork || this.getChainwork(prev);
assert(this.chainwork);
this.previous = [];
this.ancestors = [];
}
ChainBlock.BLOCK_SIZE = 116;
ChainBlock.prototype.getProof = function getProof() {
var target = utils.fromCompact(this.bits);
if (target.isNeg() || target.cmpn(0) === 0)
@ -55,104 +51,6 @@ ChainBlock.prototype.isGenesis = function isGenesis() {
return this.hash === network.genesis.hash;
};
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.writeU32(res, this.height, 80);
utils.copy(new Buffer(this.chainwork.toArray('le', 32)), res, 84);
return res;
};
ChainBlock.fromRaw = function fromRaw(chain, p) {
return new ChainBlock(chain, {
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),
height: utils.readU32(p, 80),
chainwork: new bn(p.slice(84, 116), 'le')
});
};
ChainBlock.prototype.getMedianTimeAsync = function getMedianTime(callback) {
var self = this;
var median = [];
var timeSpan = constants.block.medianTimespan;
var i = 0;
(function next(err, entry) {
if (err)
return callback(err);
if (!entry || i >= timeSpan) {
median = median.sort();
return callback(null, median[median.length / 2 | 0]);
}
median[i] = entry.ts;
i++;
entry.getPrevious(next);
})(null, this);
};
ChainBlock.prototype.isOutdatedAsync = function isOutdated(version, callback) {
return this.isSuperMajority(version, network.block.majorityRejectOutdated, callback);
};
ChainBlock.prototype.isUpgradedAsync = function isUpgraded(version, callback) {
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, callback);
};
ChainBlock.prototype.isSuperMajorityAsync = function isSuperMajority(version, required, callback) {
var self = this;
var found = 0;
var majorityWindow = network.block.majorityWindow;
var i = 0;
(function next(err, entry) {
if (err)
return callback(err);
if (!entry || i >= majorityWindow || found >= required)
return callback(null, found >= required);
if (entry.version >= version)
found++;
i++;
entry.getPrevious(next);
})(null, this);
};
ChainBlock.prototype.ensureAncestors = function ensureAncestors(callback) {
var majorityWindow = network.block.majorityWindow;
var medianTimespan = constants.block.medianTimespan;
@ -161,7 +59,7 @@ ChainBlock.prototype.ensureAncestors = function ensureAncestors(callback) {
var max = Math.max(majorityWindow, medianTimespan);
if ((this.height + 1) % powDiffInterval === 0 || allowMinDiff)
max = Math.max(max, powDiffInterval);
assert(this.previous.length === 0);
assert(this.ancestors.length === 0);
return this.alloc(max, callback);
};
@ -169,16 +67,16 @@ ChainBlock.prototype.alloc = function alloc(max, callback) {
var self = this;
var i;
return this.getAncestors(max, function(err, previous) {
return this.getAncestors(max, function(err, ancestors) {
if (err)
return callback(err);
assert(previous);
assert(ancestors);
self.previous.length = 0;
self.ancestors.length = 0;
for (i = 0; i < previous.length; i++)
self.previous.push(previous[i]);
for (i = 0; i < ancestors.length; i++)
self.ancestors.push(ancestors[i]);
return callback();
});
@ -187,26 +85,26 @@ ChainBlock.prototype.alloc = function alloc(max, callback) {
ChainBlock.prototype.getAncestors = function getAncestors(max, callback) {
var self = this;
var entry = this;
var previous = this.previous.slice();
var ancestors = this.ancestors.slice();
if (max === 0)
return callback(null, []);
if (previous.length)
entry = previous.pop();
if (ancestors.length)
entry = ancestors.pop();
assert(utils.isFinite(max));
// Try to do this iteratively and synchronously
// so we don't have to wait on nextTicks.
for (;;) {
previous.push(entry);
ancestors.push(entry);
if (previous.length >= max)
return callback(null, previous);
if (ancestors.length >= max)
return callback(null, ancestors);
if (!this.chain.db.hasCache(entry.prevBlock)) {
previous.pop();
ancestors.pop();
break;
}
@ -218,19 +116,19 @@ ChainBlock.prototype.getAncestors = function getAncestors(max, callback) {
return callback(err);
if (!entry)
return callback(null, previous);
return callback(null, ancestors);
previous.push(entry);
ancestors.push(entry);
if (previous.length >= max)
return callback(null, previous);
if (ancestors.length >= max)
return callback(null, ancestors);
entry.getPrevious(next);
})(null, entry);
};
ChainBlock.prototype.free = function free() {
this.previous.length = 0;
this.ancestors.length = 0;
};
ChainBlock.prototype.isMainChain = function isMainChain(callback) {
@ -264,14 +162,14 @@ ChainBlock.prototype.getAncestorByHeight = function getAncestorByHeight(height,
ChainBlock.prototype.getAncestor = function getAncestor(index, callback) {
assert(index >= 0);
return this.getAncestors(index + 1, function(err, previous) {
return this.getAncestors(index + 1, function(err, ancestors) {
if (err)
return callback(err);
if (previous.length !== index + 1)
if (ancestors.length !== index + 1)
return callback();
return callback(null, previous[previous.length - 1]);
return callback(null, ancestors[ancestors.length - 1]);
});
};
@ -292,16 +190,16 @@ ChainBlock.prototype.getNext = function getNext(callback) {
});
};
ChainBlock.prototype.getMedianTime = function getMedianTime(previous) {
ChainBlock.prototype.getMedianTime = function getMedianTime(ancestors) {
var entry = this;
var median = [];
var timeSpan = constants.block.medianTimespan;
var i;
if (!previous)
previous = this.previous;
if (!ancestors)
ancestors = this.ancestors;
for (i = 0; i < timeSpan && entry; i++, entry = previous[i])
for (i = 0; i < timeSpan && entry; i++, entry = ancestors[i])
median.push(entry.ts);
median = median.sort();
@ -309,27 +207,27 @@ ChainBlock.prototype.getMedianTime = function getMedianTime(previous) {
return median[median.length / 2 | 0];
};
ChainBlock.prototype.isOutdated = function isOutdated(version, previous) {
return this.isSuperMajority(version, network.block.majorityRejectOutdated, previous);
ChainBlock.prototype.isOutdated = function isOutdated(version, ancestors) {
return this.isSuperMajority(version, network.block.majorityRejectOutdated, ancestors);
};
ChainBlock.prototype.isUpgraded = function isUpgraded(version, previous) {
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, previous);
ChainBlock.prototype.isUpgraded = function isUpgraded(version, ancestors) {
return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, ancestors);
};
ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required, previous) {
ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required, ancestors) {
var entry = this;
var found = 0;
var majorityWindow = network.block.majorityWindow;
var i;
if (!previous)
previous = this.previous;
if (!ancestors)
ancestors = this.ancestors;
for (i = 0; i < majorityWindow && found < required && entry; i++) {
if (entry.version >= version)
found++;
entry = previous[i + 1];
entry = ancestors[i + 1];
}
return found >= required;
@ -338,24 +236,69 @@ ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, require
ChainBlock.prototype.getMedianTimeAsync = function getMedianTimeAsync(callback) {
var self = this;
return this.getAncestors(constants.block.medianTimespan, function(err, previous) {
return this.getAncestors(constants.block.medianTimespan, function(err, ancestors) {
if (err)
return callback(err);
return callback(null, self.getMedianTime(previous));
return callback(null, self.getMedianTime(ancestors));
});
};
ChainBlock.prototype.toRaw = function toRaw() {
var res = new Buffer(116);
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.writeU32(res, this.height, 80);
utils.copy(new Buffer(this.chainwork.toArray('le', 32)), res, 84);
return res;
};
ChainBlock.fromRaw = function fromRaw(chain, p) {
return new ChainBlock(chain, {
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),
height: utils.readU32(p, 80),
chainwork: new bn(p.slice(84, 116), 'le')
});
};
ChainBlock.prototype.toJSON = function toJSON() {
return {
version: this.version,
hash: utils.revHex(this.hash),
prevBlock: utils.revHex(this.prevBlock),
merkleRoot: utils.revHex(this.merkleRoot),
ts: this.ts,
bits: this.bits,
nonce: this.nonce,
height: this.height,
chainwork: this.chainwork.toString('hex')
};
};
ChainBlock.fromJSON = function fromJSON(chain, json) {
json.hash = utils.revHex(json.hash);
json.prevBlock = utils.revHex(json.prevBlock);
json.merkleRoot = utils.revHex(json.merkleRoot);
json.chainwork = new bn(json.chainwork, 'hex');
return new ChainBlock(chain, json);
};
ChainBlock.prototype.inspect = function inspect() {
var copy = new ChainBlock(this.chain, this, null);
copy.__proto__ = null;
copy.hash = utils.revHex(copy.hash);
copy.prevBlock = utils.revHex(copy.prevBlock);
copy.merkleRoot = utils.revHex(copy.merkleRoot);
copy.chainwork = copy.chainwork.toString(10);
delete copy.chain;
copy.previous = this.previous.length;
return copy;
var json = this.toJSON();
json.ancestors = this.ancestors.length;
return json;
};
/**

View File

@ -96,7 +96,7 @@ ChainDB.prototype._init = function _init() {
ChainDB.prototype.load = function load(callback) {
var self = this;
var genesis = bcoin.chainblock.fromJSON(this.chain, {
var genesis = new bcoin.chainblock(this.chain, {
hash: network.genesis.hash,
version: network.genesis.version,
prevBlock: network.genesis.prevBlock,
@ -104,8 +104,9 @@ ChainDB.prototype.load = function load(callback) {
ts: network.genesis.ts,
bits: network.genesis.bits,
nonce: network.genesis.nonce,
height: 0
});
height: 0,
chainwork: null
}, null);
this.loading = true;