Skip to content

Commit

Permalink
Add prediction endpoints (#46)
Browse files Browse the repository at this point in the history
* Add prediction endpoints

* .
  • Loading branch information
Redm4x authored Nov 9, 2023
1 parent 7b79198 commit 4c10690
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 17 deletions.
69 changes: 54 additions & 15 deletions api/src/db/blocksProvider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { AkashBlock as Block, AkashMessage as Message } from "@shared/dbSchemas/akash";
import { Transaction, Validator } from "@shared/dbSchemas/base";
import { averageBlockTime } from "@src/utils/constants";
import { add } from "date-fns";
import { addSeconds, differenceInSeconds } from "date-fns";

export async function getBlocks(limit: number) {
const _limit = Math.min(limit, 100);
Expand Down Expand Up @@ -32,14 +31,6 @@ export async function getBlocks(limit: number) {
}

export async function getBlock(height: number) {
// const latestBlock = await Block.findOne({
// order: [["height", "DESC"]]
// });

// if (height > latestBlock.height) {
// return getFutureBlockEstimate(height, latestBlock);
// }

const block = await Block.findOne({
where: {
height: height
Expand Down Expand Up @@ -87,9 +78,57 @@ export async function getBlock(height: number) {
};
}

async function getFutureBlockEstimate(height: number, latestBlock: Block) {
return {
height: height,
expectedDate: add(latestBlock.datetime, { seconds: (height - latestBlock.height) * averageBlockTime })
};
/**
* Calculate the estimated block time
* @param latestBlock Block to calculate the average from
* @param blockCount Block interval for calculating the average
* @returns Average block time in seconds
*/
async function calculateAverageBlockTime(latestBlock: Block, blockCount: number) {
if (blockCount <= 1) throw new Error("blockCount must be greater than 1");

const earlierBlock = await Block.findOne({
where: {
height: Math.max(latestBlock.height - blockCount, 1)
}
});

const realBlockCount = latestBlock.height - earlierBlock.height;

return differenceInSeconds(latestBlock.datetime, earlierBlock.datetime) / realBlockCount;
}

/**
* Get the predicted height at a given date
* @param date Date to predict the height of
* @param blockWindow Block interval for calculating the average
* @returns Predicted height at the given date
*/
export async function getPredictedDateHeight(date: Date, blockWindow: number) {
const latestBlock = await Block.findOne({ order: [["height", "DESC"]] });

if (date <= latestBlock.datetime) throw new Error("Date must be in the future");

const averageBlockTime = await calculateAverageBlockTime(latestBlock, blockWindow);

const dateDiff = differenceInSeconds(date, latestBlock.datetime);

return Math.floor(latestBlock.height + dateDiff / averageBlockTime);
}

/**
* Get the predicted date at a given height
* @param height Height to predict the date of
* @param blockWindow Block window for calculating the average
* @returns Predicted date at the given height
*/
export async function getPredictedBlockDate(height: number, blockWindow: number) {
const latestBlock = await Block.findOne({ order: [["height", "DESC"]] });

if (height <= latestBlock.height) throw new Error("Height must be in the future");

const averageBlockTime = await calculateAverageBlockTime(latestBlock, blockWindow);

const heightDiff = height - latestBlock.height;
return addSeconds(latestBlock.datetime, heightDiff * averageBlockTime);
}
57 changes: 55 additions & 2 deletions api/src/routers/apiRouter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from "express";
import { getBlock, getBlocks } from "@src/db/blocksProvider";
import { getBlock, getBlocks, getPredictedBlockDate, getPredictedDateHeight } from "@src/db/blocksProvider";
import { getTemplateGallery } from "@src/providers/templateReposProvider";
import { getTransaction, getTransactionByAddress, getTransactions } from "@src/db/transactionsProvider";
import {
Expand Down Expand Up @@ -65,6 +65,59 @@ apiRouter.get(
})
);

apiRouter.get(
"/predicted-block-date/:height/:blockWindow?",
asyncHandler(async (req, res) => {
const height = parseInt(req.params.height);
const blockWindow = req.params.blockWindow ? parseInt(req.params.blockWindow) : 10_000;

if (isNaN(height)) {
res.status(400).send("Invalid height.");
return;
}

if (isNaN(blockWindow)) {
res.status(400).send("Invalid block window.");
return;
}

const date = await getPredictedBlockDate(height, blockWindow);

res.send({
predictedDate: date,
height: height,
blockWindow: blockWindow
});
})
);

apiRouter.get(
"/predicted-date-height/:timestamp/:blockWindow?",
asyncHandler(async (req, res) => {
const timestamp = parseInt(req.params.timestamp);
const blockWindow = req.params.height ? parseInt(req.params.blockWindow) : 10_000;

if (isNaN(timestamp)) {
res.status(400).send("Invalid timestamp.");
return;
}

if (isNaN(blockWindow)) {
res.status(400).send("Invalid block window.");
return;
}

const date = new Date(timestamp * 1000);
const height = await getPredictedDateHeight(date, blockWindow);

res.send({
predictedHeight: height,
date: date,
blockWindow: blockWindow
});
})
);

apiRouter.get(
"/transactions",
asyncHandler(async (req, res) => {
Expand Down Expand Up @@ -265,7 +318,7 @@ apiRouter.get(
const chainStats = {
height: latestBlocks[0].height,
transactionCount: latestBlocks[0].totalTransactionCount,
...(await chainStatsQuery)
...chainStatsQuery
};

res.send({
Expand Down

0 comments on commit 4c10690

Please sign in to comment.