From 30b9ac7336464f59836af604ddb51a80439baabb Mon Sep 17 00:00:00 2001 From: uaktags Date: Tue, 20 Jul 2021 01:47:31 -0400 Subject: [PATCH] Attempting to incorporate iquidus/explorer#440 --- lib/coins/btc.js | 161 ++++++++++++++++++++++++++++++++++++++++++++++- lib/explorer.js | 66 +++++++++++-------- 2 files changed, 200 insertions(+), 27 deletions(-) diff --git a/lib/coins/btc.js b/lib/coins/btc.js index 41de14ddb..34817b0f7 100644 --- a/lib/coins/btc.js +++ b/lib/coins/btc.js @@ -29,5 +29,164 @@ module.exports = { }, name: function(){ return "Bitcoin"; - } + }, + + processVoutAddresses: function(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); + } + }, + + encodeP2PKaddress: function(p2pk_descriptor, cb) { + // find the descriptor value + module.exports.get_descriptorinfo(p2pk_descriptor, function(descriptor_info) { + // check for errors + if (descriptor_info != null) { + // encode the address using the output descriptor + module.exports.get_deriveaddresses(descriptor_info.descriptor, function(p2pkh_address) { + // check for errors + if (p2pkh_address != null) { + // return P2PKH address + return cb(p2pkh_address); + } else { + // address could not be encoded + return cb(null); + } + }); + } else { + // address could not be encoded + return cb(null); + } + }); + }, + + get_descriptorinfo: function(descriptor, cb) { + var cmd_name = 'getdescriptorinfo'; + // format the descriptor correctly for use in the getdescriptorinfo cmd + descriptor = 'pkh(' + descriptor.replace(' OP_CHECKSIG', '') + ')'; + + if (settings.use_rpc) { + rpcCommand([{method:cmd_name, parameters: [descriptor]}], function(response){ + // check if there was an error + if (response != null && response != 'There was an error. Check your console.') { + // return the rpc response + return cb(response); + } else { + // an error occurred + console.log(cmd_name + ' error: ' + (response == null ? 'Method not found' : response)); + // return null + return cb(null); + } + }); + } else { + var uri = base_url + cmd_name + '?descriptor=' + encodeURIComponent(descriptor); + request({uri: uri, json: true}, function (error, response, body) { + // check if there was an error + if (error == null && (body.message == null || body.message != 'Method not found')) { + // return the request body + return cb(body); + } else { + // an error occurred + console.log(cmd_name + ' error: ' + (error == null ? body.message : error)); + // return null + return cb(null); + } + }); + } + }, + + get_deriveaddresses: function(descriptor, cb) { + var cmd_name = 'deriveaddresses'; + + if (settings.use_rpc) { + rpcCommand([{method:cmd_name, parameters: [descriptor]}], function(response){ + // check if there was an error + if (response != null && response != 'There was an error. Check your console.') { + // return the rpc response + return cb(response); + } else { + // an error occurred + console.log(cmd_name + ' error: ' + (response == null ? 'Method not found' : response)); + // return null + return cb(null); + } + }); + } else { + var uri = base_url + cmd_name + '?descriptor=' + encodeURIComponent(descriptor); + request({uri: uri, json: true}, function (error, response, body) { + // check if there was an error + if (error == null && (body.message == null || body.message != 'Method not found')) { + // return the request body + return cb(body); + } else { + // an error occurred + console.log(cmd_name + ' error: ' + (error == null ? body.message : error)); + // return null + return cb(null); + } + }); + } + }, + + customPrepareVOUT: function(vout, cb){ + 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 + // assume the asm value is a P2PK (Pay To Pubkey) public key that should be encoded as a P2PKH (Pay To Pubkey Hash) address + encodeP2PKaddress(vout[i].scriptPubKey.asm, function(p2pkh_address) { + // check if the address was encoded properly + if (p2pkh_address != null) { + // process vout addresses + processVoutAddresses(p2pkh_address, vout[i].value, arr_vout, function(vout_array) { + // save updated array + return cb(vout_array); + }); + } else { + // could not decipher the address, move to next vout + console.log('Failed to find vout address from ' + vout[i].scriptPubKey.asm); + return cb(null); + } + }); + } else { + // process vout addresses + processVoutAddresses(address_list, vout[i].value, arr_vout, function(vout_array) { + // save updated array + return cb(vout_array); + ; + }); + } + } + }, + + customGetInputAddresses: function(vout, cb){ + // assume the asm value is a P2PK (Pay To Pubkey) public key that should be encoded as a P2PKH (Pay To Pubkey Hash) address + encodeP2PKaddress(tx.vout[i].scriptPubKey.asm, function(p2pkh_address) { + // check if the address was encoded properly + if (p2pkh_address != null) { + // save the P2PKH address + return cb(p2pkh_address); + } + }); + } } \ No newline at end of file diff --git a/lib/explorer.js b/lib/explorer.js index 3da9de373..02f18ce86 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -359,33 +359,41 @@ module.exports = { module.exports.syncLoop(vout.length, function (loop) { var i = loop.iteration(); // make sure vout has an address - if ((coin.hasOwnProperty('isValidVOUT') && coin.isValidVOUT(vout[i])) || (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); - var vout_address = ''; - if(coin.hasOwnProperty('useCustomAddresses') && coin.useCustomAddresses){ - vout_address = coin.customAddresses(vout[i].scriptPubKey); - }else{ - vout_address = vout[i].scriptPubKey.addresses[0]; - } - module.exports.is_unique(arr_vout, vout_address, 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_address, 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; - loop.next(); - }); - } + if ((coin.hasOwnProperty('customPrepareVOUT'))){ + coin.customPrepareVOUT(vout, function(voutarray){ + if(voutarray != null) + arr_vout = voutarray; + loop.next(); }); - } else { - // no address, move to next vout - loop.next(); + }else{ + if ((coin.hasOwnProperty('isValidVOUT') && coin.isValidVOUT(vout[i])) || (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); + var vout_address = ''; + if(coin.hasOwnProperty('useCustomAddresses') && coin.useCustomAddresses){ + vout_address = coin.customAddresses(vout[i].scriptPubKey); + }else{ + vout_address = vout[i].scriptPubKey.addresses[0]; + } + module.exports.is_unique(arr_vout, vout_address, 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_address, 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; + loop.next(); + }); + } + }); + } else { + // no address, move to next vout + loop.next(); + } } }, function(){ if (vout[0].scriptPubKey.type == 'nonstandard') { @@ -432,6 +440,12 @@ module.exports = { }else{ if(tx.vout[i].scriptPubKey.addresses){ vout_addresses = tx.vout[i].scriptPubKey.addresses[0]; + }else if(coin.hasOwnProperty('customGetInputAddresses')){ + coin.customGetInputAddresses(vout, function(customAddress){ + vout_addresses = customAddress; + loop.break(true); + loop.next(); + }); }else{ vout_addresses = false; }