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

Added pagination for transactions and blocks #411

Merged
merged 2 commits into from
Sep 4, 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
7 changes: 7 additions & 0 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ export abstract class API {
case 5000:
throw new ErrVochainEmptyReply(err['error']);
case 5001:
try {
return API.isVochainError(err['error']);
} catch (e) {
if (!(e instanceof ErrVochainReturnedErrorCode)) {
throw e;
}
}
throw new ErrVochainSendTxFailed(err['error']);
case 5002:
throw new ErrVochainGetTxFailed(err['error']);
Expand Down
163 changes: 71 additions & 92 deletions src/api/chain.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import axios from 'axios';
import { API, PaginationResponse } from './api';
import { ErrTransactionNotFound } from './errors';
import { Tx } from './chain/';
import {
FetchFeesParametersWithPagination,
FetchOrganizationParametersWithPagination,
FetchTransactionsParametersWithPagination,
FetchTransfersParametersWithPagination,
} from '../services';
import { Tx } from './chain';
export * from './chain/';

enum ChainAPIMethods {
INFO = '/chain/info',
COSTS = '/chain/info/electionPriceFactors',
CIRCUITS = '/chain/info/circuit',
TX_COSTS = '/chain/transactions/cost',
TX_INFO = '/chain/transactions/reference',
TX_INFO_BY_INDEX = '/chain/transactions/reference/index/{index}',
TX_INFO_BLOCK = '/chain/transactions/{blockHeight}/{txIndex}',
SUBMIT_TX = '/chain/transactions',
TX_INFO = '/chain/transactions/{txHash}',
TX_LIST = '/chain/transactions',
SUBMIT_TX = '/chain/transactions',
ORGANIZATION_LIST = '/chain/organizations',
VALIDATORS_LIST = '/chain/validators',
BLOCK_INFO = '/chain/blocks',
BLOCK_INFO_BY_HASH = '/chain/blocks/hash',
BLOCK_INFO_HASH = '/chain/blocks/hash/{blockHash}',
BLOCK_INFO_HEIGHT = '/chain/blocks/{blockHeight}',
BLOCK_LIST = '/chain/blocks',
DATE_TO_BLOCK = '/chain/dateToBlock/{timestamp}',
BLOCK_TO_DATE = '/chain/blockToDate/{height}',
FEES_LIST = '/chain/fees',
Expand Down Expand Up @@ -204,30 +203,35 @@ export interface IChainTxCosts {
}

export interface IChainTxReference {
/**
* The number of the transaction.
*/
transactionNumber: number;

/**
* The hash of the transaction.
*/
transactionHash: string;
hash: string;

/**
* The number of the block where the transaction is.
*/
blockHeight: number;
height: number;

/**
* The index of the transaction inside the block.
*/
transactionIndex: number;
index: number;

/**
* The type of the transaction.
*/
transactionType: TransactionType;
type: TransactionType;

/**
* The subtype of the transaction.
*/
subtype: string;

/**
* The signer of the transaction.
*/
signer: string;
}

export interface IChainSubmitTxResponse {
Expand All @@ -251,11 +255,30 @@ export interface IChainTxListResponse extends IChainTxList, PaginationResponse {

export interface IChainTxList {
/**
* List of transactions reference
* List of transactions
*/
transactions: Array<IChainTxReference>;
}

export interface IChainBlocksListResponse extends IChainBlocksList, PaginationResponse {}

export interface IChainBlocksList {
/**
* List of blocks
*/
blocks: Array<IBlock>;
}

export interface IBlock {
chainId: string;
height: number;
time: string;
hash: string;
proposer: string;
lastBlockHash: string;
txCount: number;
}

export interface IChainTransfersListResponse extends IChainTransfersList, PaginationResponse {}

export interface IChainTransfersList {
Expand Down Expand Up @@ -304,12 +327,6 @@ interface BlockID {
}

export interface IChainBlockInfoResponse {
data: {
txs: Array<string>;
};
evidence: {
evidence: Array<string>;
};
hash: string;
header: {
appHash: string;
Expand All @@ -330,23 +347,7 @@ export interface IChainBlockInfoResponse {
app: number;
};
};
lastCommit: {
blockId: BlockID;
height: number;
round: number;
signatures: Array<{
blockIdFlag: number;
signature: string;
timestamp: string;
validatorAddress: string;
}>;
};
}

export interface IBlockTransactionsResponse {
blockNumber: number;
transactionCount: number;
transactions: Array<IChainTxReference>;
txCount: number;
}

interface IDateToBlockResponse {
Expand Down Expand Up @@ -527,9 +528,9 @@ export abstract class ChainAPI extends API {
* @param url - API endpoint URL
* @param txHash - The transaction hash which we want to retrieve the info from
*/
public static txInfo(url: string, txHash: string): Promise<IChainTxReference> {
public static txInfo(url: string, txHash: string): Promise<Tx> {
return axios
.get<IChainTxReference>(url + ChainAPIMethods.TX_INFO + '/' + txHash)
.get<Tx>(url + ChainAPIMethods.TX_INFO.replace('{txHash}', txHash))
.then((response) => {
if (response.status === 204) {
throw new ErrTransactionNotFound();
Expand All @@ -539,45 +540,6 @@ export abstract class ChainAPI extends API {
.catch(this.isApiError);
}

/**
* Fetches information about a transaction from the blockchain by its index. The transaction index is an incremental
* counter for each transaction
*
* @param url - API endpoint URL
* @param index - The transaction index
*/
public static txByIndex(url: string, index: number): Promise<IChainTxReference> {
return axios
.get<IChainTxReference>(url + ChainAPIMethods.TX_INFO_BY_INDEX.replace('{index}', String(index)))
.then((response) => {
if (response.status === 204) {
throw new ErrTransactionNotFound();
}
return response.data;
})
.catch(this.isApiError);
}

/**
* Fetches information about a transaction by its containing block an index on the block.
*
* @param url - API endpoint URL
* @param blockHeight - Block with the containing transaction
* @param txIndex - Index on the block
*/
public static txInfoByBlock(url: string, blockHeight: number, txIndex: number): Promise<Tx> {
return axios
.get<Tx>(
url +
ChainAPIMethods.TX_INFO_BLOCK.replace('{blockHeight}', String(blockHeight)).replace(
'{txIndex}',
String(txIndex)
)
)
.then((response) => response.data)
.catch(this.isApiError);
}

/**
* Submits a transaction to the blockchain
*
Expand Down Expand Up @@ -662,39 +624,56 @@ export abstract class ChainAPI extends API {
}

/**
* Get block information by height
* Returns the list of validators
*
* @param url - API endpoint URL
* @param height - block height
*/
public static blockByHeight(url: string, height: number): Promise<IChainBlockInfoResponse> {
public static validatorsList(url: string): Promise<IChainValidatorsListResponse> {
return axios
.get<IChainBlockInfoResponse>(url + ChainAPIMethods.BLOCK_INFO + '/' + height)
.get<IChainValidatorsListResponse>(url + ChainAPIMethods.VALIDATORS_LIST)
.then((response) => response.data)
.catch(this.isApiError);
}

/**
* Returns the list of validators
* Get block information by hash
*
* @param url - API endpoint URL
* @param hash - block hash
*/
public static validatorsList(url: string): Promise<IChainValidatorsListResponse> {
public static blockInfoHash(url: string, hash: string): Promise<IChainBlockInfoResponse> {
return axios
.get<IChainValidatorsListResponse>(url + ChainAPIMethods.VALIDATORS_LIST)
.get<IChainBlockInfoResponse>(url + ChainAPIMethods.BLOCK_INFO_HASH.replace('{blockHash}', hash))
.then((response) => response.data)
.catch(this.isApiError);
}

/**
* Get block information by hash
* Get block information by height
*
* @param url - API endpoint URL
* @param hash - block hash
* @param height - block height
*/
public static blockInfoHeight(url: string, height: number): Promise<IChainBlockInfoResponse> {
return axios
.get<IChainBlockInfoResponse>(url + ChainAPIMethods.BLOCK_INFO_HEIGHT.replace('{blockHeight}', height.toString()))
.then((response) => response.data)
.catch(this.isApiError);
}

/**
* Returns the list of blocks
*
* @param url - {string} url API endpoint URL
* @param params - The parameters to filter the blocks
*/
public static blockByHash(url: string, hash: string): Promise<IChainBlockInfoResponse> {
public static blocksList(
url: string,
params?: Partial<FetchTransactionsParametersWithPagination>
): Promise<IChainBlocksListResponse> {
const queryParams = this.createQueryParams(params);
return axios
.get<IChainBlockInfoResponse>(url + ChainAPIMethods.BLOCK_INFO_BY_HASH + '/' + hash)
.get<IChainBlocksListResponse>(url + ChainAPIMethods.BLOCK_LIST + (queryParams ? '?' + queryParams : ''))
.then((response) => response.data)
.catch(this.isApiError);
}
Expand Down
1 change: 1 addition & 0 deletions src/api/chain/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface Tx {
// collectFaucet: SetKeyKeeperTx;
// };
txInfo: IChainTxReference;
signature: string;
}

export interface VoteEnvelope {
Expand Down
9 changes: 7 additions & 2 deletions src/services/chain.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Service, ServiceProperties } from './service';
import { ChainAPI, IChainGetCostsResponse, IChainTxReference, PaginationRequest } from '../api';
import { ChainAPI, IChainGetCostsResponse, PaginationRequest, Tx } from '../api';
import invariant from 'tiny-invariant';
import { delay } from '../util/common';

Expand All @@ -12,7 +12,7 @@ interface ChainServiceProperties {
type ChainServiceParameters = ServiceProperties & ChainServiceProperties;

export type ChainCosts = IChainGetCostsResponse;
export type ChainTx = IChainTxReference;
export type ChainTx = Tx;

export type FetchOrganizationParametersWithPagination = FetchOrganizationParameters & PaginationRequest;
export type FetchFeesParametersWithPagination = FetchFeesParameters & PaginationRequest;
Expand All @@ -36,7 +36,12 @@ export interface FetchTransfersParameters {
}

export interface FetchTransactionsParameters {
hash: string;
height: number;
index: number;
type: string;
subtype: string;
signer: string;
}

/**
Expand Down
9 changes: 2 additions & 7 deletions test/api/chain.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import { ChainAPI, ErrAPI, ErrTransactionNotFound } from '../../src';
import { ChainAPI, ErrCantParseHexString, ErrTransactionNotFound } from '../../src';
// @ts-ignore
import { URL } from './util/client.params';

describe('Chain API tests', () => {
it('should throw when asking for an invalid transaction', async () => {
await expect(async () => {
await ChainAPI.txInfo(URL, '0xReallyBad');
}).rejects.toThrow(ErrAPI);
}).rejects.toThrow(ErrCantParseHexString);
}, 5000);
it('should throw when asking for a non existent transaction', async () => {
await expect(async () => {
await ChainAPI.txInfo(URL, '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
}).rejects.toThrow(ErrTransactionNotFound);
}, 5000);
it('should throw when asking for a non existent transaction by index', async () => {
await expect(async () => {
await ChainAPI.txByIndex(URL, 0);
}).rejects.toThrow(ErrTransactionNotFound);
}, 5000);
});
Loading