@subsquid/portal-client 0.0.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/README.md +3 -0
- package/lib/client.d.ts +102 -0
- package/lib/client.d.ts.map +1 -0
- package/lib/client.example.d.ts +2 -0
- package/lib/client.example.d.ts.map +1 -0
- package/lib/client.example.js +158 -0
- package/lib/client.example.js.map +1 -0
- package/lib/client.js +440 -0
- package/lib/client.js.map +1 -0
- package/lib/query/common.d.ts +47 -0
- package/lib/query/common.d.ts.map +1 -0
- package/lib/query/common.js +3 -0
- package/lib/query/common.js.map +1 -0
- package/lib/query/evm.d.ts +268 -0
- package/lib/query/evm.d.ts.map +1 -0
- package/lib/query/evm.js +3 -0
- package/lib/query/evm.js.map +1 -0
- package/lib/query/index.d.ts +5 -0
- package/lib/query/index.d.ts.map +1 -0
- package/lib/query/index.js +3 -0
- package/lib/query/index.js.map +1 -0
- package/lib/query/solana.d.ts +224 -0
- package/lib/query/solana.d.ts.map +1 -0
- package/lib/query/solana.js +3 -0
- package/lib/query/solana.js.map +1 -0
- package/lib/query/substrate.d.ts +180 -0
- package/lib/query/substrate.d.ts.map +1 -0
- package/lib/query/substrate.js +3 -0
- package/lib/query/substrate.js.map +1 -0
- package/package.json +32 -0
- package/src/client.example.ts +167 -0
- package/src/client.ts +639 -0
- package/src/query/common.ts +59 -0
- package/src/query/evm.ts +367 -0
- package/src/query/index.ts +4 -0
- package/src/query/solana.ts +276 -0
- package/src/query/substrate.ts +194 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { Select, Selector, Trues, Hex, Simplify, PortalQuery } from './common';
|
|
2
|
+
/**
|
|
3
|
+
* @example 'Balances.Transfer'
|
|
4
|
+
*/
|
|
5
|
+
export type QualifiedName = string & {};
|
|
6
|
+
export type BlockHeaderFields = {
|
|
7
|
+
/**
|
|
8
|
+
* Block height
|
|
9
|
+
*/
|
|
10
|
+
number: number;
|
|
11
|
+
/**
|
|
12
|
+
* Block hash
|
|
13
|
+
*/
|
|
14
|
+
hash: Hex;
|
|
15
|
+
/**
|
|
16
|
+
* Hash of the parent block
|
|
17
|
+
*/
|
|
18
|
+
parentHash: Hex;
|
|
19
|
+
/**
|
|
20
|
+
* Root hash of the state merkle tree
|
|
21
|
+
*/
|
|
22
|
+
stateRoot: Hex;
|
|
23
|
+
/**
|
|
24
|
+
* Root hash of the extrinsics merkle tree
|
|
25
|
+
*/
|
|
26
|
+
extrinsicsRoot: Hex;
|
|
27
|
+
digest: {
|
|
28
|
+
logs: Hex[];
|
|
29
|
+
};
|
|
30
|
+
specName: string;
|
|
31
|
+
specVersion: number;
|
|
32
|
+
implName: string;
|
|
33
|
+
implVersion: number;
|
|
34
|
+
/**
|
|
35
|
+
* Block timestamp as set by `timestamp.now()` (unix epoch ms, compatible with `Date`).
|
|
36
|
+
*/
|
|
37
|
+
timestamp?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Account address of block validator
|
|
40
|
+
*/
|
|
41
|
+
validator?: Hex;
|
|
42
|
+
};
|
|
43
|
+
export type ExtrinsicSignatureFields = {
|
|
44
|
+
address: unknown;
|
|
45
|
+
signature: unknown;
|
|
46
|
+
signedExtensions: unknown;
|
|
47
|
+
};
|
|
48
|
+
export type ExtrinsicFields = {
|
|
49
|
+
/**
|
|
50
|
+
* Ordinal index in the extrinsics array of the current block
|
|
51
|
+
*/
|
|
52
|
+
index: number;
|
|
53
|
+
version: number;
|
|
54
|
+
signature?: ExtrinsicSignatureFields;
|
|
55
|
+
fee?: bigint;
|
|
56
|
+
tip?: bigint;
|
|
57
|
+
error?: unknown;
|
|
58
|
+
success?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Blake2b 128-bit hash of the raw extrinsic
|
|
61
|
+
*/
|
|
62
|
+
hash?: Hex;
|
|
63
|
+
};
|
|
64
|
+
export type CallFields = {
|
|
65
|
+
extrinsicIndex: number;
|
|
66
|
+
address: number[];
|
|
67
|
+
name: QualifiedName;
|
|
68
|
+
args: unknown;
|
|
69
|
+
origin?: unknown;
|
|
70
|
+
/**
|
|
71
|
+
* Call error.
|
|
72
|
+
*
|
|
73
|
+
* Absence of error doesn't imply that the call was executed successfully,
|
|
74
|
+
* check {@link success} property for that.
|
|
75
|
+
*/
|
|
76
|
+
error?: unknown;
|
|
77
|
+
success?: boolean;
|
|
78
|
+
_ethereumTransactTo?: Hex;
|
|
79
|
+
_ethereumTransactSighash?: Hex;
|
|
80
|
+
};
|
|
81
|
+
export type EventFields = {
|
|
82
|
+
/**
|
|
83
|
+
* Ordinal index in the event array of the current block
|
|
84
|
+
*/
|
|
85
|
+
index: number;
|
|
86
|
+
/**
|
|
87
|
+
* Event name
|
|
88
|
+
*/
|
|
89
|
+
name: QualifiedName;
|
|
90
|
+
args: unknown;
|
|
91
|
+
phase: 'Initialization' | 'ApplyExtrinsic' | 'Finalization';
|
|
92
|
+
extrinsicIndex?: number;
|
|
93
|
+
callAddress?: number[];
|
|
94
|
+
/**
|
|
95
|
+
* This field is not supported by all currently deployed archives.
|
|
96
|
+
* Requesting it may cause internal error.
|
|
97
|
+
*/
|
|
98
|
+
topics: Hex[];
|
|
99
|
+
_evmLogAddress?: Hex;
|
|
100
|
+
_evmLogTopics?: Hex[];
|
|
101
|
+
_contractAddress?: Hex;
|
|
102
|
+
_gearProgramId?: Hex;
|
|
103
|
+
};
|
|
104
|
+
export type BlockHeaderFieldSelection = Simplify<Selector<keyof BlockHeaderFields> & {
|
|
105
|
+
number: true;
|
|
106
|
+
hash: true;
|
|
107
|
+
}>;
|
|
108
|
+
export type BlockHeader<T extends BlockHeaderFieldSelection = Trues<BlockHeaderFieldSelection>> = Select<BlockHeaderFields, T>;
|
|
109
|
+
export type ExtrinsicFieldSelection = Selector<keyof ExtrinsicFields>;
|
|
110
|
+
export type Extrinsic<T extends ExtrinsicFieldSelection = Trues<ExtrinsicFieldSelection>> = Select<ExtrinsicFields, T>;
|
|
111
|
+
export type CallFieldSelection = Selector<keyof CallFields>;
|
|
112
|
+
export type Call<T extends CallFieldSelection = Trues<CallFieldSelection>> = Select<CallFields, T>;
|
|
113
|
+
export type EventFieldSelection = Selector<keyof EventFields>;
|
|
114
|
+
export type Event<T extends EventFieldSelection = Trues<CallFieldSelection>> = Select<EventFields, T>;
|
|
115
|
+
export type FieldSelection = {
|
|
116
|
+
block?: BlockHeaderFieldSelection;
|
|
117
|
+
extrinsic?: ExtrinsicFieldSelection;
|
|
118
|
+
call?: CallFieldSelection;
|
|
119
|
+
event?: EventFieldSelection;
|
|
120
|
+
};
|
|
121
|
+
export type EventRelations = {
|
|
122
|
+
extrinsic?: boolean;
|
|
123
|
+
call?: boolean;
|
|
124
|
+
stack?: boolean;
|
|
125
|
+
};
|
|
126
|
+
export type EventRequest = Simplify<{
|
|
127
|
+
name?: QualifiedName[];
|
|
128
|
+
} & EventRelations>;
|
|
129
|
+
export type CallRelations = {
|
|
130
|
+
extrinsic?: boolean;
|
|
131
|
+
stack?: boolean;
|
|
132
|
+
events?: boolean;
|
|
133
|
+
};
|
|
134
|
+
export type CallRequest = Simplify<{
|
|
135
|
+
name?: QualifiedName[];
|
|
136
|
+
} & CallRelations>;
|
|
137
|
+
export type EvmLogRequest = Simplify<{
|
|
138
|
+
address?: Hex[];
|
|
139
|
+
} & EventRelations>;
|
|
140
|
+
export type EthereumLogRequest = Simplify<{
|
|
141
|
+
address?: Hex[];
|
|
142
|
+
topic0?: Hex[];
|
|
143
|
+
topic1?: Hex[];
|
|
144
|
+
topic2?: Hex[];
|
|
145
|
+
topic3?: Hex[];
|
|
146
|
+
} & EventRelations>;
|
|
147
|
+
export type EthereumTransactRequest = Simplify<{
|
|
148
|
+
to?: Hex[];
|
|
149
|
+
sighash?: Hex[];
|
|
150
|
+
} & CallRelations>;
|
|
151
|
+
export type ContractsContractEmittedRequest = Simplify<{
|
|
152
|
+
address?: Hex[];
|
|
153
|
+
} & EventRelations>;
|
|
154
|
+
export type GearMessageQueuedRequest = Simplify<{
|
|
155
|
+
programId?: Hex[];
|
|
156
|
+
} & EventRelations>;
|
|
157
|
+
export type GearUserMessageSentRequest = Simplify<{
|
|
158
|
+
programId?: Hex[];
|
|
159
|
+
} & EventRelations>;
|
|
160
|
+
export type DataRequest = {
|
|
161
|
+
includeAllBlocks?: boolean;
|
|
162
|
+
events?: EventRequest[];
|
|
163
|
+
calls?: CallRequest[];
|
|
164
|
+
evmLogs?: EvmLogRequest[];
|
|
165
|
+
ethereumTransactions?: EthereumTransactRequest[];
|
|
166
|
+
contractsEvents?: ContractsContractEmittedRequest[];
|
|
167
|
+
gearMessagesQueued?: GearMessageQueuedRequest[];
|
|
168
|
+
gearUserMessagesSent?: GearUserMessageSentRequest[];
|
|
169
|
+
};
|
|
170
|
+
export type Query = Simplify<PortalQuery & {
|
|
171
|
+
type: 'substrate';
|
|
172
|
+
fields: FieldSelection;
|
|
173
|
+
} & DataRequest>;
|
|
174
|
+
export type Block<F extends FieldSelection> = Simplify<{
|
|
175
|
+
header: BlockHeader<F['block'] & {}>;
|
|
176
|
+
events?: Event<F['event'] & {}>[];
|
|
177
|
+
calls?: Call<F['call'] & {}>[];
|
|
178
|
+
extrinsics?: Extrinsic<F['extrinsic'] & {}>[];
|
|
179
|
+
}>;
|
|
180
|
+
//# sourceMappingURL=substrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"substrate.d.ts","sourceRoot":"","sources":["../../src/query/substrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"substrate.js","sourceRoot":"","sources":["../../src/query/substrate.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@subsquid/portal-client",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "SQD Portal API",
|
|
5
|
+
"license": "GPL-3.0-or-later",
|
|
6
|
+
"repository": "git@github.com:subsquid/squid.git",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"main": "lib/client.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"lib",
|
|
13
|
+
"src",
|
|
14
|
+
"!src/*.test.*",
|
|
15
|
+
"!lib/*.test.*"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@subsquid/util-internal": "^3.2.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@subsquid/http-client": "^1.6.1"
|
|
22
|
+
},
|
|
23
|
+
"peerDependenciesMeta": {},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@subsquid/http-client": "^1.6.1",
|
|
26
|
+
"@types/node": "^18.18.14",
|
|
27
|
+
"typescript": "5.5.4"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "rm -rf lib && tsc"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {BlockRef, createQuery, isForkException, PortalClient} from './client'
|
|
2
|
+
|
|
3
|
+
const portalUrls = {
|
|
4
|
+
evm: 'https://portal.sqd.dev/datasets/ethereum-mainnet',
|
|
5
|
+
solana: 'https://portal.sqd.dev/datasets/solana-mainnet',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const queries = {
|
|
9
|
+
evm: createQuery({
|
|
10
|
+
type: 'evm',
|
|
11
|
+
fromBlock: 23_000_000,
|
|
12
|
+
fields: {
|
|
13
|
+
block: {
|
|
14
|
+
number: true,
|
|
15
|
+
hash: true,
|
|
16
|
+
timestamp: true,
|
|
17
|
+
},
|
|
18
|
+
transaction: {
|
|
19
|
+
from: true,
|
|
20
|
+
to: true,
|
|
21
|
+
hash: true,
|
|
22
|
+
},
|
|
23
|
+
log: {
|
|
24
|
+
address: true,
|
|
25
|
+
topics: true,
|
|
26
|
+
data: true,
|
|
27
|
+
transactionHash: true,
|
|
28
|
+
logIndex: true,
|
|
29
|
+
transactionIndex: true,
|
|
30
|
+
},
|
|
31
|
+
stateDiff: {
|
|
32
|
+
kind: true,
|
|
33
|
+
next: true,
|
|
34
|
+
prev: true,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
logs: [
|
|
38
|
+
{
|
|
39
|
+
address: ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
|
|
40
|
+
topic0: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
}),
|
|
44
|
+
solana: createQuery({
|
|
45
|
+
type: 'solana',
|
|
46
|
+
fromBlock: 358_600_000,
|
|
47
|
+
fields: {
|
|
48
|
+
block: {number: true, timestamp: true, hash: true, parentHash: true},
|
|
49
|
+
transaction: {signatures: true, err: true, transactionIndex: true},
|
|
50
|
+
instruction: {
|
|
51
|
+
programId: true,
|
|
52
|
+
accounts: true,
|
|
53
|
+
data: true,
|
|
54
|
+
isCommitted: true,
|
|
55
|
+
transactionIndex: true,
|
|
56
|
+
instructionAddress: true,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
instructions: [
|
|
60
|
+
{
|
|
61
|
+
programId: ['whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc'],
|
|
62
|
+
d8: ['0xf8c69e91e17587c8'],
|
|
63
|
+
isCommitted: true,
|
|
64
|
+
innerInstructions: true,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
}),
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function main() {
|
|
71
|
+
const queryType = 'evm'
|
|
72
|
+
const query = queries[queryType]
|
|
73
|
+
|
|
74
|
+
let portal = new PortalClient({
|
|
75
|
+
url: portalUrls[queryType],
|
|
76
|
+
http: {
|
|
77
|
+
retryAttempts: Infinity,
|
|
78
|
+
},
|
|
79
|
+
minBytes: 50 * 1024 * 1024,
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
let coldHead: BlockRef | undefined = undefined
|
|
83
|
+
let hotHeads: BlockRef[] = []
|
|
84
|
+
while (true) {
|
|
85
|
+
const currentQuery = {...query}
|
|
86
|
+
|
|
87
|
+
let head = hotHeads[hotHeads.length - 1] ?? coldHead
|
|
88
|
+
if (head != null && head.number > currentQuery.fromBlock) {
|
|
89
|
+
currentQuery.fromBlock = head.number + 1
|
|
90
|
+
currentQuery.parentBlockHash = head.hash
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
for await (let {blocks, finalizedHead} of portal.getStream(query)) {
|
|
95
|
+
if (head && blocks.length > 0 && head.number >= blocks[0].header.number) {
|
|
96
|
+
throw new Error('Data is not continuous')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let unfinalizedIndex = 0
|
|
100
|
+
if (finalizedHead) {
|
|
101
|
+
unfinalizedIndex = blocks.findIndex((b) => b.header.number > finalizedHead?.number)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// all new blocks are finalized
|
|
105
|
+
if (unfinalizedIndex < 0) {
|
|
106
|
+
const finalizedRef = blocks[blocks.length - 1].header
|
|
107
|
+
coldHead = {number: finalizedRef.number, hash: finalizedRef.hash}
|
|
108
|
+
// finalize all hot heads
|
|
109
|
+
hotHeads = []
|
|
110
|
+
} else {
|
|
111
|
+
const finalizedRef = finalizedHead ?? blocks[unfinalizedIndex - 1]?.header
|
|
112
|
+
coldHead = finalizedRef ?? coldHead
|
|
113
|
+
|
|
114
|
+
// finalize all hot heads that are older than the cold head
|
|
115
|
+
if (coldHead) {
|
|
116
|
+
let finalizeIndex = hotHeads.findIndex((h) => h.number > coldHead!.number)
|
|
117
|
+
hotHeads = finalizeIndex < 0 ? [] : hotHeads.slice(finalizeIndex)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// process unfinalized blocks
|
|
121
|
+
for (let i = unfinalizedIndex; i < blocks.length; i++) {
|
|
122
|
+
hotHeads.push({number: blocks[i].header.number, hash: blocks[i].header.hash})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
head = hotHeads[hotHeads.length - 1] ?? coldHead
|
|
127
|
+
let portalHead = Math.max(head.number, finalizedHead?.number ?? -1)
|
|
128
|
+
console.log(`progress: ${head.number} / ${portalHead}` + `, blocks: ${blocks.length}`)
|
|
129
|
+
console.log(` \u001b[2mcold head: ${coldHead ? formatRef(coldHead) : 'N/A'}\u001b[0m`)
|
|
130
|
+
console.log(` \u001b[2mhot heads: ${hotHeads.map((h) => formatRef(h)).join(', ') || 'N/A'}\u001b[0m`)
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
} catch (e) {
|
|
134
|
+
if (!isForkException(e)) throw e
|
|
135
|
+
|
|
136
|
+
let chain = coldHead ? [coldHead, ...hotHeads] : hotHeads
|
|
137
|
+
let rollbackIndex = findRollbackIndex(chain, e.lastBlocks)
|
|
138
|
+
if (rollbackIndex === -1) throw new Error('Unable to process fork')
|
|
139
|
+
|
|
140
|
+
const rollbackHead = chain[rollbackIndex]
|
|
141
|
+
console.warn(`detected fork at block ${rollbackHead.number} (${e.head.number - rollbackHead.number} depth)`)
|
|
142
|
+
|
|
143
|
+
hotHeads = chain.slice(1, rollbackIndex + 1)
|
|
144
|
+
head = hotHeads[hotHeads.length - 1] ?? coldHead
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function findRollbackIndex(chainA: BlockRef[], chainB: BlockRef[]) {
|
|
150
|
+
let i = 0
|
|
151
|
+
let j = 0
|
|
152
|
+
for (; i < chainA.length; i++) {
|
|
153
|
+
const blockA = chainA[i]
|
|
154
|
+
for (; j < chainB.length; j++) {
|
|
155
|
+
let blockB = chainB[j]
|
|
156
|
+
if (blockB.number > blockA.number) break
|
|
157
|
+
if (blockB.number === blockA.number && blockB.hash !== blockA.hash) return i - 1
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return i - 1
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function formatRef(ref: BlockRef) {
|
|
164
|
+
return `${ref.number}#${ref.hash.slice(2, 8)}`
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
main()
|