Browse Source

reimplement getBlockByHashWithTransactions (the main call driving block pages) to move logic into coreApi where it can be cached better

fix-133-memory-crash
Dan Janosik 7 years ago
parent
commit
018207323e
  1. 73
      app/api/coreApi.js
  2. 191
      app/api/mockApi.js
  3. 111
      app/api/rpcApi.js
  4. 37
      app/utils.js

73
app/api/coreApi.js

@ -326,29 +326,66 @@ function getRawTransactions(txids) {
}); });
} }
function getMinerFromCoinbaseTx(tx) { function getBlockByHashWithTransactions(blockHash, txLimit, txOffset) {
if (global.miningPoolsConfig) { return new Promise(function(resolve, reject) {
for (var coinbaseTag in global.miningPoolsConfig.coinbase_tags) { getBlockByHash(blockHash).then(function(block) {
if (global.miningPoolsConfig.coinbase_tags.hasOwnProperty(coinbaseTag)) { var txids = [];
if (utils.hex2ascii(tx.vin[0].coinbase).indexOf(coinbaseTag) != -1) {
return global.miningPoolsConfig.coinbase_tags[coinbaseTag]; if (txOffset > 0) {
} txids.push(block.tx[0]);
} }
}
for (var payoutAddress in global.miningPoolsConfig.payout_addresses) { for (var i = txOffset; i < (txOffset + txLimit); i++) {
if (global.miningPoolsConfig.payout_addresses.hasOwnProperty(payoutAddress)) { txids.push(block.tx[i]);
return global.miningPoolsConfig.payout_addresses[payoutAddress];
} }
}
}
return null; getRawTransactions(txids).then(function(transactions) {
} if (transactions.length == txids.length) {
block.coinbaseTx = transactions[0];
block.miner = utils.getMinerFromCoinbaseTx(block.coinbaseTx);
}
function getBlockByHashWithTransactions(blockHash, txLimit, txOffset) { // if we're on page 2, we don't really want it anymore...
return tryCacheThenRpcApi(miscCache, "getBlockByHashWithTransactions-" + blockHash + "-" + txLimit + "-" + txOffset, 3600000, function() { if (txOffset > 0) {
return rpcApi.getBlockByHashWithTransactions(blockHash, txLimit, txOffset); transactions.shift();
}
var maxInputsTracked = 10;
var vinTxids = [];
for (var i = 0; i < transactions.length; i++) {
var transaction = transactions[i];
if (transaction) {
for (var j = 0; j < Math.min(maxInputsTracked, transaction.vin.length); j++) {
if (transaction.vin[j].txid) {
vinTxids.push(transaction.vin[j].txid);
}
}
}
}
var txInputsByTransaction = {};
getRawTransactions(vinTxids).then(function(vinTransactions) {
var vinTxById = {};
vinTransactions.forEach(function(tx) {
vinTxById[tx.txid] = tx;
});
transactions.forEach(function(tx) {
txInputsByTransaction[tx.txid] = [];
for (var i = 0; i < Math.min(maxInputsTracked, tx.vin.length); i++) {
if (vinTxById[tx.vin[i].txid]) {
txInputsByTransaction[tx.txid].push(vinTxById[tx.vin[i].txid]);
}
}
resolve({ getblock:block, transactions:transactions, txInputsByTransaction:txInputsByTransaction });
});
});
});
});
}); });
} }

191
app/api/mockApi.js

@ -283,197 +283,6 @@ function getMinerFromCoinbaseTx(tx) {
return null; return null;
} }
function getBlockByHashWithTransactions(blockHash, txLimit, txOffset) {
return new Promise(function(resolve, reject) {
resolve({
getblock:{
"hash": blockHash,
"confirmations": 3,
"strippedsize": 56098,
"size": 65384,
"weight": 233678,
"height": 123456,
"version": 536870912,
"versionHex": "20000000",
"merkleroot": "567a3d773b07372179ad651edc02776f851020af69b7375a68ad89557dcbff5b",
"tx": [
"a97a04ebcaaca0ec80a6b2f295171eb8b082b4bc5446cd085444c304dca6f014",
"223fdd9cae01f3253adc0f0133cc8e6bebdb6f1481dfa0cd9cbfebff656f32f8",
],
"time": 1529848136,
"mediantime": 1529846560,
"nonce": 3615953854,
"bits": "17376f56",
"difficulty": "5077499034879.017",
"chainwork": "00000000000000000000000000000000000000000226420affb91a60111258b4",
"previousblockhash": "0000000000000000003147c5229962ca4e38714fc5aee8cf38670cf1a4ef297b",
"nextblockhash": "0000000000000000003382a0eef5b127c5d5ea270c85d9db3f3c605d32287cc5"
},
transactions: [
{
"txid": "a97a04ebcaaca0ec80a6b2f295171eb8b082b4bc5446cd085444c304dca6f014",
"hash": "a97a04ebcaaca0ec80a6b2f295171eb8b082b4bc5446cd085444c304dca6f014",
"version": 1,
"size": 237,
"vsize": 210,
"locktime": 0,
"vin": [
{
"coinbase": "03851208fabe6d6d7bf60491521f081d77fa018fb41a167dd447bf20e7d2487426c3cee65332cdb50100000000000000266508019fcf7fcb7b01002ffd0c2f736c7573682f",
"sequence": 0
}
],
"vout": [
{
"value": 12.51946416,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 7c154ed1dc59609e3d26abb2df2ea3d587cd8c41 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"1CK6KHY6MHgYvmRQ4PAafKYDrg1ejbH1cE"
]
}
},
{
"value": 0,
"n": 1,
"scriptPubKey": {
"asm": "OP_RETURN aa21a9ed2b367f88dbcc39b83e89703d5425a9b51fa3d2d921b8f39a42bc54492b986281",
"hex": "6a24aa21a9ed2b367f88dbcc39b83e89703d5425a9b51fa3d2d921b8f39a42bc54492b986281",
"type": "nulldata"
}
}
],
"hex": "010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4503851208fabe6d6d7bf60491521f081d77fa018fb41a167dd447bf20e7d2487426c3cee65332cdb50100000000000000266508019fcf7fcb7b01002ffd0c2f736c7573682f0000000002b02f9f4a000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac0000000000000000266a24aa21a9ed2b367f88dbcc39b83e89703d5425a9b51fa3d2d921b8f39a42bc54492b9862810120000000000000000000000000000000000000000000000000000000000000000000000000",
"blockhash": "000000000000000000001542470d8261b9e5a2c3c2be2e2ab292d1a4c8250b12",
"confirmations": 3,
"time": 1529848136,
"blocktime": 1529848136
},
{
"txid": "223fdd9cae01f3253adc0f0133cc8e6bebdb6f1481dfa0cd9cbfebff656f32f8",
"hash": "223fdd9cae01f3253adc0f0133cc8e6bebdb6f1481dfa0cd9cbfebff656f32f8",
"version": 1,
"size": 237,
"vsize": 210,
"locktime": 0,
"vin": [
{
"coinbase": "03851208fabe6d6d7bf60491521f081d77fa018fb41a167dd447bf20e7d2487426c3cee65332cdb50100000000000000266508019fcf7fcb7b01002ffd0c2f736c7573682f",
"sequence": 0
}
],
"vout": [
{
"value": 12.51946416,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 7c154ed1dc59609e3d26abb2df2ea3d587cd8c41 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"1CK6KHY6MHgYvmRQ4PAafKYDrg1ejbH1cE"
]
}
},
{
"value": 0,
"n": 1,
"scriptPubKey": {
"asm": "OP_RETURN aa21a9ed2b367f88dbcc39b83e89703d5425a9b51fa3d2d921b8f39a42bc54492b986281",
"hex": "6a24aa21a9ed2b367f88dbcc39b83e89703d5425a9b51fa3d2d921b8f39a42bc54492b986281",
"type": "nulldata"
}
}
],
"hex": "010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4503851208fabe6d6d7bf60491521f081d77fa018fb41a167dd447bf20e7d2487426c3cee65332cdb50100000000000000266508019fcf7fcb7b01002ffd0c2f736c7573682f0000000002b02f9f4a000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac0000000000000000266a24aa21a9ed2b367f88dbcc39b83e89703d5425a9b51fa3d2d921b8f39a42bc54492b9862810120000000000000000000000000000000000000000000000000000000000000000000000000",
"blockhash": "000000000000000000001542470d8261b9e5a2c3c2be2e2ab292d1a4c8250b12",
"confirmations": 3,
"time": 1529848136,
"blocktime": 1529848136
}
],
txInputsByTransaction: {}
});
/*client.command('getblock', blockHash, function(errGetblock, resultGetblock, resHeadersGetblock) {
if (errGetblock) {
console.log("Error 3017hfwe0f: " + errGetblock);
reject(errGetblock);
return;
}
var txids = [];
// make sure we have the coinbase transaction since it can indicate
// "block" info that we might want to display (miner)
if (txOffset > 0) {
txids.push(resultGetblock.tx[0]);
}
for (var i = txOffset; i < Math.min(txOffset + txLimit, resultGetblock.tx.length); i++) {
txids.push(resultGetblock.tx[i]);
}
var maxInputsTracked = 10;
getRawTransactions(txids).then(function(transactions) {
var txInputsByTransaction = {};
// even if we're on "page 2" of transactions we pull the coinbase
// tx first so that we can store it
resultGetblock.coinbaseTx = transactions[0];
resultGetblock.miner = getMinerFromCoinbaseTx(transactions[0]);
// if we're on page 2, we don't really want it anymore...
if (txOffset > 0) {
transactions.shift();
}
var vinTxids = [];
var promises = [];
for (var i = 0; i < transactions.length; i++) {
var transaction = transactions[i];
if (transaction) {
//console.log("xyz: " + JSON.stringify(transaction.vin));
for (var j = 0; j < Math.min(maxInputsTracked, transaction.vin.length); j++) {
if (transaction.vin[j].txid) {
vinTxids.push(transaction.vin[j].txid);
}
}
}
}
getRawTransactions(vinTxids).then(function(vinTransactions) {
var vinTxById = {};
vinTransactions.forEach(function(tx) {
vinTxById[tx.txid] = tx;
});
transactions.forEach(function(tx) {
txInputsByTransaction[tx.txid] = [];
for (var i = 0; i < Math.min(maxInputsTracked, tx.vin.length); i++) {
if (vinTxById[tx.vin[i].txid]) {
txInputsByTransaction[tx.txid].push(vinTxById[tx.vin[i].txid]);
}
}
resolve({ getblock:resultGetblock, transactions:transactions, txInputsByTransaction:txInputsByTransaction });
});
});
});
});*/
});
}
function getHelp() { function getHelp() {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
reject("Not implemented"); reject("Not implemented");

111
app/api/rpcApi.js

@ -110,7 +110,7 @@ function getBlocksByHash(blockHashes) {
getRawTransactions(coinbaseTxids).then(function(coinbaseTxs) { getRawTransactions(coinbaseTxids).then(function(coinbaseTxs) {
for (var i = 0; i < blocks.length; i++) { for (var i = 0; i < blocks.length; i++) {
blocks[i].coinbaseTx = coinbaseTxs[i]; blocks[i].coinbaseTx = coinbaseTxs[i];
blocks[i].miner = getMinerFromCoinbaseTx(coinbaseTxs[i]); blocks[i].miner = utils.getMinerFromCoinbaseTx(coinbaseTxs[i]);
} }
resolve(blocks); resolve(blocks);
@ -191,115 +191,6 @@ function getRawTransactions(txids) {
}); });
} }
function getMinerFromCoinbaseTx(tx) {
if (global.miningPoolsConfig) {
for (var payoutAddress in global.miningPoolsConfig.payout_addresses) {
if (global.miningPoolsConfig.payout_addresses.hasOwnProperty(payoutAddress)) {
if (tx.vout && tx.vout.length > 0 && tx.vout[0].scriptPubKey && tx.vout[0].scriptPubKey.addresses && tx.vout[0].scriptPubKey.addresses.length > 0) {
if (tx.vout[0].scriptPubKey.addresses[0] == payoutAddress) {
var minerInfo = global.miningPoolsConfig.payout_addresses[payoutAddress];
minerInfo.identifiedBy = "payout address " + payoutAddress;
return minerInfo;
}
}
}
}
for (var coinbaseTag in global.miningPoolsConfig.coinbase_tags) {
if (global.miningPoolsConfig.coinbase_tags.hasOwnProperty(coinbaseTag)) {
if (utils.hex2ascii(tx.vin[0].coinbase).indexOf(coinbaseTag) != -1) {
var minerInfo = global.miningPoolsConfig.coinbase_tags[coinbaseTag];
minerInfo.identifiedBy = "coinbase tag '" + coinbaseTag + "'";
return minerInfo;
}
}
}
}
return null;
}
function getBlockByHashWithTransactions(blockHash, txLimit, txOffset) {
console.log("getBlockByHashWithTransactions: " + blockHash);
return new Promise(function(resolve, reject) {
client.command('getblock', blockHash, function(errGetblock, resultGetblock, resHeadersGetblock) {
if (errGetblock) {
console.log("Error 3017hfwe0f: " + errGetblock);
reject(errGetblock);
return;
}
var txids = [];
// make sure we have the coinbase transaction since it can indicate
// "block" info that we might want to display (miner)
if (txOffset > 0) {
txids.push(resultGetblock.tx[0]);
}
for (var i = txOffset; i < Math.min(txOffset + txLimit, resultGetblock.tx.length); i++) {
txids.push(resultGetblock.tx[i]);
}
var maxInputsTracked = 10;
getRawTransactions(txids).then(function(transactions) {
var txInputsByTransaction = {};
// even if we're on "page 2" of transactions we pull the coinbase
// tx first so that we can store it
resultGetblock.coinbaseTx = transactions[0];
resultGetblock.miner = getMinerFromCoinbaseTx(transactions[0]);
// if we're on page 2, we don't really want it anymore...
if (txOffset > 0) {
transactions.shift();
}
var vinTxids = [];
var promises = [];
for (var i = 0; i < transactions.length; i++) {
var transaction = transactions[i];
if (transaction) {
//console.log("xyz: " + JSON.stringify(transaction.vin));
for (var j = 0; j < Math.min(maxInputsTracked, transaction.vin.length); j++) {
if (transaction.vin[j].txid) {
vinTxids.push(transaction.vin[j].txid);
}
}
}
}
getRawTransactions(vinTxids).then(function(vinTransactions) {
var vinTxById = {};
vinTransactions.forEach(function(tx) {
vinTxById[tx.txid] = tx;
});
transactions.forEach(function(tx) {
txInputsByTransaction[tx.txid] = [];
for (var i = 0; i < Math.min(maxInputsTracked, tx.vin.length); i++) {
if (vinTxById[tx.vin[i].txid]) {
txInputsByTransaction[tx.txid].push(vinTxById[tx.vin[i].txid]);
}
}
resolve({ getblock:resultGetblock, transactions:transactions, txInputsByTransaction:txInputsByTransaction });
});
});
});
});
});
}
function getHelp() { function getHelp() {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
client.command('help', function(err, result, resHeaders) { client.command('help', function(err, result, resHeaders) {

37
app/utils.js

@ -149,6 +149,40 @@ function seededRandomIntBetween(seed, min, max) {
return (min + (max - min) * rand); return (min + (max - min) * rand);
} }
function getMinerFromCoinbaseTx(tx) {
if (tx == null) {
return null;
}
if (global.miningPoolsConfig) {
for (var payoutAddress in global.miningPoolsConfig.payout_addresses) {
if (global.miningPoolsConfig.payout_addresses.hasOwnProperty(payoutAddress)) {
if (tx.vout && tx.vout.length > 0 && tx.vout[0].scriptPubKey && tx.vout[0].scriptPubKey.addresses && tx.vout[0].scriptPubKey.addresses.length > 0) {
if (tx.vout[0].scriptPubKey.addresses[0] == payoutAddress) {
var minerInfo = global.miningPoolsConfig.payout_addresses[payoutAddress];
minerInfo.identifiedBy = "payout address " + payoutAddress;
return minerInfo;
}
}
}
}
for (var coinbaseTag in global.miningPoolsConfig.coinbase_tags) {
if (global.miningPoolsConfig.coinbase_tags.hasOwnProperty(coinbaseTag)) {
if (hex2ascii(tx.vin[0].coinbase).indexOf(coinbaseTag) != -1) {
var minerInfo = global.miningPoolsConfig.coinbase_tags[coinbaseTag];
minerInfo.identifiedBy = "coinbase tag '" + coinbaseTag + "'";
return minerInfo;
}
}
}
}
return null;
}
module.exports = { module.exports = {
redirectToConnectPageIfNeeded: redirectToConnectPageIfNeeded, redirectToConnectPageIfNeeded: redirectToConnectPageIfNeeded,
@ -161,5 +195,6 @@ module.exports = {
addThousandsSeparators: addThousandsSeparators, addThousandsSeparators: addThousandsSeparators,
formatCurrencyAmountInSmallestUnits: formatCurrencyAmountInSmallestUnits, formatCurrencyAmountInSmallestUnits: formatCurrencyAmountInSmallestUnits,
seededRandom: seededRandom, seededRandom: seededRandom,
seededRandomIntBetween: seededRandomIntBetween seededRandomIntBetween: seededRandomIntBetween,
getMinerFromCoinbaseTx: getMinerFromCoinbaseTx
}; };

Loading…
Cancel
Save