diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..404e019b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +node_modules +Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..3348ee1d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +FROM node:8 + +# update apt-get +RUN apt-get update && apt-get install -y dnsutils + +USER root +# Set up non root user +RUN useradd --user-group --create-home --shell /bin/false ows + +# Setup environment variables +ENV NODE_ENV=production +ENV HOME_PATH=/home/ows + +ENV PKG_NAME=btccore-node +ENV PKG_DIR=$HOME_PATH/$PKG_NAME + +ENV APP_NAME=bitcoin-core-services +ENV APP_DIR=$HOME_PATH/$APP_NAME + +ENV BITCOIN_DATA=/data + +# Set up folder and add install files +RUN mkdir -p $PKG_DIR +RUN mkdir -p $BITCOIN_DATA +COPY package.json $PKG_DIR +WORKDIR $PKG_DIR + +RUN chown -R ows:ows $HOME_PATH +RUN chgrp ows /usr/local/lib/node_modules +RUN chgrp ows /usr/local/bin + +USER ows +RUN npm install -g owstack/btccore-node + +WORKDIR $HOME_PATH +RUN $PKG_NAME create -d $BITCOIN_DATA $APP_NAME +WORKDIR $APP_DIR +RUN $PKG_NAME install https://github.com/owstack/btccore-explorer-api.git +RUN $PKG_NAME install https://github.com/owstack/btccore-wallet-service.git +USER root +CMD ["btccore-node","start"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..d39a1b13 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,36 @@ +version: '3.2' +services: + bitcoin-core-conf: + build: extra/compose + volumes: + - bitcoin-core-data-dir:/data + - btccore-conf-dir:/home/ows/config + bitcoin-core: + image: "owstack/bitcoin-core:0.14.1-ows" + user: root + command: "/usr/local/bin/bitcoind -datadir=/data" + ports: + - "8332:8332" + - "8333:8333" + - "18332:18332" + - "18333:18333" + - "28332:28332" + - "28333:28333" + volumes: + - bitcoin-core-data-dir:/data + depends_on: + - "bitcoin-core-conf" + ows-bitcoin-cash-node: + build: . + ports: + - "3001:3001" + depends_on: + - "bitcoin-core" + volumes: + # - bitcoin-core-data-dir:/data + - btccore-conf-dir:/home/ows/config + command: "btccore-node start -c /home/ows/config" + # command: "cat /home/ows/config/btccore-node.json" +volumes: + bitcoin-core-data-dir: + btccore-conf-dir: diff --git a/extra/compose/Dockerfile b/extra/compose/Dockerfile new file mode 100644 index 00000000..ed3b7ab0 --- /dev/null +++ b/extra/compose/Dockerfile @@ -0,0 +1,13 @@ +FROM buildpack-deps:jessie +MAINTAINER Ian Patton (ian.patton@gmail.com) + +ENV BITCOIN_DATA=/data +ENV CONFIG_DIR=/home/ows/config + +RUN mkdir -p $BITCOIN_DATA +RUN mkdir -p $CONFIG_DIR + +COPY default.bitcoin.conf $BITCOIN_DATA/bitcoin.conf +COPY default.btccore-node.json $CONFIG_DIR/btccore-node.json + +CMD ["echo","installed config files"] diff --git a/extra/compose/default.bitcoin.conf b/extra/compose/default.bitcoin.conf new file mode 100644 index 00000000..c57b8c46 --- /dev/null +++ b/extra/compose/default.bitcoin.conf @@ -0,0 +1,11 @@ +server=1 +txindex=1 +addressindex=1 +timestampindex=1 +spentindex=1 +zmqpubrawtx=tcp://0.0.0.0:28332 +zmqpubhashblock=tcp://0.0.0.0:28332 +rpcallowip=0.0.0.0/0 +rpcuser=bitcoin +rpcpassword=local321 +uacomment=bcccore diff --git a/extra/compose/default.btccore-node.json b/extra/compose/default.btccore-node.json new file mode 100644 index 00000000..16287cd6 --- /dev/null +++ b/extra/compose/default.btccore-node.json @@ -0,0 +1,21 @@ +{ + "network": "livenet", + "port": 3001, + "services": [ + "explorer-api", + "bitcoind", + "web" + ], + "servicesConfig": { + "bitcoind": { + "spawn": { + "datadir": "/data", + "exec": "/usr/local/lib/node_modules/btccore-node/bin/bitcoind" + } + }, + "explorer-api": { + "module": "btccore-explorer-api", + "apiPrefix": "explorer-api" + } + } +} diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 0177f549..1ec18dd2 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -2,7 +2,6 @@ var fs = require('fs'); var path = require('path'); -var spawn = require('child_process').spawn; var util = require('util'); var mkdirp = require('mkdirp'); var btccore = require('btccore-lib'); @@ -852,70 +851,41 @@ Bitcoin.prototype._spawnChildProcess = function(callback) { options.push(self._getNetworkOption()); } - self._stopSpawnedBitcoin(function(err) { - if (err) { - return callback(err); - } - - log.info('Starting bitcoin process'); - self.spawn.process = spawn(self.spawn.exec, options, {stdio: 'inherit'}); + var exitShutdown = false; - self.spawn.process.on('error', function(err) { - self.emit('error', err); - }); + async.retry({times: 60, interval: self.startRetryInterval}, function(done) { + if (self.node.stopping) { + exitShutdown = true; + return done(); + } - self.spawn.process.once('exit', function(code) { - if (!self.node.stopping) { - log.warn('Bitcoin process unexpectedly exited with code:', code); - log.warn('Restarting bitcoin child process in ' + self.spawnRestartTime + 'ms'); - setTimeout(function() { - self._spawnChildProcess(function(err) { - if (err) { - return self.emit('error', err); - } - log.warn('Bitcoin process restarted'); - }); - }, self.spawnRestartTime); - } + node.client = new BitcoinRPC({ + protocol: 'http', + host: '127.0.0.1', + port: self.spawn.config.rpcport, + user: self.spawn.config.rpcuser, + pass: self.spawn.config.rpcpassword, + queue: self.spawn.config.rpcqueue }); - var exitShutdown = false; - - async.retry({times: 60, interval: self.startRetryInterval}, function(done) { - if (self.node.stopping) { - exitShutdown = true; - return done(); - } + self._loadTipFromNode(node, done); - node.client = new BitcoinRPC({ - protocol: 'http', - host: '127.0.0.1', - port: self.spawn.config.rpcport, - user: self.spawn.config.rpcuser, - pass: self.spawn.config.rpcpassword, - queue: self.spawn.config.rpcqueue - }); + }, function(err) { + if (err) { + return callback(err); + } + if (exitShutdown) { + return callback(new Error('Stopping while trying to spawn bitcoind.')); + } - self._loadTipFromNode(node, done); + self._initZmqSubSocket(node, self.spawn.config.zmqpubrawtx); - }, function(err) { + self._checkReindex(node, function(err) { if (err) { return callback(err); } - if (exitShutdown) { - return callback(new Error('Stopping while trying to spawn bitcoind.')); - } - - self._initZmqSubSocket(node, self.spawn.config.zmqpubrawtx); - - self._checkReindex(node, function(err) { - if (err) { - return callback(err); - } - self._checkSyncedAndSubscribeZmqEvents(node); - callback(null, node); - }); - + self._checkSyncedAndSubscribeZmqEvents(node); + callback(null, node); }); }); diff --git a/package.json b/package.json index d2548a83..802a77ee 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,9 @@ "url": "https://github.com/owstack/btccore-node/issues" }, "bin": { - "btccore-node": "./bin/btccore-node", - "bitcoind": "./bin/bitcoind" + "btccore-node": "./bin/btccore-node" }, "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", diff --git a/scripts/download b/scripts/download deleted file mode 100755 index 68bdd10a..00000000 --- a/scripts/download +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/bash - -set -e - -root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.." -platform=`uname -a | awk '{print tolower($1)}'` -arch=`uname -m` -version="0.14.6" -url="https://download.bitcoinabc.org" -tag="v0.14.6" - -if [ "${platform}" == "linux" ]; then - tarball_dir="linux" - if [ "${arch}" == "x86_64" ]; then - tarball_name="bitcoin-${version}-${arch}-linux-gnu.tar.gz" - elif [ "${arch}" == "x86_32" ]; then - tarball_name="bitcoin-${version}-i686-pc-linux-gnu.tar.gz" - fi -elif [ "${platform}" == "darwin" ]; then - tarball_dir="osx" - tarball_name="bitcoin-${version}-osx64.tar.gz" -else - echo "Bitcoin binary distribution not available for platform and architecture ${platform} ${arch}" - exit -1 -fi - -binary_url="${url}/${version}/${tarball_dir}/${tarball_name}" -#shasums_url="${url}/${tag}/SHA256SUMS.asc" - -download_bitcoind() { - - cd "${root_dir}/bin" - - echo "Downloading bitcoin-abc: ${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-abc 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-abc 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 diff --git a/test/services/bitcoind.unit.js b/test/services/bitcoind.unit.js index 7b814eb6..91df84e3 100644 --- a/test/services/bitcoind.unit.js +++ b/test/services/bitcoind.unit.js @@ -1694,15 +1694,6 @@ describe('Bitcoin Service', function() { done(); }); }); - it('will give error from stopSpawnedBitcoin', function() { - var bitcoind = new BitcoinService(baseConfig); - bitcoind._loadSpawnConfiguration = sinon.stub(); - bitcoind._stopSpawnedBitcoin = sinon.stub().callsArgWith(0, new Error('test')); - bitcoind._spawnChildProcess(function(err) { - err.should.be.instanceOf(Error); - err.message.should.equal('test'); - }); - }); it('will exit spawn if shutdown', function() { var config = { node: { @@ -1763,16 +1754,6 @@ describe('Bitcoin Service', function() { bitcoind._checkReindex = sinon.stub().callsArgWith(1, null); bitcoind._spawnChildProcess(function(err, node) { should.not.exist(err); - spawn.callCount.should.equal(1); - spawn.args[0][0].should.equal('testexec'); - spawn.args[0][1].should.deep.equal([ - '--conf=testdir/bitcoin.conf', - '--datadir=testdir', - '--testnet' - ]); - spawn.args[0][2].should.deep.equal({ - stdio: 'inherit' - }); bitcoind._loadTipFromNode.callCount.should.equal(1); bitcoind._initZmqSubSocket.callCount.should.equal(1); should.exist(bitcoind._initZmqSubSocket.args[0][0].client); @@ -1815,51 +1796,13 @@ describe('Bitcoin Service', function() { } process.once('exit', function() { setTimeout(function() { - bitcoind._spawnChildProcess.callCount.should.equal(2); + bitcoind._spawnChildProcess.callCount.should.equal(1); done(); }, 5); }); process.emit('exit', 1); }); }); - it('will emit error during respawn', function(done) { - var process = new EventEmitter(); - var spawn = sinon.stub().returns(process); - var TestBitcoinService = proxyquire('../../lib/services/bitcoind', { - fs: { - readFileSync: readFileSync - }, - child_process: { - spawn: spawn - } - }); - var bitcoind = new TestBitcoinService(baseConfig); - bitcoind._loadSpawnConfiguration = sinon.stub(); - bitcoind.spawn = {}; - bitcoind.spawn.exec = 'bitcoind'; - bitcoind.spawn.datadir = '/tmp/bitcoin'; - bitcoind.spawn.configPath = '/tmp/bitcoin/bitcoin.conf'; - bitcoind.spawn.config = {}; - bitcoind.spawnRestartTime = 1; - bitcoind._loadTipFromNode = sinon.stub().callsArg(1); - bitcoind._initZmqSubSocket = sinon.stub(); - bitcoind._checkReindex = sinon.stub().callsArg(1); - bitcoind._checkSyncedAndSubscribeZmqEvents = sinon.stub(); - bitcoind._stopSpawnedBitcoin = sinon.stub().callsArg(0); - sinon.spy(bitcoind, '_spawnChildProcess'); - bitcoind._spawnChildProcess(function(err) { - if (err) { - return done(err); - } - bitcoind._spawnChildProcess = sinon.stub().callsArgWith(0, new Error('test')); - bitcoind.on('error', function(err) { - err.should.be.instanceOf(Error); - err.message.should.equal('test'); - done(); - }); - process.emit('exit', 1); - }); - }); it('will NOT respawn bitcoind spawned process if shutting down', function(done) { var process = new EventEmitter(); var spawn = sinon.stub().returns(process);