Skip to content

Commit

Permalink
Merge pull request #1380 from multiversx/API-70-tx-pool-improvements
Browse files Browse the repository at this point in the history
API-70: improve tx pool endpoint
  • Loading branch information
bogdan-rosianu authored Nov 15, 2024
2 parents 6a03f1f + 396ba41 commit 3615ee8
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 24 deletions.
7 changes: 6 additions & 1 deletion src/common/gateway/entities/tx.in.pool.fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ export class TxInPoolFields {
data: string = '';
gaslimit: number = 0;
gasprice: number = 0;
guardian: string = '';
guardiansignature: string = '';
hash: string = '';
nonce: number = 0;
receiver: string = '';
receiverusername: string = '';
receivershard: number = 0;
receiverusername: string | null = '';
sender: string = '';
sendershard: number = 0;
signature: string = '';
value: string = '';
}
2 changes: 1 addition & 1 deletion src/common/gateway/gateway.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export class GatewayService {
}

async getTransactionPool(): Promise<TxPoolGatewayResponse> {
return await this.get(`transaction/pool?fields=nonce,sender,receiver,gaslimit,gasprice,receiverusername,data,value`, GatewayComponentRequest.transactionPool);
return await this.get(`transaction/pool?fields=*`, GatewayComponentRequest.transactionPool);
}

async getTransaction(txHash: string): Promise<Transaction | undefined> {
Expand Down
2 changes: 2 additions & 0 deletions src/endpoints/pool/entities/pool.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ export class PoolFilter {

sender?: string;
receiver?: string;
senderShard?: number;
receiverShard?: number;
type?: TransactionType;
}
15 changes: 15 additions & 0 deletions src/endpoints/pool/entities/transaction.in.pool.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ export class TransactionInPool {
@ApiProperty({ type: String, example: "alice.elrond" })
receiverUsername: string = '';

@ApiProperty({ type: String, example: "erd17rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rc0pu8s7rcqqkhty3" })
guardian: string = '';

@ApiProperty({ type: String, example: "0228618b6339c5eaf71ed1a8cd71df010ccd0369a29d957c37d53b0409408161726dd97e10ac7836996f666ffd636a797b9b9abecbd276971376fb3479b48203" })
guardianSignature: string = '';

@ApiProperty({ type: Number, example: 37 })
nonce: number = 0;

Expand All @@ -33,6 +39,15 @@ export class TransactionInPool {
@ApiProperty({ type: Number, example: 50000 })
gasLimit: number = 0;

@ApiProperty({ type: Number, example: 0 })
senderShard: number = 0;

@ApiProperty({ type: Number, example: 1 })
receiverShard: number = 0;

@ApiProperty({ type: String, example: "0228618b6339c5eaf71ed1a8cd71df010ccd0369a29d957c37d53b0409408161726dd97e10ac7836996f666ffd636a797b9b9abecbd276971376fb3479b48203" })
signature: string = '';

@ApiProperty({ type: String, example: "SmartContractResult" })
type: TransactionType = TransactionType.Transaction;
}
13 changes: 11 additions & 2 deletions src/endpoints/pool/pool.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,25 @@ export class PoolController {
@ApiQuery({ name: 'size', description: 'Number of items to retrieve', required: false })
@ApiQuery({ name: 'sender', description: 'Search in transaction pool by a specific sender', required: false })
@ApiQuery({ name: 'receiver', description: 'Search in transaction pool by a specific receiver', required: false })
@ApiQuery({ name: 'senderShard', description: 'The shard of the sender', required: false })
@ApiQuery({ name: 'receiverShard', description: 'The shard of the receiver', required: false })
@ApiQuery({ name: 'type', description: 'Search in transaction pool by type', required: false })
async getTransactionPool(
@Query('from', new DefaultValuePipe(0), ParseIntPipe) from: number,
@Query('size', new DefaultValuePipe(25), ParseIntPipe) size: number,
@Query('sender', ParseAddressAndMetachainPipe) sender?: string,
@Query('receiver', ParseAddressPipe) receiver?: string,
@Query('senderShard', ParseIntPipe) senderShard?: number,
@Query('receiverShard', ParseIntPipe) receiverShard?: number,
@Query('type', new ParseEnumPipe(TransactionType)) type?: TransactionType,
): Promise<TransactionInPool[]> {
return await this.poolService.getPool(new QueryPagination({ from, size }), new PoolFilter({ sender: sender, receiver: receiver, type: type }));
return await this.poolService.getPool(new QueryPagination({ from, size }), new PoolFilter({
sender: sender,
receiver: receiver,
senderShard: senderShard,
receiverShard: receiverShard,
type: type,
}));
}

@Get("/pool/count")
Expand Down Expand Up @@ -70,5 +80,4 @@ export class PoolController {

return transaction;
}

}
1 change: 1 addition & 0 deletions src/endpoints/pool/pool.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ import { PoolService } from "./pool.service";
PoolService,
],
})

export class PoolModule { }
50 changes: 38 additions & 12 deletions src/endpoints/pool/pool.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import { TransactionType } from "../transactions/entities/transaction.type";
import { TransactionInPool } from "./entities/transaction.in.pool.dto";
import { PoolFilter } from "./entities/pool.filter";
import { TxInPoolFields } from "src/common/gateway/entities/tx.in.pool.fields";
import { AddressUtils } from "@multiversx/sdk-nestjs-common";
import { ProtocolService } from "../../common/protocol/protocol.service";

@Injectable()
export class PoolService {
constructor(
private readonly gatewayService: GatewayService,
private readonly apiConfigService: ApiConfigService,
private readonly cacheService: CacheService,
private readonly protocolService: ProtocolService,
) { }

async getTransactionFromPool(txHash: string): Promise<TransactionInPool | undefined> {
Expand All @@ -38,7 +41,7 @@ export class PoolService {
return [];
}

const { from, size } = queryPagination;
const {from, size} = queryPagination;
const entirePool = await this.getEntirePool();
const pool = this.applyFilters(entirePool, filter);
return pool.slice(from, from + size);
Expand All @@ -48,7 +51,7 @@ export class PoolService {
return await this.cacheService.getOrSet(
CacheInfo.TransactionPool.key,
async () => await this.getTxPoolRaw(),
CacheInfo.TransactionPool.ttl
CacheInfo.TransactionPool.ttl,
);
}

Expand All @@ -57,41 +60,64 @@ export class PoolService {
return this.parseTransactions(pool);
}

private parseTransactions(rawPool: TxPoolGatewayResponse): TransactionInPool[] {
private async parseTransactions(rawPool: TxPoolGatewayResponse): Promise<TransactionInPool[]> {
const transactionPool: TransactionInPool[] = [];
if (rawPool && rawPool.txPool) {
transactionPool.push(...this.processTransactionType(rawPool.txPool.regularTransactions ?? [], TransactionType.Transaction));
transactionPool.push(...this.processTransactionType(rawPool.txPool.smartContractResults ?? [], TransactionType.SmartContractResult));
transactionPool.push(...this.processTransactionType(rawPool.txPool.rewards ?? [], TransactionType.Reward));

if (rawPool?.txPool) {
const regularTransactions = this.processTransactionsWithType(rawPool.txPool.regularTransactions ?? [], TransactionType.Transaction);
const smartContractResults = this.processTransactionsWithType(rawPool.txPool.smartContractResults ?? [], TransactionType.SmartContractResult);
const rewards = this.processTransactionsWithType(rawPool.txPool.rewards ?? [], TransactionType.Reward);

const allTransactions = await Promise.all([regularTransactions, smartContractResults, rewards]);

allTransactions.forEach(transactions => transactionPool.push(...transactions));
}

return transactionPool;
}

private processTransactionType(transactions: any[], transactionType: TransactionType): TransactionInPool[] {
return transactions.map(tx => this.parseTransaction(tx.txFields, transactionType));
// eslint-disable-next-line require-await
private async processTransactionsWithType(transactions: any[], transactionType: TransactionType): Promise<TransactionInPool[]> {
return Promise.all(transactions.map(tx => this.parseTransaction(tx.txFields, transactionType)));
}

private parseTransaction(tx: TxInPoolFields, type: TransactionType): TransactionInPool {
return new TransactionInPool({
private async parseTransaction(tx: TxInPoolFields, type: TransactionType): Promise<TransactionInPool> {
const transaction: TransactionInPool = new TransactionInPool({
txHash: tx.hash ?? '',
sender: tx.sender ?? '',
receiver: tx.receiver ?? '',
receiverUsername: tx.receiverusername ?? '',
nonce: tx.nonce ?? 0,
value: tx.value ?? '',
gasPrice: tx.gasprice ?? 0,
gasLimit: tx.gaslimit ?? 0,
data: tx.data ?? '',
guardian: tx.guardian ?? '',
guardianSignature: tx.guardiansignature ?? '',
signature: tx.signature ?? '',
type: type ?? TransactionType.Transaction,
});

// TODO: after gateway's /transaction/pool returns the sendershard and receivershard correctly, remove this computation
const shardCount = await this.protocolService.getShardCount();
if (transaction.sender) {
transaction.senderShard = AddressUtils.computeShard(AddressUtils.bech32Decode(transaction.sender), shardCount);
}
if (transaction.receiver) {
transaction.receiverShard = AddressUtils.computeShard(AddressUtils.bech32Decode(transaction.receiver), shardCount);
}

return transaction;
}

private applyFilters(pool: TransactionInPool[], filters: PoolFilter): TransactionInPool[] {
return pool.filter((transaction) => {
return (
(!filters.sender || transaction.sender === filters.sender) &&
(!filters.receiver || transaction.receiver === filters.receiver) &&
(!filters.type || transaction.type === filters.type)
(!filters.type || transaction.type === filters.type) &&
(filters.senderShard === undefined || transaction.senderShard === filters.senderShard) &&
(filters.receiverShard === undefined || transaction.receiverShard === filters.receiverShard)
);
});
}
Expand Down
21 changes: 13 additions & 8 deletions src/test/mocks/pool.mock.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@
"regularTransactions": [
{
"txFields": {
"data": "",
"gaslimit": 0,
"gasprice": 0,
"hash": "9aea74b81373148be892539944d60d1dda839028dfb700283a46e026afe4a4f0",
"nonce": 100,
"receiver": "erd104jng7d9s3z2t096tt6n23kyr7a96qr90dknde4xftrlw32yfejq743kpz",
"data": "c2V0U3BlY2lhbFJvbGVANGU0NjU0MmQ2MjM0NjQzNjYzMzJANzVjYjg3YzI0MzUxYTY3Yjg5MmY1N2RjZWMwZWIyYjJhMDdhYWZhYjJmMWFhYjc0MWExMGZjNjEwNTlmMmZlOEA0NTUzNDQ1NDUyNmY2YzY1NGU0NjU0NDM3MjY1NjE3NDY1",
"gaslimit": 60000000,
"gasprice": 1000000000,
"guardian": "erd104jng7d9s3z2t096tt6n23kyr7a96qr90dknde4xftrlw32yfejq743kpz",
"guardiansignature": "erd104jng7d9s3z2t096tt6n23kyr7a96qr90dknde4xftrlw32yfejq743kpz",
"hash": "67814fdea41ad82f6a2c26d18d1e2f85253b72b81bf7adbfffd5f05bfe389d1d",
"nonce": 7774,
"receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u",
"receivershard": 4294967295,
"receiverusername": null,
"sender": "erd104jng7d9s3z2t096tt6n23kyr7a96qr90dknde4xftrlw32yfejq743kpz",
"value": "1976424131604696600"
"sender": "erd1wh9c0sjr2xn8hzf02lwwcr4jk2s84tat9ud2kaq6zr7xzpvl9l5q8awmex",
"sendershard": 0,
"signature": "erd104jng7d9s3z2t096tt6n23kyr7a96qr90dknde4xftrlw32yfejq743kpz",
"value": "0"
}
}
],
Expand Down
7 changes: 7 additions & 0 deletions src/test/unit/services/pool.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { GatewayService } from "src/common/gateway/gateway.service";
import { PoolFilter } from "src/endpoints/pool/entities/pool.filter";
import { PoolService } from "src/endpoints/pool/pool.service";
import { TransactionType } from "src/endpoints/transactions/entities/transaction.type";
import { ProtocolService } from "../../../common/protocol/protocol.service";

describe('PoolService', () => {
let service: PoolService;
Expand All @@ -28,6 +29,12 @@ describe('PoolService', () => {
getOrSet: jest.fn(),
},
},
{
provide: ProtocolService,
useValue: {
getShardCount: jest.fn(),
},
},
{
provide: ApiConfigService,
useValue: {
Expand Down

0 comments on commit 3615ee8

Please sign in to comment.