Add tests for reorg improvement, and remove nolonger need code.
This commit is contained in:
parent
60a7f5ea29
commit
50925d1e0f
@ -16,9 +16,6 @@ var errors = index.errors;
|
|||||||
var log = index.log;
|
var log = index.log;
|
||||||
var Transaction = require('../transaction');
|
var Transaction = require('../transaction');
|
||||||
var Service = require('../service');
|
var Service = require('../service');
|
||||||
var utils = require('../utils');
|
|
||||||
|
|
||||||
var MAX_STACK_DEPTH = 1000;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the current state of the bitcoin blockchain. Other services
|
* Represents the current state of the bitcoin blockchain. Other services
|
||||||
@ -48,9 +45,6 @@ function DB(options) {
|
|||||||
|
|
||||||
this._setDataPath();
|
this._setDataPath();
|
||||||
|
|
||||||
this.lastSavedMetadata = null;
|
|
||||||
this.lastSavedMetadataThreshold = 0; // Set this during syncing for faster performance
|
|
||||||
|
|
||||||
this.levelupStore = leveldown;
|
this.levelupStore = leveldown;
|
||||||
if (options.store) {
|
if (options.store) {
|
||||||
this.levelupStore = options.store;
|
this.levelupStore = options.store;
|
||||||
@ -121,18 +115,19 @@ DB.prototype.start = function(callback) {
|
|||||||
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
metadata.tip = metadata.tip;
|
|
||||||
self.getBlock(metadata.tip, function(err, tip) {
|
self.getBlock(metadata.tip, function(err, tip) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tip = tip;
|
self.tip = tip;
|
||||||
self.tip.__height = metadata.tipHeight;
|
var blockIndex = self.node.services.bitcoind.getBlockIndex(self.tip.hash);
|
||||||
|
if (!blockIndex) {
|
||||||
|
return callback(new Error('Could not get height for tip.'));
|
||||||
|
}
|
||||||
|
self.tip.__height = blockIndex.height;
|
||||||
self.sync();
|
self.sync();
|
||||||
self.emit('ready');
|
self.emit('ready');
|
||||||
setImmediate(callback);
|
setImmediate(callback);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -298,18 +293,10 @@ DB.prototype.saveMetadata = function(callback) {
|
|||||||
|
|
||||||
callback = callback || defaultCallback;
|
callback = callback || defaultCallback;
|
||||||
|
|
||||||
var threshold = self.lastSavedMetadataThreshold;
|
|
||||||
if (self.lastSavedMetadata && Date.now() < self.lastSavedMetadata.getTime() + threshold) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
var metadata = {
|
var metadata = {
|
||||||
tip: self.tip ? self.tip.hash : null,
|
tip: self.tip ? self.tip.hash : null
|
||||||
tipHeight: self.tip && self.tip.__height ? self.tip.__height : 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.lastSavedMetadata = new Date();
|
|
||||||
|
|
||||||
this.store.put('metadata', JSON.stringify(metadata), {}, callback);
|
this.store.put('metadata', JSON.stringify(metadata), {}, callback);
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -416,7 +403,7 @@ DB.prototype.findCommonAncestor = function(block, done) {
|
|||||||
var mainHashesMap = {};
|
var mainHashesMap = {};
|
||||||
var forkHashesMap = {};
|
var forkHashesMap = {};
|
||||||
|
|
||||||
mainHahesMap[mainPosition] = true;
|
mainHashesMap[mainPosition] = true;
|
||||||
forkHashesMap[forkPosition] = true;
|
forkHashesMap[forkPosition] = true;
|
||||||
|
|
||||||
var commonAncestor = null;
|
var commonAncestor = null;
|
||||||
@ -426,8 +413,9 @@ DB.prototype.findCommonAncestor = function(block, done) {
|
|||||||
return !commonAncestor;
|
return !commonAncestor;
|
||||||
},
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
|
|
||||||
if(mainPosition) {
|
if(mainPosition) {
|
||||||
var mainBlockIndex = self.node.services.bitcoind.getBlockIndex(mainTip);
|
var mainBlockIndex = self.node.services.bitcoind.getBlockIndex(mainPosition);
|
||||||
if(mainBlockIndex && mainBlockIndex.prevHash) {
|
if(mainBlockIndex && mainBlockIndex.prevHash) {
|
||||||
mainHashesMap[mainBlockIndex.prevHash] = true;
|
mainHashesMap[mainBlockIndex.prevHash] = true;
|
||||||
mainPosition = mainBlockIndex.prevHash;
|
mainPosition = mainBlockIndex.prevHash;
|
||||||
@ -437,7 +425,7 @@ DB.prototype.findCommonAncestor = function(block, done) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(forkPosition) {
|
if(forkPosition) {
|
||||||
var forkBlockIndex = self.node.services.bitcoind.getBlockIndex(forkTip);
|
var forkBlockIndex = self.node.services.bitcoind.getBlockIndex(forkPosition);
|
||||||
if(forkBlockIndex && forkBlockIndex.prevHash) {
|
if(forkBlockIndex && forkBlockIndex.prevHash) {
|
||||||
forkHashesMap[forkBlockIndex.prevHash] = true;
|
forkHashesMap[forkBlockIndex.prevHash] = true;
|
||||||
forkPosition = forkBlockIndex.prevHash;
|
forkPosition = forkBlockIndex.prevHash;
|
||||||
@ -480,6 +468,7 @@ DB.prototype.syncRewind = function(block, done) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
log.warn('Reorg common ancestor found:', ancestorHash);
|
||||||
// Rewind the chain to the common ancestor
|
// Rewind the chain to the common ancestor
|
||||||
async.whilst(
|
async.whilst(
|
||||||
function() {
|
function() {
|
||||||
@ -537,7 +526,6 @@ DB.prototype.sync = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.bitcoindSyncing = true;
|
self.bitcoindSyncing = true;
|
||||||
self.lastSavedMetadataThreshold = 30000;
|
|
||||||
|
|
||||||
var height;
|
var height;
|
||||||
|
|
||||||
@ -601,7 +589,6 @@ DB.prototype.sync = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.bitcoindSyncing = false;
|
self.bitcoindSyncing = false;
|
||||||
self.lastSavedMetadataThreshold = 0;
|
|
||||||
self.saveMetadata();
|
self.saveMetadata();
|
||||||
|
|
||||||
// If bitcoind is completely synced
|
// If bitcoind is completely synced
|
||||||
|
|||||||
@ -162,19 +162,20 @@ describe('DB Service', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('metadata from the database if it exists', function(done) {
|
it('metadata from the database if it exists', function(done) {
|
||||||
|
var tipHash = '00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206';
|
||||||
var node = {
|
var node = {
|
||||||
network: Networks.testnet,
|
network: Networks.testnet,
|
||||||
datadir: 'testdir',
|
datadir: 'testdir',
|
||||||
services: {
|
services: {
|
||||||
bitcoind: {
|
bitcoind: {
|
||||||
genesisBuffer: genesisBuffer,
|
genesisBuffer: genesisBuffer,
|
||||||
|
getBlockIndex: sinon.stub().returns({tip:tipHash}),
|
||||||
on: sinon.stub()
|
on: sinon.stub()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var tip = Block.fromBuffer(genesisBuffer);
|
var tip = Block.fromBuffer(genesisBuffer);
|
||||||
var db = new TestDB({node: node});
|
var db = new TestDB({node: node});
|
||||||
var tipHash = '00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206';
|
|
||||||
db.getMetadata = sinon.stub().callsArgWith(0, null, {
|
db.getMetadata = sinon.stub().callsArgWith(0, null, {
|
||||||
tip: tipHash,
|
tip: tipHash,
|
||||||
tipHeight: 0
|
tipHeight: 0
|
||||||
@ -535,12 +536,7 @@ describe('DB Service', function() {
|
|||||||
put: function(key, value, options, callback) {
|
put: function(key, value, options, callback) {
|
||||||
key.should.equal('metadata');
|
key.should.equal('metadata');
|
||||||
JSON.parse(value).should.deep.equal({
|
JSON.parse(value).should.deep.equal({
|
||||||
tip: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f',
|
tip: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'
|
||||||
tipHeight: 0,
|
|
||||||
cache: {
|
|
||||||
hashes: {},
|
|
||||||
chainHashes: {}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
options.should.deep.equal({});
|
options.should.deep.equal({});
|
||||||
callback.should.be.a('function');
|
callback.should.be.a('function');
|
||||||
@ -549,22 +545,6 @@ describe('DB Service', function() {
|
|||||||
};
|
};
|
||||||
db.saveMetadata();
|
db.saveMetadata();
|
||||||
});
|
});
|
||||||
it('will not call store with threshold', function(done) {
|
|
||||||
var db = new DB(baseConfig);
|
|
||||||
db.lastSavedMetadata = new Date();
|
|
||||||
db.lastSavedMetadataThreshold = 30000;
|
|
||||||
var put = sinon.stub();
|
|
||||||
db.store = {
|
|
||||||
put: put
|
|
||||||
};
|
|
||||||
db.saveMetadata(function(err) {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
put.callCount.should.equal(0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getMetadata', function() {
|
describe('#getMetadata', function() {
|
||||||
@ -689,88 +669,79 @@ describe('DB Service', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getHashes', function() {
|
|
||||||
|
|
||||||
it('should get an array of chain hashes', function(done) {
|
|
||||||
|
|
||||||
var blocks = {};
|
|
||||||
var genesisBlock = Block.fromBuffer(new Buffer(chainData[0], 'hex'));
|
|
||||||
var block1 = Block.fromBuffer(new Buffer(chainData[1], 'hex'));
|
|
||||||
var block2 = Block.fromBuffer(new Buffer(chainData[2], 'hex'));
|
|
||||||
blocks[genesisBlock.hash] = genesisBlock;
|
|
||||||
blocks[block1.hash] = block1;
|
|
||||||
blocks[block2.hash] = block2;
|
|
||||||
|
|
||||||
var db = new DB(baseConfig);
|
|
||||||
db.genesis = genesisBlock;
|
|
||||||
db.getPrevHash = function(blockHash, cb) {
|
|
||||||
// TODO: expose prevHash as a string from bitcore
|
|
||||||
var prevHash = BufferUtil.reverse(blocks[blockHash].header.prevHash).toString('hex');
|
|
||||||
cb(null, prevHash);
|
|
||||||
};
|
|
||||||
|
|
||||||
db.tip = block2;
|
|
||||||
|
|
||||||
// the test
|
|
||||||
db.getHashes(block2.hash, function(err, hashes) {
|
|
||||||
should.not.exist(err);
|
|
||||||
should.exist(hashes);
|
|
||||||
hashes.length.should.equal(3);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#findCommonAncestor', function() {
|
describe('#findCommonAncestor', function() {
|
||||||
it('will find an ancestor 6 deep', function() {
|
it('will find an ancestor 6 deep', function(done) {
|
||||||
var db = new DB(baseConfig);
|
var db = new DB(baseConfig);
|
||||||
db.getHashes = function(tipHash, callback) {
|
|
||||||
callback(null, chainHashes);
|
|
||||||
};
|
|
||||||
db.tip = {
|
db.tip = {
|
||||||
hash: chainHashes[chainHashes.length]
|
hash: chainHashes[chainHashes.length - 1]
|
||||||
};
|
};
|
||||||
|
|
||||||
var expectedAncestor = chainHashes[chainHashes.length - 6];
|
var expectedAncestor = chainHashes[chainHashes.length - 6];
|
||||||
|
|
||||||
|
var mainBlocks = {};
|
||||||
|
for(var i = chainHashes.length - 1; i > chainHashes.length - 10; i--) {
|
||||||
|
var hash = chainHashes[i];
|
||||||
|
var prevHash = hexlebuf(chainHashes[i - 1]);
|
||||||
|
mainBlocks[hash] = {
|
||||||
|
header: {
|
||||||
|
prevHash: prevHash
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var forkedBlocks = {
|
var forkedBlocks = {
|
||||||
'd7fa6f3d5b2fe35d711e6aca5530d311b8c6e45f588a65c642b8baf4b4441d82': {
|
'd7fa6f3d5b2fe35d711e6aca5530d311b8c6e45f588a65c642b8baf4b4441d82': {
|
||||||
header: {
|
header: {
|
||||||
prevHash: hexlebuf('76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a')
|
prevHash: hexlebuf('76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a')
|
||||||
}
|
},
|
||||||
|
hash: 'd7fa6f3d5b2fe35d711e6aca5530d311b8c6e45f588a65c642b8baf4b4441d82'
|
||||||
},
|
},
|
||||||
'76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a': {
|
'76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a': {
|
||||||
header: {
|
header: {
|
||||||
prevHash: hexlebuf('f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c')
|
prevHash: hexlebuf('f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c')
|
||||||
}
|
},
|
||||||
|
hash: '76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a'
|
||||||
},
|
},
|
||||||
'f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c': {
|
'f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c': {
|
||||||
header: {
|
header: {
|
||||||
prevHash: hexlebuf('2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31')
|
prevHash: hexlebuf('2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31')
|
||||||
}
|
},
|
||||||
|
hash: 'f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c'
|
||||||
},
|
},
|
||||||
'2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31': {
|
'2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31': {
|
||||||
header: {
|
header: {
|
||||||
prevHash: hexlebuf('adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453')
|
prevHash: hexlebuf('adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453')
|
||||||
}
|
},
|
||||||
|
hash: '2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31'
|
||||||
},
|
},
|
||||||
'adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453': {
|
'adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453': {
|
||||||
header: {
|
header: {
|
||||||
prevHash: hexlebuf('3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618')
|
prevHash: hexlebuf('3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618')
|
||||||
}
|
},
|
||||||
|
hash: 'adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453'
|
||||||
},
|
},
|
||||||
'3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618': {
|
'3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618': {
|
||||||
header: {
|
header: {
|
||||||
prevHash: hexlebuf(expectedAncestor)
|
prevHash: hexlebuf(expectedAncestor)
|
||||||
}
|
},
|
||||||
},
|
hash: '3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
db.node.services = {};
|
db.node.services = {};
|
||||||
db.node.services.bitcoind = {
|
db.node.services.bitcoind = {
|
||||||
getBlockIndex: function(hash) {
|
getBlockIndex: function(hash) {
|
||||||
var block = forkedBlocks[hash];
|
var forkedBlock = forkedBlocks[hash];
|
||||||
|
var mainBlock = mainBlocks[hash];
|
||||||
|
var prevHash;
|
||||||
|
if (forkedBlock && forkedBlock.header.prevHash) {
|
||||||
|
prevHash = BufferUtil.reverse(forkedBlock.header.prevHash).toString('hex');
|
||||||
|
} else if (mainBlock && mainBlock.header.prevHash){
|
||||||
|
prevHash = BufferUtil.reverse(mainBlock.header.prevHash).toString('hex');
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
prevHash: BufferUtil.reverse(block.header.prevHash).toString('hex')
|
prevHash: prevHash
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -780,6 +751,7 @@ describe('DB Service', function() {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
ancestorHash.should.equal(expectedAncestor);
|
ancestorHash.should.equal(expectedAncestor);
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -854,7 +826,6 @@ describe('DB Service', function() {
|
|||||||
__height: 0,
|
__height: 0,
|
||||||
hash: lebufhex(block.header.prevHash)
|
hash: lebufhex(block.header.prevHash)
|
||||||
};
|
};
|
||||||
db.getHashes = sinon.stub().callsArgWith(1, null);
|
|
||||||
db.saveMetadata = sinon.stub();
|
db.saveMetadata = sinon.stub();
|
||||||
db.emit = sinon.stub();
|
db.emit = sinon.stub();
|
||||||
db.cache = {
|
db.cache = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user