Browse Source

promises; listtransactions, getbalance error handling

v0.25
pbca26 7 years ago
parent
commit
59611f4d23
  1. 658
      routes/shepherd.js

658
routes/shepherd.js

@ -542,33 +542,44 @@ shepherd.verifyMerkle = function(txid, height, serverList, mainServer) {
ecl.connect();
ecl.blockchainTransactionGetMerkle(txid, height)
.then((merkleData) => {
console.log('electrum getmerkle =>');
console.log(merkleData);
ecl.close();
const _res = shepherd.getMerkleRoot(txid, merkleData.merkle, merkleData.pos);
console.log(_res);
ecl = new electrumJSCore(_randomServer[1], _randomServer[0], 'tcp');
ecl.connect();
ecl.blockchainBlockGetHeader(height)
.then((blockInfo) => {
if (merkleData &&
merkleData.merkle &&
merkleData.pos) {
console.log('electrum getmerkle =>');
console.log(merkleData);
ecl.close();
console.log('blockinfo =>');
console.log(blockInfo);
console.log(blockInfo['merkle_root']);
if (blockInfo &&
blockInfo['merkle_root']) {
if (_res === blockInfo['merkle_root']) {
resolve(true);
const _res = shepherd.getMerkleRoot(txid, merkleData.merkle, merkleData.pos);
console.log(_res);
ecl = new electrumJSCore(_randomServer[1], _randomServer[0], 'tcp');
ecl.connect();
ecl.blockchainBlockGetHeader(height)
.then((blockInfo) => {
if (blockInfo &&
blockInfo['merkle_root']) {
ecl.close();
console.log('blockinfo =>');
console.log(blockInfo);
console.log(blockInfo['merkle_root']);
if (blockInfo &&
blockInfo['merkle_root']) {
if (_res === blockInfo['merkle_root']) {
resolve(true);
} else {
resolve(false);
}
} else {
resolve(CONNECTION_ERROR_OR_INCOMPLETE_DATA);
}
} else {
resolve(false);
resolve(f);
}
} else {
resolve(CONNECTION_ERROR_OR_INCOMPLETE_DATA);
}
});
});
} else {
resolve(CONNECTION_ERROR_OR_INCOMPLETE_DATA);
}
});
});
}
@ -736,17 +747,8 @@ shepherd.kdmCalcInterest = function(locktime, value) { // value in sats
console.log(`minutes if statement ${timestampDiffMinutes}`);
let denominator = (365 * 24 * 60) / timestampDiffMinutes;
if (denominator === 0) {
denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually!
}
console.log(`denominator ${denominator}`);
// TODO: check if interest is > 5% yr
// calc ytd and 5% for 1 yr
const numerator = Number(value) * 0.00000001 / 20; // assumes 5%!
// const hoursInOneYear = 365 * 24;
// const hoursDiff = hoursInOneYear - hoursPassed;
@ -764,66 +766,93 @@ shepherd.get('/electrum/getbalance', function(req, res, next) {
ecl.connect();
ecl.blockchainAddressGetBalance(req.query.address)
.then((json) => {
if (network === 'komodo') {
ecl.connect();
ecl.blockchainAddressListunspent(req.query.address)
.then((utxoList) => {
if (utxoList &&
utxoList.length) {
// filter out < 10 KMD amounts
let _utxo = [];
if (json &&
json.hasOwnProperty('confirmed') &&
json.hasOwnProperty('unconfirmed')) {
if (network === 'komodo') {
ecl.connect();
ecl.blockchainAddressListunspent(req.query.address)
.then((utxoList) => {
if (utxoList &&
utxoList.length) {
// filter out < 10 KMD amounts
let _utxo = [];
for (let i = 0; i < utxoList.length; i++) {
console.log(`utxo ${utxoList[i]['tx_hash']} sats ${utxoList[i].value} value ${Number(utxoList[i].value) * 0.00000001}`);
if (Number(utxoList[i].value) * 0.00000001 >= 10) {
_utxo.push(utxoList[i]);
}
}
for (let i = 0; i < utxoList.length; i++) {
console.log(`utxo ${utxoList[i]['tx_hash']} sats ${utxoList[i].value} value ${Number(utxoList[i].value) * 0.00000001}`);
console.log('filtered utxo list =>');
console.log(_utxo);
if (Number(utxoList[i].value) * 0.00000001 >= 10) {
_utxo.push(utxoList[i]);
}
}
if (_utxo &&
_utxo.length) {
let interestTotal = 0;
console.log('filtered utxo list =>');
console.log(_utxo);
Promise.all(_utxo.map((_utxoItem, index) => {
return new Promise((resolve, reject) => {
ecl.blockchainTransactionGet(_utxoItem['tx_hash'])
.then((_rawtxJSON) => {
console.log('electrum gettransaction ==>');
console.log(index + ' | ' + (_rawtxJSON.length - 1));
console.log(_rawtxJSON);
if (_utxo &&
_utxo.length) {
let interestTotal = 0;
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = electrumJSTxDecoder(_rawtxJSON, _network);
for (let i = 0; i < _utxo.length; i++) {
ecl.blockchainTransactionGet(_utxo[i]['tx_hash'])
.then((_rawtxJSON) => {
console.log('electrum gettransaction ==>');
console.log(i + ' | ' + (_rawtxJSON.length - 1));
console.log(_rawtxJSON);
if (decodedTx &&
decodedTx.format &&
decodedTx.format.locktime > 0) {
interestTotal += shepherd.kdmCalcInterest(decodedTx.format.locktime, _utxoItem.value);
}
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = electrumJSTxDecoder(_rawtxJSON, _network);
console.log('decoded tx =>');
console.log(decodedTx);
if (decodedTx.format.locktime > 0) {
interestTotal += shepherd.kdmCalcInterest(decodedTx.format.locktime, _utxo[i].value);
}
console.log('decoded tx =>');
console.log(decodedTx);
console.log(decodedTx.format.locktime);
if (i === _utxo.length -1) {
const successObj = {
msg: 'success',
result: {
balance: Number((0.00000001 * json.confirmed).toFixed(8)),
unconfirmed: Number((0.00000001 * json.unconfirmed).toFixed(8)),
unconfirmedSats: json.unconfirmed,
balanceSats: json.confirmed,
interest: Number(interestTotal.toFixed(8)),
interestSats: Math.floor(interestTotal * 100000000),
total: interestTotal > 0 ? Number((0.00000001 * json.confirmed + interestTotal).toFixed(8)) : 0,
totalSats: interestTotal > 0 ?json.confirmed + Math.floor(interestTotal * 100000000) : 0,
},
};
resolve(true);
});
});
}))
.then(promiseResult => {
ecl.close();
res.end(JSON.stringify(successObj));
}
const successObj = {
msg: 'success',
result: {
balance: Number((0.00000001 * json.confirmed).toFixed(8)),
unconfirmed: Number((0.00000001 * json.unconfirmed).toFixed(8)),
unconfirmedSats: json.unconfirmed,
balanceSats: json.confirmed,
interest: Number(interestTotal.toFixed(8)),
interestSats: Math.floor(interestTotal * 100000000),
total: interestTotal > 0 ? Number((0.00000001 * json.confirmed + interestTotal).toFixed(8)) : 0,
totalSats: interestTotal > 0 ?json.confirmed + Math.floor(interestTotal * 100000000) : 0,
},
};
res.end(JSON.stringify(successObj));
});
} else {
const successObj = {
msg: 'success',
result: {
balance: Number((0.00000001 * json.confirmed).toFixed(8)),
unconfirmed: Number((0.00000001 * json.unconfirmed).toFixed(8)),
unconfirmedSats: json.unconfirmed,
balanceSats: json.confirmed,
interest: 0,
interestSats: 0,
total: 0,
totalSats: 0,
},
};
res.end(JSON.stringify(successObj));
}
} else {
const successObj = {
@ -842,33 +871,28 @@ shepherd.get('/electrum/getbalance', function(req, res, next) {
res.end(JSON.stringify(successObj));
}
} else {
const successObj = {
msg: 'success',
result: {
balance: Number((0.00000001 * json.confirmed).toFixed(8)),
unconfirmed: Number((0.00000001 * json.unconfirmed).toFixed(8)),
unconfirmedSats: json.unconfirmed,
balanceSats: json.confirmed,
interest: 0,
},
};
});
} else {
ecl.close();
console.log('electrum getbalance ==>');
console.log(json);
res.end(JSON.stringify(successObj));
}
});
} else {
ecl.close();
console.log('electrum getbalance ==>');
console.log(json);
const successObj = {
msg: 'success',
result: {
balance: Number((0.00000001 * json.confirmed).toFixed(8)),
unconfirmed: Number((0.00000001 * json.unconfirmed).toFixed(8)),
unconfirmedSats: json.unconfirmed,
balanceSats: json.confirmed,
},
};
res.end(JSON.stringify(successObj));
}
} else {
const successObj = {
msg: 'success',
result: {
balance: 0.00000001 * json.confirmed,
unconfirmed: json.unconfirmed,
sats: json.confirmed,
},
msg: 'error',
result: CONNECTION_ERROR_OR_INCOMPLETE_DATA,
};
res.end(JSON.stringify(successObj));
@ -920,54 +944,69 @@ shepherd.get('/electrum/listtransactions', function(req, res, next) {
ecl.connect();
ecl.blockchainNumblocksSubscribe()
.then(function(currentHeight) {
ecl.blockchainAddressGetHistory(req.query.address)
.then((json) => {
if (json &&
json.length) {
json = shepherd.sortTransactions(json);
json = json.slice(0, MAX_TX);
console.log(json.length);
let _rawtx = [];
// get raw tx
for (let i = 0; i < json.length; i++) {
ecl.blockchainBlockGetHeader(json[i].height)
.then((blockInfo) => {
ecl.blockchainTransactionGet(json[i]['tx_hash'])
.then((_rawtxJSON) => {
console.log('electrum gettransaction ==>');
console.log(i + ' | ' + (_rawtxJSON.length - 1));
console.log(_rawtxJSON);
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = electrumJSTxDecoder(_rawtxJSON, _network);
let txInputs = [];
console.log('decodedtx =>');
console.log(decodedTx.outputs);
if (decodedTx.inputs) {
for (let j = 0; j < decodedTx.inputs.length; j++) {
if (decodedTx.inputs[j].txid !== '0000000000000000000000000000000000000000000000000000000000000000') {
ecl.blockchainTransactionGet(decodedTx.inputs[j].txid)
.then((rawInput) => {
console.log('electrum raw input tx ==>');
const decodedVinVout = electrumJSTxDecoder(rawInput, _network);
console.log(decodedVinVout.outputs[decodedTx.inputs[j].n]);
txInputs.push(decodedVinVout.outputs[decodedTx.inputs[j].n]);
if (j === decodedTx.inputs.length - 1) {
.then((currentHeight) => {
if (currentHeight &&
Number(currentHeight) > 0) {
ecl.blockchainAddressGetHistory(req.query.address)
.then((json) => {
if (json &&
json.length) {
json = shepherd.sortTransactions(json);
json = json.slice(0, MAX_TX);
console.log(json.length);
let _rawtx = [];
Promise.all(json.map((transaction, index) => {
return new Promise((resolve, reject) => {
ecl.blockchainBlockGetHeader(transaction.height)
.then((blockInfo) => {
if (blockInfo &&
blockInfo.timestamp) {
ecl.blockchainTransactionGet(transaction['tx_hash'])
.then((_rawtxJSON) => {
console.log('electrum gettransaction ==>');
console.log(index + ' | ' + (_rawtxJSON.length - 1));
console.log(_rawtxJSON);
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = electrumJSTxDecoder(_rawtxJSON, _network);
let txInputs = [];
console.log('decodedtx =>');
console.log(decodedTx.outputs);
if (decodedTx &&
decodedTx.inputs) {
Promise.all(decodedTx.inputs.map((_decodedInput, index) => {
return new Promise((_resolve, _reject) => {
if (_decodedInput.txid !== '0000000000000000000000000000000000000000000000000000000000000000') {
ecl.blockchainTransactionGet(_decodedInput.txid)
.then((rawInput) => {
console.log('electrum raw input tx ==>');
const decodedVinVout = electrumJSTxDecoder(rawInput, _network);
if (decodedVinVout) {
console.log(decodedVinVout.outputs[_decodedInput.n]);
txInputs.push(decodedVinVout.outputs[_decodedInput.n]);
_resolve(true);
}
});
} else {
_resolve(true);
}
});
}))
.then(promiseResult => {
const _parsedTx = {
network: decodedTx.network,
format: decodedTx.format,
inputs: txInputs,
outputs: decodedTx.outputs,
height: json[i].height,
height: transaction.height,
timestamp: blockInfo.timestamp,
confirmations: currentHeight - json[i].height,
confirmations: currentHeight - transaction.height,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network);
@ -978,104 +1017,68 @@ shepherd.get('/electrum/listtransactions', function(req, res, next) {
_rawtx.push(formattedTx[0]);
_rawtx.push(formattedTx[1]);
}
if (i === json.length - 1) {
ecl.close();
console.log('electrum gettransaction array ==>');
console.log(_rawtx);
const successObj = {
msg: 'success',
result: {
listtransactions: _rawtx,
},
};
res.end(JSON.stringify(successObj));
}
}
});
} else {
if (j === decodedTx.inputs.length - 1) {
resolve(true);
});
} else {
const _parsedTx = {
network: decodedTx.network,
format: decodedTx.format,
inputs: txInputs,
outputs: decodedTx.outputs,
height: json[i].height,
format: 'cant parse',
inputs: 'cant parse',
outputs: 'cant parse',
height: transaction.height,
timestamp: blockInfo.timestamp,
confirmations: currentHeight - json[i].height,
confirmations: currentHeight - transaction.height,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network);
if (formattedTx.type) {
_rawtx.push(formattedTx);
} else {
_rawtx.push(formattedTx[0]);
_rawtx.push(formattedTx[1]);
}
if (i === json.length - 1) {
ecl.close();
console.log('electrum gettransaction array ==>');
console.log(_rawtx);
const successObj = {
msg: 'success',
result: {
listtransactions: _rawtx,
},
};
res.end(JSON.stringify(successObj));
}
_rawtx.push(formattedTx);
resolve(true);
}
}
}
} else {
const _parsedTx = {
network: decodedTx.network,
format: 'cant parse',
inputs: 'cant parse',
outputs: 'cant parse',
height: json[i].height,
timestamp: blockInfo.timestamp,
confirmations: currentHeight - json[i].height,
};
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network);
_rawtx.push(formattedTx);
if (i === json.length - 1) {
ecl.close();
console.log('electrum gettransaction array ==>');
console.log(_rawtx);
const successObj = {
msg: 'success',
result: {
listtransactions: _rawtx,
},
});
} else {
const _parsedTx = {
network: 'cant parse',
format: 'cant parse',
inputs: 'cant parse',
outputs: 'cant parse',
height: transaction.height,
timestamp: 'cant get block info',
confirmations: currentHeight - transaction.height,
};
res.end(JSON.stringify(successObj));
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network);
_rawtx.push(formattedTx);
resolve(true);
}
}
});
});
}))
.then(promiseResult => {
ecl.close();
const successObj = {
msg: 'success',
result: _rawtx,
};
res.end(JSON.stringify(successObj));
});
} else {
const successObj = {
msg: 'success',
result: [],
};
res.end(JSON.stringify(successObj));
}
} else {
const successObj = {
msg: 'success',
result: {
listtransactions: [],
},
};
});
} else {
const successObj = {
msg: 'error',
result: 'cant get current height',
};
res.end(JSON.stringify(successObj));
}
});
res.end(JSON.stringify(successObj));
}
});
}
});
@ -1388,7 +1391,7 @@ shepherd.buildSignedTx = function(sendTo, changeAddress, wif, network, utxo, cha
let key = bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network));
let tx = new bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network));
console.log(`buildSignedTx priv key ${wif}`);
// console.log(`buildSignedTx priv key ${wif}`);
console.log(`buildSignedTx pub key ${key.getAddress().toString()}`);
// console.log('buildSignedTx std tx fee ' + electrumServers[network].txfee);
@ -1701,104 +1704,117 @@ shepherd.listunspent = function(ecl, address, network, full, verify) {
ecl.blockchainNumblocksSubscribe()
.then((currentHeight) => {
// filter out unconfirmed utxos
for (let i = 0; i < _utxoJSON.length; i++) {
if (Number(currentHeight) - Number(_utxoJSON[i].height) !== 0) {
_utxo.push(_utxoJSON[i]);
if (currentHeight &&
Number(currentHeight) > 0) {
// filter out unconfirmed utxos
for (let i = 0; i < _utxoJSON.length; i++) {
if (Number(currentHeight) - Number(_utxoJSON[i].height) !== 0) {
_utxo.push(_utxoJSON[i]);
}
}
}
if (!_utxo.length) { // no confirmed utxo
resolve('no valid utxo');
} else {
Promise.all(_utxo.map((_utxoItem, index) => {
return new Promise((resolve, reject) => {
ecl.blockchainTransactionGet(_utxoItem['tx_hash'])
.then((_rawtxJSON) => {
console.log('electrum gettransaction ==>');
console.log(index + ' | ' + (_rawtxJSON.length - 1));
console.log(_rawtxJSON);
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = electrumJSTxDecoder(_rawtxJSON, _network);
console.log('decoded tx =>');
console.log(decodedTx);
if (!decodedTx) {
_atLeastOneDecodeTxFailed = true;
resolve('cant decode tx');
} else {
if (network === 'komodo') {
let interest = 0;
if (!_utxo.length) { // no confirmed utxo
resolve('no valid utxo');
} else {
Promise.all(_utxo.map((_utxoItem, index) => {
return new Promise((resolve, reject) => {
ecl.blockchainTransactionGet(_utxoItem['tx_hash'])
.then((_rawtxJSON) => {
console.log('electrum gettransaction ==>');
console.log(index + ' | ' + (_rawtxJSON.length - 1));
console.log(_rawtxJSON);
// decode tx
const _network = shepherd.getNetworkData(network);
const decodedTx = electrumJSTxDecoder(_rawtxJSON, _network);
console.log('decoded tx =>');
console.log(decodedTx);
if (!decodedTx) {
_atLeastOneDecodeTxFailed = true;
resolve('cant decode tx');
} else {
if (network === 'komodo') {
let interest = 0;
if (Number(_utxoItem.value) * 0.00000001 >= 10 &&
decodedTx.format.locktime > 0) {
interest = shepherd.kdmCalcInterest(decodedTx.format.locktime, _utxoItem.value);
}
if (Number(_utxoItem.value) * 0.00000001 >= 10 &&
decodedTx.format.locktime > 0) {
interest = shepherd.kdmCalcInterest(decodedTx.format.locktime, _utxoItem.value);
}
let _resolveObj = {
txid: _utxoItem['tx_hash'],
vout: _utxoItem['tx_pos'],
address,
amount: Number(_utxoItem.value) * 0.00000001,
amountSats: _utxoItem.value,
interest: interest,
interestSats: Math.floor(interest * 100000000),
confirmations: currentHeight - _utxoItem.height,
spendable: true,
verified: false,
};
let _resolveObj = {
txid: _utxoItem['tx_hash'],
vout: _utxoItem['tx_pos'],
address,
amount: Number(_utxoItem.value) * 0.00000001,
amountSats: _utxoItem.value,
interest: interest,
interestSats: Math.floor(interest * 100000000),
confirmations: currentHeight - _utxoItem.height,
spendable: true,
verified: false,
};
// merkle root verification agains another electrum server
if (verify) {
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height)
.then((verifyMerkleRes) => {
_resolveObj.verified = verifyMerkleRes;
// merkle root verification agains another electrum server
if (verify) {
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height)
.then((verifyMerkleRes) => {
if (verifyMerkleRes && verifyMerkleRes === CONNECTION_ERROR_OR_INCOMPLETE_DATA) {
verifyMerkleRes = false;
}
_resolveObj.verified = verifyMerkleRes;
resolve(_resolveObj);
});
} else {
resolve(_resolveObj);
});
}
} else {
resolve(_resolveObj);
}
} else {
let _resolveObj = {
txid: _utxoItem['tx_hash'],
vout: _utxoItem['tx_pos'],
address,
amount: Number(_utxoItem.value) * 0.00000001,
amountSats: _utxoItem.value,
confirmations: currentHeight - _utxoItem.height,
spendable: true,
verified: false,
};
let _resolveObj = {
txid: _utxoItem['tx_hash'],
vout: _utxoItem['tx_pos'],
address,
amount: Number(_utxoItem.value) * 0.00000001,
amountSats: _utxoItem.value,
confirmations: currentHeight - _utxoItem.height,
spendable: true,
verified: false,
};
// merkle root verification agains another electrum server
if (verify) {
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height)
.then((verifyMerkleRes) => {
_resolveObj.verified = verifyMerkleRes;
// merkle root verification agains another electrum server
if (verify) {
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height)
.then((verifyMerkleRes) => {
if (verifyMerkleRes && verifyMerkleRes === CONNECTION_ERROR_OR_INCOMPLETE_DATA) {
verifyMerkleRes = false;
}
_resolveObj.verified = verifyMerkleRes;
resolve(_resolveObj);
});
} else {
resolve(_resolveObj);
});
} else {
resolve(_resolveObj);
}
}
}
}
});
});
});
}))
.then(promiseResult => {
ecl.close();
}))
.then(promiseResult => {
ecl.close();
if (!_atLeastOneDecodeTxFailed) {
console.log(promiseResult);
resolve(promiseResult);
} else {
console.log('listunspent error, cant decode tx(s)');
resolve('decode error');
}
});
if (!_atLeastOneDecodeTxFailed) {
console.log(promiseResult);
resolve(promiseResult);
} else {
console.log('listunspent error, cant decode tx(s)');
resolve('decode error');
}
});
}
} else {
resolve('cant get current height');
}
});
} else {

Loading…
Cancel
Save