Browse Source

caching support

fix-133-memory-crash
Dan Janosik 7 years ago
parent
commit
ab5a75d17c
  1. 6
      app.js
  2. 382
      app/api/coreApi.js
  3. 507
      app/api/mockApi.js
  4. 246
      app/api/rpcApi.js
  5. 14
      app/utils.js
  6. 1
      package.json
  7. 64
      routes/baseActionsRouter.js

6
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/api/rpcApi.js");
var coreApi = require("./app/api/coreApi.js");
var coins = require("./app/coins.js");
var request = require("request");
var qrcode = require("qrcode");
@ -174,8 +174,8 @@ app.use(function(req, res, next) {
res.locals.host = req.session.host;
res.locals.port = req.session.port;
res.locals.genesisBlockHash = rpcApi.getGenesisBlockHash();
res.locals.genesisCoinbaseTransactionId = rpcApi.getGenesisCoinbaseTransactionId();
res.locals.genesisBlockHash = coreApi.getGenesisBlockHash();
res.locals.genesisCoinbaseTransactionId = coreApi.getGenesisCoinbaseTransactionId();
// currency format type

382
app/api/coreApi.js

@ -0,0 +1,382 @@
var LRU = require("lru-cache");
var utils = require("../utils.js");
var config = require("../config.js");
var coins = require("../coins.js");
// choose one of the below: RPC to a node, or mock data while testing
var rpcApi = require("./rpcApi.js");
//var rpcApi = require("./mockApi.js");
var miscCache = LRU(50);
var blockCache = LRU(50);
var txCache = LRU(200);
function getGenesisBlockHash() {
return coins[config.coin].genesisBlockHash;
}
function getGenesisCoinbaseTransactionId() {
return coins[config.coin].genesisCoinbaseTransactionId;
}
function tryCacheThenRpcApi(cache, cacheKey, cacheMaxAge, rpcApiFunction) {
console.log("tryCache: " + cacheKey + ", " + cacheMaxAge);
return new Promise(function(resolve, reject) {
var result = cache.get(cacheKey);
if (result) {
resolve(result);
} else {
rpcApiFunction().then(function(result) {
if (result) {
cache.set(cacheKey, result, cacheMaxAge);
resolve(result);
}
});
}
});
}
function getBlockchainInfo() {
return tryCacheThenRpcApi(miscCache, "getBlockchainInfo", 10000, rpcApi.getBlockchainInfo);
}
function getNetworkInfo() {
return tryCacheThenRpcApi(miscCache, "getNetworkInfo", 10000, rpcApi.getNetworkInfo);
}
function getNetTotals() {
return tryCacheThenRpcApi(miscCache, "getNetTotals", 10000, rpcApi.getNetTotals);
}
function getMempoolInfo() {
return tryCacheThenRpcApi(miscCache, "getMempoolInfo", 1000, rpcApi.getMempoolInfo);
}
function getUptimeSeconds() {
return tryCacheThenRpcApi(miscCache, "getUptimeSeconds", 1000, rpcApi.getUptimeSeconds);
}
function getMempoolStats() {
return new Promise(function(resolve, reject) {
tryCacheThenRpcApi(miscCache, "getRawMempool", 5000, rpcApi.getRawMempool).then(function(result) {
var maxFee = 0;
var maxFeePerByte = 0;
for (var txid in result) {
var txMempoolInfo = result[txid];
var fee = txMempoolInfo.modifiedfee;
var feePerByte = txMempoolInfo.modifiedfee / txMempoolInfo.size;
if (fee > maxFee) {
maxFee = txMempoolInfo.modifiedfee;
}
if (feePerByte > maxFeePerByte) {
maxFeePerByte = txMempoolInfo.modifiedfee / txMempoolInfo.size;
}
}
var satoshiPerByteBucketMaxima = coins[config.coin].feeSatoshiPerByteBucketMaxima;
var bucketCount = satoshiPerByteBucketMaxima.length + 1;
var satoshiPerByteBuckets = [];
var satoshiPerByteBucketLabels = [];
satoshiPerByteBucketLabels[0] = ("[0 - " + satoshiPerByteBucketMaxima[0] + ")");
for (var i = 0; i < bucketCount; i++) {
satoshiPerByteBuckets[i] = {"count":0, "totalFees":0, "totalBytes":0};
if (i > 0 && i < bucketCount - 1) {
satoshiPerByteBucketLabels[i] = ("[" + satoshiPerByteBucketMaxima[i - 1] + " - " + satoshiPerByteBucketMaxima[i] + ")");
}
}
satoshiPerByteBucketLabels[bucketCount - 1] = (satoshiPerByteBucketMaxima[satoshiPerByteBucketMaxima.length - 1] + "+");
var summary = {
"count":0,
"totalFees":0,
"totalBytes":0,
"satoshiPerByteBuckets":satoshiPerByteBuckets,
"satoshiPerByteBucketLabels":satoshiPerByteBucketLabels
};
for (var txid in result) {
var txMempoolInfo = result[txid];
var fee = txMempoolInfo.modifiedfee;
var feePerByte = txMempoolInfo.modifiedfee / txMempoolInfo.size;
var satoshiPerByte = feePerByte * 100000000;
var addedToBucket = false;
for (var i = 0; i < satoshiPerByteBucketMaxima.length; i++) {
if (satoshiPerByteBucketMaxima[i] > satoshiPerByte) {
satoshiPerByteBuckets[i]["count"]++;
satoshiPerByteBuckets[i]["totalFees"] += fee;
satoshiPerByteBuckets[i]["totalBytes"] += txMempoolInfo.size;
addedToBucket = true;
break;
}
}
if (!addedToBucket) {
satoshiPerByteBuckets[bucketCount - 1]["count"]++;
satoshiPerByteBuckets[bucketCount - 1]["totalFees"] += fee;
satoshiPerByteBuckets[bucketCount - 1]["totalBytes"] += txMempoolInfo.size;
}
summary["count"]++;
summary["totalFees"] += txMempoolInfo.modifiedfee;
summary["totalBytes"] += txMempoolInfo.size;
}
summary["averageFee"] = summary["totalFees"] / summary["count"];
summary["averageFeePerByte"] = summary["totalFees"] / summary["totalBytes"];
summary["satoshiPerByteBucketMaxima"] = satoshiPerByteBucketMaxima;
summary["satoshiPerByteBucketCounts"] = [];
summary["satoshiPerByteBucketTotalFees"] = [];
for (var i = 0; i < bucketCount; i++) {
summary["satoshiPerByteBucketCounts"].push(summary["satoshiPerByteBuckets"][i]["count"]);
summary["satoshiPerByteBucketTotalFees"].push(summary["satoshiPerByteBuckets"][i]["totalFees"]);
}
resolve(summary);
});
});
}
function getBlockByHeight(blockHeight) {
return tryCacheThenRpcApi(blockCache, "getBlockByHeight-" + blockHeight, 3600000, function() {
return rpcApi.getBlockByHeight(blockHeight);
});
}
function getBlocksByHeight(blockHeights) {
var blockHeightsNotInCache = [];
var blocksByIndex = {};
for (var i = 0; i < blockHeights.length; i++) {
var blockI = blockCache.get("getBlockByHeight-" + blockHeights[i]);
if (blockI == null) {
blockHeightsNotInCache.push(blockHeights[i]);
} else {
blocksByIndex[i] = blockI;
}
}
return new Promise(function(resolve, reject) {
var combinedBlocks = [];
if (blockHeightsNotInCache.length > 0) {
rpcApi.getBlocksByHeight(blockHeightsNotInCache).then(function(queriedBlocks) {
console.log("qbs: " + queriedBlocks);
var queriedBlocksCurrentIndex = 0;
for (var i = 0; i < blockHeights.length; i++) {
if (blocksByIndex.hasOwnProperty(i)) {
combinedBlocks.push(blocksByIndex[i]);
} else {
var queriedBlock = queriedBlocks[queriedBlocksCurrentIndex];
console.log("queriedBlock: " + queriedBlock);
combinedBlocks.push(queriedBlock);
blockCache.set("getBlockByHeight-" + queriedBlock.height, queriedBlock, 3600000);
queriedBlocksCurrentIndex++;
}
}
resolve(combinedBlocks);
}).catch(function(err) {
console.log("Error 39g2rfyewgf: " + err);
});
} else {
for (var i = 0; i < blockHeights.length; i++) {
combinedBlocks.push(blocksByIndex[i]);
}
resolve(combinedBlocks);
}
});
}
function getBlockByHash(blockHash) {
return tryCacheThenRpcApi(blockCache, "getBlockByHash-" + blockHash, 3600000, function() {
return rpcApi.getBlockByHash(blockHash);
});
}
function getBlocksByHash(blockHashes) {
var blockHashesNotInCache = [];
var blocksByIndex = {};
for (var i = 0; i < blockHashes.length; i++) {
var blockI = blockCache.get("getBlockByHash-" + blockHashes[i]);
if (blockI == null) {
blockHashesNotInCache.push(blockHashes[i]);
} else {
blocksByIndex[i] = blockI;
}
}
return new Promise(function(resolve, reject) {
var combinedBlocks = [];
if (blockHashesNotInCache.length > 0) {
rpcApi.getBlocksByHash(blockHashesNotInCache).then(function(queriedBlocks) {
var queriedBlocksCurrentIndex = 0;
for (var i = 0; i < blockHashes.length; i++) {
if (blocksByIndex.hasOwnProperty(i)) {
combinedBlocks.push(blocksByIndex[i]);
} else {
var queriedBlock = queriedBlocks[queriedBlocksCurrentIndex];
combinedBlocks.push(queriedBlock);
blockCache.set("getBlockByHash-" + queriedBlock.hash, queriedBlock, 3600000);
queriedBlocksCurrentIndex++;
}
}
resolve(combinedBlocks);
});
} else {
for (var i = 0; i < blockHeights.length; i++) {
combinedBlocks.push(blocksByIndex[i]);
}
resolve(combinedBlocks);
}
});
}
function getRawTransaction(txid) {
return tryCacheThenRpcApi(txCache, "getRawTransaction-" + txid, 3600000, function() {
return rpcApi.getRawTransaction(txid);
});
}
function getAddress(address) {
return tryCacheThenRpcApi(miscCache, "getAddress-" + address, 3600000, function() {
return rpcApi.getAddress(address);
});
}
function getRawTransactions(txids) {
var txidsNotInCache = [];
var txsByIndex = {};
for (var i = 0; i < txids.length; i++) {
var txI = txCache.get("getRawTransaction-" + txids[i]);
if (txI == null) {
txidsNotInCache.push(txids[i]);
} else {
txsByIndex[i] = txI;
}
}
return new Promise(function(resolve, reject) {
var combinedTxs = [];
if (txidsNotInCache.length > 0) {
rpcApi.getRawTransactions(txidsNotInCache).then(function(queriedTxs) {
var queriedTxsCurrentIndex = 0;
for (var i = 0; i < txids.length; i++) {
if (txsByIndex.hasOwnProperty(i)) {
combinedTxs.push(txsByIndex[i]);
} else {
var queriedTx = queriedTxs[queriedTxsCurrentIndex];
combinedTxs.push(queriedTx);
txCache.set("getRawTransaction-" + queriedTx.txid, queriedTx, 3600000);
queriedTxsCurrentIndex++;
}
}
resolve(combinedTxs);
});
} else {
for (var i = 0; i < txids.length; i++) {
combinedTxs.push(txsByIndex[i]);
}
resolve(combinedTxs);
}
});
}
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) {
return tryCacheThenRpcApi(miscCache, "getBlockByHashWithTransactions-" + blockHash + "-" + txLimit + "-" + txOffset, 3600000, function() {
return rpcApi.getBlockByHashWithTransactions(blockHash, txLimit, txOffset);
});
}
function getHelp() {
return tryCacheThenRpcApi(miscCache, "getHelp", 3600000, function() {
return rpcApi.getHelp();
});
}
function getRpcMethodHelp(methodName) {
return tryCacheThenRpcApi(miscCache, "getHelp-" + methodName, 3600000, function() {
return rpcApi.getRpcMethodHelp(methodName);
});
}
module.exports = {
getGenesisBlockHash: getGenesisBlockHash,
getGenesisCoinbaseTransactionId: getGenesisCoinbaseTransactionId,
getBlockchainInfo: getBlockchainInfo,
getNetworkInfo: getNetworkInfo,
getNetTotals: getNetTotals,
getMempoolInfo: getMempoolInfo,
getBlockByHeight: getBlockByHeight,
getBlocksByHeight: getBlocksByHeight,
getBlockByHash: getBlockByHash,
getBlockByHashWithTransactions: getBlockByHashWithTransactions,
getRawTransaction: getRawTransaction,
getRawTransactions: getRawTransactions,
getMempoolStats: getMempoolStats,
getUptimeSeconds: getUptimeSeconds,
getHelp: getHelp,
getRpcMethodHelp: getRpcMethodHelp,
getAddress: getAddress
};

507
app/api/mockApi.js

@ -0,0 +1,507 @@
var utils = require("../utils.js");
var config = require("../config.js");
var coins = require("../coins.js");
var SHA256 = require("crypto-js/sha256");
var earliestBlockTime = 1231006505;
var avgBlockTime = 200000;
var currentBlockHeight = 1234567;
function getBlockchainInfo() {
return new Promise(function(resolve, reject) {
resolve({
blocks: currentBlockHeight
});
});
}
function getNetworkInfo() {
return getRpcData("getnetworkinfo");
}
function getNetTotals() {
return getRpcData("getnettotals");
}
function getMempoolInfo() {
return getRpcData("getmempoolinfo");
}
function getUptimeSeconds() {
return getRpcData("uptime");
}
function getRawMempool() {
return getRpcDataWithParams("getrawmempool", true);
}
function getBlockByHeight(blockHeight) {
var txCount = utils.seededRandomIntBetween(blockHeight, 1, 20);
var txids = [];
for (var i = 0; i < txCount; i++) {
txids.push(SHA256("" + blockHeight + "_" + i));
}
return new Promise(function(resolve, reject) {
resolve({
"hash": SHA256("" + blockHeight),
"confirmations": currentBlockHeight - blockHeight,
"strippedsize": 56098,
"size": 65384,
"weight": 233678,
"height": blockHeight,
"version": 536870912,
"versionHex": "20000000",
"merkleroot": "567a3d773b07372179ad651edc02776f851020af69b7375a68ad89557dcbff5b",
"tx": txids,
"time": 1529848136,
"mediantime": 1529846560,
"nonce": 3615953854,
"bits": "17376f56",
"difficulty": "5077499034879.017",
"chainwork": SHA256("xyz" + blockHeight),
"previousblockhash": SHA256("" + (blockHeight - 1)),
"nextblockhash": SHA256("" + (blockHeight + 1))
});
});
}
function getBlocksByHeight(blockHeights) {
console.log("mock.getBlocksByHeight: " + blockHeights);
return new Promise(function(resolve, reject) {
var blocks = [];
for (var i = 0; i < blockHeights.length; i++) {
getBlockByHeight(blockHeights[i]).then(function(result) {
blocks.push(result);
});
/*blocks.push({
"hash": "000000000000000000001542470d8261b9e5a2c3c2be2e2ab292d1a4c8250b12",
"confirmations": 3,
"strippedsize": 56098,
"size": 65384,
"weight": 233678,
"height": blockHeights[i],
"version": 536870912,
"versionHex": "20000000",
"merkleroot": "567a3d773b07372179ad651edc02776f851020af69b7375a68ad89557dcbff5b",
"tx": [
"a97a04ebcaaca0ec80a6b2f295171eb8b082b4bc5446cd085444c304dca6f014",
"223fdd9cae01f3253adc0f0133cc8e6bebdb6f1481dfa0cd9cbfebff656f32f8",
"e999b2b8f1ee1e0b1adcc138d96d16e4fb65f2b422fc08d59a3b306b6a5c73d6",
"328ae013c7870ab29ffd93e1a1c01db6205229f261a91a04e73539c99861923f",
"b0604a447db9a0170a10a8d6cd2d68258783ae3061e5bfe5e26bcb6e76728c08",
],
"time": 1529848136,
"mediantime": 1529846560,
"nonce": 3615953854,
"bits": "17376f56",
"difficulty": "5077499034879.017",
"chainwork": "00000000000000000000000000000000000000000226420affb91a60111258b4",
"previousblockhash": "0000000000000000003147c5229962ca4e38714fc5aee8cf38670cf1a4ef297b",
"nextblockhash": "0000000000000000003382a0eef5b127c5d5ea270c85d9db3f3c605d32287cc5"
});*/
}
resolve(blocks);
});
}
function getBlockByHash(blockHash) {
return new Promise(function(resolve, reject) {
resolve({
"hash": blockHash,
"confirmations": 3,
"strippedsize": 56098,
"size": 65384,
"weight": 233678,
"height": 123456,
"version": 536870912,
"versionHex": "20000000",
"merkleroot": "567a3d773b07372179ad651edc02776f851020af69b7375a68ad89557dcbff5b",
"tx": [
"a97a04ebcaaca0ec80a6b2f295171eb8b082b4bc5446cd085444c304dca6f014",
"223fdd9cae01f3253adc0f0133cc8e6bebdb6f1481dfa0cd9cbfebff656f32f8",
"e999b2b8f1ee1e0b1adcc138d96d16e4fb65f2b422fc08d59a3b306b6a5c73d6",
"328ae013c7870ab29ffd93e1a1c01db6205229f261a91a04e73539c99861923f",
"b0604a447db9a0170a10a8d6cd2d68258783ae3061e5bfe5e26bcb6e76728c08",
],
"time": 1529848136,
"mediantime": 1529846560,
"nonce": 3615953854,
"bits": "17376f56",
"difficulty": "5077499034879.017",
"chainwork": "00000000000000000000000000000000000000000226420affb91a60111258b4",
"previousblockhash": "0000000000000000003147c5229962ca4e38714fc5aee8cf38670cf1a4ef297b",
"nextblockhash": "0000000000000000003382a0eef5b127c5d5ea270c85d9db3f3c605d32287cc5"
});
});
}
function getBlocksByHash(blockHashes) {
return new Promise(function(resolve, reject) {
var blocks = [];
for (var i = 0; i < blockHashes.length; i++) {
blocks.push({
"hash": blockHashes[i],
"confirmations": 3,
"strippedsize": 56098,
"size": 65384,
"weight": 233678,
"height": 123456,
"version": 536870912,
"versionHex": "20000000",
"merkleroot": "567a3d773b07372179ad651edc02776f851020af69b7375a68ad89557dcbff5b",
"tx": [
"a97a04ebcaaca0ec80a6b2f295171eb8b082b4bc5446cd085444c304dca6f014",
"223fdd9cae01f3253adc0f0133cc8e6bebdb6f1481dfa0cd9cbfebff656f32f8",
"e999b2b8f1ee1e0b1adcc138d96d16e4fb65f2b422fc08d59a3b306b6a5c73d6",
"328ae013c7870ab29ffd93e1a1c01db6205229f261a91a04e73539c99861923f",
"b0604a447db9a0170a10a8d6cd2d68258783ae3061e5bfe5e26bcb6e76728c08",
],
"time": 1529848136,
"mediantime": 1529846560,
"nonce": 3615953854,
"bits": "17376f56",
"difficulty": "5077499034879.017",
"chainwork": "00000000000000000000000000000000000000000226420affb91a60111258b4",
"previousblockhash": "0000000000000000003147c5229962ca4e38714fc5aee8cf38670cf1a4ef297b",
"nextblockhash": "0000000000000000003382a0eef5b127c5d5ea270c85d9db3f3c605d32287cc5"
});
}
resolve(blocks);
});
}
function getRawTransaction(txid) {
return new Promise(function(resolve, reject) {
resolve({
"txid": txid,
"hash": txid,
"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
});
});
}
function getAddress(address) {
return getRpcDataWithParams("validateaddress", address);
}
function getRawTransactions(txids) {
return new Promise(function(resolve, reject) {
var txs = [];
for (var i = 0; i < txids.length; i++) {
txs.push({
"txid": txid,
"hash": txid,
"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
});
}
resolve(txs);
});
}
function getMinerFromCoinbaseTx(tx) {
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() {
return new Promise(function(resolve, reject) {
reject("Not implemented");
});
}
function getRpcMethodHelp(methodName) {
return new Promise(function(resolve, reject) {
reject("Not implemented");
});
}
module.exports = {
getBlockchainInfo: getBlockchainInfo,
getNetworkInfo: getNetworkInfo,
getNetTotals: getNetTotals,
getMempoolInfo: getMempoolInfo,
getBlockByHeight: getBlockByHeight,
getBlocksByHeight: getBlocksByHeight,
getBlockByHash: getBlockByHash,
getBlockByHashWithTransactions: getBlockByHashWithTransactions,
getRawTransaction: getRawTransaction,
getRawTransactions: getRawTransactions,
getRawMempool: getRawMempool,
getUptimeSeconds: getUptimeSeconds,
getHelp: getHelp,
getRpcMethodHelp: getRpcMethodHelp,
getAddress: getAddress
};

246
app/api/rpcApi.js

@ -3,48 +3,6 @@ var config = require("../config.js");
var coins = require("../coins.js");
function getGenesisBlockHash() {
return coins[config.coin].genesisBlockHash;
}
function getGenesisCoinbaseTransactionId() {
return coins[config.coin].genesisCoinbaseTransactionId;
}
function getRpcData(cmd) {
return new Promise(function(resolve, reject) {
client.command(cmd, function(err, result, resHeaders) {
if (err) {
console.log("Error for RPC command '" + cmd + "': " + err);
reject(err);
return;
}
resolve(result);
});
});
}
function getRpcDataWithParams(cmd, params) {
return new Promise(function(resolve, reject) {
client.command(cmd, params, function(err, result, resHeaders) {
if (err) {
console.log("Error for RPC command '" + cmd + "': " + err);
reject(err);
return;
}
resolve(result);
});
});
}
function getBlockchainInfo() {
return getRpcData("getblockchaininfo");
}
@ -65,103 +23,8 @@ function getUptimeSeconds() {
return getRpcData("uptime");
}
function getMempoolStats() {
return new Promise(function(resolve, reject) {
client.command('getrawmempool', true, function(err, result, resHeaders) {
if (err) {
console.log("Error 428thwre0ufg: " + err);
reject(err);
return;
}
var maxFee = 0;
var maxFeePerByte = 0;
for (var txid in result) {
var txMempoolInfo = result[txid];
var fee = txMempoolInfo.modifiedfee;
var feePerByte = txMempoolInfo.modifiedfee / txMempoolInfo.size;
if (fee > maxFee) {
maxFee = txMempoolInfo.modifiedfee;
}
if (feePerByte > maxFeePerByte) {
maxFeePerByte = txMempoolInfo.modifiedfee / txMempoolInfo.size;
}
}
var satoshiPerByteBucketMaxima = coins[config.coin].feeSatoshiPerByteBucketMaxima;
var bucketCount = satoshiPerByteBucketMaxima.length + 1;
var satoshiPerByteBuckets = [];
var satoshiPerByteBucketLabels = [];
satoshiPerByteBucketLabels[0] = ("[0 - " + satoshiPerByteBucketMaxima[0] + ")");
for (var i = 0; i < bucketCount; i++) {
satoshiPerByteBuckets[i] = {"count":0, "totalFees":0, "totalBytes":0};
if (i > 0 && i < bucketCount - 1) {
satoshiPerByteBucketLabels[i] = ("[" + satoshiPerByteBucketMaxima[i - 1] + " - " + satoshiPerByteBucketMaxima[i] + ")");
}
}
satoshiPerByteBucketLabels[bucketCount - 1] = (satoshiPerByteBucketMaxima[satoshiPerByteBucketMaxima.length - 1] + "+");
var summary = {
"count":0,
"totalFees":0,
"totalBytes":0,
"satoshiPerByteBuckets":satoshiPerByteBuckets,
"satoshiPerByteBucketLabels":satoshiPerByteBucketLabels
};
for (var txid in result) {
var txMempoolInfo = result[txid];
var fee = txMempoolInfo.modifiedfee;
var feePerByte = txMempoolInfo.modifiedfee / txMempoolInfo.size;
var satoshiPerByte = feePerByte * 100000000;
var addedToBucket = false;
for (var i = 0; i < satoshiPerByteBucketMaxima.length; i++) {
if (satoshiPerByteBucketMaxima[i] > satoshiPerByte) {
satoshiPerByteBuckets[i]["count"]++;
satoshiPerByteBuckets[i]["totalFees"] += fee;
satoshiPerByteBuckets[i]["totalBytes"] += txMempoolInfo.size;
addedToBucket = true;
break;
}
}
if (!addedToBucket) {
satoshiPerByteBuckets[bucketCount - 1]["count"]++;
satoshiPerByteBuckets[bucketCount - 1]["totalFees"] += fee;
satoshiPerByteBuckets[bucketCount - 1]["totalBytes"] += txMempoolInfo.size;
}
summary["count"]++;
summary["totalFees"] += txMempoolInfo.modifiedfee;
summary["totalBytes"] += txMempoolInfo.size;
}
summary["averageFee"] = summary["totalFees"] / summary["count"];
summary["averageFeePerByte"] = summary["totalFees"] / summary["totalBytes"];
summary["satoshiPerByteBucketMaxima"] = satoshiPerByteBucketMaxima;
summary["satoshiPerByteBucketCounts"] = [];
summary["satoshiPerByteBucketTotalFees"] = [];
for (var i = 0; i < bucketCount; i++) {
summary["satoshiPerByteBucketCounts"].push(summary["satoshiPerByteBuckets"][i]["count"]);
summary["satoshiPerByteBucketTotalFees"].push(summary["satoshiPerByteBuckets"][i]["totalFees"]);
}
resolve(summary);
});
});
function getRawMempool() {
return getRpcDataWithParams("getrawmempool", true);
}
function getBlockByHeight(blockHeight) {
@ -322,40 +185,6 @@ function getRawTransactions(txids) {
});
}
function executeBatchesSequentially(batches, resultFunc) {
var batchId = utils.getRandomString(20, 'aA#');
console.log("Starting " + batches.length + "-item batch " + batchId + "...");
executeBatchesSequentiallyInternal(batchId, batches, 0, [], resultFunc);
}
function executeBatchesSequentiallyInternal(batchId, batches, currentIndex, accumulatedResults, resultFunc) {
if (currentIndex == batches.length) {
console.log("Finishing batch " + batchId + "...");
resultFunc(accumulatedResults);
return;
}
console.log("Executing item #" + (currentIndex + 1) + " (of " + batches.length + ") for batch " + batchId);
var count = batches[currentIndex].length;
client.command(batches[currentIndex]).then(function(results) {
results.forEach((item) => {
accumulatedResults.push(item);
count--;
});
if (count == 0) {
executeBatchesSequentiallyInternal(batchId, batches, currentIndex + 1, accumulatedResults, resultFunc);
}
});
}
function getMinerFromCoinbaseTx(tx) {
if (global.miningPoolsConfig) {
for (var coinbaseTag in global.miningPoolsConfig.coinbase_tags) {
@ -575,9 +404,74 @@ function getRpcMethodHelp(methodName) {
});
}
function getRpcData(cmd) {
return new Promise(function(resolve, reject) {
client.command(cmd, function(err, result, resHeaders) {
if (err) {
console.log("Error for RPC command '" + cmd + "': " + err);
reject(err);
} else {
resolve(result);
}
});
});
}
function getRpcDataWithParams(cmd, params) {
return new Promise(function(resolve, reject) {
client.command(cmd, params, function(err, result, resHeaders) {
if (err) {
console.log("Error for RPC command '" + cmd + "': " + err);
reject(err);
} else {
resolve(result);
}
});
});
}
function executeBatchesSequentially(batches, resultFunc) {
var batchId = utils.getRandomString(20, 'aA#');
console.log("Starting " + batches.length + "-item batch " + batchId + "...");
executeBatchesSequentiallyInternal(batchId, batches, 0, [], resultFunc);
}
function executeBatchesSequentiallyInternal(batchId, batches, currentIndex, accumulatedResults, resultFunc) {
if (currentIndex == batches.length) {
console.log("Finishing batch " + batchId + "...");
resultFunc(accumulatedResults);
return;
}
console.log("Executing item #" + (currentIndex + 1) + " (of " + batches.length + ") for batch " + batchId);
var count = batches[currentIndex].length;
client.command(batches[currentIndex]).then(function(results) {
results.forEach((item) => {
accumulatedResults.push(item);
count--;
});
if (count == 0) {
executeBatchesSequentiallyInternal(batchId, batches, currentIndex + 1, accumulatedResults, resultFunc);
}
});
}
module.exports = {
getGenesisBlockHash: getGenesisBlockHash,
getGenesisCoinbaseTransactionId: getGenesisCoinbaseTransactionId,
getBlockchainInfo: getBlockchainInfo,
getNetworkInfo: getNetworkInfo,
getNetTotals: getNetTotals,
@ -588,7 +482,7 @@ module.exports = {
getBlockByHashWithTransactions: getBlockByHashWithTransactions,
getRawTransaction: getRawTransaction,
getRawTransactions: getRawTransactions,
getMempoolStats: getMempoolStats,
getRawMempool: getRawMempool,
getUptimeSeconds: getUptimeSeconds,
getHelp: getHelp,
getRpcMethodHelp: getRpcMethodHelp,

14
app/utils.js

@ -139,6 +139,16 @@ function formatExchangedCurrency(amount) {
return "";
}
function seededRandom(seed) {
var x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
}
function seededRandomIntBetween(seed, min, max) {
var rand = seededRandom(seed);
return (min + (max - min) * rand);
}
module.exports = {
redirectToConnectPageIfNeeded: redirectToConnectPageIfNeeded,
@ -149,5 +159,7 @@ module.exports = {
formatCurrencyAmount: formatCurrencyAmount,
formatExchangedCurrency: formatExchangedCurrency,
addThousandsSeparators: addThousandsSeparators,
formatCurrencyAmountInSmallestUnits: formatCurrencyAmountInSmallestUnits
formatCurrencyAmountInSmallestUnits: formatCurrencyAmountInSmallestUnits,
seededRandom: seededRandom,
seededRandomIntBetween: seededRandomIntBetween
};

1
package.json

@ -16,6 +16,7 @@
"express": "~4.16.3",
"express-session": "1.15.6",
"jstransformer-markdown-it": "^2.0.0",
"lru-cache": "4.1.3",
"moment": "^2.21.0",
"moment-duration-format": "2.2.2",
"morgan": "~1.9.0",

64
routes/baseActionsRouter.js

@ -2,14 +2,15 @@ var express = require('express');
var router = express.Router();
var util = require('util');
var moment = require('moment');
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/api/rpcApi.js");
var qrcode = require('qrcode');
var bitcoinjs = require('bitcoinjs-lib');
var utils = require('./../app/utils.js');
var coins = require("./../app/coins.js");
var config = require("./../app/config.js");
var coreApi = require("./../app/api/coreApi.js");
router.get("/", function(req, res) {
if (req.session.host == null || req.session.host.trim() == "") {
if (req.cookies['rpc-host']) {
@ -30,7 +31,7 @@ router.get("/", function(req, res) {
return;
}
rpcApi.getBlockchainInfo().then(function(getblockchaininfo) {
coreApi.getBlockchainInfo().then(function(getblockchaininfo) {
res.locals.getblockchaininfo = getblockchaininfo;
var blockHeights = [];
@ -40,7 +41,7 @@ router.get("/", function(req, res) {
}
}
rpcApi.getBlocksByHeight(blockHeights).then(function(latestBlocks) {
coreApi.getBlocksByHeight(blockHeights).then(function(latestBlocks) {
res.locals.latestBlocks = latestBlocks;
res.render("index");
@ -53,16 +54,16 @@ router.get("/", function(req, res) {
});
router.get("/node-status", function(req, res) {
rpcApi.getBlockchainInfo().then(function(getblockchaininfo) {
coreApi.getBlockchainInfo().then(function(getblockchaininfo) {
res.locals.getblockchaininfo = getblockchaininfo;
rpcApi.getNetworkInfo().then(function(getnetworkinfo) {
coreApi.getNetworkInfo().then(function(getnetworkinfo) {
res.locals.getnetworkinfo = getnetworkinfo;
rpcApi.getUptimeSeconds().then(function(uptimeSeconds) {
coreApi.getUptimeSeconds().then(function(uptimeSeconds) {
res.locals.uptimeSeconds = uptimeSeconds;
rpcApi.getNetTotals().then(function(getnettotals) {
coreApi.getNetTotals().then(function(getnettotals) {
res.locals.getnettotals = getnettotals;
res.render("node-status");
@ -90,10 +91,10 @@ router.get("/node-status", function(req, res) {
});
router.get("/mempool-summary", function(req, res) {
rpcApi.getMempoolInfo().then(function(getmempoolinfo) {
coreApi.getMempoolInfo().then(function(getmempoolinfo) {
res.locals.getmempoolinfo = getmempoolinfo;
rpcApi.getMempoolStats().then(function(mempoolstats) {
coreApi.getMempoolStats().then(function(mempoolstats) {
res.locals.mempoolstats = mempoolstats;
res.render("mempool-summary");
@ -188,7 +189,7 @@ router.get("/blocks", function(req, res) {
res.locals.sort = sort;
res.locals.paginationBaseUrl = "/blocks";
rpcApi.getBlockchainInfo().then(function(getblockchaininfo) {
coreApi.getBlockchainInfo().then(function(getblockchaininfo) {
res.locals.blockCount = getblockchaininfo.blocks;
res.locals.blockOffset = offset;
@ -203,7 +204,7 @@ router.get("/blocks", function(req, res) {
}
}
rpcApi.getBlocksByHeight(blockHeights).then(function(blocks) {
coreApi.getBlocksByHeight(blockHeights).then(function(blocks) {
res.locals.blocks = blocks;
res.render("blocks");
@ -230,21 +231,21 @@ router.post("/search", function(req, res) {
req.session.query = req.body.query;
if (query.length == 64) {
rpcApi.getRawTransaction(query).then(function(tx) {
coreApi.getRawTransaction(query).then(function(tx) {
if (tx) {
res.redirect("/tx/" + query);
return;
}
rpcApi.getBlockByHash(query).then(function(blockByHash) {
coreApi.getBlockByHash(query).then(function(blockByHash) {
if (blockByHash) {
res.redirect("/block/" + query);
return;
}
rpcApi.getAddress(rawCaseQuery).then(function(validateaddress) {
coreApi.getAddress(rawCaseQuery).then(function(validateaddress) {
if (validateaddress && validateaddress.isvalid) {
res.redirect("/address/" + rawCaseQuery);
@ -263,7 +264,7 @@ router.post("/search", function(req, res) {
});
}).catch(function(err) {
rpcApi.getBlockByHash(query).then(function(blockByHash) {
coreApi.getBlockByHash(query).then(function(blockByHash) {
if (blockByHash) {
res.redirect("/block/" + query);
@ -282,7 +283,7 @@ router.post("/search", function(req, res) {
});
} else if (!isNaN(query)) {
rpcApi.getBlockByHeight(parseInt(query)).then(function(blockByHeight) {
coreApi.getBlockByHeight(parseInt(query)).then(function(blockByHeight) {
if (blockByHeight) {
res.redirect("/block-height/" + query);
@ -294,7 +295,7 @@ router.post("/search", function(req, res) {
res.redirect("/");
});
} else {
rpcApi.getAddress(rawCaseQuery).then(function(validateaddress) {
coreApi.getAddress(rawCaseQuery).then(function(validateaddress) {
if (validateaddress && validateaddress.isvalid) {
res.redirect("/address/" + rawCaseQuery);
@ -330,15 +331,10 @@ router.get("/block-height/:blockHeight", function(req, res) {
res.locals.offset = offset;
res.locals.paginationBaseUrl = "/block-height/" + blockHeight;
client.command('getblockhash', blockHeight, function(err, result, resHeaders) {
if (err) {
// TODO handle RPC error
return console.log(err);
}
res.locals.result.getblockhash = result;
coreApi.getBlockByHeight(blockHeight).then(function(result) {
res.locals.result.getblockbyheight = result;
rpcApi.getBlockByHashWithTransactions(result, limit, offset).then(function(result) {
coreApi.getBlockByHashWithTransactions(result.hash, 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 +367,7 @@ router.get("/block/:blockHash", function(req, res) {
res.locals.paginationBaseUrl = "/block/" + blockHash;
// TODO handle RPC error
rpcApi.getBlockByHashWithTransactions(blockHash, limit, offset).then(function(result) {
coreApi.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;
@ -393,7 +389,7 @@ router.get("/tx/:transactionId", function(req, res) {
res.locals.result = {};
rpcApi.getRawTransaction(txid).then(function(rawTxResult) {
coreApi.getRawTransaction(txid).then(function(rawTxResult) {
res.locals.result.getrawtransaction = rawTxResult;
client.command('getblock', rawTxResult.blockhash, function(err3, result3, resHeaders3) {
@ -406,7 +402,7 @@ router.get("/tx/:transactionId", function(req, res) {
}
}
rpcApi.getRawTransactions(txids).then(function(txInputs) {
coreApi.getRawTransactions(txids).then(function(txInputs) {
res.locals.result.txInputs = txInputs;
res.render("transaction");
@ -440,7 +436,7 @@ router.get("/address/:address", function(req, res) {
}
}
rpcApi.getAddress(address).then(function(result) {
coreApi.getAddress(address).then(function(result) {
res.locals.result.validateaddress = result;
qrcode.toDataURL(address, function(err, url) {
@ -544,13 +540,13 @@ router.get("/rpc-browser", function(req, res) {
}
}
rpcApi.getHelp().then(function(result) {
coreApi.getHelp().then(function(result) {
res.locals.gethelp = result;
if (req.query.method) {
res.locals.method = req.query.method;
rpcApi.getRpcMethodHelp(req.query.method.trim()).then(function(result2) {
coreApi.getRpcMethodHelp(req.query.method.trim()).then(function(result2) {
res.locals.methodhelp = result2;
if (req.query.execute) {

Loading…
Cancel
Save