Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add lru cache and block info pagination #26

Merged
merged 1 commit into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"));

Expand Down
31 changes: 31 additions & 0 deletions cache.js
Original file line number Diff line number Diff line change
@@ -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;
143 changes: 141 additions & 2 deletions routes/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
var { createClient } = require("../baseNodeClient");

var express = require("express");
const cache = require("../cache");
var router = express.Router();

function fromHexString(hexString) {
Expand Down Expand Up @@ -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);

Expand All @@ -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) {
Expand Down
40 changes: 32 additions & 8 deletions views/blocks.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,28 @@
</tr>
</table>

{{#with this.block.body}}
{{#with this.body}}
<table>
<thead>
<tr>
<th>
<h2>Outputs({{outputs.length}})</h2>
<h2>Outputs({{outputs_length}})</h2>
<p>
{{#if outputsPrevLink}}
<a href="{{outputsPrevLink}}">&lt Outputs {{outputsPrev}}</a>
{{/if}}
{{#if outputsNextLink}}
<a href="{{outputsNextLink}}">Outputs {{outputsNext}} &gt;</a>
{{/if}}
</p>
</th>
</tr>
</thead>
<tbody>
{{#each outputs as |output|}}
<tr>
<td>
<h3>Output {{@index}}</h3>
<h3>Output {{add @index ../outputsFrom}}</h3>
{{>TransactionOutput output}}
</td>
</tr>
Expand All @@ -98,15 +106,23 @@
<thead>
<tr>
<th>
<h2>Inputs({{inputs.length}})</h2>
<h2>Inputs({{inputs_length}})</h2>
<p>
{{#if inputsPrevLink}}
<a href="{{inputsPrevLink}}">&lt Inputs {{inputsPrev}}</a>
{{/if}}
{{#if inputsNextLink}}
<a href="{{inputsNextLink}}">Inputs {{inputsNext}} &gt;</a>
{{/if}}
</p>
</th>
</tr>
</thead>
<tbody>
{{#each inputs as |input|}}
<tr>
<td>
<h3>Input {{@index}}</h4>
<h3>Input {{add @index ../inputsFrom}}</h4>
{{>TransactionInput input}}
</td>
</tr>
Expand All @@ -118,19 +134,27 @@
<thead>
<tr>
<th>
<h2>Kernels({{kernels.length}})</h2>
<h2>Kernels({{kernels_length}})</h2>
<p>
{{#if kernelsPrevLink}}
<a href="{{kernelsPrevLink}}">&lt Kernels {{kernelsPrev}}</a>
{{/if}}
{{#if kernelsNextLink}}
<a href="{{kernelsNextLink}}">Kernels {{kernelsNext}} &gt;</a>
{{/if}}
</p>
</th>
</tr>
</thead>
<tbody>
{{#each kernels as |kernel|}}
<tr>
<td>
<h3>Kernel {{@index}}</h3>
<h3>Kernel {{add @index ../kernelsFrom}}</h4>
{{>TransactionKernel kernel}}
</td>
</tr>
{{/each}}
</tbody>
</table>
{{/with}}
{{/with}}