This commit is contained in:
Chris Kleeschulte 2017-06-20 09:47:59 -04:00
parent ac8e8b6577
commit c4e90875a9
12 changed files with 85 additions and 451 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,169 +0,0 @@
'use strict';
var benchmark = require('benchmark');
var bitcoin = require('bitcoin');
var async = require('async');
var maxTime = 20;
console.log('Bitcoin Service native interface vs. Bitcoin JSON RPC interface');
console.log('----------------------------------------------------------------------');
// To run the benchmarks a fully synced Bitcore Core directory is needed. The RPC comands
// can be modified to match the settings in bitcoin.conf.
var fixtureData = {
blockHashes: [
'00000000fa7a4acea40e5d0591d64faf48fd862fa3561d111d967fc3a6a94177',
'000000000017e9e0afc4bc55339f60ffffb9cbe883f7348a9fbc198a486d5488',
'000000000019ddb889b534c5d85fca2c91a73feef6fd775cd228dea45353bae1',
'0000000000977ac3d9f5261efc88a3c2d25af92a91350750d00ad67744fa8d03'
],
txHashes: [
'5523b432c1bd6c101bee704ad6c560fd09aefc483f8a4998df6741feaa74e6eb',
'ff48393e7731507c789cfa9cbfae045b10e023ce34ace699a63cdad88c8b43f8',
'5d35c5eebf704877badd0a131b0a86588041997d40dbee8ccff21ca5b7e5e333',
'88842f2cf9d8659c3434f6bc0c515e22d87f33e864e504d2d7117163a572a3aa',
]
};
var bitcoind = require('../').services.Bitcoin({
node: {
datadir: process.env.HOME + '/.bitcoin',
network: {
name: 'testnet'
}
}
});
bitcoind.on('error', function(err) {
console.error(err.message);
});
bitcoind.start(function(err) {
if (err) {
throw err;
}
console.log('Bitcoin Core started');
});
bitcoind.on('ready', function() {
console.log('Bitcoin Core ready');
var client = new bitcoin.Client({
host: 'localhost',
port: 18332,
user: 'bitcoin',
pass: 'local321'
});
async.series([
function(next) {
var c = 0;
var hashesLength = fixtureData.blockHashes.length;
var txLength = fixtureData.txHashes.length;
function bitcoindGetBlockNative(deffered) {
if (c >= hashesLength) {
c = 0;
}
var hash = fixtureData.blockHashes[c];
bitcoind.getBlock(hash, function(err, block) {
if (err) {
throw err;
}
deffered.resolve();
});
c++;
}
function bitcoindGetBlockJsonRpc(deffered) {
if (c >= hashesLength) {
c = 0;
}
var hash = fixtureData.blockHashes[c];
client.getBlock(hash, false, function(err, block) {
if (err) {
throw err;
}
deffered.resolve();
});
c++;
}
function bitcoinGetTransactionNative(deffered) {
if (c >= txLength) {
c = 0;
}
var hash = fixtureData.txHashes[c];
bitcoind.getTransaction(hash, true, function(err, tx) {
if (err) {
throw err;
}
deffered.resolve();
});
c++;
}
function bitcoinGetTransactionJsonRpc(deffered) {
if (c >= txLength) {
c = 0;
}
var hash = fixtureData.txHashes[c];
client.getRawTransaction(hash, function(err, tx) {
if (err) {
throw err;
}
deffered.resolve();
});
c++;
}
var suite = new benchmark.Suite();
suite.add('bitcoind getblock (native)', bitcoindGetBlockNative, {
defer: true,
maxTime: maxTime
});
suite.add('bitcoind getblock (json rpc)', bitcoindGetBlockJsonRpc, {
defer: true,
maxTime: maxTime
});
suite.add('bitcoind gettransaction (native)', bitcoinGetTransactionNative, {
defer: true,
maxTime: maxTime
});
suite.add('bitcoind gettransaction (json rpc)', bitcoinGetTransactionJsonRpc, {
defer: true,
maxTime: maxTime
});
suite
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').pluck('name'));
console.log('----------------------------------------------------------------------');
next();
})
.run();
}
], function(err) {
if (err) {
throw err;
}
console.log('Finished');
bitcoind.stop(function(err) {
if (err) {
console.error('Fail to stop services: ' + err);
process.exit(1);
}
process.exit(0);
});
});
});

View File

@ -6,6 +6,7 @@ module.exports = {
livenet: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f',
regtest: '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206',
testnet: '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943' //this is testnet3
testnet5: '000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943' //this is testnet5
}
};

View File

@ -12,35 +12,18 @@ var log = index.log;
var Bus = require('./bus');
var errors = require('./errors');
/**
* A node is a hub of services, and will manage starting and stopping the services in
* the correct order based the the dependency chain. The node also holds common configuration
* properties that can be shared across services, such as network settings.
*
* The array of services should have the format:
* ```js
* {
* name: 'bitcoind',
* config: {}, // options to pass into constructor
* module: ServiceConstructor
* }
* ```
*
* @param {Object} config - The configuration of the node
* @param {Array} config.formatLogs - Option to disable formatting of logs
* @param {Array} config.services - The array of services
* @param {Number} config.port - The HTTP port for services
* @param {Boolean} config.https - Enable https
* @param {Object} config.httpsOptions - Options for https
* @param {String} config.httpsOptions.key - Path to key file
* @param {String} config.httpsOptions.cert - Path to cert file
* @param {}
*/
function Node(config) {
/* jshint maxstatements: 20 */
if(!(this instanceof Node)) {
return new Node(config);
}
this._init(config);
}
util.inherits(Node, EventEmitter);
Node.prototype._init = function(config) {
this.configPath = config.path;
this.errors = errors;
this.log = log;
@ -54,7 +37,6 @@ function Node(config) {
this.services = {};
this._unloadedServices = [];
// TODO type check the arguments of config.services
if (config.services) {
$.checkArgument(Array.isArray(config.services));
this._unloadedServices = config.services;
@ -63,15 +45,8 @@ function Node(config) {
this.https = config.https;
this.httpsOptions = config.httpsOptions;
this._setNetwork(config);
}
};
util.inherits(Node, EventEmitter);
/**
* Will set the this.network based on a network string.
* @param {Object} config
* @param {String} config.network - Possible options "testnet", "regtest" or "livenet"
*/
Node.prototype._setNetwork = function(config) {
if (config.network === 'testnet') {
this.network = Networks.get('testnet');
@ -84,10 +59,6 @@ Node.prototype._setNetwork = function(config) {
$.checkState(this.network, 'Unrecognized network');
};
/**
* Will instantiate a new Bus for this node.
* @returns {Bus}
*/
Node.prototype.openBus = function(options) {
if (!options) {
options = {};
@ -95,10 +66,6 @@ Node.prototype.openBus = function(options) {
return new Bus({node: this, remoteAddress: options.remoteAddress});
};
/**
* Will get an array of API method descriptions from all of the available services.
* @returns {Array}
*/
Node.prototype.getAllAPIMethods = function() {
var methods = [];
for(var i in this.services) {
@ -110,10 +77,6 @@ Node.prototype.getAllAPIMethods = function() {
return methods;
};
/**
* Will get an array of events from all of the available services.
* @returns {Array}
*/
Node.prototype.getAllPublishEvents = function() {
var events = [];
for (var i in this.services) {
@ -125,16 +88,10 @@ Node.prototype.getAllPublishEvents = function() {
return events;
};
/**
* Will organize services into the order that they should be started
* based on the service's dependencies.
* @returns {Array}
*/
Node.prototype.getServiceOrder = function() {
var services = this._unloadedServices;
// organize data for sorting
var names = [];
var servicesByName = {};
for (var i = 0; i < services.length; i++) {
@ -153,10 +110,8 @@ Node.prototype.getServiceOrder = function() {
var service = servicesByName[name];
$.checkState(service, 'Required dependency "' + name + '" not available.');
// first add the dependencies
addToStack(service.module.dependencies);
// add to the stack if it hasn't been added
if(!stackNames[name]) {
stack.push(service);
stackNames[name] = true;
@ -170,17 +125,6 @@ Node.prototype.getServiceOrder = function() {
return stack;
};
/**
* Will instantiate an instance of the service module, add it to the node
* services, start the service and add available API methods to the node and
* checking for any conflicts.
* @param {Object} serviceInfo
* @param {String} serviceInfo.name - The name of the service
* @param {Object} serviceInfo.module - The service module constructor
* @param {Object} serviceInfo.config - Options to pass into the constructor
* @param {Function} callback - Called when the service is started
* @private
*/
Node.prototype._startService = function(serviceInfo, callback) {
var self = this;
@ -200,7 +144,6 @@ Node.prototype._startService = function(serviceInfo, callback) {
config.name = serviceInfo.name;
var service = new serviceInfo.module(config);
// include in loaded services
self.services[serviceInfo.name] = service;
service.start(function(err) {
@ -208,7 +151,6 @@ Node.prototype._startService = function(serviceInfo, callback) {
return callback(err);
}
// add API methods
if (service.getAPIMethods) {
var methodData = service.getAPIMethods();
var methodNameConflicts = [];
@ -245,10 +187,6 @@ Node.prototype._logTitle = function() {
};
/**
* Will start all running services in the order based on the dependency chain.
* @param {Function} callback - Called when all services are started
*/
Node.prototype.start = function(callback) {
var self = this;
var servicesOrder = this.getServiceOrder();
@ -279,11 +217,6 @@ Node.prototype.getNetworkName = function() {
return network;
};
/**
* Will stop all running services in the reverse order that they
* were initially started.
* @param {Function} callback - Called when all services are stopped
*/
Node.prototype.stop = function(callback) {
log.info('Beginning shutdown');
@ -305,7 +238,7 @@ Node.prototype.stop = function(callback) {
setImmediate(next);
}
},
function(err) {
function() {
if (callback) {
callback();
}

View File

@ -11,50 +11,6 @@ var fs = require('fs');
log.debug = function() {};
/**
* Checks for configuration options from version 2. This includes an "address" and
* "db" service, or having "datadir" at the root of the config.
*/
//function checkConfigVersion2(fullConfig) {
// // TODO: Remove
// return false;
//
// var datadirUndefined = _.isUndefined(fullConfig.datadir);
// var addressDefined = (fullConfig.services.indexOf('address') >= 0);
// var dbDefined = (fullConfig.services.indexOf('db') >= 0);
//
// if (!datadirUndefined || addressDefined || dbDefined) {
//
// console.warn('\nConfiguration file is not compatible with this version. \n' +
// 'A reindex for bitcoind is necessary for this upgrade with the "reindex=1" bitcoin.conf option. \n' +
// 'There are changes necessary in both bitcoin.conf and bitcore-node.json. \n\n' +
// 'To upgrade please see the details below and documentation at: \n' +
// 'https://github.com/bitpay/bitcore-node/blob/bitcoind/docs/upgrade.md \n');
//
// if (!datadirUndefined) {
// console.warn('Please remove "datadir" and add it to the config at ' + fullConfig.path + ' with:');
// var missingConfig = {
// servicesConfig: {
// bitcoind: {
// spawn: {
// datadir: fullConfig.datadir,
// exec: path.resolve(__dirname, '../../bin/bitcoind')
// }
// }
// }
// };
// console.warn(JSON.stringify(missingConfig, null, 2) + '\n');
// }
//
// if (addressDefined || dbDefined) {
// console.warn('Please remove "address" and/or "db" from "services" in: ' + fullConfig.path + '\n');
// }
//
// return true;
// }
//
// return false;
//}
/**
* This function will instantiate and start a Node, requiring the necessary service
@ -116,7 +72,6 @@ function start(options) {
* @param {Object} service
*/
function checkService(service) {
// check that the service supports expected methods
if (!service.module.prototype ||
!service.module.dependencies ||
!service.module.prototype.start ||
@ -139,7 +94,7 @@ function lookInRequirePathConfig(req, service) {
var serviceFile = service.config.requirePath.replace(/.js$/, '');
return req(serviceFile);
} catch(e) {
// we want to throw in all cases expect file not found
log.info('Checked the service\'s requirePath value, but could not find the service, checking elsewhere.');
}
}
@ -147,7 +102,7 @@ function lookInCwd(req, service) {
try {
return req(process.cwd + '/' + service);
} catch(e) {
// throw in all cases expect file not found
log.info('Checked the current working directory, but did not find the service.');
}
}
@ -156,7 +111,7 @@ function lookInBuiltInPath(req, service) {
var serviceFile = path.resolve(__dirname, '../services/' + service.name);
return req(serviceFile);
} catch(e) {
throw e;
log.info('Checked the built-in path: lib/services, but did not find the service.');
}
}
@ -165,23 +120,18 @@ function lookInModuleManifest(req, service) {
var servicePackage = req(service.name + '/package.json');
var serviceModule = service.name;
if (servicePackage.bitcoreNode) {
serviceModule = service.name + '/' + servicePackage.bitcoreNode;
serviceModule = serviceModule + '/' + servicePackage.bitcoreNode;
return req(serviceModule);
}
} catch(e) {
log.info('Checked the module\'s package.json for \'bitcoreNode\' field, but found no service.');
}
}
/**
* Will require a module from local services directory first
* and then from available node_modules
* @param {Function} req
* @param {Object} service
*/
function loadModule(req, service) {
var serviceCode;
//first, if we have explicitly set the require path for our service, use this.
//first, if we have explicitly set the require path for our service:
serviceCode = lookInRequirePathConfig(req, service);
//second, look in the current working directory (of the controlling terminal, if there is one) for the service code

View File

@ -8,15 +8,6 @@ var log = index.log;
var BaseService = require('../../service');
var assert = require('assert');
/*
Purpose:
1. join a P2P
2. relay messages
3. publish new transactions (pub/sub)
4. publish new blocks (pub/sub)
5. broadcast messages on behalf of subscribers (block headers, blocks, bloom filters)
*/
var P2P = function(options) {
if (!(this instanceof P2P)) {

View File

@ -56,12 +56,6 @@ utils.reverseBufferToString = function(buf) {
return BufferUtil.reverse(buf).toString('hex');
};
//TODO: write some code here
utils.getIpAddressInfo = function(ipStr) {
//is this ipv4 or ipv6, 4 is 32 bits, 6 is 128 bits
//does this string have colons or periods?
};
utils.getAddressStringFromScript = function(script, network) {
var address = script.toAddress(network);
@ -78,4 +72,64 @@ utils.getAddressStringFromScript = function(script, network) {
};
utils.sendError = function(err, res) {
if (err.statusCode) {
res.status(err.statusCode).send(err.message);
} else {
console.error(err.stack);
res.status(503).send(err.message);
}
};
utils.getWalletId = exports.generateJobId = function() {
return crypto.randomBytes(16).toString('hex');
};
utils.getWalletId = exports.generateJobId = function() {
return crypto.randomBytes(16).toString('hex');
};
utils.toJSONL = function(obj) {
var str = JSON.stringify(obj);
str = str.replace(/\n/g, '');
return str + '\n';
}
utils.normalizeTimeStamp = function(value) {
if (value > 0xffffffff) {
value = Math.round(value/1000);
}
return value;
};
utils.delimitedStringParse = function(delim, str) {
function tryJSONparse(str) {
try {
return JSON.parse(str);
} catch(e) {
return false;
}
}
var ret = [];
if (delim === null) {
return tryJSONparse(str);
}
var list = str.split(delim);
for(var i = 0; i < list.length; i++) {
ret.push(tryJSONparse(list[i]));
}
ret = _.compact(ret);
return ret.length === 0 ? false : ret;
};
utils.toIntIfNumberLike = function(a) {
if (!/[^\d]+/.test(a)) {
return parseInt(a);
}
return a;
};
module.exports = utils;

View File

@ -32,7 +32,6 @@
},
"scripts": {
"preinstall": "./scripts/download",
"verify": "./scripts/download --skip-bitcoin-download --verify-bitcoin-download",
"test": "mocha -R spec --recursive",
"regtest": "./scripts/regtest",
"jshint": "jshint --reporter=node_modules/jshint-stylish ./lib",
@ -41,7 +40,12 @@
},
"tags": [
"bitcoin",
"bitcoind"
"bitcoind",
"bcoin",
"bitcoin full node",
"bitcoin index",
"block explorer",
"wallet backend"
],
"dependencies": {
"async": "^1.3.0",
@ -65,15 +69,15 @@
"socket.io": "^1.4.5",
"socket.io-client": "^1.4.5",
"ttyread": "^1.0.2",
"zmq": "^2.14.0"
"bitcore-p2p": ""
},
"optionalDependencies": {
"bufferutil": "~1.2.1",
"utf-8-validate": "~1.2.1"
},
"devDependencies": {
"zmq": "^2.14.0",
"benchmark": "1.0.0",
"bitcore-p2p": "",
"chai": "^3.5.0",
"coveralls": "^2.11.9",
"istanbul": "^0.4.3",

View File

@ -1,119 +0,0 @@
#!/bin/bash
exit 0
set -e
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
platform=`uname -a | awk '{print tolower($1)}'`
arch=`uname -m`
version="0.12.1"
url="https://github.com/bitpay/bitcoin/releases/download"
tag="v0.12.1-bitcore-4"
if [ "${platform}" == "linux" ]; then
if [ "${arch}" == "x86_64" ]; then
tarball_name="bitcoin-${version}-linux64.tar.gz"
elif [ "${arch}" == "x86_32" ]; then
tarball_name="bitcoin-${version}-linux32.tar.gz"
fi
elif [ "${platform}" == "darwin" ]; then
tarball_name="bitcoin-${version}-osx64.tar.gz"
else
echo "Bitcoin binary distribution not available for platform and architecture"
exit -1
fi
binary_url="${url}/${tag}/${tarball_name}"
shasums_url="${url}/${tag}/SHA256SUMS.asc"
download_bitcoind() {
cd "${root_dir}/bin"
echo "Downloading bitcoin: ${binary_url}"
is_curl=true
if hash curl 2>/dev/null; then
curl --fail -I $binary_url >/dev/null 2>&1
else
is_curl=false
wget --server-response --spider $binary_url >/dev/null 2>&1
fi
if test $? -eq 0; then
if [ "${is_curl}" = true ]; then
curl -L $binary_url > $tarball_name
curl -L $shasums_url > SHA256SUMS.asc
else
wget $binary_url
wget $shasums_url
fi
if test -e "${tarball_name}"; then
echo "Unpacking bitcoin distribution"
tar -xvzf $tarball_name
if test $? -eq 0; then
ln -sf "bitcoin-${version}/bin/bitcoind"
return;
fi
fi
fi
echo "Bitcoin binary distribution could not be downloaded"
exit -1
}
verify_download() {
echo "Verifying signatures of bitcoin download"
gpg --verify "${root_dir}/bin/SHA256SUMS.asc"
if hash shasum 2>/dev/null; then
shasum_cmd="shasum -a 256"
else
shasum_cmd="sha256sum"
fi
download_sha=$(${shasum_cmd} "${root_dir}/bin/${tarball_name}" | awk '{print $1}')
expected_sha=$(cat "${root_dir}/bin/SHA256SUMS.asc" | grep "${tarball_name}" | awk '{print $1}')
echo "Checksum (download): ${download_sha}"
echo "Checksum (verified): ${expected_sha}"
if [ "${download_sha}" != "${expected_sha}" ]; then
echo -e "\033[1;31mChecksums did NOT match!\033[0m\n"
exit 1
else
echo -e "\033[1;32mChecksums matched!\033[0m\n"
fi
}
download=1
verify=0
if [ "${SKIP_BITCOIN_DOWNLOAD}" = 1 ]; then
download=0;
fi
if [ "${VERIFY_BITCOIN_DOWNLOAD}" = 1 ]; then
verify=1;
fi
while [ -n "$1" ]; do
param="$1"
value="$2"
case $param in
--skip-bitcoin-download)
download=0
;;
--verify-bitcoin-download)
verify=1
;;
esac
shift
done
if [ "${download}" = 1 ]; then
download_bitcoind
fi
if [ "${verify}" = 1 ]; then
verify_download
fi
exit 0

View File

@ -1,8 +0,0 @@
#!/bin/bash
set -e
_mocha -R spec regtest/p2p.js
_mocha -R spec regtest/bitcoind.js
_mocha -R spec regtest/cluster.js
_mocha -R spec regtest/node.js