diff --git a/README.md b/README.md index 132441f..03d1bc9 100644 --- a/README.md +++ b/README.md @@ -6,72 +6,55 @@ This is installed on a Secure Node to allow it to communicate with the zensystem Each secure node must have a unique IP address (v4 or v6), a stake address with 42 ZEN, about 1 ZEN for challenges in a z-address on the node, and be able to perform challenges in less than 300 seconds. See the About page on the server for more information. -## UPDATE 0.1.0 - BETA-MAINNET - - Updated for use on mainnet - - Setup will use ZEN_HOME environment variable if found for the zen.conf file - - Added check for a balance in all existing z-addresses to help work around 0 balance after a challenge - -The regional servers run on mainnet as of December 1st 2017. - -### About This Phase of the Beta - Mainnet - This phase migrates existing nodes to mainnet. Earning and payouts start after a short testing period. +## UPDATE 0.2.0 - BETA-MAINNET + - Add ability to assign home server for load balancing + - Add ability to update server list for failover + - Fix status when zen is back up + - Add an environment variable for location of zen.conf + - Fix for using IPv6 -### IMPORTANT UPDATE STEPS -- Switching to mainnet: -These are upgrade and migration instructions. If you are doing a new install see the New Installation instructions further down. - - #### Make sure your zen node is no longer on testnet. - 1. Stop zend: zen-cli stop - 2. Remove 'testnet=1' from your zen.conf - 3. Start zend and let it sync with the main blockchain. - 4. Adjust steps as needed if using monitoring applications. - 5. Optional: delete the .zen/testnet3 folder to save space - - #### Create a z_address for the challenges - 1. Run: zen-cli z_getnewaddress - 2. Send 1 ZEN split into 4 to 5 separate transactions to that address. - 3. Optional: this version checks for multiple z_addresses. Create one or more additional and split the 1 ZEN across them. - - #### Prepare a stake address - It is suggested a stake address exists that does not reside on the node. - 1. Identify your stake address or create one in a wallet. It must contain at least 42 ZEN. +### IMPORTANT UPDATE STEPS: +These are update instructions. If you are doing a new install see the New Installation instructions further down. #### Check the version of nodejs 1. Run: node -v - Suggested version is 8.9.x since it will have long term support. - To change run: sudo n 8.9 + To change run: + * sudo n 8.9 #### Update secnodetracker - 1. Stop the tracker application. - - 2. Delete the following files in the secnodetracker/config folder: - - nodeid, serverurl, lastChalBlock, lastExecSec, stakeaddr + - 3. Change to the secnodetracker folder and update the tracker application. - This may be '~/zencash/secnodetracker' if the install guides were followed. Run the following commands: + 1. Change to the secnodetracker folder and update the tracker application. + This may be '~/zencash/secnodetracker' if the install guides were followed. + Run the following commands: * git fetch origin * git checkout master * git pull + If git complains about overwritting a file use: git checkout -- filename + Then run the above commands again - 4. If the servers are available, run the tracker setup and follow the prompts. + 2. Run setup (this will refresh the list of servers) in the scenodetracker folder. + You should be able to accept all the previous values. * node setup - 5. If the servers are available, start the tracer app. The tracker should connect to the mainnet servers and register. + 2. Stop the tracker application and restart it + * Ctrl-c * node app + * or restart using your managment application such as PM2 - When the tracker successfully connects it will indicate it has registered and authenticated. - - + ## Version Notes -This is Beta-Mainnet and is not meant to run on testnet. +This is Beta-Mainnet but may be run on testnet following the instructions on the testnet home page: https://securenodes-testnet.zensystem.io/ ## New Installation If you have followed Part 1, Part 2, and Part 2.5, and/or Part 3 of guides for creating a Secure Node, you should be ready to install this on your node. -You will need about 1 zen in the node wallet in a private address. Send multiple small amounts (0.2 each) to work around an issue with 0 balances due to waiting for change to return after a challenge. +You will need about 1 zen in the node wallet in a private address. Send multiple small amounts (0.2 each) to work around an issue with 0 balances due to waiting for change to return after a challenge. Alternately create an additional private address and split the amounts between them. The private z-address needs to be created manually if not present (zen-cli z_getnewaddress). If already present the balance is checked when the app starts and the address is displayed on the tracker console. @@ -81,6 +64,7 @@ Note: real ZEN transparent addresses (t-address) start wtih a 'zn' (testnet addr ### Install npm and Node.js Log into your secure node. The following installs the NPM and Node.js (a javascript virtual machine). + - Suggested version is 8.9.x since it will have long term support. * sudo apt-get install npm * sudo npm install -g n @@ -88,7 +72,7 @@ Log into your secure node. The following installs the NPM and Node.js (a javasc ### Clone this repository If you followed the Guides you should have a ~/zencash folder with the zen folder in it. -Put this repository in the zencash folder too. +Put this repository in the zencash folder too or the folder of your choice. * cd ~/zencash * git clone https://github.com/ZencashOfficial/secnodetracker.git @@ -99,7 +83,7 @@ Put this repository in the zencash folder too. * npm install ### Run setup -You will need your staking address (with at least 42 ZEN) and an email address for alerts (if you do not want alerts enter 'none' for the email address). During setup press Enter to accept the default or enter new information. +You will need your staking address (with at least 42 ZEN) and an email address for alerts (if you do not want alerts enter 'none' for the email address). During setup press Enter to accept the default or enter new information. See the Note below on finding the zen.conf file. * node setup @@ -121,6 +105,19 @@ For community support, ask question in the zencash Discord #securenodes channel. Instructions on installing a monitoring tool like nodemon or PM2 may be found separately. +**Locating zen.conf** +There are two optional environment variables that may be used to locate zen.conf which is needed for rpc configuration. + + ZENCONF - if this is found it must contain the full path to zen.conf including the file name. + ZEN_HOME - if this is found it should be a base path. '/.zen/zen.conf' is appended to it. + + If the above two are not found the operating system is used for the home path. + The search is then peformed in the following order: + oshome + "/.zen/zen.conf"; + oshome + "/zencash/.zen/zen.conf"; + oshome + "/AppData/Roaming/Zen/zen.conf"; + + diff --git a/SecNodeTracker.js b/SecNodeTracker.js index 24e0bcc..f89c936 100644 --- a/SecNodeTracker.js +++ b/SecNodeTracker.js @@ -48,17 +48,9 @@ class SecNode { this.waiting = false; this.zenDownInterval = 1000 * 61; this.zenDownTimer = null; - this.zenDownLoop = () => { - this.getPrimaryAddress((err, amt) => { - if (err) { - console.error(logtime(), err); - } else { - console.log(logtime(), 'Zen connected.'); - clearInterval(this.zenDownTimer); - this.collectStats(); - } - }); - }; + this.zenDownLoop = () =>{ + this.checkZen(); + } } static auto() { @@ -71,6 +63,19 @@ class SecNode { this.statsTimer = setInterval(this.statsLoop, this.statsInterval); } + checkZen() { + const self = this; + self.getPrimaryAddress((err, amt) => { + if (err) { + console.error(logtime(), err); + } else { + console.log(logtime(), 'Zen connected.'); + clearInterval(self.zenDownTimer); + self.collectStats(); + } + }); + } + getPrimaryAddress(cb) { const self = this; this.corerpc.getAddressesByAccount("", (err, data) => { @@ -124,9 +129,18 @@ class SecNode { if (count === results.length && !called) { cb(null, { "addr": addrbal.addr, "bal": addrbal.bal, "valid": valid, "lastChalBlock": lastChalBlockNum }); } + }) + .catch(err => { + console.error("Error: zen z_getbalance ", err); }); } + }) + .catch(err => { + console.error("Error: zen z_listaddresses ", err); }); + }) + .catch(err => { + console.error("Error: zen getinfo ", err); }); } @@ -176,14 +190,16 @@ class SecNode { console.log("OperationId=" + opid); self.chalStart = new Date(); self.chalRunning = true; - self.opTimer = setInterval(() => { - self.checkOp(opid, chal); + if (!self.opTimer) { + self.opTimer = setInterval(() => { + self.checkOp(opid, chal); + } + , self.opTimerInterval); } - , self.opTimerInterval); return }) .catch(err => { - let resp = { "crid": chal.crid, "status": "error", "error": err } + let resp = { "crid": chal.crid, "status": "error", "error": 'unable to create transaction' } resp.ident = self.ident; console.error(logtime(), "Challenge: unable to create and send transaction."); console.error(err); @@ -270,7 +286,7 @@ class SecNode { }) .catch(err => { self.chalRunning = false; - console.error("challenge error"); + console.log(logtime(), "Challenge error: could not get operation status."); console.error(err); clearInterval(self.opTimer); return diff --git a/app.js b/app.js index 8a1bc03..14a44e0 100644 --- a/app.js +++ b/app.js @@ -12,14 +12,21 @@ if (local.length == 0) { process.exit(); } +const ipv = local.getItem('ipv'); +if (ipv.trim() === '6') { + console.log("You setup ipv6 connectivity. We need to apply a workaround for dns resolution."); + require('./ipv6-dns-workaround'); +} + // host names without domain -const servers = local.getItem('servers').split(','); -const home = local.getItem('home'); +let servers = local.getItem('servers').split(','); +let home = local.getItem('home'); if (!home) return console.log("ERROR SETTING THE HOME SERVER. Please try running setup again or report the issue.") let curIdx = servers.indexOf(home); let curServer = home; -const protocol = `${init.protocol}://`; +let protocol = `${init.protocol}://`; let domain = `.${init.domain}`; + let socket = io(protocol + curServer + domain, { multiplex: false }); let failoverTimer; @@ -106,7 +113,7 @@ const initialize = () => { SecNode.getNetworks(null, (err, nets) => { ident.nets = nets; socket.emit('initnode', ident, () => { - //only pass email and nets on init. + //only pass email and nets on init. delete ident.email; delete ident.nets; }); @@ -182,10 +189,20 @@ const setSocketEvents = () => { case 'networks': SecNode.getNets(data); break; - + case 'changeServer': switchServer(data.server); break; + + case 'changeHome': + changeHome(data.server); + break; + + case 'updateServers': + servers = data.servers; + local.setItem("servers", servers); + console.log(logtime(), "Updated server list"); + break; } }) } @@ -212,6 +229,23 @@ const switchServer = (server) => { ident.con.cur = curServer; } +const changeHome = (server) =>{ + home = server; + local.setItem("home", server); + curServer = home; + curIdx = servers.indexOf(home); + returningHome = true; + console.log(logtime(), `Change home server to ${curServer}.`); + socket.close(); + ident.con.home = home; + ident.con.cur = curServer; + + socket = io(protocol + curServer + domain, { forceNew: true }); + setSocketEvents(); + SecNode.socket = socket; + returningHome = false; +} + const conCheck = () => { setInterval(() => { @@ -230,4 +264,3 @@ const conCheck = () => { SecNode.socket = socket; SecNode.initialize(); conCheck(); - diff --git a/init.json b/init.json index 1217db2..163dcc1 100644 --- a/init.json +++ b/init.json @@ -1,5 +1,5 @@ { - "lookupServer": "https://securenodes.zensystem.io/api/srvlist", + "lookupServer": "https://securenodes2.zensystem.io/api/srvlist", "domain":"zensystem.io", "protocol": "https" -} \ No newline at end of file +} diff --git a/ipv6-dns-workaround.js b/ipv6-dns-workaround.js new file mode 100644 index 0000000..2c7aadd --- /dev/null +++ b/ipv6-dns-workaround.js @@ -0,0 +1,7 @@ +'use strict'; + +const dns = require('dns'), {lookup} = dns; +dns.lookup = function(name, opts, cb) { + if (typeof cb !== 'function') return lookup(name, {verbatim:true}, opts); + return lookup(name, Object.assign({verbatim:true}, opts), cb); +}; diff --git a/package.json b/package.json index 415d714..3381a93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zensecnodetracker", - "version": "0.1.0", + "version": "0.2.0", "description": "zencash secure node tracking application", "repository" : { "type" : "git", diff --git a/setup.js b/setup.js index d99f006..45a6233 100644 --- a/setup.js +++ b/setup.js @@ -175,7 +175,9 @@ const getRPC = () => { let path2 = oshome + "/zencash/.zen/zen.conf"; let path3 = oshome + "/AppData/Roaming/Zen/zen.conf"; - if (fs.existsSync(path1)) { + if (process.env.ZENCONF) { + lines = fs.readFileSync(process.env.ZENCONF, "utf8").split("\n"); + } else if (fs.existsSync(path1)) { lines = fs.readFileSync(path1, "utf8").split("\n"); } else if (fs.existsSync(path2)) { lines = fs.readFileSync(path2, "utf8").split("\n"); @@ -197,7 +199,7 @@ const getRPC = () => { let ipfound = false; lines.forEach(line => { line = line.trim(); - if (line.indexOf('#') === -1 && line.indexOf("rpc") === 0) { + if (!line.startsWith('#') && line.indexOf("rpc") === 0) { let idx = line.indexOf("="); //don't use split since user or pw could have = let key = line.substring(0, idx); let val = line.substring(idx + 1);