Skip to content

Commit

Permalink
fix: protect all HTTP API calls with calls limiter
Browse files Browse the repository at this point in the history
  • Loading branch information
iccicci committed Dec 5, 2024
1 parent 3c8b7ef commit c8e6060
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 20 deletions.
5 changes: 3 additions & 2 deletions src/methods/estimate-fee.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { prepareMessage } from '../utils/message.js';
import { blockfrostAPI } from '../utils/blockfrost-api.js';
import { MessageId } from '../types/message.js';
import { limiter } from '../utils/limiter.js';

export default async (id: MessageId, clientId: string): Promise<string> => {
const epochsLatest = await blockfrostAPI.epochsLatest();
const epochsParameters = await blockfrostAPI.epochsParameters(epochsLatest.epoch);
const epochsLatest = await limiter(() => blockfrostAPI.epochsLatest());
const epochsParameters = await limiter(() => blockfrostAPI.epochsParameters(epochsLatest.epoch));

const message = prepareMessage({
id,
Expand Down
5 changes: 3 additions & 2 deletions src/methods/get-ada-handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { prepareMessage } from '../utils/message.js';
import { blockfrostAPI } from '../utils/blockfrost-api.js';
import { MessageId } from '../types/message.js';
import { BlockfrostServerError } from '@blockfrost/blockfrost-js';
import { limiter } from '../utils/limiter.js';

const policyID = 'f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a';

export default async (id: MessageId, clientId: string, name: string): Promise<string> => {
let data: { address: string } | null;

try {
const result = await blockfrostAPI.assetsAddresses(
policyID + Buffer.from(name, 'utf8').toString('hex'),
const result = await limiter(() =>
blockfrostAPI.assetsAddresses(policyID + Buffer.from(name, 'utf8').toString('hex')),
);

if (result.length > 1) {
Expand Down
3 changes: 2 additions & 1 deletion src/methods/get-block.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { prepareMessage } from '../utils/message.js';
import { blockfrostAPI } from '../utils/blockfrost-api.js';
import { MessageId } from '../types/message.js';
import { limiter } from '../utils/limiter.js';

export default async (
id: MessageId,
clientId: string,
hashOrNumber: string | number,
): Promise<string> => {
const data = await blockfrostAPI.blocks(hashOrNumber);
const data = await limiter(() => blockfrostAPI.blocks(hashOrNumber));
const message = prepareMessage({ id, clientId, data });

return message;
Expand Down
9 changes: 7 additions & 2 deletions src/methods/get-server-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import * as os from 'os';
import { prepareMessage } from '../utils/message.js';
import { blockfrostAPI } from '../utils/blockfrost-api.js';
import { MessageId } from '../types/message.js';
import { limiter } from '../utils/limiter.js';

export const getServerInfo = async () => {
const isTestnet = blockfrostAPI.options.network !== 'mainnet';
const info = await blockfrostAPI.root();
const latestBlock = await blockfrostAPI.blocksLatest();

const [info, latestBlock] = await Promise.all([
limiter(() => blockfrostAPI.root()),
limiter(() => blockfrostAPI.blocksLatest()),
]);

const serverInfo = {
hostname: os.hostname(),
name: 'Cardano',
Expand Down
9 changes: 5 additions & 4 deletions src/utils/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,10 @@ export const getAddressesData = async (

export const getStakingData = async (stakeAddress: string): Promise<Addresses.StakingData> => {
try {
const stakeAddressData = await blockfrostAPI.accounts(stakeAddress);
const drepData = stakeAddressData.drep_id
? await blockfrostAPI.governance.drepsById(stakeAddressData.drep_id)
const stakeAddressData = await limiter(() => blockfrostAPI.accounts(stakeAddress));
const { drep_id } = stakeAddressData;
const drepData = drep_id
? await limiter(() => blockfrostAPI.governance.drepsById(drep_id))
: null;

return {
Expand All @@ -306,7 +307,7 @@ export const getStakingAccountTotal = async (
stakeAddress: string,
): Promise<Responses['account_addresses_total']> => {
try {
const total = await blockfrostAPI.accountsAddressesTotal(stakeAddress);
const total = await limiter(() => blockfrostAPI.accountsAddressesTotal(stakeAddress));

return total;
} catch (error) {
Expand Down
13 changes: 7 additions & 6 deletions src/utils/blockfrost-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createRequire } from 'module';
import { BLOCKFROST_REQUEST_TIMEOUT } from '../constants/config.js';
import { logger } from './logger.js';
import { AffectedAddressesInBlock } from '../types/events.js';
import { limiter } from './limiter.js';
const require = createRequire(import.meta.url);
const packageJson = require('../../package.json');

Expand All @@ -30,15 +31,15 @@ export const getBlockData = async (options?: {
// Fetch latest block and all addresses affected in the block
// Fetching of affected addresses may fail, there are 3 retry attempts before throwing an error
const MAX_ATTEMPTS = 3;
const latestBlock = options?.block
? await blockfrostAPI.blocks(options.block)
: await blockfrostAPI.blocksLatest();
const latestBlock = await limiter(() =>
options?.block ? blockfrostAPI.blocks(options.block) : blockfrostAPI.blocksLatest(),
);
let affectedAddresses: AffectedAddressesInBlock = [];

try {
affectedAddresses = await blockfrostAPI.blocksAddressesAll(latestBlock.hash, {
batchSize: 2,
});
affectedAddresses = await limiter(() =>
blockfrostAPI.blocksAddressesAll(latestBlock.hash, { batchSize: 2 }),
);
} catch (error) {
if (
error instanceof BlockfrostServerError &&
Expand Down
9 changes: 6 additions & 3 deletions src/utils/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ export const sortTransactionsCmp = <

const fetchTxWithUtxo = async (txHash: string, address: string, cbor?: boolean) => {
try {
const txUtxo = await limiter(() => blockfrostAPI.txsUtxos(txHash));
const txData = await fetchTransactionData(txHash, cbor);
const txUtxos = await transformTransactionUtxo(txUtxo);
const [txUtxos, txData] = await Promise.all([
limiter(() => blockfrostAPI.txsUtxos(txHash)).then(txUtxo =>
transformTransactionUtxo(txUtxo),
),
fetchTransactionData(txHash, cbor),
]);

return { txData, txUtxos, address, txHash };
} catch (error) {
Expand Down

0 comments on commit c8e6060

Please sign in to comment.