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

Loading…
Cancel
Save