Browse Source

Fix #31

- Some reorganization and renaming
- Ensure that blocks include their coinbase tx so we can query it to guess miner identity
- Use open-source miner-identification list to guess
fix-133-memory-crash
Dan Janosik 6 years ago
parent
commit
be6a73223e
  1. 18
      app.js
  2. 136
      app/api/rpcApi.js
  3. 8
      routes/baseActionsRouter.js
  4. 5
      views/includes/block-content.pug
  5. 6
      views/includes/blocks-list.pug

18
app.js

@ -17,7 +17,7 @@ var Decimal = require('decimal.js');
var bitcoinCore = require("bitcoin-core");
var pug = require("pug");
var momentDurationFormat = require("moment-duration-format");
var rpcApi = require("./app/rpcApi.js");
var rpcApi = require("./app/api/rpcApi.js");
var coins = require("./app/coins.js");
var request = require("request");
var qrcode = require("qrcode");
@ -127,6 +127,22 @@ app.runOnStartup = function() {
});
}
if (config.miningPoolsConfigUrl) {
request(config.miningPoolsConfigUrl, function(error, response, body) {
if (!error && response && response.statusCode && response.statusCode == 200) {
var responseBody = JSON.parse(body);
global.miningPoolsConfig = responseBody;
} else {
console.log("Error:");
console.log(error);
console.log("Response:");
console.log(response);
}
});
}
if (global.sourcecodeVersion == null) {
simpleGit(".").log(["-n 1"], function(err, log) {
global.sourcecodeVersion = log.all[0].hash.substring(0, 10);

136
app/rpcApi.js → app/api/rpcApi.js

@ -1,6 +1,6 @@
var utils = require("./utils.js");
var config = require("./config.js");
var coins = require("./coins.js");
var utils = require("../utils.js");
var config = require("../config.js");
var coins = require("../coins.js");
@ -198,27 +198,8 @@ function getBlocksByHeight(blockHeights) {
});
if (blockHashes.length == batch.length) {
var batch2 = [];
for (var i = 0; i < blockHashes.length; i++) {
batch2.push({
method: 'getblock',
parameters: [ blockHashes[i] ]
});
}
var blocks = [];
client.command(batch2).then((responses2) => {
//console.log(responses2);
if (false) {
console.log("Error 138ryweufdf: " + err2);
} else {
responses2.forEach((item) => {
blocks.push(item);
});
resolve(blocks);
}
getBlocksByHash(blockHashes).then(function(blocks) {
resolve(blocks);
});
}
});
@ -226,22 +207,49 @@ function getBlocksByHeight(blockHeights) {
}
function getBlockByHash(blockHash) {
return getRpcDataWithParams("getblock", blockHash);
}
return new Promise(function(resolve, reject) {
getBlocksByHash([blockHash]).then(function(results) {
if (results && results.length > 0) {
resolve(results[0]);
function getTransactionInputs(transaction, inputLimit=0) {
console.log("getTransactionInputs: " + transaction.txid);
} else {
resolve(null);
}
}).catch(function(err) {
reject(err);
});
});
}
function getBlocksByHash(blockHashes) {
return new Promise(function(resolve, reject) {
var txids = [];
for (var i = 0; i < transaction.vin.length; i++) {
if (i < inputLimit || inputLimit == 0) {
txids.push(transaction.vin[i].txid);
}
var batch = [];
for (var i = 0; i < blockHashes.length; i++) {
batch.push({
method: 'getblock',
parameters: [ blockHashes[i] ]
});
}
getRawTransactions(txids).then(function(inputTransactions) {
resolve({ txid:transaction.txid, inputTransactions:inputTransactions });
var blocks = [];
client.command(batch).then((responses) => {
responses.forEach((item) => {
blocks.push(item);
});
var coinbaseTxids = [];
for (var i = 0; i < blocks.length; i++) {
coinbaseTxids.push(blocks[i].tx[0])
}
getRawTransactions(coinbaseTxids).then(function(coinbaseTxs) {
for (var i = 0; i < blocks.length; i++) {
blocks[i].coinbaseTx = coinbaseTxs[i];
blocks[i].miner = getMinerFromCoinbaseTx(coinbaseTxs[i]);
}
resolve(blocks);
});
});
});
}
@ -348,28 +356,65 @@ function executeBatchesSequentiallyInternal(batchId, batches, currentIndex, accu
});
}
function getBlockData(blockHash, txLimit, txOffset) {
console.log("getBlockData: " + blockHash);
function getMinerFromCoinbaseTx(tx) {
if (global.miningPoolsConfig) {
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) {
return global.miningPoolsConfig.coinbase_tags[coinbaseTag];
}
}
}
for (var payoutAddress in global.miningPoolsConfig.payout_addresses) {
if (global.miningPoolsConfig.payout_addresses.hasOwnProperty(payoutAddress)) {
return global.miningPoolsConfig.payout_addresses[payoutAddress];
}
}
}
return null;
}
function getBlockByHashWithTransactions(blockHash, txLimit, txOffset) {
console.log("getBlockByHashWithTransactions: " + blockHash);
return new Promise(function(resolve, reject) {
client.command('getblock', blockHash, function(err2, result2, resHeaders2) {
if (err2) {
console.log("Error 3017hfwe0f: " + err2);
client.command('getblock', blockHash, function(errGetblock, resultGetblock, resHeadersGetblock) {
if (errGetblock) {
console.log("Error 3017hfwe0f: " + errGetblock);
reject(err2);
reject(errGetblock);
return;
}
var txids = [];
for (var i = txOffset; i < Math.min(txOffset + txLimit, result2.tx.length); i++) {
txids.push(result2.tx[i]);
// 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++) {
@ -402,7 +447,7 @@ function getBlockData(blockHash, txLimit, txOffset) {
}
}
resolve({ getblock:result2, transactions:transactions, txInputsByTransaction:txInputsByTransaction });
resolve({ getblock:resultGetblock, transactions:transactions, txInputsByTransaction:txInputsByTransaction });
});
});
});
@ -540,8 +585,7 @@ module.exports = {
getBlockByHeight: getBlockByHeight,
getBlocksByHeight: getBlocksByHeight,
getBlockByHash: getBlockByHash,
getTransactionInputs: getTransactionInputs,
getBlockData: getBlockData,
getBlockByHashWithTransactions: getBlockByHashWithTransactions,
getRawTransaction: getRawTransaction,
getRawTransactions: getRawTransactions,
getMempoolStats: getMempoolStats,

8
routes/baseActionsRouter.js

@ -6,7 +6,7 @@ var utils = require('./../app/utils');
var coins = require("./../app/coins.js");
var config = require("./../app/config.js");
var bitcoinCore = require("bitcoin-core");
var rpcApi = require("./../app/rpcApi");
var rpcApi = require("./../app/api/rpcApi.js");
var qrcode = require('qrcode');
var bitcoinjs = require('bitcoinjs-lib');
@ -338,7 +338,7 @@ router.get("/block-height/:blockHeight", function(req, res) {
res.locals.result.getblockhash = result;
rpcApi.getBlockData(result, limit, offset).then(function(result) {
rpcApi.getBlockByHashWithTransactions(result, limit, offset).then(function(result) {
res.locals.result.getblock = result.getblock;
res.locals.result.transactions = result.transactions;
res.locals.result.txInputsByTransaction = result.txInputsByTransaction;
@ -371,7 +371,7 @@ router.get("/block/:blockHash", function(req, res) {
res.locals.paginationBaseUrl = "/block/" + blockHash;
// TODO handle RPC error
rpcApi.getBlockData(blockHash, limit, offset).then(function(result) {
rpcApi.getBlockByHashWithTransactions(blockHash, limit, offset).then(function(result) {
res.locals.result.getblock = result.getblock;
res.locals.result.transactions = result.transactions;
res.locals.result.txInputsByTransaction = result.txInputsByTransaction;
@ -413,7 +413,7 @@ router.get("/tx/:transactionId", function(req, res) {
});
});
}).catch(function(err) {
res.locals.userMessage = "Failed to load transaction with txid=" + txid + " (" + err + ")";
res.locals.userMessage = "Failed to load transaction with txid=" + txid + ": " + err;
res.render("transaction");
});

5
views/includes/block-content.pug

@ -123,6 +123,11 @@ div(class="tab-content")
th(class="table-active text-right") Chainwork
td(class="monospace word-wrap") #{result.getblock.chainwork}
if (result.getblock.miner)
tr
th(class="table-active text-right") Miner
td(class="monospace word-wrap") #{result.getblock.miner.name}
hr
div(class="card mb-3")

6
views/includes/blocks-list.pug

@ -5,6 +5,7 @@ table(class="table table-striped table-responsive-sm")
th(class="data-header") Height
th(class="data-header") Timestamp (utc)
th(class="data-header text-right") Age
th(class="data-header") Miner
th(class="data-header text-right") Transactions
th(class="data-header text-right") Size (bytes)
tbody
@ -18,5 +19,10 @@ table(class="table table-striped table-responsive-sm")
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(block.time) * 1000))));
td(class="data-cell monospace text-right") #{timeAgo.format()}
td(class="data-cell monospace")
if (block.miner && block.miner.name)
span #{block.miner.name}
else
span ?
td(class="data-cell monospace text-right") #{block.tx.length.toLocaleString()}
td(class="data-cell monospace text-right") #{block.size.toLocaleString()}
Loading…
Cancel
Save