diff --git a/app.js b/app.js
index 7b0f83c..3fd0cb7 100644
--- a/app.js
+++ b/app.js
@@ -13,7 +13,9 @@ var favicon = require("serve-favicon");
var indexRouter = require("./routes/index");
var blockDataRouter = require("./routes/block_data");
var blocksRouter = require("./routes/blocks");
+var exportRouter = require("./routes/export");
var mempoolRouter = require("./routes/mempool");
+var minersRouter = require("./routes/miners");
var searchCommitmentsRouter = require("./routes/search_commitments");
var searchKernelsRouter = require("./routes/search_kernels");
var healthz = require("./routes/healthz");
@@ -102,7 +104,9 @@ app.use("/", indexRouter);
app.use("/blocks", blocksRouter);
app.use("/block_data", blockDataRouter);
app.use("/assets", assetsRouter);
+// app.use("/export", exportRouter);
app.use("/mempool", mempoolRouter);
+app.use("/miners", minersRouter);
app.use("/search_commitments", searchCommitmentsRouter);
app.use("/search_kernels", searchKernelsRouter);
app.use("/healthz", healthz);
diff --git a/applications/minotari_app_grpc/proto/base_node.proto b/applications/minotari_app_grpc/proto/base_node.proto
index 84b7f07..5728ccd 100644
--- a/applications/minotari_app_grpc/proto/base_node.proto
+++ b/applications/minotari_app_grpc/proto/base_node.proto
@@ -217,6 +217,8 @@ message NetworkDifficultyResponse {
uint64 pow_algo = 5;
uint64 sha3x_estimated_hash_rate = 6;
uint64 randomx_estimated_hash_rate = 7;
+ uint64 num_coinbases = 8;
+ bytes first_coinbase_extra = 9;
}
// A generic single value response for a specific height
@@ -339,10 +341,11 @@ message MetaData {
uint64 best_block_height = 1;
// The block hash of the current tip of the longest valid chain, or `None` for an empty chain
bytes best_block_hash = 2;
- // This is the min height this node can provide complete blocks for. A 0 here means this node is archival and can provide complete blocks for every height.
- uint64 pruned_height = 6;
// The current geometric mean of the pow of the chain tip, or `None` if there is no chain
bytes accumulated_difficulty = 5;
+ // This is the min height this node can provide complete blocks for. A 0 here means this node is archival and can provide complete blocks for every height.
+ uint64 pruned_height = 6;
+ uint64 timestamp = 7;
}
message SyncInfoResponse {
diff --git a/package-lock.json b/package-lock.json
index 79d1a43..2d04611 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"cookie-parser": "~1.4.4",
"cors": "^2.8.5",
"express": "~4.16.1",
+ "fast-csv": "^5.0.1",
"hbs": "^4.1.2",
"http-errors": "~1.6.3",
"morgan": "~1.9.1",
@@ -699,6 +700,31 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
+ "node_modules/@fast-csv/format": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-5.0.0.tgz",
+ "integrity": "sha512-IyMpHwYIOGa2f0BJi6Wk55UF0oBA5urdIydoEDYxPo88LFbeb3Yr4rgpu98OAO1glUWheSnNtUgS80LE+/dqmw==",
+ "dependencies": {
+ "lodash.escaperegexp": "^4.1.2",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isequal": "^4.5.0",
+ "lodash.isfunction": "^3.0.9",
+ "lodash.isnil": "^4.0.0"
+ }
+ },
+ "node_modules/@fast-csv/parse": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-5.0.0.tgz",
+ "integrity": "sha512-ecF8tCm3jVxeRjEB6VPzmA+1wGaJ5JgaUX2uesOXdXD6qQp0B3EdshOIed4yT1Xlj/F2f8v4zHSo0Oi31L697g==",
+ "dependencies": {
+ "lodash.escaperegexp": "^4.1.2",
+ "lodash.groupby": "^4.6.0",
+ "lodash.isfunction": "^3.0.9",
+ "lodash.isnil": "^4.0.0",
+ "lodash.isundefined": "^3.0.1",
+ "lodash.uniq": "^4.5.0"
+ }
+ },
"node_modules/@grpc/grpc-js": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.2.tgz",
@@ -1706,6 +1732,18 @@
"node": ">= 0.6"
}
},
+ "node_modules/fast-csv": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-5.0.1.tgz",
+ "integrity": "sha512-Q43zC4NdQD5MAWOVQOF8KA+D6ddvTJjX2ib8zqysm74jZhtk6+dc8C75/OqRV6Y9CLc4kgvbC3PLG8YL4YZfgw==",
+ "dependencies": {
+ "@fast-csv/format": "5.0.0",
+ "@fast-csv/parse": "5.0.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2194,6 +2232,41 @@
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
},
+ "node_modules/lodash.escaperegexp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
+ "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="
+ },
+ "node_modules/lodash.groupby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
+ "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
+ },
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+ },
+ "node_modules/lodash.isfunction": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
+ "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="
+ },
+ "node_modules/lodash.isnil": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
+ "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="
+ },
+ "node_modules/lodash.isundefined": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz",
+ "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA=="
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -2206,6 +2279,11 @@
"integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
"dev": true
},
+ "node_modules/lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="
+ },
"node_modules/long": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
@@ -3673,6 +3751,31 @@
}
}
},
+ "@fast-csv/format": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-5.0.0.tgz",
+ "integrity": "sha512-IyMpHwYIOGa2f0BJi6Wk55UF0oBA5urdIydoEDYxPo88LFbeb3Yr4rgpu98OAO1glUWheSnNtUgS80LE+/dqmw==",
+ "requires": {
+ "lodash.escaperegexp": "^4.1.2",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isequal": "^4.5.0",
+ "lodash.isfunction": "^3.0.9",
+ "lodash.isnil": "^4.0.0"
+ }
+ },
+ "@fast-csv/parse": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-5.0.0.tgz",
+ "integrity": "sha512-ecF8tCm3jVxeRjEB6VPzmA+1wGaJ5JgaUX2uesOXdXD6qQp0B3EdshOIed4yT1Xlj/F2f8v4zHSo0Oi31L697g==",
+ "requires": {
+ "lodash.escaperegexp": "^4.1.2",
+ "lodash.groupby": "^4.6.0",
+ "lodash.isfunction": "^3.0.9",
+ "lodash.isnil": "^4.0.0",
+ "lodash.isundefined": "^3.0.1",
+ "lodash.uniq": "^4.5.0"
+ }
+ },
"@grpc/grpc-js": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.2.tgz",
@@ -4442,6 +4545,15 @@
}
}
},
+ "fast-csv": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-5.0.1.tgz",
+ "integrity": "sha512-Q43zC4NdQD5MAWOVQOF8KA+D6ddvTJjX2ib8zqysm74jZhtk6+dc8C75/OqRV6Y9CLc4kgvbC3PLG8YL4YZfgw==",
+ "requires": {
+ "@fast-csv/format": "5.0.0",
+ "@fast-csv/parse": "5.0.0"
+ }
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -4811,6 +4923,41 @@
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
},
+ "lodash.escaperegexp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
+ "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="
+ },
+ "lodash.groupby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
+ "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="
+ },
+ "lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
+ },
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+ },
+ "lodash.isfunction": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
+ "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="
+ },
+ "lodash.isnil": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
+ "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="
+ },
+ "lodash.isundefined": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz",
+ "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA=="
+ },
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -4823,6 +4970,11 @@
"integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
"dev": true
},
+ "lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="
+ },
"long": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
diff --git a/package.json b/package.json
index 696aa69..845e35c 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"cookie-parser": "~1.4.4",
"cors": "^2.8.5",
"express": "~4.16.1",
+ "fast-csv": "^5.0.1",
"hbs": "^4.1.2",
"http-errors": "~1.6.3",
"morgan": "~1.9.1",
diff --git a/routes/export.js b/routes/export.js
new file mode 100644
index 0000000..1e931bc
--- /dev/null
+++ b/routes/export.js
@@ -0,0 +1,35 @@
+var { createClient } = require("../baseNodeClient");
+
+var express = require("express");
+const { format } = require("@fast-csv/format");
+var router = express.Router();
+
+router.get("/", async function (req, res) {
+ try {
+ let client = createClient();
+ let lastDifficulties = await client.getNetworkDifficulty({
+ from_tip: 1000,
+ });
+
+ const csvStream = format({ headers: true });
+ res.setHeader("Content-Disposition", 'attachment; filename="data.csv"');
+ res.setHeader("Content-Type", "text/csv");
+
+ csvStream.pipe(res);
+
+ // Example data
+
+ for (let i = 0; i < lastDifficulties.length; i++) {
+ csvStream.write(lastDifficulties[i]);
+ }
+
+ csvStream.end();
+ } catch (error) {
+ res.status(500);
+ if (req.query.json !== undefined) {
+ res.json({ error: error });
+ } else {
+ res.render("error", { error: error });
+ }
+ }
+});
diff --git a/routes/index.js b/routes/index.js
index 60deefb..9997667 100644
--- a/routes/index.js
+++ b/routes/index.js
@@ -83,7 +83,7 @@ router.get("/", async function (req, res) {
let mempool = await client.getMempoolTransactions({});
// estimated hash rates
- let lastDifficulties = await client.getNetworkDifficulty({ from_tip: 100 });
+ let lastDifficulties = await client.getNetworkDifficulty({ from_tip: 180 });
let totalHashRates = getHashRates(lastDifficulties, [
"estimated_hash_rate",
]);
@@ -123,14 +123,16 @@ router.get("/", async function (req, res) {
limit,
from,
algoSplit,
- blockTimes: getBlockTimes(last100Headers),
- moneroTimes: getBlockTimes(last100Headers, "0"),
- shaTimes: getBlockTimes(last100Headers, "1"),
+ blockTimes: getBlockTimes(last100Headers, null, 2),
+ moneroTimes: getBlockTimes(last100Headers, "0", 4),
+ shaTimes: getBlockTimes(last100Headers, "1", 4),
currentHashRate: totalHashRates[totalHashRates.length - 1],
totalHashRates,
currentShaHashRate: shaHashRates[shaHashRates.length - 1],
shaHashRates,
+ averageShaMiners: shaHashRates[shaHashRates.length - 1] / 200_000_000, // Hashrate of an NVidia 1070
currentMoneroHashRate: moneroHashRates[moneroHashRates.length - 1],
+ averageMoneroMiners: moneroHashRates[moneroHashRates.length - 1] / 2700, // Average apple m1 hashrate
moneroHashRates,
activeVns,
};
@@ -151,7 +153,7 @@ router.get("/", async function (req, res) {
function getHashRates(difficulties, properties) {
const end_idx = difficulties.length - 1;
- const start_idx = end_idx - 60;
+ const start_idx = end_idx - 720;
return difficulties
.map((d) =>
@@ -163,7 +165,7 @@ function getHashRates(difficulties, properties) {
.slice(start_idx, end_idx);
}
-function getBlockTimes(last100Headers, algo) {
+function getBlockTimes(last100Headers, algo, targetTime) {
let blocktimes = [];
let i = 0;
if (algo === "0" || algo === "1") {
@@ -184,11 +186,12 @@ function getBlockTimes(last100Headers, algo) {
while (i < last100Headers.length && blocktimes.length < 60) {
if (!algo || last100Headers[i].pow.pow_algo === algo) {
blocktimes.push(
- (lastBlockTime - parseInt(last100Headers[i].timestamp)) / 60
+ (lastBlockTime - parseInt(last100Headers[i].timestamp)) / 60 -
+ targetTime
);
lastBlockTime = parseInt(last100Headers[i].timestamp);
} else {
- blocktimes.push(0);
+ blocktimes.push(targetTime);
}
i++;
}
diff --git a/routes/miners.js b/routes/miners.js
new file mode 100644
index 0000000..503051a
--- /dev/null
+++ b/routes/miners.js
@@ -0,0 +1,130 @@
+var { createClient } = require("../baseNodeClient");
+
+var express = require("express");
+var router = express.Router();
+
+router.get("/", async function (req, res) {
+ try {
+ let client = createClient();
+ let lastDifficulties = await client.getNetworkDifficulty({ from_tip: 720 });
+
+ let data = {
+ num_blocks: lastDifficulties.length,
+ difficulties: lastDifficulties,
+ extras: [],
+ unique_ids: {},
+ os: {},
+ versions: {},
+ now: Math.floor(Date.now() / 1000),
+ };
+
+ for (let i = 0; i < lastDifficulties.length; i++) {
+ let extra = lastDifficulties[i].first_coinbase_extra.toString();
+ let split = extra.split(",");
+
+ let unique_id =
+ lastDifficulties[i].first_coinbase_extra === ""
+ ? "Non-universe miner"
+ : lastDifficulties[i].first_coinbase_extra;
+ let os = "Non-universe miner";
+ let version = "Non-universe miner";
+
+ if (split.length >= 6) {
+ unique_id = split[1];
+ os = split[4];
+ version = split[5];
+ }
+
+ if (data.unique_ids[unique_id] === undefined) {
+ data.unique_ids[unique_id] = {
+ sha: {
+ count: 0,
+ version: version,
+ os: os,
+ last_block_time: 0,
+ time_since_last_block: null,
+ recent_blocks: 0,
+ },
+ randomx: {
+ count: 0,
+ version: version,
+ os: os,
+ last_block_time: 0,
+ time_since_last_block: null,
+ recent_blocks: 0,
+ },
+ };
+ }
+ data.unique_ids[unique_id][
+ lastDifficulties[i].pow_algo === "0" ? "randomx" : "sha"
+ ].count += 1;
+ data.unique_ids[unique_id][
+ lastDifficulties[i].pow_algo === "0" ? "randomx" : "sha"
+ ].version = version;
+ data.unique_ids[unique_id][
+ lastDifficulties[i].pow_algo === "0" ? "randomx" : "sha"
+ ].last_block_time = lastDifficulties[i].timestamp;
+ data.unique_ids[unique_id][
+ lastDifficulties[i].pow_algo === "0" ? "randomx" : "sha"
+ ].time_since_last_block = Math.ceil(
+ (data.now - lastDifficulties[i].timestamp) / 60
+ );
+
+ if (
+ data.unique_ids[unique_id][
+ lastDifficulties[i].pow_algo === "0" ? "randomx" : "sha"
+ ].time_since_last_block < 120
+ ) {
+ data.unique_ids[unique_id][
+ lastDifficulties[i].pow_algo === "0" ? "randomx" : "sha"
+ ].recent_blocks += 1;
+ }
+
+ if (data.os[os] === undefined) {
+ data.os[os] = 0;
+ }
+ data.os[os] += 1;
+ if (data.versions[version] === undefined) {
+ data.versions[version] = 0;
+ }
+ data.versions[version] += 1;
+
+ data.extras.push({
+ height: lastDifficulties[i].height,
+ extra: extra,
+ unique_id,
+ os,
+ version,
+ });
+ }
+
+ data.active_miners = {};
+ for (const unique_id of Object.keys(data.unique_ids)) {
+ console.log(unique_id);
+ let miner = data.unique_ids[unique_id];
+ console.log(miner);
+ if (
+ (miner.sha.time_since_last_block || 1000) < 120 ||
+ (miner.randomx.time_since_last_block || 1000) < 120
+ ) {
+ data.active_miners[unique_id] = miner;
+ }
+ }
+
+ if (req.query.json !== undefined) {
+ res.json(data);
+ } else {
+ res.render("miners", data);
+ }
+ } catch (error) {
+ res.status(500);
+ if (req.query.json !== undefined) {
+ res.json({ error: error });
+ } else {
+ res.render("error", { error: error });
+ }
+ }
+});
+
+
+module.exports = router;
\ No newline at end of file
diff --git a/views/export.hbs b/views/export.hbs
new file mode 100644
index 0000000..1815627
--- /dev/null
+++ b/views/export.hbs
@@ -0,0 +1,9 @@
+block_height, hashrate
+{{#each outputs as |output|}}
+
+
+ Output {{add @index ../outputsFrom}}
+ {{>TransactionOutput output}}
+
+
+{{/each}}
\ No newline at end of file
diff --git a/views/index.hbs b/views/index.hbs
index 8e1188e..add4ade 100644
--- a/views/index.hbs
+++ b/views/index.hbs
@@ -78,13 +78,13 @@
Monero
- Target time: 3.3 minutes
+ Target time: 4 minutes
{{chart this.moneroTimes 15}}
SHA3
- Target time: 5 minutes
+ Target time: 4 minutes
{{chart this.shaTimes 15}}
@@ -93,32 +93,22 @@
-
-
- Estimated Hash Rate
- Current total estimated Hash Rate:
- {{this.currentHashRate}}
- H/s
- {{chart this.totalHashRates 15}}
-
-
-
-
-
Monero
- Current estimated Hash Rate:
+ Current estimated Hash Rate (180 blocks, 1.5 hours):
{{this.currentMoneroHashRate}}
- H/s
+ H/s ({{this.averageMoneroMiners}} average miners)
{{chart this.moneroHashRates 15}}
+
+
SHA3
- Current estimated Hash Rate:
+ Current estimated Hash Rate (180 blocks, 1.5 hours):
{{this.currentShaHashRate}}
- H/s
+ H/s ({{this.averageShaMiners}} average miners)
{{chart this.shaHashRates 15}}
@@ -140,15 +130,15 @@
{{#each this.headers}}
-
- {{this.height}}
- {{timestamp this.timestamp}}
+
+ {{this.height}}
+ {{timestamp this.timestamp}}
- {{this.powText}}
- {{hex this.hash}}
- {{kernels}}
- {{outputs}}
-
+ {{this.powText}}
+ {{hex this.hash}}
+ {{kernels}}
+ {{outputs}}
+
{{/each}}
@@ -179,17 +169,17 @@
{{#each mempool}}
- {{#with this.transaction.body}}
-
- {{hex
- this.signature
- }}
- {{this.total_fees}}
- {{this.outputs.length}}
- {{this.kernels.length}}
- {{this.inputs.length}}
-
- {{/with}}
+ {{#with this.transaction.body}}
+
+ {{hex
+ this.signature
+ }}
+ {{this.total_fees}}
+ {{this.outputs.length}}
+ {{this.kernels.length}}
+ {{this.inputs.length}}
+
+ {{/with}}
{{/each}}
@@ -205,10 +195,10 @@
{{#each this.activeVns}}
-
- {{hex this.public_key}}
- {{hex this.shard_key}}
-
+
+ {{hex this.public_key}}
+ {{hex this.shard_key}}
+
{{/each}}
@@ -225,4 +215,4 @@
search
-
+
\ No newline at end of file
diff --git a/views/miners.hbs b/views/miners.hbs
new file mode 100644
index 0000000..58c56a0
--- /dev/null
+++ b/views/miners.hbs
@@ -0,0 +1,132 @@
+Versions
+
+
+ Version
+ Blocks Mined
+
+ {{#each this.versions}}
+
+ {{@key}}
+ {{this}}
+
+ {{/each}}
+
+
+
+Operating System
+
+
+ OS
+ Blocks mined
+
+ {{#each this.os}}
+
+ {{@key}}
+ {{this}}
+
+ {{/each}}
+
+
+
+Active miners
+
+
+ Uniqueid
+ Resource
+ Blocks won (total)
+ Blocks won (last 2 hours)
+ Version
+ OS
+ Last block
+
+ {{#each this.active_miners}}
+ {{#if this.sha.count }}
+
+ {{@key}}
+ gpu
+ {{this.sha.count}}
+ {{this.sha.recent_blocks}}
+ {{this.sha.version}}
+ {{this.sha.os}}
+ {{this.sha.time_since_last_block}} minutes ago
+
+ {{/if}}
+ {{#if this.randomx.count }}
+
+ {{@key}}
+ cpu
+ {{this.randomx.count}}
+ {{this.randomx.recent_blocks}}
+ {{this.randomx.version}}
+ {{this.randomx.os}}
+ {{this.randomx.time_since_last_block}} minutes ago
+
+ {{/if}}
+ {{/each}}
+
+
+Unique miners (GPU)
+
+
+ Uniqueid
+ Resource
+ Blocks won
+ Version
+ OS
+ Last block
+
+ {{#each this.unique_ids}}
+ {{#if this.sha.count }}
+
+ {{@key}}
+ gpu
+ {{this.sha.count}}
+ {{this.sha.version}}
+ {{this.sha.os}}
+ {{this.sha.time_since_last_block}} minutes ago
+
+ {{/if}}
+ {{/each}}
+
+
+
+Unique miners (CPU)
+
+
+ Uniqueid
+ Resource
+ Blocks won
+ Version
+ OS
+ Last block
+
+ {{#each this.unique_ids}}
+ {{#if this.randomx.count }}
+
+ {{@key}}
+ cpu
+ {{this.randomx.count}}
+ {{this.randomx.version}}
+ {{this.randomx.os}}
+ {{this.randomx.time_since_last_block}} minutes ago
+
+
+ {{/if}}
+ {{/each}}
+
+
+
+
+
+All extra fields
+
+ {{# each this.extras}}
+
+ {{this.height}}
+ {{this.extra}}
+ {{this.unique_id}}
+ {{this.os}}
+ {{this.version}}
+
+ {{/each}}
+
\ No newline at end of file