...
 
Commits (99)
This diff is collapsed.
......@@ -137,7 +137,7 @@ class ApiHelper {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
params,
`ApiHelper.validateEntitiesParams() : Invalid arguments`
`API : ApiHelper.validateEntitiesParams() : Invalid arguments`
)
}
}
......
......@@ -46,7 +46,7 @@ class FeesRestApi {
} catch (e) {
HttpServer.sendError(res, e)
} finally {
debugApi && Logger.info(`Completed GET /fees`)
debugApi && Logger.info(`API : Completed GET /fees`)
}
}
......
......@@ -49,7 +49,7 @@ class HeadersRestApi {
} catch(e) {
HttpServer.sendError(res, e)
} finally {
debugApi && Logger.info(`Completed GET /header/${req.params.hash}`)
debugApi && Logger.info(`API : Completed GET /header/${req.params.hash}`)
}
}
......@@ -66,7 +66,7 @@ class HeadersRestApi {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.params.hash,
'HeadersRestApi.validateArgsGetHeader() : Invalid hash'
'API : HeadersRestApi.validateArgsGetHeader() : Invalid hash'
)
} else {
next()
......
......@@ -20,15 +20,15 @@ if (cluster.isMaster) {
})
cluster.on('listening', function(worker) {
Logger.info(`Cluster ${worker.process.pid} connected`)
Logger.info(`API : Cluster ${worker.process.pid} connected`)
})
cluster.on('disconnect', function(worker) {
Logger.info(`Cluster ${worker.process.pid} disconnected`)
Logger.info(`API : Cluster ${worker.process.pid} disconnected`)
})
cluster.on('exit', function(worker) {
Logger.info(`Cluster ${worker.process.pid} is dead`)
Logger.info(`API : Cluster ${worker.process.pid} is dead`)
// Ensuring a new cluster will start if an old one dies
cluster.fork()
})
......
......@@ -28,8 +28,8 @@
/**
* Samourai REST API
*/
Logger.info('Process ID: ' + process.pid)
Logger.info('Preparing the REST API')
Logger.info('API : Process ID: ' + process.pid)
Logger.info('API : Preparing the REST API')
// Wait for Bitcoind RPC API
// being ready to process requests
......@@ -52,8 +52,9 @@
hdaHelper.activateExternalDerivation()
// Initialize the http server
const host = keys.apiBind
const port = keys.ports.account
const httpServer = new HttpServer(port)
const httpServer = new HttpServer(port, host)
// Initialize the rest api endpoints
const authRestApi = new AuthRestApi(httpServer)
......
......@@ -85,7 +85,7 @@ class MultiaddrRestApi {
${req.query.bip49 ? req.query.bip49 : ''} \
${req.query.bip84 ? req.query.bip84 : ''}`
Logger.info(`Completed GET /multiaddr ${strParams}`)
Logger.info(`API : Completed GET /multiaddr ${strParams}`)
}
}
}
......@@ -126,7 +126,7 @@ class MultiaddrRestApi {
${req.body.bip49 ? req.body.bip49 : ''} \
${req.body.bip84 ? req.body.bip84 : ''}`
Logger.info(`Completed POST /multiaddr ${strParams}`)
Logger.info(`API : Completed POST /multiaddr ${strParams}`)
}
}
}
......
......@@ -61,7 +61,7 @@ class NotificationsServer {
const header = JSON.parse(message.toString())
this.notifService.notifyBlock(header)
} catch(e) {
Logger.error(e, 'NotificationServer._initTrackerSocket() : Error in block message')
Logger.error(e, 'API : NotificationServer._initTrackerSocket() : Error in block message')
}
break
case 'transaction':
......@@ -69,11 +69,11 @@ class NotificationsServer {
const tx = JSON.parse(message.toString())
this.notifService.notifyTransaction(tx)
} catch(e) {
Logger.error(e, 'NotificationServer._initTrackerSocket() : Error in transaction message')
Logger.error(e, 'API : NotificationServer._initTrackerSocket() : Error in transaction message')
}
break
default:
Logger.info(`Unknown ZMQ message topic: "${topic}"`)
Logger.info(`API : Unknown ZMQ message topic: "${topic}"`)
}
})
}
......
......@@ -59,7 +59,7 @@ class NotificationsService {
_initWSServer(server) {
this.ws = new WebSocket.server({httpServer: server})
Logger.info('Created WebSocket server')
Logger.info('API : Created WebSocket server')
this.ws.on('request', req => {
try {
......@@ -67,14 +67,14 @@ class NotificationsService {
conn.id = status.sessions++
conn.subs = []
debug && Logger.info(`Client ${conn.id} connected`)
debug && Logger.info(`API : Client ${conn.id} connected`)
conn.on('close', () => {
this._closeWSConnection(conn, false)
})
conn.on('error', err => {
Logger.error(err, `NotificationsService : Error on connection ${conn.id}`)
Logger.error(err, `API : NotificationsService : Error on connection ${conn.id}`)
if (conn.connected)
this._closeWSConnection(conn, true)
})
......@@ -91,7 +91,7 @@ class NotificationsService {
status.maxConn = Math.max(status.maxConn, Object.keys(this.conn).length)
} catch(e) {
Logger.error(e, `NotificationsService._initWSServer() : Error during request accept`)
Logger.error(e, `API : NotificationsService._initWSServer() : Error during request accept`)
}
})
}
......@@ -120,10 +120,10 @@ class NotificationsService {
if (forcedClose && conn.connected)
conn.drop(1008, 'Get out of here!')
debug && Logger.info(`Client ${conn.id} disconnected`)
debug && Logger.info(`API : Client ${conn.id} disconnected`)
} catch(e) {
Logger.error(e, 'NotificationsService._closeWSConnection()')
Logger.error(e, 'API : NotificationsService._closeWSConnection()')
}
}
......@@ -134,7 +134,7 @@ class NotificationsService {
*/
_filterWSMessage(msg) {
if (this.cacheSubs.has(msg)) {
debug && Logger.info('Duplicate subscriptions detected')
debug && Logger.info('API : Duplicate subscriptions detected')
return false
} else {
this.cacheSubs.set(msg, true)
......@@ -150,7 +150,7 @@ class NotificationsService {
*/
_handleWSMessage(msg, conn) {
try {
debug && Logger.info(`Received from client ${conn.id}: ${msg}`)
debug && Logger.info(`API : Received from client ${conn.id}: ${msg}`)
const data = JSON.parse(msg)
......@@ -183,7 +183,7 @@ class NotificationsService {
break
}
} catch(e) {
Logger.error(e, 'NotificationsService._handleWSMessage() : WebSocket message error')
Logger.error(e, 'API : NotificationsService._handleWSMessage() : WebSocket message error')
}
}
......@@ -223,7 +223,7 @@ class NotificationsService {
this.subs[topic].push(conn.id)
debug && Logger.info(`Client ${conn.id} subscribed to ${topic}`)
debug && Logger.info(`API : Client ${conn.id} subscribed to ${topic}`)
}
/**
......@@ -267,7 +267,7 @@ class NotificationsService {
try {
this.conn[cid].sendUTF(msg)
} catch(e) {
Logger.error(e, `NotificationsService.dispatch() : Error sending dispatch for ${topic} to client ${cid}`)
Logger.error(e, `API : NotificationsService.dispatch() : Error sending dispatch for ${topic} to client ${cid}`)
}
}
}
......@@ -284,7 +284,7 @@ class NotificationsService {
}
this.dispatch('block', JSON.stringify(data))
} catch(e) {
Logger.error(e, `NotificationsService.notifyBlock()`)
Logger.error(e, `API : NotificationsService.notifyBlock()`)
}
}
......@@ -440,14 +440,14 @@ class NotificationsService {
try {
this.conn[cid].sendUTF(JSON.stringify(data))
debug && Logger.error(`Sent ctx ${ctx.hash} to client ${cid}`)
debug && Logger.error(`API : Sent ctx ${ctx.hash} to client ${cid}`)
} catch(e) {
Logger.error(e, `NotificationsService.notifyTransaction() : Trouble sending ctx to client ${cid}`)
Logger.error(e, `API : NotificationsService.notifyTransaction() : Trouble sending ctx to client ${cid}`)
}
}
} catch(e) {
Logger.error(e, `NotificationsService.notifyTransaction()`)
Logger.error(e, `API : NotificationsService.notifyTransaction()`)
}
}
......@@ -464,9 +464,9 @@ class NotificationsService {
try {
this.conn[cid].sendUTF(JSON.stringify(data))
debug && Logger.error(`Sent authentication error to client ${cid}`)
debug && Logger.error(`API : Sent authentication error to client ${cid}`)
} catch(e) {
Logger.error(e, `NotificationsService.notifyAuthError() : Trouble sending authentication error to client ${cid}`)
Logger.error(e, `API : NotificationsService.notifyAuthError() : Trouble sending authentication error to client ${cid}`)
}
}
......
......@@ -47,7 +47,7 @@ class StatusRestApi {
} catch(e) {
HttpServer.sendError(res, e)
} finally {
debugApi && Logger.info(`Completed GET /status`)
debugApi && Logger.info(`API : Completed GET /status`)
}
}
......
......@@ -108,7 +108,7 @@ class SupportRestApi {
HttpServer.sendError(res, errors.generic.GEN)
} finally {
debugApi && Logger.info(`Completed GET /support/address/${req.params.addr}/info`)
debugApi && Logger.info(`API : Completed GET /support/address/${req.params.addr}/info`)
}
}
......@@ -175,7 +175,7 @@ class SupportRestApi {
HttpServer.sendError(res, errors.generic.GEN)
} finally {
debugApi && Logger.info(`Completed GET /support/address/${req.params.addr}/rescan`)
debugApi && Logger.info(`API : Completed GET /support/address/${req.params.addr}/rescan`)
}
}
......@@ -212,7 +212,7 @@ class SupportRestApi {
HttpServer.sendError(res, errors.generic.GEN)
} finally {
debugApi && Logger.info(`Completed GET /support/xpub/${req.params.xpub}/info`)
debugApi && Logger.info(`API : Completed GET /support/xpub/${req.params.xpub}/info`)
}
}
......@@ -270,7 +270,7 @@ class SupportRestApi {
HttpServer.sendRawData(res, JSON.stringify(ret, null, 2))
} else {
ret.status = 'Rescan Error'
Logger.error(e, 'SupportRestApi.getXpubRescan() : Support rescan error')
Logger.error(e, 'API : SupportRestApi.getXpubRescan() : Support rescan error')
HttpServer.sendError(res, JSON.stringify(ret, null, 2))
}
}
......@@ -279,7 +279,7 @@ class SupportRestApi {
HttpServer.sendError(res, errors.generic.GEN)
} finally {
debugApi && Logger.info(`Completed GET /support/xpub/${req.params.xpub}/rescan`)
debugApi && Logger.info(`API : Completed GET /support/xpub/${req.params.xpub}/rescan`)
}
}
......@@ -300,10 +300,10 @@ class SupportRestApi {
const ret = {
status: 'error'
}
Logger.error(e, 'SupportRestApi.getPairing() : Support pairing error')
Logger.error(e, 'API : SupportRestApi.getPairing() : Support pairing error')
HttpServer.sendError(res, JSON.stringify(ret, null, 2))
} finally {
debugApi && Logger.info(`Completed GET /pairing`)
debugApi && Logger.info(`API : Completed GET /pairing`)
}
}
......@@ -318,7 +318,7 @@ class SupportRestApi {
url = fs.readFileSync('/var/lib/tor/hsv3explorer/hostname', 'utf8')
url = url.replace('\n', '')
} catch(e) {
Logger.error(e, 'SupportRestApi.getPairing() : Cannot read explorer onion address')
Logger.error(e, 'API : SupportRestApi.getPairing() : Cannot read explorer onion address')
}
}
const ret = {
......@@ -333,10 +333,10 @@ class SupportRestApi {
const ret = {
status: 'error'
}
Logger.error(e, 'SupportRestApi.getPairingExplorer() : Support pairing error')
Logger.error(e, 'API : SupportRestApi.getPairingExplorer() : Support pairing error')
HttpServer.sendError(res, JSON.stringify(ret, null, 2))
} finally {
debugApi && Logger.info(`Completed GET /pairing/explorer`)
debugApi && Logger.info(`API : Completed GET /pairing/explorer`)
}
}
......@@ -351,7 +351,7 @@ class SupportRestApi {
if (!isValidXpub) {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(null, `SupportRestApi.validateArgsGetXpubInfo() : Invalid xpub ${req.params.xpub}`)
Logger.error(null, `API : SupportRestApi.validateArgsGetXpubInfo() : Invalid xpub ${req.params.xpub}`)
} else {
next()
}
......@@ -369,7 +369,7 @@ class SupportRestApi {
if (!(isValidXpub && isValidGap)) {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(null, 'SupportRestApi.validateArgsGetXpubRescan() : Invalid arguments')
Logger.error(null, 'API : SupportRestApi.validateArgsGetXpubRescan() : Invalid arguments')
} else {
next()
}
......@@ -386,7 +386,7 @@ class SupportRestApi {
if (!isValidAddress) {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(null, `SupportRestApi.validateAddress() : Invalid address ${req.params.addr}`)
Logger.error(null, `API : SupportRestApi.validateAddress() : Invalid address ${req.params.addr}`)
} else {
next()
}
......
......@@ -63,7 +63,7 @@ class TransactionsRestApi {
HttpServer.sendError(res, e)
} finally {
const strParams = `${req.query.fees ? req.query.fees : ''}`
debugApi && Logger.info(`Completed GET /tx/${req.params.txid} ${strParams}`)
debugApi && Logger.info(`API : Completed GET /tx/${req.params.txid} ${strParams}`)
}
}
......@@ -97,7 +97,7 @@ class TransactionsRestApi {
${req.query.page ? req.query.page : ''} \
${req.query.count ? req.query.count : ''}`
debugApi && Logger.info(`Completed GET /txs ${strParams}`)
debugApi && Logger.info(`API : Completed GET /txs ${strParams}`)
}
}
......@@ -118,7 +118,7 @@ class TransactionsRestApi {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.params,
'HeadersRestApi.validateArgsGetTransaction() : Invalid arguments'
'API : HeadersRestApi.validateArgsGetTransaction() : Invalid arguments'
)
Logger.error(req.query, '')
} else {
......@@ -145,7 +145,7 @@ class TransactionsRestApi {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.query,
'HeadersRestApi.validateArgsGetTransactions() : Invalid arguments'
'API : HeadersRestApi.validateArgsGetTransactions() : Invalid arguments'
)
} else {
next()
......
......@@ -85,7 +85,7 @@ class UnspentRestApi {
${req.query.bip49 ? req.query.bip49 : ''} \
${req.query.bip84 ? req.query.bip84 : ''}`
Logger.info(`Completed GET /unspent ${strParams}`)
Logger.info(`API : Completed GET /unspent ${strParams}`)
}
}
}
......@@ -126,7 +126,7 @@ class UnspentRestApi {
${req.body.bip49 ? req.body.bip49 : ''} \
${req.body.bip84 ? req.body.bip84 : ''}`
Logger.info(`Completed POST /unspent ${strParams}`)
Logger.info(`API : Completed POST /unspent ${strParams}`)
}
}
}
......
......@@ -151,7 +151,7 @@ class XPubRestApi {
return HttpServer.sendError(res, errors.generic.GEN)
} finally {
debugApi && Logger.info(`Completed POST /xpub ${req.body.xpub}`)
debugApi && Logger.info(`API : Completed POST /xpub ${req.body.xpub}`)
}
}
......@@ -194,11 +194,11 @@ class XPubRestApi {
HttpServer.sendOkData(res, ret)
} catch(e) {
Logger.error(e, 'XpubRestApi.getXpub()')
Logger.error(e, 'API : XpubRestApi.getXpub()')
HttpServer.sendError(res, e)
} finally {
debugApi && Logger.info(`Completed GET /xpub/${req.params.xpub}`)
debugApi && Logger.info(`API : Completed GET /xpub/${req.params.xpub}`)
}
}
......@@ -253,7 +253,7 @@ class XPubRestApi {
}
} finally {
debugApi && Logger.info(`Completed POST /xpub/${req.params.xpub}/lock`)
debugApi && Logger.info(`API : Completed POST /xpub/${req.params.xpub}/lock`)
}
}
......@@ -303,7 +303,7 @@ class XPubRestApi {
HttpServer.sendError(res, errors.generic.GEN)
} finally {
debugApi && Logger.info(`Completed DELETE /xpub/${req.params.xpub}`)
debugApi && Logger.info(`API : Completed DELETE /xpub/${req.params.xpub}`)
}
}
......@@ -327,8 +327,8 @@ class XPubRestApi {
xpub = hdaHelper.xlatXPUB(origXpub)
scheme = isYpub ? hdaHelper.BIP49 : hdaHelper.BIP84
if (trace) {
Logger.info('Converted: ' + origXpub)
Logger.info('Resulting xpub: ' + xpub)
Logger.info('API : Converted: ' + origXpub)
Logger.info('API : Resulting xpub: ' + xpub)
}
}
......@@ -371,7 +371,7 @@ class XPubRestApi {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.body,
'XpubRestApi.validateArgsPostXpub() : Invalid arguments'
'API : XpubRestApi.validateArgsPostXpub() : Invalid arguments'
)
} else {
next()
......@@ -391,7 +391,7 @@ class XPubRestApi {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.params.xpub,
'XpubRestApi.validateArgsGetXpub() : Invalid arguments'
'API : XpubRestApi.validateArgsGetXpub() : Invalid arguments'
)
} else {
next()
......@@ -414,7 +414,7 @@ class XPubRestApi {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.params,
'XpubRestApi.validateArgsPostLockXpub() : Invalid arguments'
'API : XpubRestApi.validateArgsPostLockXpub() : Invalid arguments'
)
Logger.error(req.body, '')
} else {
......@@ -437,7 +437,7 @@ class XPubRestApi {
HttpServer.sendError(res, errors.body.INVDATA)
Logger.error(
req.params,
'XpubRestApi.validateArgsDeleteXpub() : Invalid arguments'
'API : XpubRestApi.validateArgsDeleteXpub() : Invalid arguments'
)
Logger.error(req.body, '')
} else {
......
......@@ -9,6 +9,7 @@ A word of caution, though, the default values of these options try to maximize y
## Table of Content ##
- [Local indexer of Bitcoin addresses](#local_indexer)
- [Local Electrum server used as data source for imports/rescans](#local_electrum)
- [Local Whirlpool client](#local_whirlpool)
- [External Bitcoin full node](#external_bitcoind)
- [bitcoind RPC API ans ZMQ notifications exposed to external apps](#exposed_rpc_zmq)
- [Static onion address for bitcoind hidden service](#static_onion)
......@@ -117,6 +118,80 @@ nano ./conf/docker-node.conf
```
<a name="local_whirlpool"/>
## Local Whirlpool client ##
This setup allows to install and run a [Whirlpool client](https://github.com/Samourai-Wallet/whirlpool-client-cli) inside MyDojo.
The client can be configured and controlled through a REST API exposed as a Tor hidden service.
### Procedure ###
```
# If you're installing a new Dojo or if you're upgrading from a Dojo version < 1.6, edit the docker-whirlpool.conf.tpl file
nano ./conf/docker-whirlpool.conf.tpl
# Otherwise, edit the docker-whirlpool.conf file
nano ./conf/docker-whirlpool.conf
#
# Set the value of WHIRLPOOL_INSTALL to "on"
## Save and exit nano
#
```
### Installation of Whirlpool GUI ###
The [Whirlpool GUI application]((https://github.com/Samourai-Wallet/whirlpool-gui)) provides a graphical interface for your Whirlpool client.
These steps describe how to install the Whirlpool GUI application how a computer and how to connect it to your Whirlpool client.
**Requirements**
- MyDojo has been fully initialized,
- Whirlpool client has been activated in MyDojo,
- Your Samourai Wallet is paired to MyDojo,
- MyDojo is running.
- Tor browser is installed on the computer that will run the Whirlpool GUI application.
**Procedure**
- Retrieve the onion address of the API provided by your Whirlpool client
```
# Open a terminal console on the computer hosting your Dojo
# Retrieve the onion address of the Whirlpool API
./dojo.sh onion
```
- Install and configure the Whirlpool GUI application
```
# If needed, install Tor browser on the computer that will run the Whirlpool GUI application
# Launch the Tor browser
# Install the Whirlpool GUI application on the computer and launch it
# Select 'Advanced: remote CLI'
# Set 'CLI address' with 'http://your_onion_address' where your_onion_address is the address of the Whirlpool API
# Check that the 'Tor proxy' field has the correct socks5 port used by your Tor browser.
# Click 'Connect'.
# Paste the pairing payload from your mobile device when prompted:
# Select the Samourai Wallet Menu (3 dots top right),
# Go to Settings -> Transactions -> Pair to Whirlpool GUI,
# Copy the payload and send to your main computer using any method you prefer,
# Paste the payload.
# The GUI will restart and prompt for you to enter your Samourai Wallet passphrase.
# You are all set and ready to mix!
```
<a name="external_bitcoind"/>
## External Bitcoin full node ##
......
......@@ -111,9 +111,9 @@ __"Download the most recent release of Dojo from Github"__ until you reach __"La
Once you Reach Step __"Launch the Installation of Your Dojo with"__ from above you will need to read and follow the instructions from [here](https://github.com/Samourai-Wallet/samourai-dojo/blob/develop/doc/DOCKER_advanced_setups.md)
Once adjustments are made to your external bitcoind bitcoin.conf __(location dependent on what device you have bitcoind)__ and docker-bitcoind.conf.tpl __(dojo_dir > docker > my-dojo > conf)__ you can proceed with Install and revert back to original instructions [here](https://github.com/Samourai-Wallet/samourai-dojo/blob/develop/doc/DOCKER_setup.md) at section __"Launch the Installation of Your Dojo with"__
_Note: For tracking progress, open terminal, change directory to my-dojo and run /dojo.sh logs tracker
_Note: For tracking progress, open terminal, change directory to my-dojo and run /dojo.sh logs nodejs
__Some possible optimization tips:__
If you notice that progress has stopped. Click the whale icon and select Restart. Restart Logs Tracker from step above to verify progress has resumed.
If you notice that progress has stopped. Click the whale icon and select Restart. Restart logs nodejs from step above to verify progress has resumed.
This may optimize speed: open __Activity Monitor__, check the PID (Process ID) of your docker process. Open Terminal and type:
......
......@@ -27,42 +27,41 @@ MyDojo is a set of Docker containers providing a full Samourai backend composed
## Architecture ##
------------------- ------------------- --------------------
| Samourai Wallet | | Sentinel | | Bitcoin full nodes |
------------------- ------------------- --------------------
|_______________________|_______________________|
|
------------
Tor network
------------
|
Host machine | (Tor hidden services)
______________________________ | _____________________________
| | |
| --------- dmznet |
| --------| Tor |------------ |
| | --------- | |
| | | |
| --------- | |
| --| Nginx |-------- | |
| | --------- | | |
|- - - - -|- - - - - - - - - - -|- - - - - - - - -|- - - - - - |
| | | | |
| ---------- ---------- ---------- |
| | Nodejs |----------| Explorer |------| Bitcoind | |
| ---------- ---------- ---------- |
| | | | | |
| | ------- | | |
| | | | | |
| ---------- | ---------- | |
| | MySQL | ----| Indexer |----------- |
| ---------- ---------- |
| dojonet |
|______________________________________________________________|
------------------ -------------------- --------------- -----------------------
| Mobile Wallets | | Bitcoin full nodes | | Whirlpool GUI | | Whirlpool Coordinator |
------------------ -------------------- --------------- -----------------------
|_______________________|____________________|_______________________|
|
-------------
| |
---------------------- | Tor network |
| | |
| ------------
| |
| | (Tor hidden services)
_____ | ____________________________ | _________________________________________
| | | | |
| | | --------- dmznet |
| | | -----------| Tor |------------------------ |
| | | | --------- | |
| | --------- | |
| | | nginx | - - - - - - - - - - - - - - - - - - - - - -|- - - - - - |
| | --------- | |
| | | | | | |
| | --- | ---------------------------- | |
| | | | | | | |
| ----------- | ---------- ---------- ---------- |
| | whirlpool | | | Nodejs |----------| Explorer |------| Bitcoind | |
| ----------- | ---------- ---------- ---------- |
| | | | | | |
| | | ------- | | |
| | | | | | |
| | ---------- | ---------- | |
| | | MySQL | ----| Indexer |----------- |
| | ---------- ---------- |
| whirlnet | dojonet |
|_________________|______________________________________________________________|
Host machine
......@@ -160,6 +159,7 @@ This procedure allows to install a new Dojo from scratch.
* Dojo provides a few additional settings for advanced setups:
* installation of an address indexer used for fast imports and rescans,
* support of an external electrum server (ElectrumX or electrs) used for fast imports and rescans,
* installation of a Whirlpool client,
* static onion address for your full node,
* bitcoind RPC API exposed to external apps,
* use of an external full node,
......@@ -182,7 +182,7 @@ Docker and Docker Compose are going to build the images and containers of your D
* Monitor the progress made for the initialization of the database with this command displaying the logs of the tracker
```
./dojo.sh logs tracker
./dojo.sh logs nodejs
```
Exit the logs with CTRL+C when the syncing of the database has completed.
......@@ -245,23 +245,22 @@ Available commands:
install Install your Dojo.
logs [module] [options] Display the logs of your Dojo. Use CTRL+C to stop the logs.
logs [module] [options] Display the logs of your dojo.
By default, the command displays the live logs. Use CTRL+C to stop the logs.
Use the -n option to display past logs.
Available modules:
dojo.sh logs : display the logs of all containers
dojo.sh logs : display the logs of all the Docker containers
dojo.sh logs bitcoind : display the logs of bitcoind
dojo.sh logs db : display the logs of the MySQL database
dojo.sh logs tor : display the logs of tor
dojo.sh logs nginx : display the logs of nginx
dojo.sh logs indexer : display the logs of the internal indexer
dojo.sh logs api : display the logs of the REST API (nodejs)
dojo.sh logs tracker : display the logs of the Tracker (nodejs)
dojo.sh logs pushtx : display the logs of the pushTx API (nodejs)
dojo.sh logs pushtx-orchest : display the logs of the Orchestrator (nodejs)
dojo.sh logs nodejs : display the logs of NodeJS modules (API, Tracker, PushTx API, Orchestrator)
dojo.sh logs explorer : display the logs of the Explorer
dojo.sh logs whirlpool : display the logs of the Whirlpool client
Available options (for api, tracker, pushtx, pushtx-orchest and explorer modules):
-d [VALUE] : select the type of log to be displayed.
VALUE can be output (default) or error.
Available options:
-n [VALUE] : display the last VALUE lines
onion Display the Tor onion addresses allowing to access the API, maintenance tool and block explorer of your Dojo.
......@@ -277,6 +276,12 @@ Available commands:
upgrade Upgrade your Dojo.
version Display the version of dojo.
whirlpool [action] Interact with the internal whirlpool-cli mdule."
Available actions:"
apikey : display the API key generated by whirlpool-cli."
reset : reset the whirlpool-cli instance (delete configuration file)."
```
......@@ -346,6 +351,10 @@ The maintenance tool is accessed as a Tor hidden service (static onion address).
The block explorer is accessed as a Tor hidden service (static onion address).
The Whirlpool API is accessed as a Tor hidden service (static onion address).
The Whirlpool client connects to the Whirlpool Coordinator hidden service.
The Bitcoin node only allows incoming connections from Tor (ephemeral onion address).
The Bitcoin node attempts outgoing connections to both Tor and clearnet nodes (through the Tor local proxy).
......@@ -20,7 +20,7 @@ This will install Dojo on your Synology hardware.
<a name="install"/>
## Install procedure
## Install
- Connect to Synology web ui as administrator
- Open `Package center`, search for `Docker`, click `Install`.
......@@ -55,3 +55,41 @@ db | WARNING: no logs are available with the 'db' log driver
* nodejs
* tor
- Select a container (ie `bitcoind`), click `Detail`, `Log` to see container's logs in real time
## Usage
- Retrieve the Tor onion addresses (v3) of the API and block explorer of your Dojo
```
./dojo.sh onion
```
Use Tor Browser for:
- Explorer: <explorer-onion-address>.onion (username=any, password=<EXPLORER_KEY>)
- Maintenance tool: <api-onion-address>.onion/admin (password=<NODE_ADMIN_KEY>)
## Upgrade
- Open SSH terminal to your Synology
- Stop Dojo
```
cd <dojo_dir>
./docker/my-dojo/dojo.sh stop
```
- Backup
```
cp -r ./ ../dojo-backup
```
- Download latest Dojo from [GitHub releases](https://github.com/Samourai-Wallet/samourai-dojo/releases)
```
mkdir newDojo
cd newDojo
wget https://github.com/Samourai-Wallet/samourai-dojo/archive/v1.5.0.tar.gz
tar xzvf v1.5.0.tar.gz
cp -r samourai-dojo-1.5.0/* ../
cd ..
```
- Upgrade
```
./docker/my-dojo/dojo.sh upgrade
```
- Clean
```
rm -Rf newDojo
```
......@@ -5,6 +5,7 @@ Push a transaction to the network.
```
POST /pushtx/
```
Parameters must be passed in the body of the request as url encoded arguments.
## Parameters
* **tx** - `hex string` - The raw transaction hex
......@@ -14,7 +15,9 @@ POST /pushtx/
### Example
```
POST /pushtx/?tx=abcdef0123456789
POST /pushtx/
tx=abcdef0123456789
```
#### Success
......
......@@ -10,14 +10,15 @@
COMPOSE_CONVERT_WINDOWS_PATHS=1
DOJO_VERSION_TAG=1.5.0
DOJO_DB_VERSION_TAG=1.1.1
DOJO_BITCOIND_VERSION_TAG=1.5.0
DOJO_NODEJS_VERSION_TAG=1.5.0
DOJO_NGINX_VERSION_TAG=1.4.0
DOJO_TOR_VERSION_TAG=1.3.0
DOJO_EXPLORER_VERSION_TAG=1.2.0
DOJO_INDEXER_VERSION_TAG=1.0.0
DOJO_VERSION_TAG=1.6.0
DOJO_DB_VERSION_TAG=1.2.0
DOJO_BITCOIND_VERSION_TAG=1.6.0
DOJO_NODEJS_VERSION_TAG=1.6.0
DOJO_NGINX_VERSION_TAG=1.5.0
DOJO_TOR_VERSION_TAG=1.4.0
DOJO_EXPLORER_VERSION_TAG=1.3.0
DOJO_INDEXER_VERSION_TAG=1.1.0
DOJO_WHIRLPOOL_VERSION_TAG=1.0.0
#########################################
......
......@@ -5,10 +5,10 @@ FROM debian:buster
# INSTALL BITCOIN
#################################################################
ENV BITCOIN_HOME /home/bitcoin
ENV BITCOIN_VERSION 0.19.1
ENV BITCOIN_URL https://bitcoincore.org/bin/bitcoin-core-0.19.1/bitcoin-0.19.1-aarch64-linux-gnu.tar.gz
ENV BITCOIN_SHA256 3a80431717842672df682bdb619e66523b59541483297772a7969413be3502ff
ENV BITCOIN_ASC_URL https://bitcoincore.org/bin/bitcoin-core-0.19.1/SHA256SUMS.asc
ENV BITCOIN_VERSION 0.20.0
ENV BITCOIN_URL https://bitcoincore.org/bin/bitcoin-core-0.20.0/bitcoin-0.20.0-aarch64-linux-gnu.tar.gz
ENV BITCOIN_SHA256 081b30b0f1af95656242c83eef30bbf7216b1a30fa8e8f29b3b160fe520d28f6
ENV BITCOIN_ASC_URL https://bitcoincore.org/bin/bitcoin-core-0.20.0/SHA256SUMS.asc
ENV BITCOIN_PGP_KS_URI hkp://keyserver.ubuntu.com:80
ENV BITCOIN_PGP_KEY 01EA5486DE18A882D4C2684590C8019E36C2E964
......
......@@ -6,6 +6,7 @@ echo "## Start bitcoind #############################"
bitcoind_options=(
-bind=172.28.1.5
-datadir=/home/bitcoin/.bitcoin
-printtoconsole=1
-dbcache=$BITCOIND_DB_CACHE
-disablewallet=1
-dns=$BITCOIND_DNS
......
#########################################
# CONFIGURATION OF WHIRLPOOL CONTAINER
#########################################
# Install and run an instance of whirlpool-cli inside Docker
# Value: on | off
WHIRLPOOL_INSTALL=on
#
# EXPERT SETTINGS
#
# Activate debug logs
# Value: on | off
WHIRLPOOL_DEBUG=off
# Activate more debug logs
# Value: on | off
WHIRLPOOL_DEBUG_CLIENT=off
......@@ -15,6 +15,11 @@ services:
- "3306"
volumes:
- data-mysql:/var/lib/mysql
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "10"
networks:
dojonet:
ipv4_address: 172.28.1.1
......@@ -40,8 +45,12 @@ services:
- "8081"
- "8082"
volumes:
- data-nodejs:/data
- data-tor:/var/lib/tor
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "10"
depends_on:
- db
networks:
......@@ -61,11 +70,16 @@ services:
expose:
- "80"
- "9080"
volumes:
- data-nginx:/data
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "10"
depends_on:
- node
networks:
whirlnet:
ipv4_address: 172.30.1.3
dmznet:
ipv4_address: 172.29.1.3
dojonet:
......@@ -79,11 +93,17 @@ services:
env_file:
- ./.env
- ./conf/docker-explorer.conf
- ./conf/docker-whirlpool.conf
- ./conf/docker-tor.conf
restart: always
command: /restart.sh
volumes:
- data-tor:/var/lib/tor
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "10"
networks:
dmznet:
ipv4_address: 172.29.1.4
......@@ -103,9 +123,13 @@ networks:
driver: default
config:
- subnet: 172.29.0.0/16
whirlnet:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.30.0.0/16
volumes:
data-mysql:
data-nodejs:
data-nginx:
data-tor:
This diff is collapsed.
FROM node:12-buster
ENV LOGS_DIR /data/logs
ENV APP_DIR /home/node/app
ENV EXPLORER_URL https://github.com/janoside/btc-rpc-explorer/archive
ENV EXPLORER_VERSION 1.1.9
ENV EXPLORER_VERSION 2.0.0
# Install netcat
RUN set -ex && \
apt-get update && \
apt-get install -y netcat
# Create logs and apps directory
RUN mkdir -p "$LOGS_DIR" && \
chown -R node:node "$LOGS_DIR" && \
mkdir "$APP_DIR"
# Download the source code and install it
RUN set -ex && \
mkdir "$APP_DIR" && \
wget -qO explorer.tar.gz "$EXPLORER_URL/v$EXPLORER_VERSION.tar.gz" && \
tar -xzvf explorer.tar.gz -C "$APP_DIR/" --strip-components 1 && \
rm explorer.tar.gz && \
......
......@@ -13,6 +13,7 @@ explorer_options=(
--bitcoind-pass "$BITCOIND_RPC_PASSWORD"
--no-rates
--privacy-mode
--slow-device-mode
)
# Blacklist all functions provided by the RPC API
......@@ -41,4 +42,4 @@ if [ "$NODE_ACTIVE_INDEXER" == "local_indexer" ]; then
fi
fi
node ./bin/cli.js "${explorer_options[@]}" > /data/logs/explorer-error.log 2> /data/logs/explorer-output.log
node ./bin/cli.js "${explorer_options[@]}"
FROM rust:1.37.0-slim
FROM rust:1.42.0-slim-buster
ENV INDEXER_HOME /home/indexer
ENV INDEXER_VERSION 0.1.0
ENV INDEXER_VERSION 0.3.0
ENV INDEXER_URL https://github.com/Samourai-Wallet/addrindexrs.git
RUN apt-get update && \
......
......@@ -12,6 +12,12 @@ else
source ./conf/docker-explorer.conf.tpl
fi
if [ -f ./conf/docker-whirlpool.conf ]; then
source ./conf/docker-whirlpool.conf
else
source ./conf/docker-whirlpool.conf.tpl
fi
if [ -f ./conf/docker-common.conf ]; then
source ./conf/docker-common.conf
else
......@@ -76,6 +82,9 @@ init_config_files() {
cp ./conf/docker-indexer.conf.tpl ./conf/docker-indexer.conf
echo "Initialized docker-indexer.conf"
cp ./conf/docker-whirlpool.conf.tpl ./conf/docker-whirlpool.conf
echo "Initialized docker-whirlpool.conf"
if [ "$EXPLORER_INSTALL" == "on" ]; then
cp ./nginx/explorer.conf ./nginx/dojo-explorer.conf
else
......@@ -83,6 +92,13 @@ init_config_files() {
fi
echo "Initialized dojo-explorer.conf (nginx)"
if [ "$WHIRLPOOL_INSTALL" == "on" ]; then
cp ./nginx/whirlpool.conf ./nginx/dojo-whirlpool.conf
else
cp /dev/null ./nginx/dojo-whirlpool.conf
fi
echo "Initialized dojo-whirlpool.conf (nginx)"
# Initialize config files for nginx and the maintenance tool
if [ "$COMMON_BTC_NETWORK" == "testnet" ]; then
cp ./nginx/testnet.conf ./nginx/dojo.conf
......
......@@ -12,6 +12,12 @@ else
source ./conf/docker-explorer.conf.tpl
fi
if [ -f ./conf/docker-whirlpool.conf ]; then
source ./conf/docker-whirlpool.conf
else
source ./conf/docker-whirlpool.conf.tpl
fi
source ./conf/docker-bitcoind.conf
# Confirm upgrade operation
......@@ -60,6 +66,9 @@ update_config_files() {
update_config_file ./conf/docker-indexer.conf ./conf/docker-indexer.conf.tpl
echo "Initialized docker-indexer.conf"
update_config_file ./conf/docker-whirlpool.conf ./conf/docker-whirlpool.conf.tpl
echo "Initialized docker-whirlpool.conf"
# Initialize config files for nginx and the maintenance tool
if [ "$EXPLORER_INSTALL" == "on" ]; then
cp ./nginx/explorer.conf ./nginx/dojo-explorer.conf
......@@ -68,6 +77,13 @@ update_config_files() {
fi
echo "Initialized dojo-explorer.conf (nginx)"
if [ "$WHIRLPOOL_INSTALL" == "on" ]; then
cp ./nginx/whirlpool.conf ./nginx/dojo-whirlpool.conf
else
cp /dev/null ./nginx/dojo-whirlpool.conf
fi
echo "Initialized dojo-whirlpool.conf (nginx)"
if [ "$COMMON_BTC_NETWORK" == "testnet" ]; then
cp ./nginx/testnet.conf ./nginx/dojo.conf
echo "Initialized dojo.conf (nginx)"
......@@ -112,6 +128,40 @@ update_dojo_db() {
# Clean-up
cleanup() {
#################
# Clean-up v1.6.0
#################
# Remove docker volume my-dojo_data-explorer
explorerVolumeFound=$(docker volume ls | grep my-dojo_data-explorer | wc -l)
if [ $explorerVolumeFound -ne 0 ]; then
explorerContainerFound=$(docker container ls -a | grep explorer | wc -l)
if [ $explorerContainerFound -ne 0 ]; then
docker container rm explorer
fi
docker volume rm my-dojo_data-explorer
fi
# Remove docker volume my-dojo_data-nginx
nginxVolumeFound=$(docker volume ls | grep my-dojo_data-nginx | wc -l)
if [ $nginxVolumeFound -ne 0 ]; then
nginxContainerFound=$(docker container ls -a | grep nginx | wc -l)
if [ $nginxContainerFound -ne 0 ]; then
docker container rm nginx
fi
docker volume rm my-dojo_data-nginx
fi
# Remove docker volume my-dojo_data-nodejs
nodeVolumeFound=$(docker volume ls | grep my-dojo_data-nodejs | wc -l)
if [ $nodeVolumeFound -ne 0 ]; then
nodeContainerFound=$(docker container ls -a | grep nodejs | wc -l)
if [ $nodeContainerFound -ne 0 ]; then
docker container rm nodejs
fi
docker volume rm my-dojo_data-nodejs
fi
#################
# Clean-up v1.3.0
#################
......@@ -131,3 +181,17 @@ cleanup() {
fi
}
# Post start clean-up
post_start_cleanup() {
#################
# Clean-up v1.6.0
#################
# Remove debug.log from bitcoind volume
if [ "$COMMON_BTC_NETWORK" == "testnet" ]; then
docker exec -it bitcoind rm /home/bitcoin/.bitcoin/testnet3/debug.log
else
docker exec -it bitcoind rm /home/bitcoin/.bitcoin/debug.log
fi
}
\ No newline at end of file
FROM nginx:1.15.10-alpine
# Create data directory
ENV LOGS_DIR /data/logs
RUN mkdir -p "$LOGS_DIR" && \
chown -R nginx:nginx "$LOGS_DIR"
# Copy configuration files
COPY ./nginx.conf /etc/nginx/nginx.conf
COPY ./dojo.conf /etc/nginx/sites-enabled/dojo.conf
COPY ./dojo-explorer.conf /etc/nginx/sites-enabled/dojo-explorer.conf
COPY ./dojo-whirlpool.conf /etc/nginx/sites-enabled/dojo-whirlpool.conf
# Copy wait-for script
COPY ./wait-for /wait-for
......
......@@ -2,8 +2,9 @@ user nginx;
worker_processes auto;
daemon off;
# Log critical errors and higher