flosight-api/regtest/reorg.js
Chris Kleeschulte 7de52afbe6
Fixed reorg.
2017-09-08 14:11:25 -04:00

278 lines
6.4 KiB
JavaScript

'use strict';
var expect = require('chai').expect;
var net = require('net');
var spawn = require('child_process').spawn;
var rimraf = require('rimraf');
var mkdirp = require('mkdirp');
var fs = require('fs');
var p2p = require('bitcore-p2p');
var bitcore = require('bitcore-lib');
var Networks = bitcore.Networks;
var BlockHeader = bitcore.BlockHeader;
var Block = bitcore.Block;
var BcoinBlock = require('bcoin').block;
var http = require('http');
Networks.enableRegtest();
var messages = new p2p.Messages({ network: Networks.get('regtest'), Block: BcoinBlock, BlockHeader: BlockHeader });
var server;
var rawBlocks = require('./data/blocks.json');
var rawReorgBlocks = require('./data/blocks_reorg.json')[0];
var reorgBlock = BcoinBlock.fromRaw(rawReorgBlocks, 'hex');
var blocks = rawBlocks.map(function(rawBlock) {
return new Block(new Buffer(rawBlock, 'hex'));
});
var headers = blocks.map(function(block) {
return block.header;
});
var debug = true;
var bitcoreDataDir = '/tmp/bitcore';
var bitcore = {
configFile: {
file: bitcoreDataDir + '/bitcore-node.json',
conf: {
network: 'regtest',
port: 53001,
datadir: bitcoreDataDir,
services: [
'p2p',
'db',
'header',
'block',
'address',
'transaction',
'mempool',
'web',
'insight-api',
'fee',
'timestamp'
],
servicesConfig: {
'p2p': {
'peers': [
{ 'ip': { 'v4': '127.0.0.1' }, port: 18444 }
]
},
'insight-api': {
'routePrefix': 'api'
}
}
}
},
httpOpts: {
protocol: 'http:',
hostname: 'localhost',
port: 53001,
},
opts: { cwd: bitcoreDataDir },
datadir: bitcoreDataDir,
exec: 'bitcored', // ensure this on your path or add the full, absolute path.
args: ['start'],
process: null
};
var blockIndex = 0;
var tcpSocket;
var startFakeNode = function() {
server = net.createServer(function(socket) {
tcpSocket = socket;
socket.on('end', function() {
console.log('bitcore-node has ended the connection');
});
socket.on('data', function(data) {
var command = data.slice(4, 16).toString('hex');
var message;
if (command === '76657273696f6e0000000000') { //version
message = messages.Version();
}
if (command === '76657261636b000000000000') { //verack
message = messages.VerAck();
}
if (command === '676574686561646572730000') { //getheaders
message = messages.Headers(headers);
}
if (command === '676574626c6f636b73000000') { //getblocks
var block = blocks[blockIndex];
if (!block) {
return;
}
var blockHash = block.hash;
var inv = p2p.Inventory.forBlock(blockHash);
message = messages.Inventory([inv]);
}
if (command === '676574646174610000000000') { //getdata
var raw = rawBlocks[blockIndex++];
var blk = BcoinBlock.fromRaw(raw, 'hex');
message = messages.Block(blk, { Block: BcoinBlock });
}
if (message) {
socket.write(message.toBuffer());
}
});
socket.pipe(socket);
});
server.listen(18444, '127.0.0.1');
};
var shutdownFakeNode = function() {
server.close();
};
var shutdownBitcore = function(callback) {
if (bitcore.process) {
bitcore.process.kill();
}
callback();
};
var startBitcore = function(callback) {
rimraf(bitcoreDataDir, function(err) {
if(err) {
return callback(err);
}
mkdirp(bitcoreDataDir, function(err) {
if(err) {
return callback(err);
}
fs.writeFileSync(bitcore.configFile.file, JSON.stringify(bitcore.configFile.conf));
var args = bitcore.args;
bitcore.process = spawn(bitcore.exec, args, bitcore.opts);
bitcore.process.stdout.on('data', function(data) {
if (debug) {
process.stdout.write(data.toString());
}
});
bitcore.process.stderr.on('data', function(data) {
if (debug) {
process.stderr.write(data.toString());
}
});
callback();
});
});
};
describe('Reorg', function() {
// 1. spin up bitcore-node and have it connect to our custom tcp socket
// 2. feed it a few headers
// 3. feed it a few blocks
// 4. feed it a block that reorgs
this.timeout(60000);
before(function(done) {
startFakeNode();
startBitcore(done);
});
after(function(done) {
shutdownFakeNode();
shutdownBitcore(function() {
setTimeout(done, 3000);
});
});
it('should reorg correctly when already synced', function(done) {
// at this point we have a fully synced chain at height 7....
// we now want to send a new block number 7 whose prev hash is block 6 (it should be block 7)
// we then should reorg back to block 6 then back up to the new block 7
setTimeout(function() {
console.log('From Test: reorging to block: ' + reorgBlock.rhash());
// send the reorg block
rawBlocks.push(rawReorgBlocks);
var blockHash = reorgBlock.rhash();
var inv = p2p.Inventory.forBlock(blockHash);
var msg = messages.Inventory([inv]);
tcpSocket.write(msg.toBuffer());
// wait 5 secs until the reorg happens, if it takes any longer the test ought to fail anyway
setTimeout(function() {
var error;
var request = http.request('http://localhost:53001/api/block/' + reorgBlock.rhash(), function(res) {
if (res.statusCode !== 200 && res.statusCode !== 201) {
if (error) {
return;
}
return done('Error from bitcore-node webserver: ' + res.statusCode);
}
var resError;
var resData = '';
res.on('error', function(e) {
resError = e;
});
res.on('data', function(data) {
resData += data;
});
res.on('end', function() {
if (error) {
return;
}
var data = JSON.parse(resData);
expect(data.height).to.equal(7);
expect(data.hash).to.equal(reorgBlock.rhash());
done(resError, resData);
});
});
request.on('error', function(e) {
error = e;
done(error);
});
request.write('');
request.end();
}, 5000);
}, 2000);
});
});