feat: backport remote BTC node support
This commit is contained in:
parent
24473de6d5
commit
1b6ba5e6dc
15 changed files with 272 additions and 55 deletions
|
|
@ -1,54 +1,61 @@
|
|||
const path = require('path')
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const { utils: coinUtils } = require('@lamassu/coins')
|
||||
|
||||
const common = require('./common')
|
||||
const { isDevMode, isRemoteNode } = require('../environment-helper')
|
||||
|
||||
module.exports = { setup, updateCore }
|
||||
|
||||
const coinRec = coinUtils.getCryptoCurrency('BTC')
|
||||
|
||||
const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR
|
||||
|
||||
const tmpDir = isDevMode() ? path.resolve(BLOCKCHAIN_DIR, 'tmp') : '/tmp'
|
||||
const usrBinDir = isDevMode() ? path.resolve(BLOCKCHAIN_DIR, 'bin') : '/usr/local/bin'
|
||||
|
||||
function setup (dataDir) {
|
||||
common.firewall([coinRec.defaultPort])
|
||||
!isDevMode() && common.firewall([coinRec.defaultPort])
|
||||
const config = buildConfig()
|
||||
common.writeFile(path.resolve(dataDir, coinRec.configFile), config)
|
||||
const cmd = `/usr/local/bin/${coinRec.daemon} -datadir=${dataDir}`
|
||||
common.writeSupervisorConfig(coinRec, cmd)
|
||||
const cmd = `${usrBinDir}/${coinRec.daemon} -datadir=${dataDir}`
|
||||
!isDevMode() && common.writeSupervisorConfig(coinRec, cmd)
|
||||
}
|
||||
|
||||
function updateCore (coinRec, isCurrentlyRunning) {
|
||||
common.logger.info('Updating Bitcoin Core. This may take a minute...')
|
||||
common.es(`sudo supervisorctl stop bitcoin`)
|
||||
!isDevMode() && common.es(`sudo supervisorctl stop bitcoin`)
|
||||
common.es(`curl -#o /tmp/bitcoin.tar.gz ${coinRec.url}`)
|
||||
common.es(`tar -xzf /tmp/bitcoin.tar.gz -C /tmp/`)
|
||||
|
||||
common.logger.info('Updating wallet...')
|
||||
common.es(`cp /tmp/${coinRec.dir}/* /usr/local/bin/`)
|
||||
common.es(`rm -r /tmp/${coinRec.dir.replace('/bin', '')}`)
|
||||
common.es(`rm /tmp/bitcoin.tar.gz`)
|
||||
common.es(`cp ${tmpDir}/${coinRec.dir}/* ${usrBinDir}/`)
|
||||
common.es(`rm -r ${tmpDir}/${coinRec.dir.replace('/bin', '')}`)
|
||||
common.es(`rm ${tmpDir}/bitcoin.tar.gz`)
|
||||
|
||||
if (common.es(`grep "addresstype=p2sh-segwit" /mnt/blockchains/bitcoin/bitcoin.conf || true`)) {
|
||||
if (common.es(`grep "addresstype=p2sh-segwit" ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf || true`)) {
|
||||
common.logger.info(`Enabling bech32 receiving addresses in config file..`)
|
||||
common.es(`sed -i 's/addresstype=p2sh-segwit/addresstype=bech32/g' /mnt/blockchains/bitcoin/bitcoin.conf`)
|
||||
common.es(`sed -i 's/addresstype=p2sh-segwit/addresstype=bech32/g' ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`)
|
||||
} else {
|
||||
common.logger.info(`bech32 receiving addresses already defined, skipping...`)
|
||||
}
|
||||
|
||||
if (common.es(`grep "changetype=" /mnt/blockchains/bitcoin/bitcoin.conf || true`)) {
|
||||
if (common.es(`grep "changetype=" ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf || true`)) {
|
||||
common.logger.info(`changetype already defined, skipping...`)
|
||||
} else {
|
||||
common.logger.info(`Enabling bech32 change addresses in config file..`)
|
||||
common.es(`echo "\nchangetype=bech32" >> /mnt/blockchains/bitcoin/bitcoin.conf`)
|
||||
common.es(`echo "\nchangetype=bech32" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`)
|
||||
}
|
||||
|
||||
if (common.es(`grep "listenonion=" /mnt/blockchains/bitcoin/bitcoin.conf || true`)) {
|
||||
if (common.es(`grep "listenonion=" ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf || true`)) {
|
||||
common.logger.info(`listenonion already defined, skipping...`)
|
||||
} else {
|
||||
common.logger.info(`Setting 'listenonion=0' in config file...`)
|
||||
common.es(`echo "\nlistenonion=0" >> /mnt/blockchains/bitcoin/bitcoin.conf`)
|
||||
common.es(`echo "\nlistenonion=0" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`)
|
||||
}
|
||||
|
||||
if (isCurrentlyRunning) {
|
||||
if (isCurrentlyRunning && !isDevMode()) {
|
||||
common.logger.info('Starting wallet...')
|
||||
common.es(`sudo supervisorctl start bitcoin`)
|
||||
}
|
||||
|
|
@ -59,6 +66,7 @@ function updateCore (coinRec, isCurrentlyRunning) {
|
|||
function buildConfig () {
|
||||
return `rpcuser=lamassuserver
|
||||
rpcpassword=${common.randomPass()}
|
||||
${isDevMode() ? `regtest=1` : ``}
|
||||
dbcache=500
|
||||
server=1
|
||||
connections=40
|
||||
|
|
@ -68,8 +76,16 @@ daemon=0
|
|||
addresstype=bech32
|
||||
changetype=bech32
|
||||
walletrbf=1
|
||||
bind=0.0.0.0:8332
|
||||
rpcport=8333
|
||||
listenonion=0
|
||||
fallbackfee=0.00005
|
||||
rpcworkqueue=2000
|
||||
${isDevMode()
|
||||
? `[regtest]
|
||||
rpcport=18333
|
||||
bind=0.0.0.0:18332
|
||||
${isRemoteNode(coinRec) ? `connect=${process.env.BTC_NODE_HOST}:${process.env.BTC_NODE_PORT}` : ``}`
|
||||
: `rpcport=8333
|
||||
bind=0.0.0.0:8332
|
||||
${isRemoteNode(coinRec) ? `connect=${process.env.BTC_NODE_HOST}:${process.env.BTC_NODE_PORT}` : ``}`}
|
||||
`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,16 @@ const os = require('os')
|
|||
const path = require('path')
|
||||
const cp = require('child_process')
|
||||
const fs = require('fs')
|
||||
const makeDir = require('make-dir')
|
||||
|
||||
const _ = require('lodash/fp')
|
||||
|
||||
const logger = require('console-log-level')({level: 'info'})
|
||||
|
||||
const { isDevMode } = require('../environment-helper')
|
||||
|
||||
const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR
|
||||
|
||||
module.exports = {
|
||||
es,
|
||||
writeSupervisorConfig,
|
||||
|
|
@ -106,6 +111,11 @@ function writeSupervisorConfig (coinRec, cmd, walletCmd = '') {
|
|||
}
|
||||
|
||||
function isInstalledSoftware (coinRec) {
|
||||
if (isDevMode()) {
|
||||
return fs.existsSync(`${BLOCKCHAIN_DIR}/${coinRec.code}/${coinRec.configFile}`)
|
||||
&& fs.existsSync(`${BLOCKCHAIN_DIR}/bin/${coinRec.daemon}`)
|
||||
}
|
||||
|
||||
const nodeInstalled = fs.existsSync(`/etc/supervisor/conf.d/${coinRec.code}.conf`)
|
||||
const walletInstalled = _.isNil(coinRec.wallet)
|
||||
? true
|
||||
|
|
@ -127,13 +137,19 @@ function fetchAndInstall (coinRec) {
|
|||
es(`wget -q ${url}`)
|
||||
es(`tar -xf ${downloadFile}`)
|
||||
|
||||
const usrBinDir = isDevMode() ? path.resolve(BLOCKCHAIN_DIR, 'bin') : '/usr/local/bin'
|
||||
|
||||
if (isDevMode()) {
|
||||
makeDir.sync(usrBinDir)
|
||||
}
|
||||
|
||||
if (_.isEmpty(binaries.files)) {
|
||||
es(`sudo cp ${binDir}/* /usr/local/bin`)
|
||||
es(`sudo cp ${binDir}/* ${usrBinDir}`)
|
||||
return
|
||||
}
|
||||
|
||||
_.forEach(([source, target]) => {
|
||||
es(`sudo cp ${binDir}/${source} /usr/local/bin/${target}`)
|
||||
es(`sudo cp ${binDir}/${source} ${usrBinDir}/${target}`)
|
||||
}, binaries.files)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const _ = require('lodash/fp')
|
|||
const { utils: coinUtils } = require('@lamassu/coins')
|
||||
const settingsLoader = require('../new-settings-loader')
|
||||
const wallet = require('../wallet')
|
||||
const { isDevMode, isRemoteNode, isRemoteWallet } = require('../environment-helper')
|
||||
|
||||
const common = require('./common')
|
||||
const doVolume = require('./do-volume')
|
||||
|
|
@ -30,7 +31,10 @@ const PLUGINS = {
|
|||
|
||||
const BLOCKCHAIN_DIR = process.env.BLOCKCHAIN_DIR
|
||||
|
||||
module.exports = {run}
|
||||
module.exports = {
|
||||
isEnvironmentValid,
|
||||
run
|
||||
}
|
||||
|
||||
function installedVolumeFilePath (crypto) {
|
||||
return path.resolve(coinUtils.cryptoDir(crypto, BLOCKCHAIN_DIR), '.installed')
|
||||
|
|
@ -52,43 +56,94 @@ function processCryptos (codes) {
|
|||
|
||||
logger.info('Thanks! Installing: %s. Will take a while...', _.join(', ', codes))
|
||||
|
||||
const goodVolume = doVolume.prepareVolume()
|
||||
|
||||
if (!goodVolume) {
|
||||
logger.error('There was an error preparing the disk volume. Exiting.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const selectedCryptos = _.map(code => _.find(['code', code], cryptos), codes)
|
||||
_.forEach(setupCrypto, selectedCryptos)
|
||||
common.es('sudo supervisorctl reread')
|
||||
common.es('sudo supervisorctl update')
|
||||
|
||||
const blockchainDir = BLOCKCHAIN_DIR
|
||||
const backupDir = path.resolve(os.homedir(), 'backups')
|
||||
const rsyncCmd = `( \
|
||||
(crontab -l 2>/dev/null || echo -n "") | grep -v "@daily rsync ".*"wallet.dat"; \
|
||||
echo "@daily rsync -r --prune-empty-dirs --include='*/' \
|
||||
--include='wallet.dat' \
|
||||
--exclude='*' ${blockchainDir} ${backupDir} > /dev/null" \
|
||||
) | crontab -`
|
||||
common.es(rsyncCmd)
|
||||
if (isDevMode()) {
|
||||
_.forEach(setupCrypto, selectedCryptos)
|
||||
} else {
|
||||
const goodVolume = doVolume.prepareVolume()
|
||||
|
||||
_.forEach(c => {
|
||||
updateCrypto(c)
|
||||
common.es(`sudo supervisorctl start ${c.code}`)
|
||||
}, selectedCryptos)
|
||||
if (!goodVolume) {
|
||||
logger.error('There was an error preparing the disk volume. Exiting.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
_.forEach(setupCrypto, selectedCryptos)
|
||||
common.es('sudo supervisorctl reread')
|
||||
common.es('sudo supervisorctl update')
|
||||
|
||||
const blockchainDir = BLOCKCHAIN_DIR
|
||||
const backupDir = path.resolve(os.homedir(), 'backups')
|
||||
const rsyncCmd = `( \
|
||||
(crontab -l 2>/dev/null || echo -n "") | grep -v "@daily rsync ".*"wallet.dat"; \
|
||||
echo "@daily rsync -r --prune-empty-dirs --include='*/' \
|
||||
--include='wallet.dat' \
|
||||
--exclude='*' ${blockchainDir} ${backupDir} > /dev/null" \
|
||||
) | crontab -`
|
||||
common.es(rsyncCmd)
|
||||
|
||||
_.forEach(c => {
|
||||
updateCrypto(c)
|
||||
common.es(`sudo supervisorctl start ${c.code}`)
|
||||
}, selectedCryptos)
|
||||
}
|
||||
|
||||
logger.info('Installation complete.')
|
||||
}
|
||||
|
||||
function isEnvironmentValid (crypto) {
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_NODE_LOCATION`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_NODE_LOCATION is not set!`)
|
||||
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_WALLET_LOCATION`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_WALLET_LOCATION is not set!`)
|
||||
|
||||
if (isRemoteWallet(crypto) && !isRemoteNode(crypto))
|
||||
throw new Error(`Invalid environment setup for ${crypto.display}: It's not possible to use a remote wallet without using a remote node!`)
|
||||
|
||||
if (isRemoteNode(crypto) && !isRemoteWallet(crypto)) {
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_NODE_HOST`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_NODE_HOST is not set!`)
|
||||
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_NODE_PORT`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_NODE_PORT is not set!`)
|
||||
|
||||
if (_.isEmpty(process.env.BLOCKCHAIN_DIR))
|
||||
throw new Error(`The environment variable for BLOCKCHAIN_DIR is not set!`)
|
||||
}
|
||||
|
||||
if (isRemoteWallet(crypto)) {
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_NODE_RPC_HOST`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_NODE_RPC_HOST is not set!`)
|
||||
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_NODE_RPC_PORT`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_NODE_RPC_PORT is not set!`)
|
||||
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_NODE_USER`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_NODE_USER is not set!`)
|
||||
|
||||
if (_.isEmpty(process.env[`${crypto.cryptoCode}_NODE_PASSWORD`]))
|
||||
throw new Error(`The environment variable for ${crypto.cryptoCode}_NODE_PASSWORD is not set!`)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function setupCrypto (crypto) {
|
||||
logger.info(`Installing ${crypto.display}...`)
|
||||
|
||||
if (!isEnvironmentValid(crypto)) throw new Error(`Environment error for ${crypto.display}`)
|
||||
|
||||
if (isRemoteWallet(crypto)) {
|
||||
logger.info(`Environment variable ${crypto.cryptoCode}_WALLET_LOCATION is set as 'remote', so there's no need to install a node in the system. Exiting...`)
|
||||
return
|
||||
}
|
||||
|
||||
const cryptoDir = coinUtils.cryptoDir(crypto, BLOCKCHAIN_DIR)
|
||||
makeDir.sync(cryptoDir)
|
||||
const cryptoPlugin = plugin(crypto)
|
||||
const oldDir = process.cwd()
|
||||
const tmpDir = '/tmp/blockchain-install'
|
||||
const tmpDir = isDevMode() ? path.resolve(BLOCKCHAIN_DIR, 'tmp', 'blockchain-install') : '/tmp/blockchain-install'
|
||||
|
||||
makeDir.sync(tmpDir)
|
||||
process.chdir(tmpDir)
|
||||
|
|
@ -97,7 +152,10 @@ function setupCrypto (crypto) {
|
|||
|
||||
cryptoPlugin.setup(cryptoDir)
|
||||
|
||||
common.writeFile(installedVolumeFilePath(crypto), '')
|
||||
if (!isDevMode()) {
|
||||
common.writeFile(installedVolumeFilePath(crypto), '')
|
||||
}
|
||||
|
||||
process.chdir(oldDir)
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +179,8 @@ function plugin (crypto) {
|
|||
function getBlockchainSyncStatus (cryptoList) {
|
||||
return settingsLoader.loadLatest()
|
||||
.then(settings => {
|
||||
if (isDevMode()) return new Array(_.size(cryptoList)).fill('ready')
|
||||
|
||||
const blockchainStatuses = _.reduce((acc, value) => {
|
||||
const processStatus = common.es(`sudo supervisorctl status ${value.code} | awk '{ print $2 }'`).trim()
|
||||
return acc.then(a => {
|
||||
|
|
@ -140,7 +200,9 @@ function getBlockchainSyncStatus (cryptoList) {
|
|||
}
|
||||
|
||||
function isInstalled (crypto) {
|
||||
return isInstalledSoftware(crypto) && isInstalledVolume(crypto)
|
||||
return isDevMode()
|
||||
? isInstalledSoftware(crypto)
|
||||
: isInstalledSoftware(crypto) && isInstalledVolume(crypto)
|
||||
}
|
||||
|
||||
function isDisabled (crypto) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue