Skip to content

Commit 14805d5

Browse files
added executionresults index queries for blocks list
1 parent ce0e26f commit 14805d5

4 files changed

Lines changed: 72 additions & 1 deletion

File tree

src/common/indexer/elastic/elastic.indexer.service.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,19 @@ export class ElasticIndexerService implements IndexerInterface {
255255
return await this.elasticService.getItem('executionresults', 'hash', hash);
256256
}
257257

258+
async getExecutionResultsForHashes(hashes: string[]): Promise<Block[]> {
259+
if (!hashes || hashes.length === 0) {
260+
return [];
261+
}
262+
263+
const elasticQuery = ElasticQuery.create()
264+
.withPagination({ from: 0, size: hashes.length + 1 })
265+
.withShouldCondition(hashes.map(h => QueryType.Match('_id', h)));
266+
267+
// Map _id into "hash" on the response objects for easy joining
268+
return await this.elasticService.getList('executionresults', 'hash', elasticQuery);
269+
}
270+
258271
async getBlockByMiniBlockHash(miniBlockHash: string): Promise<Block | undefined> {
259272
const elasticQuery = ElasticQuery.create()
260273
.withCondition(QueryConditionOptions.must, [QueryType.Match('miniBlocksHashes', miniBlockHash)])

src/common/indexer/indexer.interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export interface IndexerInterface {
7676

7777
getExecutionResults(hash: string): Promise<Block>
7878

79+
getExecutionResultsForHashes(hashes: string[]): Promise<Block[]>
80+
7981
getBlockByMiniBlockHash(miniBlockHash: string): Promise<Block | undefined>
8082

8183
getMiniBlock(miniBlockHash: string): Promise<MiniBlock>

src/common/indexer/indexer.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ export class IndexerService implements IndexerInterface {
171171
return await this.indexerInterface.getExecutionResults(hash);
172172
}
173173

174+
@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
175+
async getExecutionResultsForHashes(hashes: string[]): Promise<Block[]> {
176+
return await this.indexerInterface.getExecutionResultsForHashes(hashes);
177+
}
178+
174179
@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
175180
async getBlockByMiniBlockHash(miniBlockHash: string): Promise<Block | undefined> {
176181
return await this.indexerInterface.getBlockByMiniBlockHash(miniBlockHash);

src/endpoints/blocks/block.service.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ import { IdentitiesService } from "../identities/identities.service";
1212
import { ApiConfigService } from "../../common/api-config/api.config.service";
1313
import { ConcurrencyUtils } from "src/utils/concurrency.utils";
1414
import { ApiUtils } from "@multiversx/sdk-nestjs-http";
15+
import { OriginLogger } from "@multiversx/sdk-nestjs-common";
1516
import { GatewayService } from "../../common/gateway/gateway.service";
1617

1718
@Injectable()
1819
export class BlockService {
20+
private readonly logger = new OriginLogger(BlockService.name);
21+
1922
constructor(
2023
private readonly indexerService: IndexerService,
2124
private readonly cachingService: CacheService,
@@ -39,6 +42,17 @@ export class BlockService {
3942
async getBlocks(filter: BlockFilter, queryPagination: QueryPagination, withProposerIdentity?: boolean): Promise<Block[]> {
4043
const result = await this.indexerService.getBlocks(filter, queryPagination);
4144

45+
// If Supernova is enabled for any of these blocks, bulk fetch execution results and merge them
46+
const execMap = await this.fetchExecutionResultsForBlocks(result as any[]);
47+
if (execMap.size > 0) {
48+
for (const item of result as any[]) {
49+
const er = execMap.get(item.hash);
50+
if (er) {
51+
ApiUtils.mergeObjects(item, er);
52+
}
53+
}
54+
}
55+
4256
const blocks = await Promise.all(result.map(async (item) => {
4357
const blockRaw = await this.computeProposerAndValidators(item);
4458

@@ -58,6 +72,43 @@ export class BlockService {
5872
return blocks;
5973
}
6074

75+
private async fetchExecutionResultsForBlocks(items: any[]): Promise<Map<string, any>> {
76+
const map = new Map<string, any>();
77+
if (!items || items.length === 0) {
78+
return map;
79+
}
80+
81+
const supernovaEnableEpoch = await this.getSupernovaEnableEpoch();
82+
if (supernovaEnableEpoch === -1) {
83+
return map;
84+
}
85+
86+
const eligible = items.filter((r: any) => (r?.epoch ?? -1) >= supernovaEnableEpoch);
87+
if (eligible.length === 0) {
88+
return map;
89+
}
90+
91+
const hashes = eligible.map((r: any) => r.hash).filter(Boolean);
92+
if (hashes.length === 0) {
93+
return map;
94+
}
95+
96+
try {
97+
const executionResults = await this.indexerService.getExecutionResultsForHashes(hashes);
98+
for (const er of executionResults as any[]) {
99+
if (er?.hash) {
100+
map.set(er.hash, er);
101+
}
102+
}
103+
this.logger.log(`Applied executionresults for ${map.size} blocks out of ${eligible.length}.`);
104+
} catch {
105+
// Keep endpoint resilient if executionresults index is unavailable
106+
return map;
107+
}
108+
109+
return map;
110+
}
111+
61112
private async applyProposerIdentity(blocks: Block[]): Promise<void> {
62113
const proposerBlses = blocks.map(x => x.proposer);
63114

@@ -176,7 +227,7 @@ export class BlockService {
176227

177228
async getSupernovaEnableEpoch(): Promise<number> {
178229
const enableEpochs = await this.getNetworkEnableEpochs();
179-
return enableEpochs["erd_supernova_enable_epoch"] ?? -1;
230+
return enableEpochs?.["erd_supernova_enable_epoch"] ?? -1;
180231
}
181232

182233
async getNetworkEnableEpochs(): Promise<Record<string, number>> {

0 commit comments

Comments
 (0)