From 5d236c63fb558a62b3f3cc9aea1c7d3a7f6a7cdd Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 16 Apr 2014 11:50:58 -0600 Subject: [PATCH] Added documentation for p2p usage --- README.md | 31 +++++++++++++++++++------------ lib/peer.js | 32 +++++++++++++++++++++----------- lib/pool.js | 35 ++++++++++++++++++++--------------- 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 00e35cb..14c35c7 100644 --- a/README.md +++ b/README.md @@ -46,15 +46,15 @@ Features Under development: -* ✗ *Keccak* (CopperLark [CLR]) -* ✗ *Max* (Maxcoin [MAX], HelixCoin [HXC]) +* ✗ *Keccak* (Maxcoin [MAX], HelixCoin, CryptoMeth, eCoin, CopperLark) * ✗ *Skein* (Skeincoin [SKC]) -* ✗ *Bcrypt* (Taojingcoin [TJC]) +* ✗ *Groestl* (MyriadCoin [MYR] +* ✗ *Qubit* (QubitCoin [Q2C], MyriadCoin [MYR]) * ✗ *Hefty1* (Heavycoin [HVC]) * ✗ *Blake* (Blakecoin [BLC]) * ✗ *Fugue* (Fuguecoin [FC]) * ✗ *SHAvite-3* (INKcoin [INK]) - +* ✗ *Bcrypt* (Taojingcoin [TJC]) #### Under development @@ -223,23 +223,29 @@ var pool = Stratum.createPool({ ], - /* This allows the pool to connect to the daemon as a node peer to recieve block updates. + /* This allows the pool to connect to the daemon as a node peer to receive block updates. It may be the most efficient way to get block updates (faster than polling, less - intensive than blocknotify script). However its still under development (not yet working). */ + intensive than blocknotify script). It requires additional setup: the 'magic' field must + be exact (extracted from the coin source code). */ "p2p": { "enabled": false, + + /* Host for daemon */ "host": "127.0.0.1", + + /* Port configured for daemon (this is the actual peer port not RPC port) */ "port": 19333, + /* If your coin daemon is new enough (i.e. not a shitcoin) then it will support a p2p feature + that prevents the daemon from spamming our peer node with unnecessary transaction data. + Assume its supported but if you have problems try disabling it. */ + "disableTransactions": true, + /* Magic value is different for main/testnet and for each coin. It is found in the daemon source code as the pchMessageStart variable. For example, litecoin mainnet magic: http://git.io/Bi8YFw - And for litecoin testnet magic: http://git.io/NXBYJA - */ - "magic": "fcc1b7dc", - - //Found in src as the PROTOCOL_VERSION variable, for example: http://git.io/KjuCrw - "protocolVersion": 70002, + And for litecoin testnet magic: http://git.io/NXBYJA */ + "magic": "fcc1b7dc" } }, function(ip, workerName, password, callback){ //stratum authorization function @@ -311,6 +317,7 @@ pool.start(); Credits ------- * [vekexasia](https://github.com/vekexasia) - co-developer & great tester +* [LucasJones(//github.com/LucasJones) - getting p2p block notify script working * [TheSeven](https://github.com/TheSeven) - answering an absurd amount of my questions, found the block 1-16 problem, provided example code for peer node functionality * [pronooob](https://dogehouse.org) - knowledgeable & helpful * [Slush0](https://github.com/slush0/stratum-mining) - stratum protocol, documentation and original python code diff --git a/lib/peer.js b/lib/peer.js index d5fc4d9..a3b4365 100644 --- a/lib/peer.js +++ b/lib/peer.js @@ -46,9 +46,10 @@ var Peer = module.exports = function (options) { var _this = this; var client; - var magic = new Buffer(options.magic, 'hex'); + var magic = new Buffer(options.p2p.magic, 'hex'); var magicInt = magic.readUInt32LE(0); var verack = false; + var validConnectionConfig = true; //https://en.bitcoin.it/wiki/Protocol_specification#Inventory_Vectors var invCodes = { @@ -64,7 +65,7 @@ var Peer = module.exports = function (options) { //If protocol version is new enough, add do not relay transactions flag byte, outlined in BIP37 //https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#extensions-to-existing-messages - var relayTransactions = options.protocolVersion >= 70001 ? new Buffer([false]) : new Buffer([]); + var relayTransactions = options.p2p.disableTransactions === true ? new Buffer([false]) : new Buffer([]); var commands = { version: commandStringBuffer('version'), @@ -83,19 +84,28 @@ var Peer = module.exports = function (options) { function Connect() { client = net.connect({ - host: options.host, - port: options.port + host: options.p2p.host, + port: options.p2p.port }, function () { - _this.emit('connected'); SendVersion(); }); - client.on('end', function () { - _this.emit('disconnected'); - verack = false; - Connect(); + client.on('close', function () { + if (verack) { + _this.emit('disconnected'); + verack = false; + Connect(); + } + else if (validConnectionConfig) + _this.emit('connectionRejected'); + }); client.on('error', function (e) { - _this.emit('connectionFailed', e); + if (e.code === 'ECONNREFUSED') { + validConnectionConfig = false; + _this.emit('connectionFailed'); + } + else + _this.emit('socketError', e); }); @@ -175,7 +185,7 @@ var Peer = module.exports = function (options) { case commands.verack.toString(): if(!verack) { verack = true; - _this.emit('verack'); + _this.emit('connected'); } break; default: diff --git a/lib/pool.js b/lib/pool.js index 29f0c86..724ba32 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -195,17 +195,21 @@ var pool = module.exports = function pool(options, authorizeFn){ function SetupPeer(){ if (!options.p2p || !options.p2p.enabled) return; - _this.peer = new peer(options.p2p); - _this.peer.on('connected', function(){ - emitLog('connected to daemon as a peer node'); + _this.peer = new peer(options); + _this.peer.on('connected', function() { + emitLog('p2p connection successful'); + }).on('connectionRejected', function(){ + emitErrorLog('p2p connection failed - likely incorrect p2p magic value'); }).on('disconnected', function(){ - emitWarningLog('peer node disconnected - attempting reconnection...'); - }).on('connectionFailed', function(){ - emitErrorLog('failed to connect to daemon as a peer node'); + emitWarningLog('p2p peer node disconnected - attempting reconnection...'); + }).on('connectionFailed', function(e){ + emitErrorLog('p2p connection failed - likely incorrect host or port'); + }).on('socketError', function(e){ + emitErrorLog('p2p had a socket error ' + JSON.stringify(e)); }).on('error', function(msg){ - emitWarningLog(msg); + emitWarningLog('p2p had an error ' + msg); }).on('blockFound', function(hash){ - _this.processBlockNotify(hash); + _this.processBlockNotify(hash, 'p2p'); }); } @@ -334,7 +338,6 @@ var pool = module.exports = function pool(options, authorizeFn){ //TODO: Convert this all into a batch RPC call for better performance - async.waterfall([ function(callback){ @@ -457,6 +460,7 @@ var pool = module.exports = function pool(options, authorizeFn){ })[0].response; options.testnet = infoResult.testnet; + options.protocolVersion = infoResult.protocolversion; options.initStats = { connections: infoResult.connections, difficulty: infoResult.difficulty }; @@ -626,7 +630,10 @@ var pool = module.exports = function pool(options, authorizeFn){ var pollingInterval = options.blockRefreshInterval; blockPollingIntervalId = setInterval(function () { - GetBlockTemplate(function(error, result){}); + GetBlockTemplate(function(error, result, foundNewBlock){ + if (foundNewBlock) + emitLog('Block notification via RPC polling'); + }); }, pollingInterval); } @@ -651,7 +658,7 @@ var pool = module.exports = function pool(options, authorizeFn){ } - callback(null, result.response); + callback(null, result.response, processedNewBlock); callback = function(){}; } }, true @@ -682,13 +689,12 @@ var pool = module.exports = function pool(options, authorizeFn){ - /** * This method is being called from the blockNotify so that when a new block is discovered by the daemon * We can inform our miners about the newly found block **/ - this.processBlockNotify = function(blockHash) { - + this.processBlockNotify = function(blockHash, sourceTrigger) { + emitLog('Block notification via ' + sourceTrigger); if (typeof(_this.jobManager.currentJob) !== 'undefined' && blockHash !== _this.jobManager.currentJob.rpcData.previousblockhash){ GetBlockTemplate(function(error, result){ if (error) @@ -698,7 +704,6 @@ var pool = module.exports = function pool(options, authorizeFn){ }; - this.relinquishMiners = function(filterFn, resultCback) { var origStratumClients = this.stratumServer.getStratumClients();