@ -1,9 +1,23 @@
var debug = require ( 'debug' ) ( 'rpcApi' ) ;
var debug = require ( 'debug' ) ( 'btcexp:rpcApi' ) ;
var async = require ( "async" ) ;
var utils = require ( "../utils.js" ) ;
var utils = require ( "../utils.js" ) ;
var config = require ( "../config.js" ) ;
var config = require ( "../config.js" ) ;
var coins = require ( "../coins.js" ) ;
var coins = require ( "../coins.js" ) ;
var rpcQueue = async . queue ( function ( task , callback ) {
task . rpcCall ( ) ;
if ( callback != null ) {
callback ( ) ;
}
} , config . rpcConcurrency ) ;
function getBlockchainInfo ( ) {
function getBlockchainInfo ( ) {
return getRpcData ( "getblockchaininfo" ) ;
return getRpcData ( "getblockchaininfo" ) ;
}
}
@ -33,51 +47,22 @@ function getPeerInfo() {
}
}
function getRawMempool ( ) {
function getRawMempool ( ) {
return getRpcDataWithParams ( "getrawmempool", true ) ;
return getRpcDataWithParams ( { method : "getrawmempool", parameters : [ true ] } ) ;
}
}
function getChainTxStats ( blockCount ) {
function getChainTxStats ( blockCount ) {
return getRpcDataWithParams ( "getchaintxstats", blockCount ) ;
return getRpcDataWithParams ( { method : "getchaintxstats", parameters : [ blockCount ] } ) ;
}
}
function getBlockByHeight ( blockHeight ) {
function getBlockByHeight ( blockHeight ) {
return new Promise ( function ( resolve , reject ) {
return new Promise ( function ( resolve , reject ) {
getBlocksByHeight ( [ blockHeight ] ) . then ( function ( results ) {
getRpcDataWithParams ( { method : "getblockhash" , parameters : [ blockHeight ] } ) . then ( function ( blockhash ) {
if ( results && results . length > 0 ) {
getBlockByHash ( blockhash ) . then ( function ( block ) {
resolve ( results [ 0 ] ) ;
resolve ( block ) ;
} else {
} ) . catch ( function ( err ) {
resolve ( null ) ;
reject ( err ) ;
}
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
}
function getBlocksByHeight ( blockHeights ) {
//debug("getBlocksByHeight: " + blockHeights);
return new Promise ( function ( resolve , reject ) {
var batch = [ ] ;
for ( var i = 0 ; i < blockHeights . length ; i ++ ) {
batch . push ( {
method : 'getblockhash' ,
parameters : [ blockHeights [ i ] ]
} ) ;
}
var blockHashes = [ ] ;
client . command ( batch ) . then ( ( responses ) => {
responses . forEach ( ( item ) => {
blockHashes . push ( item ) ;
} ) ;
} ) ;
if ( blockHashes . length == batch . length ) {
getBlocksByHash ( blockHashes ) . then ( function ( blocks ) {
resolve ( blocks ) ;
} ) ;
}
} ) . catch ( function ( err ) {
} ) . catch ( function ( err ) {
reject ( err ) ;
reject ( err ) ;
} ) ;
} ) ;
@ -85,53 +70,19 @@ function getBlocksByHeight(blockHeights) {
}
}
function getBlockByHash ( blockHash ) {
function getBlockByHash ( blockHash ) {
return new Promise ( function ( resolve , reject ) {
debug ( "getBlockByHash: %s" , blockHash ) ;
getBlocksByHash ( [ blockHash ] ) . then ( function ( results ) {
if ( results && results . length > 0 ) {
resolve ( results [ 0 ] ) ;
} else {
resolve ( null ) ;
}
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
}
function getBlocksByHash ( blockHashes ) {
debug ( "rpc.getBlocksByHash: " + blockHashes ) ;
return new Promise ( function ( resolve , reject ) {
return new Promise ( function ( resolve , reject ) {
var batch = [ ] ;
getRpcDataWithParams ( { method : "getblock" , parameters : [ blockHash ] } ) . then ( function ( block ) {
for ( var i = 0 ; i < blockHashes . length ; i ++ ) {
getRawTransaction ( block . tx [ 0 ] ) . then ( function ( tx ) {
batch . push ( {
block . coinbaseTx = tx ;
method : 'getblock' ,
block . totalFees = utils . getBlockTotalFeesFromCoinbaseTxAndBlockHeight ( tx , block . height ) ;
parameters : [ blockHashes [ i ] ]
block . miner = utils . getMinerFromCoinbaseTx ( tx ) ;
} ) ;
}
var blocks = [ ] ;
client . command ( batch ) . then ( ( responses ) => {
responses . forEach ( ( item ) => {
if ( item . tx ) {
blocks . push ( item ) ;
}
} ) ;
var coinbaseTxids = [ ] ;
resolve ( block ) ;
for ( var i = 0 ; i < blocks . length ; i ++ ) {
coinbaseTxids . push ( blocks [ i ] . tx [ 0 ] )
}
getRawTransactions ( coinbaseTxids ) . then ( function ( coinbaseTxs ) {
for ( var i = 0 ; i < blocks . length ; i ++ ) {
blocks [ i ] . coinbaseTx = coinbaseTxs [ i ] ;
blocks [ i ] . totalFees = utils . getBlockTotalFeesFromCoinbaseTxAndBlockHeight ( coinbaseTxs [ i ] , blocks [ i ] . height ) ;
blocks [ i ] . miner = utils . getMinerFromCoinbaseTx ( coinbaseTxs [ i ] ) ;
}
resolve ( blocks ) ;
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
} ) . catch ( function ( err ) {
} ) . catch ( function ( err ) {
reject ( err ) ;
reject ( err ) ;
@ -139,89 +90,36 @@ function getBlocksByHash(blockHashes) {
} ) ;
} ) ;
}
}
function getRawTransaction ( txid ) {
return new Promise ( function ( resolve , reject ) {
getRawTransactions ( [ txid ] ) . then ( function ( results ) {
if ( results && results . length > 0 ) {
if ( results [ 0 ] . txid ) {
resolve ( results [ 0 ] ) ;
} else {
resolve ( null ) ;
}
} else {
resolve ( null ) ;
}
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
}
function getAddress ( address ) {
function getAddress ( address ) {
return getRpcDataWithParams ( "validateaddress", address ) ;
return getRpcDataWithParams ( { method : "validateaddress" , parameters : [ address ] } ) ;
}
}
function getRawTransactions ( txids ) {
function getRawTransaction ( txid ) {
//debug("getRawTransactions: " + txids);
debug ( "getRawTransaction: %s" , txid ) ;
return new Promise ( function ( resolve , reject ) {
return new Promise ( function ( resolve , reject ) {
if ( ! txids || txids . length == 0 ) {
if ( coins [ config . coin ] . genesisCoinbaseTransactionId && txid == coins [ config . coin ] . genesisCoinbaseTransactionId ) {
resolve ( [ ] ) ;
// copy the "confirmations" field from genesis block to the genesis-coinbase tx
promises . push ( new Promise ( function ( resolve2 , reject2 ) {
return ;
getBlockchainInfo ( ) . then ( function ( blockchainInfoResult ) {
}
var result = coins [ config . coin ] . genesisCoinbaseTransaction ;
result . confirmations = blockchainInfoResult . blocks ;
var requests = [ ] ;
var promises = [ ] ;
for ( var i = 0 ; i < txids . length ; i ++ ) {
var txid = txids [ i ] ;
if ( txid ) {
resolve ( [ result ] ) ;
if ( coins [ config . coin ] . genesisCoinbaseTransactionId && txid == coins [ config . coin ] . genesisCoinbaseTransactionId ) {
// copy the "confirmations" field from genesis block to the genesis-coinbase tx
promises . push ( new Promise ( function ( resolve2 , reject2 ) {
getBlockchainInfo ( ) . then ( function ( blockchainInfoResult ) {
var result = coins [ config . coin ] . genesisCoinbaseTransaction ;
result . confirmations = blockchainInfoResult . blocks ;
resolve2 ( [ result ] ) ;
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) . catch ( function ( err ) {
} ) ;
reject2 ( err ) ;
} ) ) ;
} ) ;
} ) ) ;
} else {
requests . push ( {
method : 'getrawtransaction' ,
parameters : [ txid , 1 ]
} ) ;
}
}
}
var requestBatches = utils . splitArrayIntoChunks ( requests , 100 ) ;
} else {
getRpcDataWithParams ( { method : "getrawtransaction" , parameters : [ txid , 1 ] } ) . then ( function ( result ) {
resolve ( result ) ;
promises . push ( new Promise ( function ( resolve2 , reject2 ) {
} ) . catch ( function ( err ) {
executeBatchesSequentially ( requestBatches , function ( results ) {
reject ( err ) ;
resolve2 ( results ) ;
} ) ;
} ) ;
} ) ) ;
}
Promise . all ( promises ) . then ( function ( results ) {
var finalResults = [ ] ;
for ( var i = 0 ; i < results . length ; i ++ ) {
for ( var j = 0 ; j < results [ i ] . length ; j ++ ) {
finalResults . push ( results [ i ] [ j ] ) ;
}
}
resolve ( finalResults ) ;
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
} ) ;
}
}
@ -356,73 +254,45 @@ function getRpcMethodHelp(methodName) {
function getRpcData ( cmd ) {
function getRpcData ( cmd ) {
return new Promise ( function ( resolve , reject ) {
return new Promise ( function ( resolve , reject ) {
debug ( ` RPC: ${ cmd } ` ) ;
debug ( ` RPC: ${ cmd } ` ) ;
client . command ( cmd , function ( err , result , resHeaders ) {
if ( err ) {
console . log ( "Error for RPC command '" + cmd + "': " + err ) ;
reject ( err ) ;
} else {
rpcCall = function ( ) {
resolve ( result ) ;
client . command ( cmd , function ( err , result , resHeaders ) {
}
if ( err ) {
} ) . catch ( function ( err ) {
console . log ( ` Error for RPC command ' ${ cmd } ': ${ err } ` ) ;
reject ( err ) ;
} ) ;
} ) ;
}
function getRpcDataWithParams ( cmd , params ) {
reject ( err ) ;
return new Promise ( function ( resolve , reject ) {
debug ( ` RPC: ${ cmd } ( ${ params } ) ` ) ;
client . command ( cmd , params , function ( err , result , resHeaders ) {
if ( err ) {
console . log ( "Error for RPC command '" + cmd + "': " + err ) ;
} else {
resolve ( result ) ;
}
} ) . catch ( function ( err ) {
reject ( err ) ;
reject ( err ) ;
} ) ;
} ;
} else {
rpcQueue . push ( { rpcCall : rpcCall } ) ;
resolve ( result ) ;
}
} ) . catch ( function ( err ) {
reject ( err ) ;
} ) ;
} ) ;
} ) ;
}
}
function executeBatchesSequentially ( batches , resultFunc ) {
function getRpcDataWithParams ( request ) {
var batchId = utils . getRandomString ( 20 , 'aA#' ) ;
return new Promise ( function ( resolve , reject ) {
debug ( ` RPC: ${ request } ` ) ;
debug ( ` Starting ${ batches . length } -item batch ${ batchId } ... ` ) ;
executeBatchesSequentiallyInternal ( batchId , batches , 0 , [ ] , resultFunc ) ;
}
function executeBatchesSequentiallyInternal ( batchId , batches , currentIndex , accumulatedResults , resultFunc ) {
if ( currentIndex == batches . length ) {
debug ( ` Finishing batch ${ batchId } ... ` ) ;
resultFunc ( accumulatedResults ) ;
return ;
}
debug ( ` Executing item # ${ ( currentIndex + 1 ) } (of ${ batches . length } ) for batch ${ batchId } ` ) ;
rpcCall = function ( ) {
client . command ( [ request ] , function ( err , result , resHeaders ) {
if ( err != null ) {
console . log ( ` Error for RPC command ${ request } : ${ err } ` ) ;
var count = batches [ currentIndex ] . length ;
reject ( err ) ;
debug ( ` RPC: ${ JSON . stringify ( batches [ currentIndex ] ) } ` ) ;
return ;
client . command ( batches [ currentIndex ] ) . then ( function ( results ) {
}
results . forEach ( ( item ) => {
accumulatedResults . push ( item ) ;
count -- ;
resolve ( result [ 0 ] ) ;
} ) ;
} ) ;
} ;
if ( count == 0 ) {
rpcQueue . push ( { rpcCall : rpcCall } ) ;
executeBatchesSequentiallyInternal ( batchId , batches , currentIndex + 1 , accumulatedResults , resultFunc ) ;
}
} ) . catch ( function ( err ) {
throw err ;
} ) ;
} ) ;
}
}
@ -434,10 +304,8 @@ module.exports = {
getMempoolInfo : getMempoolInfo ,
getMempoolInfo : getMempoolInfo ,
getMiningInfo : getMiningInfo ,
getMiningInfo : getMiningInfo ,
getBlockByHeight : getBlockByHeight ,
getBlockByHeight : getBlockByHeight ,
getBlocksByHeight : getBlocksByHeight ,
getBlockByHash : getBlockByHash ,
getBlockByHash : getBlockByHash ,
getRawTransaction : getRawTransaction ,
getRawTransaction : getRawTransaction ,
getRawTransactions : getRawTransactions ,
getRawMempool : getRawMempool ,
getRawMempool : getRawMempool ,
getUptimeSeconds : getUptimeSeconds ,
getUptimeSeconds : getUptimeSeconds ,
getHelp : getHelp ,
getHelp : getHelp ,