@substrate/api-sidecar 20.12.0 → 20.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/package.json +5 -5
- package/build/src/controllers/accounts/AccountsVestingInfoController.d.ts +18 -3
- package/build/src/controllers/accounts/AccountsVestingInfoController.js +24 -6
- package/build/src/controllers/accounts/AccountsVestingInfoController.js.map +1 -1
- package/build/src/controllers/rc/accounts/RcAccountsVestingInfoController.d.ts +12 -1
- package/build/src/controllers/rc/accounts/RcAccountsVestingInfoController.js +15 -3
- package/build/src/controllers/rc/accounts/RcAccountsVestingInfoController.js.map +1 -1
- package/build/src/services/accounts/AccountsVestingInfoService.d.ts +42 -1
- package/build/src/services/accounts/AccountsVestingInfoService.js +236 -5
- package/build/src/services/accounts/AccountsVestingInfoService.js.map +1 -1
- package/build/src/services/paras/ParasInclusionService.d.ts +3 -11
- package/build/src/services/paras/ParasInclusionService.js +7 -60
- package/build/src/services/paras/ParasInclusionService.js.map +1 -1
- package/build/src/types/responses/AccountVestingInfo.d.ts +56 -1
- package/build/src/util/relay/getRelayParentNumber.d.ts +80 -0
- package/build/src/util/relay/getRelayParentNumber.js +170 -0
- package/build/src/util/relay/getRelayParentNumber.js.map +1 -0
- package/build/src/util/relay/getRelayParentNumber.spec.d.ts +1 -0
- package/build/src/util/relay/getRelayParentNumber.spec.js +201 -0
- package/build/src/util/relay/getRelayParentNumber.spec.js.map +1 -0
- package/build/src/util/vesting/vestingCalculations.d.ts +87 -0
- package/build/src/util/vesting/vestingCalculations.js +141 -0
- package/build/src/util/vesting/vestingCalculations.js.map +1 -0
- package/build/src/util/vesting/vestingCalculations.spec.d.ts +1 -0
- package/build/src/util/vesting/vestingCalculations.spec.js +335 -0
- package/build/src/util/vesting/vestingCalculations.spec.js.map +1 -0
- package/package.json +5 -5
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.ParasInclusionService = void 0;
|
|
19
19
|
const apiRegistry_1 = require("../../apiRegistry");
|
|
20
|
+
const getRelayParentNumber_1 = require("../../util/relay/getRelayParentNumber");
|
|
20
21
|
const AbstractService_1 = require("../AbstractService");
|
|
21
22
|
class ParasInclusionService extends AbstractService_1.AbstractService {
|
|
22
23
|
constructor(api) {
|
|
@@ -25,8 +26,9 @@ class ParasInclusionService extends AbstractService_1.AbstractService {
|
|
|
25
26
|
/**
|
|
26
27
|
* Find the relay chain inclusion information for a specific parachain block.
|
|
27
28
|
*
|
|
28
|
-
* @param hash - The
|
|
29
|
-
* @param
|
|
29
|
+
* @param hash - The parachain block hash
|
|
30
|
+
* @param paraId - The parachain ID
|
|
31
|
+
* @param number - The parachain block number
|
|
30
32
|
* @param depth - Search depth (defaults to 10)
|
|
31
33
|
*/
|
|
32
34
|
async getParachainInclusion(hash, paraId, number, depth = 10) {
|
|
@@ -36,19 +38,11 @@ class ParasInclusionService extends AbstractService_1.AbstractService {
|
|
|
36
38
|
if (!rcApi) {
|
|
37
39
|
throw new Error('Relay chain api must be available');
|
|
38
40
|
}
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
return ext.method.method.toString() === 'setValidationData';
|
|
42
|
-
});
|
|
43
|
-
if (!setValidationData) {
|
|
44
|
-
throw new Error("Block contains no set validation data. Can't find relayParentNumber");
|
|
45
|
-
}
|
|
46
|
-
const callArgs = apiAt.registry.createType('Call', setValidationData.method);
|
|
47
|
-
const { relayParentNumber } = callArgs.toJSON().args.data.validationData;
|
|
41
|
+
// Extract relay parent number from the parachain block
|
|
42
|
+
const relayParentNumber = await (0, getRelayParentNumber_1.getRelayParentNumberRaw)(api, hash);
|
|
48
43
|
// Search for inclusion starting from relay_parent_number + 1
|
|
49
|
-
const inclusionNumber = await
|
|
44
|
+
const inclusionNumber = await (0, getRelayParentNumber_1.searchForInclusionBlock)(rcApi, paraId.toNumber(), number, // parachain block number
|
|
50
45
|
relayParentNumber, depth);
|
|
51
|
-
// For now, return a placeholder response
|
|
52
46
|
return {
|
|
53
47
|
parachainBlock: parseInt(number, 10),
|
|
54
48
|
parachainBlockHash: hash.toString(),
|
|
@@ -58,53 +52,6 @@ class ParasInclusionService extends AbstractService_1.AbstractService {
|
|
|
58
52
|
found: inclusionNumber !== null,
|
|
59
53
|
};
|
|
60
54
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Search relay chain blocks for inclusion of a specific parachain block
|
|
63
|
-
* Uses optimized candidate_events runtime API when available, falls back to system events for historical support
|
|
64
|
-
*/
|
|
65
|
-
async searchForInclusion(rcApi, paraId, parachainBlockNumber, relayParentNumber, maxDepth) {
|
|
66
|
-
return this.searchWithSystemEvents(rcApi, paraId, parachainBlockNumber, relayParentNumber, maxDepth);
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Search using system events
|
|
70
|
-
*/
|
|
71
|
-
async searchWithSystemEvents(rcApi, paraId, parachainBlockNumber, relayParentNumber, maxDepth) {
|
|
72
|
-
// The number is 5 here since most searches are relative to 2-4 blocks from the `relayParentNumber`.
|
|
73
|
-
// Therefore we give 1 extra block for extra room, while also minimizing the amount of searches we do.
|
|
74
|
-
const BATCH_SIZE = 5;
|
|
75
|
-
// Search in batches of 5 for optimal performance
|
|
76
|
-
for (let offset = 0; offset < maxDepth; offset += BATCH_SIZE) {
|
|
77
|
-
const batchSize = Math.min(BATCH_SIZE, maxDepth - offset);
|
|
78
|
-
const searchBlocks = Array.from({ length: batchSize }, (_, i) => relayParentNumber + offset + i + 1);
|
|
79
|
-
const searchPromises = searchBlocks.map(async (blockNum) => {
|
|
80
|
-
try {
|
|
81
|
-
const relayBlockHash = await rcApi.rpc.chain.getBlockHash(blockNum);
|
|
82
|
-
const rcApiAt = await rcApi.at(relayBlockHash);
|
|
83
|
-
const events = await rcApiAt.query.system.events();
|
|
84
|
-
const foundInclusion = events.find((record) => {
|
|
85
|
-
if (record.event.section === 'paraInclusion' && record.event.method === 'CandidateIncluded') {
|
|
86
|
-
const eventData = record.event.data[0].toJSON();
|
|
87
|
-
if (eventData.descriptor.paraId === paraId) {
|
|
88
|
-
const header = rcApiAt.registry.createType('Header', record.event.data[1]);
|
|
89
|
-
return header.number.toString() === parachainBlockNumber;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
});
|
|
94
|
-
return foundInclusion ? blockNum : null;
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
const results = await Promise.all(searchPromises);
|
|
101
|
-
const found = results.find((result) => result !== null);
|
|
102
|
-
if (found) {
|
|
103
|
-
return found; // Early termination when found in this batch
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return null; // Not found within search depth
|
|
107
|
-
}
|
|
108
55
|
}
|
|
109
56
|
exports.ParasInclusionService = ParasInclusionService;
|
|
110
57
|
//# sourceMappingURL=ParasInclusionService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParasInclusionService.js","sourceRoot":"","sources":["../../../../src/services/paras/ParasInclusionService.ts"],"names":[],"mappings":";AAAA,oDAAoD;AACpD,8CAA8C;AAC9C,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,oEAAoE;AACpE,sCAAsC;AACtC,EAAE;AACF,kEAAkE;AAClE,iEAAiE;AACjE,gEAAgE;AAChE,+CAA+C;AAC/C,EAAE;AACF,oEAAoE;AACpE,wEAAwE;;;
|
|
1
|
+
{"version":3,"file":"ParasInclusionService.js","sourceRoot":"","sources":["../../../../src/services/paras/ParasInclusionService.ts"],"names":[],"mappings":";AAAA,oDAAoD;AACpD,8CAA8C;AAC9C,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,oEAAoE;AACpE,sCAAsC;AACtC,EAAE;AACF,kEAAkE;AAClE,iEAAiE;AACjE,gEAAgE;AAChE,+CAA+C;AAC/C,EAAE;AACF,oEAAoE;AACpE,wEAAwE;;;AAKxE,mDAAuD;AAEvD,gFAAyG;AACzG,wDAAqD;AAErD,MAAa,qBAAsB,SAAQ,iCAAe;IACzD,YAAY,GAAW;QACtB,KAAK,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,qBAAqB,CAAC,IAAe,EAAE,MAAW,EAAE,MAAc,EAAE,KAAK,GAAG,EAAE;;QACnF,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACrB,MAAM,KAAK,GAAG,MAAA,gCAAkB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,0CAAE,GAAG,CAAC;QAE/D,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACtD,CAAC;QAED,uDAAuD;QACvD,MAAM,iBAAiB,GAAG,MAAM,IAAA,8CAAuB,EAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAEnE,6DAA6D;QAC7D,MAAM,eAAe,GAAG,MAAM,IAAA,8CAAuB,EACpD,KAAK,EACL,MAAM,CAAC,QAAQ,EAAE,EACjB,MAAM,EAAE,yBAAyB;QACjC,iBAAiB,EACjB,KAAK,CACL,CAAC;QAEF,OAAO;YACN,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YACpC,kBAAkB,EAAE,IAAI,CAAC,QAAQ,EAAE;YACnC,WAAW,EAAE,MAAM,CAAC,QAAQ,EAAE;YAC9B,iBAAiB;YACjB,eAAe,EAAE,eAAe,IAAI,IAAI;YACxC,KAAK,EAAE,eAAe,KAAK,IAAI;SAC/B,CAAC;IACH,CAAC;CACD;AA1CD,sDA0CC"}
|
|
@@ -1,10 +1,65 @@
|
|
|
1
1
|
import { Option } from '@polkadot/types/codec';
|
|
2
2
|
import { VestingInfo } from '@polkadot/types/interfaces';
|
|
3
3
|
import { IAt } from '.';
|
|
4
|
+
/**
|
|
5
|
+
* Vesting schedule with calculated vested amount.
|
|
6
|
+
* Extends the base VestingInfo with additional computed fields.
|
|
7
|
+
*/
|
|
8
|
+
export interface IVestingSchedule {
|
|
9
|
+
/** Total amount of tokens locked at the start of vesting */
|
|
10
|
+
locked: string;
|
|
11
|
+
/** Number of tokens that unlock per block */
|
|
12
|
+
perBlock: string;
|
|
13
|
+
/** Block number when vesting/unlocking begins */
|
|
14
|
+
startingBlock: string;
|
|
15
|
+
/** Amount that has vested based on time elapsed at the queried block */
|
|
16
|
+
vested: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Indicates which chain's block number was used for vesting calculations.
|
|
20
|
+
* - 'relay': Relay chain block number (used for Asset Hub post-migration)
|
|
21
|
+
* - 'self': The queried chain's own block number (used for relay chain pre-migration)
|
|
22
|
+
*/
|
|
23
|
+
export type BlockNumberSource = 'relay' | 'self';
|
|
4
24
|
export interface IAccountVestingInfo {
|
|
5
25
|
at: IAt;
|
|
6
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Array of vesting schedules for the account.
|
|
28
|
+
* Can be raw VestingInfo from the pallet or enhanced IVestingSchedule with vested amounts.
|
|
29
|
+
*/
|
|
30
|
+
vesting: Option<VestingInfo> | IVestingSchedule[] | {};
|
|
31
|
+
/**
|
|
32
|
+
* Total amount that has vested across all schedules (sum of per-schedule vested).
|
|
33
|
+
* Only present when vesting calculations are performed.
|
|
34
|
+
*/
|
|
35
|
+
vestedBalance?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Total locked amount across all vesting schedules.
|
|
38
|
+
* Only present when vesting calculations are performed.
|
|
39
|
+
*/
|
|
40
|
+
vestingTotal?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Actual amount that can be claimed/unlocked right now.
|
|
43
|
+
* Calculated as: vestingLocked - (vestingTotal - vestedBalance)
|
|
44
|
+
* This accounts for previous claims that reduced the on-chain lock.
|
|
45
|
+
* Only present when vesting calculations are performed.
|
|
46
|
+
*/
|
|
47
|
+
vestedClaimable?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The block number used for calculating vested amounts.
|
|
50
|
+
* For Asset Hub post-migration, this is the relay chain block number.
|
|
51
|
+
* For relay chain pre-migration, this is the queried block number.
|
|
52
|
+
*/
|
|
53
|
+
blockNumberForCalculation?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Indicates which chain's block number was used for the calculation.
|
|
56
|
+
* 'relay' for Asset Hub post-migration, 'self' for relay chain pre-migration.
|
|
57
|
+
*/
|
|
58
|
+
blockNumberSource?: BlockNumberSource;
|
|
59
|
+
/** Relay chain block hash (when using useRcBlock parameter) */
|
|
7
60
|
rcBlockHash?: string;
|
|
61
|
+
/** Relay chain block number (when using useRcBlock parameter) */
|
|
8
62
|
rcBlockNumber?: string;
|
|
63
|
+
/** Asset Hub timestamp (when using useRcBlock parameter) */
|
|
9
64
|
ahTimestamp?: string;
|
|
10
65
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ApiPromise } from '@polkadot/api';
|
|
2
|
+
import { BlockHash } from '@polkadot/types/interfaces';
|
|
3
|
+
import BN from 'bn.js';
|
|
4
|
+
/**
|
|
5
|
+
* Result of searching for a parachain block's inclusion on the relay chain.
|
|
6
|
+
*/
|
|
7
|
+
export interface IInclusionSearchResult {
|
|
8
|
+
/** The relay chain block number where the parachain block was included */
|
|
9
|
+
inclusionBlockNumber: number | null;
|
|
10
|
+
/** The relay parent number from setValidationData */
|
|
11
|
+
relayParentNumber: number;
|
|
12
|
+
/** Whether the inclusion was found */
|
|
13
|
+
found: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Extract the relay chain parent block number from a parachain block.
|
|
17
|
+
*
|
|
18
|
+
* Parachain blocks contain a `parachainSystem.setValidationData` extrinsic that
|
|
19
|
+
* includes the relay chain block number that was the parent when the parachain
|
|
20
|
+
* block was created.
|
|
21
|
+
*
|
|
22
|
+
* Note: This is the relay PARENT, not the inclusion block. For the actual
|
|
23
|
+
* inclusion block, use `getInclusionBlockNumber` or `searchForInclusionBlock`.
|
|
24
|
+
*
|
|
25
|
+
* @param api - The ApiPromise instance connected to the parachain
|
|
26
|
+
* @param blockHash - The hash of the parachain block to extract relay parent from
|
|
27
|
+
* @returns The relay chain parent block number as a BN
|
|
28
|
+
* @throws Error if the block doesn't contain setValidationData extrinsic
|
|
29
|
+
*/
|
|
30
|
+
export declare const getRelayParentNumber: (api: ApiPromise, blockHash: BlockHash) => Promise<BN>;
|
|
31
|
+
/**
|
|
32
|
+
* Extract relay parent number as a plain number (for use with search functions).
|
|
33
|
+
*
|
|
34
|
+
* @param api - The ApiPromise instance connected to the parachain
|
|
35
|
+
* @param blockHash - The hash of the parachain block
|
|
36
|
+
* @returns The relay chain parent block number as a number
|
|
37
|
+
*/
|
|
38
|
+
export declare const getRelayParentNumberRaw: (api: ApiPromise, blockHash: BlockHash) => Promise<number>;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a block contains the setValidationData extrinsic.
|
|
41
|
+
*
|
|
42
|
+
* This can be used to determine if a block is from a parachain (has validation data)
|
|
43
|
+
* or a relay chain (does not have validation data).
|
|
44
|
+
*
|
|
45
|
+
* @param api - The ApiPromise instance
|
|
46
|
+
* @param blockHash - The hash of the block to check
|
|
47
|
+
* @returns true if the block contains setValidationData, false otherwise
|
|
48
|
+
*/
|
|
49
|
+
export declare const hasRelayParentData: (api: ApiPromise, blockHash: BlockHash) => Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Search relay chain blocks for the inclusion of a specific parachain block.
|
|
52
|
+
*
|
|
53
|
+
* This searches relay chain blocks starting from `relayParentNumber + 1` looking
|
|
54
|
+
* for a `paraInclusion.CandidateIncluded` event that matches the given parachain
|
|
55
|
+
* block number and paraId.
|
|
56
|
+
*
|
|
57
|
+
* @param rcApi - The ApiPromise instance connected to the relay chain
|
|
58
|
+
* @param paraId - The parachain ID (e.g., 1000 for Asset Hub)
|
|
59
|
+
* @param parachainBlockNumber - The parachain block number to search for
|
|
60
|
+
* @param relayParentNumber - The relay parent number from setValidationData
|
|
61
|
+
* @param maxDepth - Maximum number of relay blocks to search (default: 10)
|
|
62
|
+
* @returns The relay chain block number where inclusion was found, or null if not found
|
|
63
|
+
*/
|
|
64
|
+
export declare const searchForInclusionBlock: (rcApi: ApiPromise, paraId: number, parachainBlockNumber: string, relayParentNumber: number, maxDepth?: number) => Promise<number | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Get the relay chain block number where a parachain block was included.
|
|
67
|
+
*
|
|
68
|
+
* This is the main function for finding the accurate relay chain block number
|
|
69
|
+
* corresponding to a parachain block. It:
|
|
70
|
+
* 1. Extracts the relayParentNumber from the parachain block's setValidationData
|
|
71
|
+
* 2. Searches relay chain blocks for the actual inclusion event
|
|
72
|
+
*
|
|
73
|
+
* @param parachainApi - The ApiPromise instance connected to the parachain
|
|
74
|
+
* @param rcApi - The ApiPromise instance connected to the relay chain
|
|
75
|
+
* @param parachainBlockHash - The hash of the parachain block
|
|
76
|
+
* @param paraId - The parachain ID (e.g., 1000 for Asset Hub)
|
|
77
|
+
* @param maxDepth - Maximum number of relay blocks to search (default: 10)
|
|
78
|
+
* @returns The inclusion search result with inclusionBlockNumber, relayParentNumber, and found status
|
|
79
|
+
*/
|
|
80
|
+
export declare const getInclusionBlockNumber: (parachainApi: ApiPromise, rcApi: ApiPromise, parachainBlockHash: BlockHash, paraId: number, maxDepth?: number) => Promise<IInclusionSearchResult>;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2017-2025 Parity Technologies (UK) Ltd.
|
|
3
|
+
// This file is part of Substrate API Sidecar.
|
|
4
|
+
//
|
|
5
|
+
// Substrate API Sidecar is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU General Public License
|
|
16
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.getInclusionBlockNumber = exports.searchForInclusionBlock = exports.hasRelayParentData = exports.getRelayParentNumberRaw = exports.getRelayParentNumber = void 0;
|
|
22
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
23
|
+
/** Default search depth for inclusion search */
|
|
24
|
+
const DEFAULT_SEARCH_DEPTH = 10;
|
|
25
|
+
/** Batch size for parallel searches */
|
|
26
|
+
const BATCH_SIZE = 5;
|
|
27
|
+
/**
|
|
28
|
+
* Extract the relay chain parent block number from a parachain block.
|
|
29
|
+
*
|
|
30
|
+
* Parachain blocks contain a `parachainSystem.setValidationData` extrinsic that
|
|
31
|
+
* includes the relay chain block number that was the parent when the parachain
|
|
32
|
+
* block was created.
|
|
33
|
+
*
|
|
34
|
+
* Note: This is the relay PARENT, not the inclusion block. For the actual
|
|
35
|
+
* inclusion block, use `getInclusionBlockNumber` or `searchForInclusionBlock`.
|
|
36
|
+
*
|
|
37
|
+
* @param api - The ApiPromise instance connected to the parachain
|
|
38
|
+
* @param blockHash - The hash of the parachain block to extract relay parent from
|
|
39
|
+
* @returns The relay chain parent block number as a BN
|
|
40
|
+
* @throws Error if the block doesn't contain setValidationData extrinsic
|
|
41
|
+
*/
|
|
42
|
+
const getRelayParentNumber = async (api, blockHash) => {
|
|
43
|
+
const [apiAt, { block }] = await Promise.all([api.at(blockHash), api.rpc.chain.getBlock(blockHash)]);
|
|
44
|
+
const setValidationData = block.extrinsics.find((ext) => {
|
|
45
|
+
return ext.method.method.toString() === 'setValidationData';
|
|
46
|
+
});
|
|
47
|
+
if (!setValidationData) {
|
|
48
|
+
throw new Error('Block does not contain setValidationData extrinsic. Cannot determine relay parent number.');
|
|
49
|
+
}
|
|
50
|
+
const callArgs = apiAt.registry.createType('Call', setValidationData.method);
|
|
51
|
+
const { relayParentNumber } = callArgs.toJSON().args.data.validationData;
|
|
52
|
+
return new bn_js_1.default(relayParentNumber);
|
|
53
|
+
};
|
|
54
|
+
exports.getRelayParentNumber = getRelayParentNumber;
|
|
55
|
+
/**
|
|
56
|
+
* Extract relay parent number as a plain number (for use with search functions).
|
|
57
|
+
*
|
|
58
|
+
* @param api - The ApiPromise instance connected to the parachain
|
|
59
|
+
* @param blockHash - The hash of the parachain block
|
|
60
|
+
* @returns The relay chain parent block number as a number
|
|
61
|
+
*/
|
|
62
|
+
const getRelayParentNumberRaw = async (api, blockHash) => {
|
|
63
|
+
const [apiAt, { block }] = await Promise.all([api.at(blockHash), api.rpc.chain.getBlock(blockHash)]);
|
|
64
|
+
const setValidationData = block.extrinsics.find((ext) => {
|
|
65
|
+
return ext.method.method.toString() === 'setValidationData';
|
|
66
|
+
});
|
|
67
|
+
if (!setValidationData) {
|
|
68
|
+
throw new Error('Block does not contain setValidationData extrinsic. Cannot determine relay parent number.');
|
|
69
|
+
}
|
|
70
|
+
const callArgs = apiAt.registry.createType('Call', setValidationData.method);
|
|
71
|
+
const { relayParentNumber } = callArgs.toJSON().args.data.validationData;
|
|
72
|
+
return relayParentNumber;
|
|
73
|
+
};
|
|
74
|
+
exports.getRelayParentNumberRaw = getRelayParentNumberRaw;
|
|
75
|
+
/**
|
|
76
|
+
* Check if a block contains the setValidationData extrinsic.
|
|
77
|
+
*
|
|
78
|
+
* This can be used to determine if a block is from a parachain (has validation data)
|
|
79
|
+
* or a relay chain (does not have validation data).
|
|
80
|
+
*
|
|
81
|
+
* @param api - The ApiPromise instance
|
|
82
|
+
* @param blockHash - The hash of the block to check
|
|
83
|
+
* @returns true if the block contains setValidationData, false otherwise
|
|
84
|
+
*/
|
|
85
|
+
const hasRelayParentData = async (api, blockHash) => {
|
|
86
|
+
const { block } = await api.rpc.chain.getBlock(blockHash);
|
|
87
|
+
return block.extrinsics.some((ext) => ext.method.method.toString() === 'setValidationData');
|
|
88
|
+
};
|
|
89
|
+
exports.hasRelayParentData = hasRelayParentData;
|
|
90
|
+
/**
|
|
91
|
+
* Search relay chain blocks for the inclusion of a specific parachain block.
|
|
92
|
+
*
|
|
93
|
+
* This searches relay chain blocks starting from `relayParentNumber + 1` looking
|
|
94
|
+
* for a `paraInclusion.CandidateIncluded` event that matches the given parachain
|
|
95
|
+
* block number and paraId.
|
|
96
|
+
*
|
|
97
|
+
* @param rcApi - The ApiPromise instance connected to the relay chain
|
|
98
|
+
* @param paraId - The parachain ID (e.g., 1000 for Asset Hub)
|
|
99
|
+
* @param parachainBlockNumber - The parachain block number to search for
|
|
100
|
+
* @param relayParentNumber - The relay parent number from setValidationData
|
|
101
|
+
* @param maxDepth - Maximum number of relay blocks to search (default: 10)
|
|
102
|
+
* @returns The relay chain block number where inclusion was found, or null if not found
|
|
103
|
+
*/
|
|
104
|
+
const searchForInclusionBlock = async (rcApi, paraId, parachainBlockNumber, relayParentNumber, maxDepth = DEFAULT_SEARCH_DEPTH) => {
|
|
105
|
+
// Search in batches for optimal performance
|
|
106
|
+
// Most inclusions happen within 2-4 blocks of relayParentNumber
|
|
107
|
+
for (let offset = 0; offset < maxDepth; offset += BATCH_SIZE) {
|
|
108
|
+
const batchSize = Math.min(BATCH_SIZE, maxDepth - offset);
|
|
109
|
+
const searchBlocks = Array.from({ length: batchSize }, (_, i) => relayParentNumber + offset + i + 1);
|
|
110
|
+
const searchPromises = searchBlocks.map(async (blockNum) => {
|
|
111
|
+
try {
|
|
112
|
+
const relayBlockHash = await rcApi.rpc.chain.getBlockHash(blockNum);
|
|
113
|
+
const rcApiAt = await rcApi.at(relayBlockHash);
|
|
114
|
+
const events = await rcApiAt.query.system.events();
|
|
115
|
+
const foundInclusion = events.find((record) => {
|
|
116
|
+
if (record.event.section === 'paraInclusion' && record.event.method === 'CandidateIncluded') {
|
|
117
|
+
const eventData = record.event.data[0].toJSON();
|
|
118
|
+
if (eventData.descriptor.paraId === paraId) {
|
|
119
|
+
const header = rcApiAt.registry.createType('Header', record.event.data[1]);
|
|
120
|
+
return header.number.toString() === parachainBlockNumber;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
});
|
|
125
|
+
return foundInclusion ? blockNum : null;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const results = await Promise.all(searchPromises);
|
|
132
|
+
const found = results.find((result) => result !== null);
|
|
133
|
+
if (found) {
|
|
134
|
+
return found; // Early termination when found in this batch
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null; // Not found within search depth
|
|
138
|
+
};
|
|
139
|
+
exports.searchForInclusionBlock = searchForInclusionBlock;
|
|
140
|
+
/**
|
|
141
|
+
* Get the relay chain block number where a parachain block was included.
|
|
142
|
+
*
|
|
143
|
+
* This is the main function for finding the accurate relay chain block number
|
|
144
|
+
* corresponding to a parachain block. It:
|
|
145
|
+
* 1. Extracts the relayParentNumber from the parachain block's setValidationData
|
|
146
|
+
* 2. Searches relay chain blocks for the actual inclusion event
|
|
147
|
+
*
|
|
148
|
+
* @param parachainApi - The ApiPromise instance connected to the parachain
|
|
149
|
+
* @param rcApi - The ApiPromise instance connected to the relay chain
|
|
150
|
+
* @param parachainBlockHash - The hash of the parachain block
|
|
151
|
+
* @param paraId - The parachain ID (e.g., 1000 for Asset Hub)
|
|
152
|
+
* @param maxDepth - Maximum number of relay blocks to search (default: 10)
|
|
153
|
+
* @returns The inclusion search result with inclusionBlockNumber, relayParentNumber, and found status
|
|
154
|
+
*/
|
|
155
|
+
const getInclusionBlockNumber = async (parachainApi, rcApi, parachainBlockHash, paraId, maxDepth = DEFAULT_SEARCH_DEPTH) => {
|
|
156
|
+
// Get the parachain block header to get the block number
|
|
157
|
+
const header = await parachainApi.rpc.chain.getHeader(parachainBlockHash);
|
|
158
|
+
const parachainBlockNumber = header.number.unwrap().toString();
|
|
159
|
+
// Extract relay parent number from the parachain block
|
|
160
|
+
const relayParentNumber = await (0, exports.getRelayParentNumberRaw)(parachainApi, parachainBlockHash);
|
|
161
|
+
// Search for the actual inclusion block
|
|
162
|
+
const inclusionBlockNumber = await (0, exports.searchForInclusionBlock)(rcApi, paraId, parachainBlockNumber, relayParentNumber, maxDepth);
|
|
163
|
+
return {
|
|
164
|
+
inclusionBlockNumber,
|
|
165
|
+
relayParentNumber,
|
|
166
|
+
found: inclusionBlockNumber !== null,
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
exports.getInclusionBlockNumber = getInclusionBlockNumber;
|
|
170
|
+
//# sourceMappingURL=getRelayParentNumber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRelayParentNumber.js","sourceRoot":"","sources":["../../../../src/util/relay/getRelayParentNumber.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2017-2025 Parity Technologies (UK) Ltd.
|
|
3
|
+
// This file is part of Substrate API Sidecar.
|
|
4
|
+
//
|
|
5
|
+
// Substrate API Sidecar is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU General Public License
|
|
16
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
22
|
+
const registries_1 = require("../../test-helpers/registries");
|
|
23
|
+
const getRelayParentNumber_1 = require("./getRelayParentNumber");
|
|
24
|
+
const mockBlockHash = registries_1.polkadotRegistry.createType('BlockHash', '0x7b713de604a99857f6c25eacc115a4f28d2611a23d9ddff99ab0e4f1c17a8578');
|
|
25
|
+
const mockRelayParentNumber = 28500000;
|
|
26
|
+
/**
|
|
27
|
+
* Create a mock extrinsic that simulates setValidationData
|
|
28
|
+
*/
|
|
29
|
+
const createMockSetValidationDataExtrinsic = () => ({
|
|
30
|
+
method: {
|
|
31
|
+
method: {
|
|
32
|
+
toString: () => 'setValidationData',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Create a mock extrinsic that is NOT setValidationData
|
|
38
|
+
*/
|
|
39
|
+
const createMockOtherExtrinsic = (methodName) => ({
|
|
40
|
+
method: {
|
|
41
|
+
method: {
|
|
42
|
+
toString: () => methodName,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Create a mock registry.createType that returns the expected structure
|
|
48
|
+
*/
|
|
49
|
+
const createMockCreateType = (relayParentNumber) => {
|
|
50
|
+
return (_typeName, _data) => ({
|
|
51
|
+
toJSON: () => ({
|
|
52
|
+
args: {
|
|
53
|
+
data: {
|
|
54
|
+
validationData: {
|
|
55
|
+
relayParentNumber,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
describe('getRelayParentNumber', () => {
|
|
63
|
+
describe('getRelayParentNumber', () => {
|
|
64
|
+
it('should extract relay parent number from a parachain block', async () => {
|
|
65
|
+
const mockApiAt = {
|
|
66
|
+
registry: {
|
|
67
|
+
createType: createMockCreateType(mockRelayParentNumber),
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const mockAt = jest.fn().mockResolvedValue(mockApiAt);
|
|
71
|
+
const mockGetBlock = jest.fn().mockResolvedValue({
|
|
72
|
+
block: {
|
|
73
|
+
extrinsics: [
|
|
74
|
+
createMockOtherExtrinsic('timestamp'),
|
|
75
|
+
createMockSetValidationDataExtrinsic(),
|
|
76
|
+
createMockOtherExtrinsic('transfer'),
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
const mockApi = {
|
|
81
|
+
at: mockAt,
|
|
82
|
+
rpc: {
|
|
83
|
+
chain: {
|
|
84
|
+
getBlock: mockGetBlock,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
const result = await (0, getRelayParentNumber_1.getRelayParentNumber)(mockApi, mockBlockHash);
|
|
89
|
+
expect(result).toBeInstanceOf(bn_js_1.default);
|
|
90
|
+
expect(result.toNumber()).toBe(mockRelayParentNumber);
|
|
91
|
+
expect(mockAt).toHaveBeenCalledWith(mockBlockHash);
|
|
92
|
+
expect(mockGetBlock).toHaveBeenCalledWith(mockBlockHash);
|
|
93
|
+
});
|
|
94
|
+
it('should throw error when setValidationData extrinsic is not found', async () => {
|
|
95
|
+
const mockApi = {
|
|
96
|
+
at: jest.fn().mockResolvedValue({}),
|
|
97
|
+
rpc: {
|
|
98
|
+
chain: {
|
|
99
|
+
getBlock: jest.fn().mockResolvedValue({
|
|
100
|
+
block: {
|
|
101
|
+
extrinsics: [createMockOtherExtrinsic('timestamp'), createMockOtherExtrinsic('transfer')],
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
await expect((0, getRelayParentNumber_1.getRelayParentNumber)(mockApi, mockBlockHash)).rejects.toThrow('Block does not contain setValidationData extrinsic. Cannot determine relay parent number.');
|
|
108
|
+
});
|
|
109
|
+
it('should handle block with only setValidationData extrinsic', async () => {
|
|
110
|
+
const mockApiAt = {
|
|
111
|
+
registry: {
|
|
112
|
+
createType: createMockCreateType(12345678),
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
const mockApi = {
|
|
116
|
+
at: jest.fn().mockResolvedValue(mockApiAt),
|
|
117
|
+
rpc: {
|
|
118
|
+
chain: {
|
|
119
|
+
getBlock: jest.fn().mockResolvedValue({
|
|
120
|
+
block: {
|
|
121
|
+
extrinsics: [createMockSetValidationDataExtrinsic()],
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
const result = await (0, getRelayParentNumber_1.getRelayParentNumber)(mockApi, mockBlockHash);
|
|
128
|
+
expect(result.toNumber()).toBe(12345678);
|
|
129
|
+
});
|
|
130
|
+
it('should handle large relay parent numbers', async () => {
|
|
131
|
+
const largeBlockNumber = 999999999;
|
|
132
|
+
const mockApiAt = {
|
|
133
|
+
registry: {
|
|
134
|
+
createType: createMockCreateType(largeBlockNumber),
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
const mockApi = {
|
|
138
|
+
at: jest.fn().mockResolvedValue(mockApiAt),
|
|
139
|
+
rpc: {
|
|
140
|
+
chain: {
|
|
141
|
+
getBlock: jest.fn().mockResolvedValue({
|
|
142
|
+
block: {
|
|
143
|
+
extrinsics: [createMockSetValidationDataExtrinsic()],
|
|
144
|
+
},
|
|
145
|
+
}),
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
const result = await (0, getRelayParentNumber_1.getRelayParentNumber)(mockApi, mockBlockHash);
|
|
150
|
+
expect(result.toNumber()).toBe(largeBlockNumber);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('hasRelayParentData', () => {
|
|
154
|
+
it('should return true when block contains setValidationData', async () => {
|
|
155
|
+
const mockApi = {
|
|
156
|
+
rpc: {
|
|
157
|
+
chain: {
|
|
158
|
+
getBlock: jest.fn().mockResolvedValue({
|
|
159
|
+
block: {
|
|
160
|
+
extrinsics: [createMockOtherExtrinsic('timestamp'), createMockSetValidationDataExtrinsic()],
|
|
161
|
+
},
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
const result = await (0, getRelayParentNumber_1.hasRelayParentData)(mockApi, mockBlockHash);
|
|
167
|
+
expect(result).toBe(true);
|
|
168
|
+
});
|
|
169
|
+
it('should return false when block does not contain setValidationData', async () => {
|
|
170
|
+
const mockApi = {
|
|
171
|
+
rpc: {
|
|
172
|
+
chain: {
|
|
173
|
+
getBlock: jest.fn().mockResolvedValue({
|
|
174
|
+
block: {
|
|
175
|
+
extrinsics: [createMockOtherExtrinsic('timestamp'), createMockOtherExtrinsic('transfer')],
|
|
176
|
+
},
|
|
177
|
+
}),
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
const result = await (0, getRelayParentNumber_1.hasRelayParentData)(mockApi, mockBlockHash);
|
|
182
|
+
expect(result).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
it('should return false for empty extrinsics array', async () => {
|
|
185
|
+
const mockApi = {
|
|
186
|
+
rpc: {
|
|
187
|
+
chain: {
|
|
188
|
+
getBlock: jest.fn().mockResolvedValue({
|
|
189
|
+
block: {
|
|
190
|
+
extrinsics: [],
|
|
191
|
+
},
|
|
192
|
+
}),
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
const result = await (0, getRelayParentNumber_1.hasRelayParentData)(mockApi, mockBlockHash);
|
|
197
|
+
expect(result).toBe(false);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=getRelayParentNumber.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRelayParentNumber.spec.js","sourceRoot":"","sources":["../../../../src/util/relay/getRelayParentNumber.spec.ts"],"names":[],"mappings":"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"}
|