From 9a42211c38668b5794be89d3e474011a84b21eb9 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Sat, 19 Apr 2014 13:46:34 -0600 Subject: [PATCH] Converted init coin info detection from RPC waterfall to batch RPC call. Added getblocktemplate after submitting block --- lib/daemon.js | 2 +- lib/pool.js | 272 +++++++++++++++----------------------------------- 2 files changed, 82 insertions(+), 192 deletions(-) diff --git a/lib/daemon.js b/lib/daemon.js index 24ef5b3..5c9dabc 100644 --- a/lib/daemon.js +++ b/lib/daemon.js @@ -132,7 +132,7 @@ function DaemonInterface(options){ performHttpRequest(instances[0], serializedRequest, function(error, result){ callback(error, result); - }, 'fuck'); + }); } diff --git a/lib/pool.js b/lib/pool.js index dacfba1..00b077d 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -297,6 +297,12 @@ var pool = module.exports = function pool(options, authorizeFn){ isValidBlock = isAccepted; shareData.txHash = tx; emitShare(); + + GetBlockTemplate(function(error, result, foundNewBlock){ + if (foundNewBlock) + emitLog('Block notification via RPC after block submission'); + }); + }); }); } @@ -332,199 +338,83 @@ var pool = module.exports = function pool(options, authorizeFn){ function DetectCoinData(finishedCallback){ + var batchRpcCalls = [ + ['validateaddress', [options.address]], + ['getdifficulty', []], + ['getinfo', []], + ['getmininginfo', []], + ['submitblock', []] + ]; - //TODO: Convert this all into a batch RPC call for better performance - - async.waterfall([ - - function(callback){ - _this.daemon.cmd('validateaddress', [options.address], function(results){ - - //Make sure address is valid with each daemon - var allValid = results.every(function(result){ - if (result.error || !result.response){ - emitErrorLog('validateaddress rpc error on daemon instance ' + - result.instance.index + ' - ' + JSON.stringify(result.error)); - } - else if (!result.response.isvalid) - emitErrorLog('Daemon instance ' + result.instance.index + - ' reports address is not valid'); - return result.response && result.response.isvalid; - }); - - if (!allValid){ - callback('not all addresses are valid'); - return; - } - - //Try to find result that owns address in case of POS coin with multi daemons - var ownedInfo = results.filter(function(r){ - return r.response.ismine; - }); - - options.coin.addressByte = util.getVersionByte(options.address); - - callback(null, ownedInfo.length > 0 ? ownedInfo[0].response : results[0].response); - - }); - }, - - function(addressInfo, callback){ - var examplePubKey = new Buffer([options.coin.addressByte, new Buffer('010966776006953D5567439E5E39F86A0D273BEE', 'hex')]); - var dHashed = util.sha256d(examplePubKey); - var binaryAddress = - - callback(null, addressInfo); - }, - - function(addressInfo, callback){ - _this.daemon.cmd('getdifficulty', [], function(results){ - - //This detects if a coin is POS because getdiff returns an object instead of a number - - var isPos = results.every(function(result){ - - if (result.error){ - emitErrorLog('getinfo on init failed with daemon instance ' + - result.instance.index + ', error ' + JSON.stringify(result.error) - ); - return false; - } - - return isNaN(result.response) && 'proof-of-stake' in result.response; - }); - - options.coin.reward = isPos ? 'POS' : 'POW'; - - /* POS coins must use the pubkey in coinbase transaction, and pubkey is - only given if address is owned by wallet.*/ - if (options.coin.reward === 'POS' && typeof(addressInfo.pubkey) == 'undefined') { - emitErrorLog('The address provided is not from the daemon wallet - this is required for POS coins.'); - return; - } - - options.publicKeyBuffer = (function(){ - switch(options.coin.reward){ - case 'POS': - return util.pubkeyToScript(addressInfo.pubkey); - case 'POW': - return util.addressToScript(addressInfo.address); - } - })(); - - callback(null); - - }); - }, - - function(callback){ - _this.daemon.cmd('getinfo', [], function(results){ - - // Print which network each daemon is running on - - var isTestnet; - var allValid = results.every(function(result){ - - if (result.error){ - emitErrorLog('getinfo on init failed with daemon instance ' + - result.instance.index + ', error ' + JSON.stringify(result.error) - ); - return false; - } - - //Make sure every daemon is on the correct network or the config is wrong - if (typeof isTestnet === 'undefined'){ - isTestnet = result.response.testnet; - return true; - } - else if (isTestnet !== result.response.testnet){ - emitErrorLog('not all daemons are on same network'); - return false; - } - else - return true; - }); - - - if (!allValid){ - callback('could not getinfo correctly on each daemon'); - return; - } - - //Find and return the response with the largest block height (most in-sync) - var infoResult = results.sort(function(a, b){ - return b.response.blocks - a.response.blocks; - })[0].response; - - options.testnet = infoResult.testnet; - options.protocolVersion = infoResult.protocolversion; - - options.initStats = { connections: infoResult.connections, difficulty: infoResult.difficulty }; - - callback(null); - - }); - }, - - function(callback){ - _this.daemon.cmd('getmininginfo', [], function(results){ - var allValid = results.every(function(result){ - if (result.error){ - emitErrorLog('getmininginfo on init failed with daemon instance ' + - result.instance.index + ', error ' + JSON.stringify(result.error) - ); - return false; - } - return true; - }); - - if (!allValid){ - callback('could not getmininginfo correctly on each daemon'); - return; - } - - //Find and return the response with the largest block height (most in-sync) - var miningInfoResult = results.sort(function(a, b){ - return b.response.blocks - a.response.blocks; - })[0].response; - - options.initStats.networkHashRate = miningInfoResult.networkhashps; - - callback(null); - - }); - }, - - function(callback){ - /* This checks to see whether the daemon uses submitblock - or getblocktemplate for submitting new blocks */ - _this.daemon.cmd('submitblock', [], function(results){ - var couldNotDetectMethod = results.every(function(result){ - if (result.error && result.error.message === 'Method not found'){ - options.hasSubmitMethod = false; - callback(null); - return false; - } - else if (result.error && result.error.code === -1){ - options.hasSubmitMethod = true; - callback(null); - return false; - } - else - return true; - }); - if (couldNotDetectMethod){ - emitErrorLog('Could not detect block submission RPC method, ' + JSON.stringify(results)); - callback('block submission detection failed'); - } - }); - } - ], function(err, results){ - if (err){ - emitErrorLog('Could not start pool, ' + JSON.stringify(err)); + _this.daemon.batchCmd(batchRpcCalls, function(error, results){ + if (error || !results){ + emitErrorLog('Could not start pool, error with init batch RPC call: ' + JSON.stringify(error)); return; } + + var rpcResults = {}; + + for (var i = 0; i < results.length; i++){ + var rpcCall = batchRpcCalls[i][0]; + var r = results[i]; + rpcResults[rpcCall] = r.result || r.error; + + if (rpcCall !== 'submitblock' && (r.error || !r.result)){ + emitErrorLog('Could not start pool, error with init RPC ' + rpcCall + ' - ' + JSON.stringify(r.error)); + return; + } + } + + if (!rpcResults.validateaddress.isvalid){ + emitErrorLog('Daemon reports address is not valid'); + return; + } + + if (isNaN(rpcResults.getdifficulty) && 'proof-of-stake' in rpcResults.getdifficulty) + options.coin.reward = 'POS'; + else + options.coin.reward = 'POW'; + + + /* POS coins must use the pubkey in coinbase transaction, and pubkey is + only given if address is owned by wallet.*/ + if (options.coin.reward === 'POS' && typeof(rpcResults.validateaddress.pubkey) == 'undefined') { + emitErrorLog('The address provided is not from the daemon wallet - this is required for POS coins.'); + return; + } + + options.publicKeyBuffer = (function(){ + switch(options.coin.reward){ + case 'POS': + return util.pubkeyToScript(rpcResults.validateaddress.pubkey); + case 'POW': + return util.addressToScript(rpcResults.validateaddress.address); + } + })(); + + options.testnet = rpcResults.getinfo.testnet; + options.protocolVersion = rpcResults.getinfo.protocolversion; + + options.initStats = { + connections: rpcResults.getinfo.connections, + difficulty: rpcResults.getinfo.difficulty, + networkHashRate: rpcResults.getmininginfo.networkhashps + }; + + + if (rpcResults.submitblock.message === 'Method not found'){ + options.hasSubmitMethod = false; + } + else if (rpcResults.submitblock.code === -1){ + options.hasSubmitMethod = true; + } + else { + emitErrorLog('Could not detect block submission RPC method, ' + JSON.stringify(results)); + return; + } + finishedCallback(); + }); } @@ -669,7 +559,7 @@ var pool = module.exports = function pool(options, authorizeFn){ function CheckBlockAccepted(blockHash, callback){ - setTimeout(function(){ + //setTimeout(function(){ _this.daemon.cmd('getblock', [blockHash], function(results){ @@ -685,7 +575,7 @@ var pool = module.exports = function pool(options, authorizeFn){ } } ); - }, 500); + //}, 500); }