Refactor to blockchain
This commit is contained in:
parent
9c7fa5cfaf
commit
1907e5f92b
@ -6,7 +6,11 @@ var _ = bitcore.deps._;
|
|||||||
|
|
||||||
function BlockChain() {
|
function BlockChain() {
|
||||||
this.tip = null;
|
this.tip = null;
|
||||||
this.headers = {};
|
this.work = {
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000000': 0
|
||||||
|
};
|
||||||
|
this.height = {};
|
||||||
|
this.hashByHeight = {};
|
||||||
this.next = {};
|
this.next = {};
|
||||||
this.prev = {};
|
this.prev = {};
|
||||||
}
|
}
|
||||||
@ -14,26 +18,127 @@ function BlockChain() {
|
|||||||
BlockChain.fromObject = function(obj) {
|
BlockChain.fromObject = function(obj) {
|
||||||
var blockchain = new BlockChain();
|
var blockchain = new BlockChain();
|
||||||
blockchain.tip = obj.tip;
|
blockchain.tip = obj.tip;
|
||||||
blockchain.headers = obj.headers;
|
blockchain.work = obj.work;
|
||||||
|
blockchain.hashByHeight = obj.hashByHeight;
|
||||||
|
blockchain.height = obj.height;
|
||||||
blockchain.next = obj.next;
|
blockchain.next = obj.next;
|
||||||
blockchain.prev = obj.prev;
|
blockchain.prev = obj.prev;
|
||||||
return blockchain;
|
return blockchain;
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockChain.prototype.setTip = function(block) {
|
var getWork = function(bits) {
|
||||||
|
var bytes = ((bits >>> 24) & 0xff) >>> 0;
|
||||||
|
return ((bits & 0xffffff) << (8 * (bytes - 3))) >>> 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockChain.prototype.addData = function(block) {
|
||||||
$.checkArgument(block instanceof bitcore.Block, 'Argument is not a Block instance');
|
$.checkArgument(block instanceof bitcore.Block, 'Argument is not a Block instance');
|
||||||
this.tip = block.hash;
|
|
||||||
this.headers[block.hash] = block.header;
|
|
||||||
var prevHash = bitcore.util.buffer.reverse(block.header.prevHash).toString('hex');
|
var prevHash = bitcore.util.buffer.reverse(block.header.prevHash).toString('hex');
|
||||||
this.next[prevHash] = block.hash;
|
|
||||||
|
this.work[block.hash] = this.work[prevHash].work + getWork(block.header.bits);
|
||||||
this.prev[block.hash] = prevHash;
|
this.prev[block.hash] = prevHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BlockChain.prototype.proposeNewBlock = function(block) {
|
||||||
|
$.checkArgument(block instanceof bitcore.Block, 'Argument is not a Block instance');
|
||||||
|
var prevHash = bitcore.util.buffer.reverse(block.header.prevHash).toString('hex');
|
||||||
|
|
||||||
|
if (!this.work[prevHash]) {
|
||||||
|
throw new Error('No previous data to estimate work');
|
||||||
|
}
|
||||||
|
this.addData(block);
|
||||||
|
|
||||||
|
if (this.work[block.hash] > this.work[this.tip]) {
|
||||||
|
|
||||||
|
var toUnconfirm = [];
|
||||||
|
var toConfirm = [];
|
||||||
|
var commonAncestor;
|
||||||
|
|
||||||
|
var pointer = block.hash;
|
||||||
|
while (!this.height[pointer]) {
|
||||||
|
toConfirm.push(pointer);
|
||||||
|
pointer = this.prev[pointer];
|
||||||
|
}
|
||||||
|
commonAncestor = pointer;
|
||||||
|
|
||||||
|
pointer = this.tip;
|
||||||
|
while (pointer != commonAncestor) {
|
||||||
|
toUnconfirm.push(pointer);
|
||||||
|
pointer = this.prev[pointer];
|
||||||
|
}
|
||||||
|
|
||||||
|
toConfirm.reverse();
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
toUnconfirm.map(function(hash) {
|
||||||
|
self.unconfirm(hash);
|
||||||
|
});
|
||||||
|
toConfirm.map(function(hash) {
|
||||||
|
self.confirm(hash);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
unconfirmed: toUnconfirm,
|
||||||
|
confirmed: toConfirm
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
unconfirmed: [],
|
||||||
|
confirmed: []
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockChain.prototype.confirm = function(hash) {
|
||||||
|
var prevHash = this.prev[hash];
|
||||||
|
$.checkState(prevHash === this.tip);
|
||||||
|
|
||||||
|
this.tip = hash;
|
||||||
|
var height = this.height[prevHash] + 1;
|
||||||
|
this.next[prevHash] = hash;
|
||||||
|
this.hashByHeight[height] = hash;
|
||||||
|
this.height[hash] = height;
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockChain.prototype.unconfirm = function(hash) {
|
||||||
|
var prevHash = this.prev[hash];
|
||||||
|
$.checkState(hash === this.tip);
|
||||||
|
|
||||||
|
this.tip = prevHash;
|
||||||
|
var height = this.height[hash];
|
||||||
|
this.next[prevHash] = undefined;
|
||||||
|
this.hashByHeight[height] = undefined;
|
||||||
|
this.height[hash] = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockChain.prototype.getBlockLocator = function() {
|
||||||
|
$.checkState(this.tip);
|
||||||
|
$.checkState(this.height[this.tip]);
|
||||||
|
|
||||||
|
var result = [];
|
||||||
|
var currentHeight = this.height[this.tip];
|
||||||
|
var exponentialBackOff = 1;
|
||||||
|
for (var i = 0; i < 10; i++) {
|
||||||
|
result.push(this.hashByHeight[currentHeight--]);
|
||||||
|
}
|
||||||
|
while (currentHeight > 0) {
|
||||||
|
result.push(this.hashByHeight[currentHeight]);
|
||||||
|
currentHeight -= exponentialBackOff;
|
||||||
|
exponentialBackOff *= 2;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
BlockChain.prototype.hasData = function(hash) {
|
||||||
|
return !!this.prev[hash];
|
||||||
|
};
|
||||||
|
|
||||||
BlockChain.prototype.toObject = function() {
|
BlockChain.prototype.toObject = function() {
|
||||||
return {
|
return {
|
||||||
tip: this.tip,
|
tip: this.tip,
|
||||||
headers: _.map(this.headers, function(header) { return header.toObject(); }),
|
work: this.work,
|
||||||
next: this.next,
|
next: this.next,
|
||||||
|
hashByHeight: this.hashByHeight,
|
||||||
|
height: this.height,
|
||||||
prev: this.prev
|
prev: this.prev
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user