Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add P2PK transaction support #440

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
/*
Expand All @@ -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'));
Expand Down
190 changes: 171 additions & 19 deletions lib/explorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,54 @@ 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 encodeP2PKaddress(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);
}
});
}

module.exports = {

convert_to_satoshi: function(amount, cb) {
Expand Down Expand Up @@ -334,7 +382,75 @@ module.exports = {
});
}
},


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);
}
});
}
},

// synchonous loop used to interate through an array,
// avoid use unless absolutely neccessary
syncLoop: function(iterations, process, exit){
Expand Down Expand Up @@ -497,24 +613,49 @@ 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();
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
// check if there is a single address defined
if (vout[i].scriptPubKey.address == null) {
// no single address 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
arr_vout = vout_array;
// move to next vout
loop.next();
});
} else {
// could not decipher the address, move to next vout
console.log('Failed to find vout address from ' + vout[i].scriptPubKey.asm);
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;
// process vout addresses
processVoutAddresses([vout[i].scriptPubKey.address], vout[i].value, arr_vout, function(vout_array) {
// save updated array
arr_vout = vout_array;
// 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();
Expand Down Expand Up @@ -557,13 +698,24 @@ 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});
}
if (tx.vout[i].scriptPubKey.addresses || tx.vout[i].scriptPubKey.address) {
var new_address = tx.vout[i].scriptPubKey.address || tx.vout[i].scriptPubKey.addresses[0];
addresses.push({hash: new_address, amount:tx.vout[i].value});
loop.break(true);
loop.next();
//});
} else {
// 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(tx.vout[i].scriptPubKey.asm, function(p2pkh_address) {
// check if the address was encoded properly
if (p2pkh_address != null) {
// save the P2PKH address
addresses.push({hash: p2pkh_address, amount: tx.vout[i].value});
}
loop.break(true);
loop.next();
});
}
} else {
loop.next();
}
Expand Down