diff --git a/app.js b/app.js index f4ddf7e9a..4586ae2fc 100644 --- a/app.js +++ b/app.js @@ -19,7 +19,8 @@ var app = express(); bitcoinapi.setWalletDetails(settings.wallet); if (settings.heavy != true) { bitcoinapi.setAccess('only', ['getinfo', 'getnetworkhashps', 'getmininginfo', 'getdifficulty', 'getconnectioncount', - 'getblockcount', 'getblockhash', 'getblock', 'getrawtransaction', 'getpeerinfo', 'gettxoutsetinfo', 'verifymessage']); + 'getblockcount', 'getblockhash', 'getblock', 'getrawtransaction', 'getpeerinfo', 'gettxoutsetinfo', 'verifymessage', + 'getdescriptorinfo', 'deriveaddresses']); } else { // enable additional heavy api calls /* @@ -36,7 +37,7 @@ if (settings.heavy != true) { bitcoinapi.setAccess('only', ['getinfo', 'getstakinginfo', 'getnetworkhashps', 'getdifficulty', 'getconnectioncount', 'getblockcount', 'getblockhash', 'getblock', 'getrawtransaction', 'getmaxmoney', 'getvote', 'getmaxvote', 'getphase', 'getreward', 'getnextrewardestimate', 'getnextrewardwhenstr', - 'getnextrewardwhensec', 'getsupply', 'gettxoutsetinfo', 'verifymessage']); + 'getnextrewardwhensec', 'getsupply', 'gettxoutsetinfo', 'verifymessage', 'getdescriptorinfo', 'deriveaddresses']); } // view engine setup app.set('views', path.join(__dirname, 'views')); diff --git a/lib/explorer.js b/lib/explorer.js index 2a6739b69..43fdf1fba 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -31,6 +31,60 @@ function rpcCommand(params, cb) { }); } +function processVoutAddresses(address_list, vout_value, arr_vout, cb) { + // check if there are any addresses to process + if (address_list != null && address_list.length > 0) { + // check if vout address is unique, if so add to array, if not add its amount to existing index + module.exports.is_unique(arr_vout, address_list[0], function(unique, index) { + if (unique == true) { + // unique vout + module.exports.convert_to_satoshi(parseFloat(vout_value), function(amount_sat){ + arr_vout.push({addresses: address_list[0], amount: amount_sat}); + return cb(arr_vout); + }); + } else { + // already exists + module.exports.convert_to_satoshi(parseFloat(vout_value), function(amount_sat){ + arr_vout[index].amount = arr_vout[index].amount + amount_sat; + return cb(arr_vout); + }); + } + }); + } else { + // no address, move to next vout + return cb(arr_vout); + } +} + +function decodeP2PKaddress(encoded_address, cb) { + // first find the descriptor value + var uri = base_url + 'getdescriptorinfo?descriptor=' + encodeURIComponent('pkh(' + encoded_address.replace(' OP_CHECKSIG', '') + ')'); + request({uri: uri, json: true}, function (error, response, body) { + // check if there was an error + if (error == null) { + // decode the address using the output descriptor + uri = base_url + 'deriveaddresses?descriptor=' + encodeURIComponent(body.descriptor); + request({uri: uri, json: true}, function (error, response, body) { + // check if there was an error + if (error == null) { + // return decoded address + return cb(body); + } else { + // an error occurred + console.log('deriveaddresses error: ' + error); + // return null + return cb(null); + } + }); + } else { + // an error occurred + console.log('getdescriptorinfo error: ' + error); + // return null + return cb(null); + } + }); +} + module.exports = { convert_to_satoshi: function(amount, cb) { @@ -497,24 +551,36 @@ module.exports = { module.exports.syncLoop(vout.length, function (loop) { var i = loop.iteration(); // make sure vout has an address - if (vout[i].scriptPubKey.type != 'nonstandard' && vout[i].scriptPubKey.type != 'nulldata') { - // check if vout address is unique, if so add it array, if not add its amount to existing index - //console.log('vout:' + i + ':' + txid); - module.exports.is_unique(arr_vout, vout[i].scriptPubKey.addresses[0], function(unique, index) { - if (unique == true) { - // unique vout - module.exports.convert_to_satoshi(parseFloat(vout[i].value), function(amount_sat){ - arr_vout.push({addresses: vout[i].scriptPubKey.addresses[0], amount: amount_sat}); - loop.next(); - }); - } else { - // already exists - module.exports.convert_to_satoshi(parseFloat(vout[i].value), function(amount_sat){ - arr_vout[index].amount = arr_vout[index].amount + amount_sat; + if (vout[i].scriptPubKey.type != 'nonstandard' && vout[i].scriptPubKey.type != 'nulldata') { + var address_list = vout[i].scriptPubKey.addresses; + // check if there are one or more addresses in the vout + if (address_list == null || address_list.length == 0) { + // no addresses defined + // try to decode the asm value as P2PK (Pay To Pubkey) + decodeP2PKaddress(vout[i].scriptPubKey.asm, function(decoded_address) { + // check if the address was decoded properly + if (decoded_address != null) { + // process vout addresses + processVoutAddresses(decoded_address, vout[i].value, arr_vout, function(vout_array) { + // save updated array + arr_vout = vout_array; + // move to next vout + loop.next(); + }); + } else { + // could not decode address, move to next vout loop.next(); - }); - } - }); + } + }); + } else { + // process vout addresses + processVoutAddresses(address_list, vout[i].value, arr_vout, function(vout_array) { + // save updated array + arr_vout = vout_array; + // move to next vout + loop.next(); + }); + } } else { // no address, move to next vout loop.next(); @@ -557,13 +623,23 @@ module.exports = { module.exports.syncLoop(tx.vout.length, function (loop) { var i = loop.iteration(); if (tx.vout[i].n == input.vout) { - //module.exports.convert_to_satoshi(parseFloat(tx.vout[i].value), function(amount_sat){ if (tx.vout[i].scriptPubKey.addresses) { addresses.push({hash: tx.vout[i].scriptPubKey.addresses[0], amount:tx.vout[i].value}); - } loop.break(true); loop.next(); - //}); + } else { + // no addresses defined + // try to decode the asm value as P2PK (Pay To Pubkey) + decodeP2PKaddress(tx.vout[i].scriptPubKey.asm, function(decoded_address) { + // check if the address was decoded properly + if (decoded_address != null) { + // save the decoded address + addresses.push({hash: decoded_address, amount: tx.vout[i].value}); + } + loop.break(true); + loop.next(); + }); + } } else { loop.next(); }