From e2e44dd2f239e180d9b2e3e470d22daf342e9168 Mon Sep 17 00:00:00 2001 From: Martin Stefcek Date: Wed, 28 Feb 2024 11:42:59 +0400 Subject: [PATCH] feat: add lru cache and block info pagination --- app.js | 3 + cache.js | 31 ++++++++++ routes/blocks.js | 143 ++++++++++++++++++++++++++++++++++++++++++++++- views/blocks.hbs | 40 ++++++++++--- 4 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 cache.js diff --git a/app.js b/app.js index f0b3c98..a60d65f 100644 --- a/app.js +++ b/app.js @@ -71,6 +71,9 @@ hbs.registerHelper("chart", function (data, height) { hbs.registerHelper("json", function (obj) { return JSON.stringify(obj); }); +hbs.registerHelper("add", function (a, b) { + return a + b; +}); hbs.registerPartials(path.join(__dirname, "partials")); diff --git a/cache.js b/cache.js new file mode 100644 index 0000000..c5a0f8b --- /dev/null +++ b/cache.js @@ -0,0 +1,31 @@ +class Cache { + constructor(limit = 1000) { + this.limit = limit; + this.cache = new Map(); + } + + set(key, value) { + if (this.cache.size >= this.limit) { + const firstItemKey = this.cache.keys().next().value; + this.cache.delete(firstItemKey); + } + this.cache.set(key, value); + } + + async get(func, args) { + let cache_key = JSON.stringify(args); + if (this.cache.has(cache_key)) { + const temp = this.cache.get(cache_key); + this.cache.delete(cache_key); + this.cache.set(cache_key, temp); + return temp; + } + let result = await func(args); + console.log("Actual call", args); + this.set(cache_key, result); + return result; + } +} + +var cache = new Cache(); +module.exports = cache; diff --git a/routes/blocks.js b/routes/blocks.js index 37fd86e..8b41919 100644 --- a/routes/blocks.js +++ b/routes/blocks.js @@ -23,6 +23,7 @@ var { createClient } = require("../baseNodeClient"); var express = require("express"); +const cache = require("../cache"); var router = express.Router(); function fromHexString(hexString) { @@ -55,13 +56,151 @@ router.get("/:height_or_hash", async function (req, res) { height = parseInt(height_or_hash); } - block = await client.getBlocks({ heights: [height] }); + let request = { heights: [height] }; + block = await cache.get(client.getBlocks, request); if (!block || block.length === 0) { res.status(404); res.render("404", { message: `Block at height ${height} not found` }); return; } + let outputs_from = +(req.query.outputs_from || 0); + let outputs_to = +(req.query.outputs_to || 10); + let inputs_from = req.query.inputs_from || 0; + let inputs_to = +(req.query.inputs_to || 10); + let kernels_from = +(req.query.kernels_from || 0); + let kernels_to = +(req.query.kernels_to || 10); + let body = { + outputs_length: block[0].block.body.outputs.length, + inputs_length: block[0].block.body.inputs.length, + kernels_length: block[0].block.body.kernels.length, + outputs: block[0].block.body.outputs.slice(outputs_from, outputs_to), + inputs: block[0].block.body.inputs.slice(inputs_from, inputs_to), + kernels: block[0].block.body.kernels.slice(kernels_from, kernels_to), + outputsNext: null, + outputsNextLink: null, + outputsPrev: null, + outputsPrevLink: null, + outputsFrom: outputs_from, + inputsNext: null, + inputsNextLink: null, + inputsPrev: null, + inputsPrevLink: null, + inputsFrom: inputs_from, + kernelsNext: null, + kernelsNextLink: null, + kernelsPrev: null, + kernelsPrevLink: null, + kernelsFrom: kernels_from, + }; + if (outputs_from > 0) { + body.outputsPrev = `${outputs_from - 10}..${outputs_from - 1}`; + body.outputsPrevLink = + "/blocks/" + + height + + "?outputs_from=" + + (outputs_from - 10) + + "&outputs_to=" + + (outputs_to - 10) + + "&inputs_from=" + + inputs_from + + "&inputs_to=" + + inputs_to + + "&kernels_from=" + + kernels_from + + "&kernels_to=" + + kernels_to; + } + if (outputs_to < body.outputs_length) { + body.outputsNext = `${outputs_to}..${outputs_to + 9}`; + body.outputsNextLink = + "/blocks/" + + height + + "?outputs_from=" + + (outputs_from + 10) + + "&outputs_to=" + + (outputs_to + 10) + + "&inputs_from=" + + inputs_from + + "&inputs_to=" + + inputs_to + + "&kernels_from=" + + kernels_from + + "&kernels_to=" + + kernels_to; + } + if (inputs_from > 0) { + body.inputsPrev = `${inputs_from - 10}..${inputs_from - 1}`; + body.inputsPrevLink = + "/blocks/" + + height + + "?outputs_from=" + + outputs_from + + "&outputs_to=" + + outputs_to + + "&inputs_from=" + + (inputs_from - 10) + + "&inputs_to=" + + (inputs_to - 10) + + "&kernels_from=" + + kernels_from + + "&kernels_to=" + + kernels_to; + } + if (inputs_to < body.inputs_length) { + body.inputsNext = `${inputs_to}..${inputs_to + 9}`; + body.inputsNextLink = + "/blocks/" + + height + + "?outputs_from=" + + outputs_from + + "&outputs_to=" + + outputs_to + + "&inputs_from=" + + (inputs_from + 10) + + "&inputs_to=" + + (inputs_to + 10) + + "&kernels_from=" + + kernels_from + + "&kernels_to=" + + kernels_to; + } + if (kernels_from > 0) { + body.kernelsPrev = `${kernels_from - 10}..${kernels_from - 1}`; + body.kernelsPrevLink = + "/blocks/" + + height + + "?outputs_from=" + + outputs_from + + "&outputs_to=" + + outputs_to + + "&inputs_from=" + + inputs_from + + "&inputs_to=" + + inputs_to + + "&kernels_from=" + + (kernels_from - 10) + + "&kernels_to=" + + (kernels_to - 10); + } + if (kernels_to < body.kernels_length) { + body.kernelsNext = `${kernels_to}..${kernels_to + 9}`; + body.kernelsNextLink = + "/blocks/" + + height + + "?outputs_from=" + + outputs_from + + "&outputs_to=" + + outputs_to + + "&inputs_from=" + + inputs_from + + "&inputs_to=" + + inputs_to + + "&kernels_from=" + + (kernels_from + 10) + + "&kernels_to=" + + (kernels_to + 10); + } let tipInfo = await client.getTipInfo({}); let tipHeight = parseInt(tipInfo.metadata.height_of_longest_chain); @@ -81,7 +220,7 @@ router.get("/:height_or_hash", async function (req, res) { prevHeight, nextLink, nextHeight, - block: block[0].block, + body: body, pows: { 0: "Monero", 1: "SHA-3" }, }; if (req.query.json !== undefined) { diff --git a/views/blocks.hbs b/views/blocks.hbs index 0428bf1..2efe5d1 100644 --- a/views/blocks.hbs +++ b/views/blocks.hbs @@ -73,12 +73,20 @@ -{{#with this.block.body}} +{{#with this.body}} @@ -86,7 +94,7 @@ {{#each outputs as |output|}} @@ -98,7 +106,15 @@ @@ -106,7 +122,7 @@ {{#each inputs as |input|}} @@ -118,7 +134,15 @@ @@ -126,11 +150,11 @@ {{#each kernels as |kernel|}} {{/each}}
-

Outputs({{outputs.length}})

+

Outputs({{outputs_length}})

+

+ {{#if outputsPrevLink}} + < Outputs {{outputsPrev}} + {{/if}} + {{#if outputsNextLink}} + Outputs {{outputsNext}} > + {{/if}} +

-

Output {{@index}}

+

Output {{add @index ../outputsFrom}}

{{>TransactionOutput output}}
-

Inputs({{inputs.length}})

+

Inputs({{inputs_length}})

+

+ {{#if inputsPrevLink}} + < Inputs {{inputsPrev}} + {{/if}} + {{#if inputsNextLink}} + Inputs {{inputsNext}} > + {{/if}} +

-

Input {{@index}}

+

Input {{add @index ../inputsFrom}}

{{>TransactionInput input}}
-

Kernels({{kernels.length}})

+

Kernels({{kernels_length}})

+

+ {{#if kernelsPrevLink}} + < Kernels {{kernelsPrev}} + {{/if}} + {{#if kernelsNextLink}} + Kernels {{kernelsNext}} > + {{/if}} +

-

Kernel {{@index}}

+

Kernel {{add @index ../kernelsFrom}}

{{>TransactionKernel kernel}}
-{{/with}} \ No newline at end of file +{{/with}}