0
# RPC Operations
1
2
Direct access to node RPC methods for chain information, state queries, and system operations. The RPC interface provides raw access to the underlying blockchain node functionality through standardized JSON-RPC calls.
3
4
## Capabilities
5
6
### Chain RPC Methods
7
8
Access blockchain and block-related information.
9
10
```typescript { .api }
11
interface ChainRpc<ApiType> {
12
/**
13
* Get block by hash
14
* @param hash - Block hash (optional, defaults to best block)
15
* @returns Block information
16
*/
17
getBlock(hash?: Hash): ApiType extends 'rxjs' ? Observable<SignedBlock> : Promise<SignedBlock>;
18
19
/**
20
* Get block hash by number
21
* @param blockNumber - Block number (optional, defaults to best block)
22
* @returns Block hash
23
*/
24
getBlockHash(blockNumber?: BlockNumber): ApiType extends 'rxjs' ? Observable<Hash> : Promise<Hash>;
25
26
/**
27
* Get block header by hash
28
* @param hash - Block hash (optional, defaults to best block)
29
* @returns Block header
30
*/
31
getHeader(hash?: Hash): ApiType extends 'rxjs' ? Observable<Header> : Promise<Header>;
32
33
/**
34
* Subscribe to new block headers
35
* @param callback - Callback function for new headers
36
* @returns Unsubscribe function or Observable
37
*/
38
subscribeNewHeads(callback?: (header: Header) => void): ApiType extends 'rxjs'
39
? Observable<Header>
40
: UnsubscribePromise;
41
42
/**
43
* Subscribe to all new block headers including forks
44
* @param callback - Callback function for new headers
45
* @returns Unsubscribe function or Observable
46
*/
47
subscribeAllHeads(callback?: (header: Header) => void): ApiType extends 'rxjs'
48
? Observable<Header>
49
: UnsubscribePromise;
50
51
/**
52
* Subscribe to finalized block headers
53
* @param callback - Callback function for finalized headers
54
* @returns Unsubscribe function or Observable
55
*/
56
subscribeFinalizedHeads(callback?: (header: Header) => void): ApiType extends 'rxjs'
57
? Observable<Header>
58
: UnsubscribePromise;
59
}
60
```
61
62
### State RPC Methods
63
64
Query and subscribe to chain state changes.
65
66
```typescript { .api }
67
interface StateRpc<ApiType> {
68
/**
69
* Get storage value by key
70
* @param key - Storage key
71
* @param at - Block hash to query at (optional)
72
* @returns Storage value
73
*/
74
getStorage(key: StorageKey, at?: Hash): ApiType extends 'rxjs'
75
? Observable<StorageData | null>
76
: Promise<StorageData | null>;
77
78
/**
79
* Get multiple storage values by keys
80
* @param keys - Array of storage keys
81
* @param at - Block hash to query at (optional)
82
* @returns Array of storage values
83
*/
84
queryStorage(keys: StorageKey[], at?: Hash): ApiType extends 'rxjs'
85
? Observable<[Hash, StorageChangeSet][]>
86
: Promise<[Hash, StorageChangeSet][]>;
87
88
/**
89
* Subscribe to storage changes
90
* @param keys - Storage keys to watch
91
* @param callback - Callback for storage changes
92
* @returns Unsubscribe function or Observable
93
*/
94
subscribeStorage(
95
keys: StorageKey[],
96
callback?: (changes: StorageChangeSet) => void
97
): ApiType extends 'rxjs'
98
? Observable<StorageChangeSet>
99
: UnsubscribePromise;
100
101
/**
102
* Get runtime metadata
103
* @param at - Block hash to query at (optional)
104
* @returns Runtime metadata
105
*/
106
getMetadata(at?: Hash): ApiType extends 'rxjs'
107
? Observable<Metadata>
108
: Promise<Metadata>;
109
110
/**
111
* Get runtime version
112
* @param at - Block hash to query at (optional)
113
* @returns Runtime version
114
*/
115
getRuntimeVersion(at?: Hash): ApiType extends 'rxjs'
116
? Observable<RuntimeVersion>
117
: Promise<RuntimeVersion>;
118
119
/**
120
* Call runtime API method
121
* @param method - Runtime API method name
122
* @param data - Method parameters
123
* @param at - Block hash to query at (optional)
124
* @returns Runtime API result
125
*/
126
call(method: string, data: Bytes, at?: Hash): ApiType extends 'rxjs'
127
? Observable<Bytes>
128
: Promise<Bytes>;
129
130
/**
131
* Get storage keys with pagination
132
* @param prefix - Storage key prefix
133
* @param pageSize - Number of keys per page
134
* @param startKey - Starting key for pagination
135
* @param at - Block hash to query at (optional)
136
* @returns Array of storage keys
137
*/
138
getKeysPaged(
139
prefix: StorageKey,
140
pageSize: number,
141
startKey?: StorageKey,
142
at?: Hash
143
): ApiType extends 'rxjs'
144
? Observable<StorageKey[]>
145
: Promise<StorageKey[]>;
146
}
147
```
148
149
### System RPC Methods
150
151
Access node and network information.
152
153
```typescript { .api }
154
interface SystemRpc<ApiType> {
155
/**
156
* Get chain name
157
* @returns Chain name
158
*/
159
chain(): ApiType extends 'rxjs' ? Observable<Text> : Promise<Text>;
160
161
/**
162
* Get node name
163
* @returns Node implementation name
164
*/
165
name(): ApiType extends 'rxjs' ? Observable<Text> : Promise<Text>;
166
167
/**
168
* Get node version
169
* @returns Node version
170
*/
171
version(): ApiType extends 'rxjs' ? Observable<Text> : Promise<Text>;
172
173
/**
174
* Get account next index (nonce)
175
* @param account - Account address
176
* @returns Account nonce
177
*/
178
accountNextIndex(account: AccountId): ApiType extends 'rxjs'
179
? Observable<Index>
180
: Promise<Index>;
181
182
/**
183
* Add reserved peer
184
* @param peer - Peer multiaddress
185
* @returns Success result
186
*/
187
addReservedPeer(peer: string): ApiType extends 'rxjs'
188
? Observable<Text>
189
: Promise<Text>;
190
191
/**
192
* Get node health status
193
* @returns Health information
194
*/
195
health(): ApiType extends 'rxjs' ? Observable<Health> : Promise<Health>;
196
197
/**
198
* Get local peer ID
199
* @returns Peer ID
200
*/
201
localPeerId(): ApiType extends 'rxjs' ? Observable<Text> : Promise<Text>;
202
203
/**
204
* Get connected peers
205
* @returns Array of peer information
206
*/
207
peers(): ApiType extends 'rxjs' ? Observable<PeerInfo[]> : Promise<PeerInfo[]>;
208
209
/**
210
* Get node properties
211
* @returns Node properties
212
*/
213
properties(): ApiType extends 'rxjs' ? Observable<ChainProperties> : Promise<ChainProperties>;
214
}
215
```
216
217
### Author RPC Methods
218
219
Submit and manage transactions in the transaction pool.
220
221
```typescript { .api }
222
interface AuthorRpc<ApiType> {
223
/**
224
* Submit transaction to the pool
225
* @param extrinsic - Signed extrinsic
226
* @returns Transaction hash
227
*/
228
submitExtrinsic(extrinsic: Extrinsic): ApiType extends 'rxjs'
229
? Observable<Hash>
230
: Promise<Hash>;
231
232
/**
233
* Submit and watch transaction status
234
* @param extrinsic - Signed extrinsic
235
* @param callback - Status callback
236
* @returns Unsubscribe function or Observable
237
*/
238
submitAndWatchExtrinsic(
239
extrinsic: Extrinsic,
240
callback?: (status: ExtrinsicStatus) => void
241
): ApiType extends 'rxjs'
242
? Observable<ExtrinsicStatus>
243
: UnsubscribePromise;
244
245
/**
246
* Get pending extrinsics
247
* @returns Array of pending extrinsics
248
*/
249
pendingExtrinsics(): ApiType extends 'rxjs'
250
? Observable<Extrinsic[]>
251
: Promise<Extrinsic[]>;
252
253
/**
254
* Remove extrinsic from pool
255
* @param bytesOrHash - Extrinsic bytes or hash
256
* @returns Array of removed transaction hashes
257
*/
258
removeExtrinsic(bytesOrHash: Vec<ExtrinsicOrHash>): ApiType extends 'rxjs'
259
? Observable<Hash[]>
260
: Promise<Hash[]>;
261
}
262
```
263
264
## Usage Examples
265
266
### Chain Information Queries
267
268
```typescript
269
import { ApiPromise } from "@polkadot/api";
270
271
const api = await ApiPromise.create();
272
273
// Get basic chain information
274
const [chain, nodeName, nodeVersion] = await Promise.all([
275
api.rpc.system.chain(),
276
api.rpc.system.name(),
277
api.rpc.system.version()
278
]);
279
280
console.log(`Connected to ${chain} using ${nodeName} v${nodeVersion}`);
281
282
// Get current block information
283
const bestHash = await api.rpc.chain.getBlockHash();
284
const bestBlock = await api.rpc.chain.getBlock(bestHash);
285
const header = bestBlock.block.header;
286
287
console.log(`Best block: #${header.number} (${bestHash})`);
288
console.log(`Parent hash: ${header.parentHash}`);
289
console.log(`State root: ${header.stateRoot}`);
290
```
291
292
### Block Subscriptions
293
294
```typescript
295
import { ApiPromise } from "@polkadot/api";
296
297
const api = await ApiPromise.create();
298
299
// Subscribe to new blocks
300
const unsubscribeHeads = await api.rpc.chain.subscribeNewHeads((header) => {
301
console.log(`New block #${header.number} with hash ${header.hash}`);
302
console.log(` Parent: ${header.parentHash}`);
303
console.log(` Extrinsics root: ${header.extrinsicsRoot}`);
304
});
305
306
// Subscribe to finalized blocks only
307
const unsubscribeFinalized = await api.rpc.chain.subscribeFinalizedHeads((header) => {
308
console.log(`Finalized block #${header.number}`);
309
});
310
311
// Stop subscriptions
312
// unsubscribeHeads();
313
// unsubscribeFinalized();
314
```
315
316
### State Queries
317
318
```typescript
319
import { ApiPromise } from "@polkadot/api";
320
321
const api = await ApiPromise.create();
322
323
// Query specific storage item
324
const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";
325
const storageKey = api.query.system.account.key(account);
326
const accountData = await api.rpc.state.getStorage(storageKey);
327
328
if (accountData) {
329
const decoded = api.createType('AccountInfo', accountData);
330
console.log(`Balance: ${decoded.data.free.toHuman()}`);
331
}
332
333
// Query at specific block
334
const blockHash = await api.rpc.chain.getBlockHash(1000000);
335
const historicalData = await api.rpc.state.getStorage(storageKey, blockHash);
336
```
337
338
### Storage Subscriptions
339
340
```typescript
341
import { ApiPromise } from "@polkadot/api";
342
343
const api = await ApiPromise.create();
344
345
// Subscribe to storage changes
346
const account = "1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg";
347
const storageKey = api.query.system.account.key(account);
348
349
const unsubscribe = await api.rpc.state.subscribeStorage([storageKey], (changes) => {
350
console.log(`Block: ${changes.block}`);
351
changes.changes.forEach(([key, value]) => {
352
if (value) {
353
const decoded = api.createType('AccountInfo', value);
354
console.log(`Account balance changed: ${decoded.data.free.toHuman()}`);
355
}
356
});
357
});
358
```
359
360
### Transaction Submission
361
362
```typescript
363
import { ApiPromise } from "@polkadot/api";
364
import { Keyring } from "@polkadot/keyring";
365
366
const api = await ApiPromise.create();
367
const keyring = new Keyring({ type: 'sr25519' });
368
369
// Create account from seed
370
const alice = keyring.addFromUri('//Alice');
371
372
// Create and sign transaction
373
const transfer = api.tx.balances.transferAllowDeath(
374
'1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg',
375
1000000000000
376
);
377
378
const signedTx = await transfer.signAsync(alice);
379
380
// Submit transaction
381
const txHash = await api.rpc.author.submitExtrinsic(signedTx);
382
console.log(`Transaction submitted: ${txHash}`);
383
384
// Submit and watch transaction
385
const unsubscribe = await api.rpc.author.submitAndWatchExtrinsic(signedTx, (status) => {
386
console.log(`Transaction status: ${status.type}`);
387
388
if (status.isInBlock) {
389
console.log(`Included in block: ${status.asInBlock}`);
390
} else if (status.isFinalized) {
391
console.log(`Finalized in block: ${status.asFinalized}`);
392
unsubscribe();
393
} else if (status.isError) {
394
console.log('Transaction error');
395
unsubscribe();
396
}
397
});
398
```
399
400
### Runtime API Calls
401
402
```typescript
403
import { ApiPromise } from "@polkadot/api";
404
405
const api = await ApiPromise.create();
406
407
// Get runtime metadata
408
const metadata = await api.rpc.state.getMetadata();
409
console.log(`Metadata version: ${metadata.version}`);
410
411
// Get runtime version
412
const runtimeVersion = await api.rpc.state.getRuntimeVersion();
413
console.log(`Runtime: ${runtimeVersion.specName} v${runtimeVersion.specVersion}`);
414
415
// Call custom runtime API
416
const method = 'TransactionPaymentApi_query_info';
417
const tx = api.tx.balances.transferAllowDeath('1FRMM8PEiWXYax7rpS6X4XZX1aAAxSWx1CrKTyrVYhV24fg', 1000);
418
const callData = api.createType('(Bytes, u32)', [tx.toHex(), tx.encodedLength]).toHex();
419
420
const result = await api.rpc.state.call(method, callData);
421
const feeInfo = api.createType('RuntimeDispatchInfo', result);
422
console.log(`Transaction fee: ${feeInfo.partialFee.toHuman()}`);
423
```
424
425
### Node Information
426
427
```typescript
428
import { ApiPromise } from "@polkadot/api";
429
430
const api = await ApiPromise.create();
431
432
// Get node health
433
const health = await api.rpc.system.health();
434
console.log(`Peers: ${health.peers}, Syncing: ${health.isSyncing}`);
435
436
// Get connected peers
437
const peers = await api.rpc.system.peers();
438
console.log(`Connected to ${peers.length} peers:`);
439
peers.forEach(peer => {
440
console.log(` ${peer.peerId}: ${peer.roles.toString()}`);
441
});
442
443
// Get chain properties
444
const properties = await api.rpc.system.properties();
445
console.log(`SS58 Format: ${properties.ss58Format?.toNumber()}`);
446
console.log(`Token symbol: ${properties.tokenSymbol?.toString()}`);
447
console.log(`Token decimals: ${properties.tokenDecimals?.toNumber()}`);
448
```
449
450
### RxJS RPC Operations
451
452
```typescript
453
import { ApiRx } from "@polkadot/api";
454
import { switchMap, tap } from "rxjs";
455
456
const api$ = ApiRx.create();
457
458
// Chain RxJS operations
459
api$.pipe(
460
switchMap(api => api.rpc.chain.subscribeNewHeads()),
461
tap(header => console.log(`Block #${header.number}`)),
462
switchMap(header => api$.pipe(
463
switchMap(api => api.rpc.chain.getBlock(header.hash))
464
))
465
).subscribe(block => {
466
console.log(`Block has ${block.block.extrinsics.length} extrinsics`);
467
});
468
469
// Combine multiple RPC streams
470
import { combineLatest } from "rxjs";
471
472
api$.pipe(
473
switchMap(api =>
474
combineLatest([
475
api.rpc.chain.subscribeNewHeads(),
476
api.rpc.system.health()
477
])
478
)
479
).subscribe(([header, health]) => {
480
console.log(`Block #${header.number}, Peers: ${health.peers}`);
481
});
482
```