Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/light-base/src/json_rpc_service/background.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2023  Pierre Krieger
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program 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
18
use crate::{
19
    log, network_service,
20
    platform::PlatformRef,
21
    runtime_service, sync_service, transactions_service,
22
    util::{self, SipHasherBuild},
23
};
24
25
use alloc::{
26
    borrow::{Cow, ToOwned as _},
27
    boxed::Box,
28
    collections::{BTreeSet, VecDeque},
29
    format,
30
    string::{String, ToString as _},
31
    sync::Arc,
32
    vec,
33
    vec::Vec,
34
};
35
use core::{
36
    iter, mem,
37
    num::{NonZeroU32, NonZeroUsize},
38
    pin::Pin,
39
    time::Duration,
40
};
41
use futures_lite::{FutureExt as _, StreamExt as _};
42
use futures_util::{future, stream};
43
use rand_chacha::{
44
    rand_core::{RngCore as _, SeedableRng as _},
45
    ChaCha20Rng,
46
};
47
use smoldot::{
48
    header,
49
    informant::HashDisplay,
50
    json_rpc::{self, methods, parse},
51
    libp2p::{multiaddr, PeerId},
52
    network::codec,
53
};
54
55
/// Configuration for a JSON-RPC service.
56
pub(super) struct Config<TPlat: PlatformRef> {
57
    /// Access to the platform's capabilities.
58
    // TODO: redundant with Config above?
59
    pub platform: TPlat,
60
61
    /// Access to the network, and identifier of the chain from the point of view of the network
62
    /// service.
63
    pub network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
64
65
    /// Service responsible for synchronizing the chain.
66
    pub sync_service: Arc<sync_service::SyncService<TPlat>>,
67
68
    /// Service responsible for emitting transactions and tracking their state.
69
    pub transactions_service: Arc<transactions_service::TransactionsService<TPlat>>,
70
71
    /// Service that provides a ready-to-be-called runtime for the current best block.
72
    pub runtime_service: Arc<runtime_service::RuntimeService<TPlat>>,
73
74
    /// Name of the chain, as found in the chain specification.
75
    pub chain_name: String,
76
    /// Type of chain, as found in the chain specification.
77
    pub chain_ty: String,
78
    /// JSON-encoded properties of the chain, as found in the chain specification.
79
    pub chain_properties_json: String,
80
    /// Whether the chain is a live network. Found in the chain specification.
81
    pub chain_is_live: bool,
82
83
    /// Value to return when the `system_name` RPC is called. Should be set to the name of the
84
    /// final executable.
85
    pub system_name: String,
86
87
    /// Value to return when the `system_version` RPC is called. Should be set to the version of
88
    /// the final executable.
89
    pub system_version: String,
90
91
    /// Hash of the genesis block of the chain.
92
    pub genesis_block_hash: [u8; 32],
93
}
94
95
/// Fields used to process JSON-RPC requests in the background.
96
struct Background<TPlat: PlatformRef> {
97
    /// Target to use for all the logs.
98
    log_target: String,
99
100
    /// Access to the platform's capabilities.
101
    platform: TPlat,
102
103
    /// Name of the chain, as found in the chain specification.
104
    chain_name: String,
105
    /// Type of chain, as found in the chain specification.
106
    chain_ty: String,
107
    /// JSON-encoded properties of the chain, as found in the chain specification.
108
    chain_properties_json: String,
109
    /// Whether the chain is a live network. Found in the chain specification.
110
    chain_is_live: bool,
111
    /// Value to return when the `system_name` RPC is called.
112
    system_name: String,
113
    /// Value to return when the `system_version` RPC is called.
114
    system_version: String,
115
    /// Hash of the genesis block.
116
    /// Keeping the genesis block is important, as the genesis block hash is included in
117
    /// transaction signatures, and must therefore be queried by upper-level UIs.
118
    genesis_block_hash: [u8; 32],
119
120
    /// Randomness used for various purposes, such as generating subscription IDs.
121
    randomness: ChaCha20Rng,
122
123
    /// See [`Config::network_service`].
124
    network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
125
    /// See [`Config::sync_service`].
126
    sync_service: Arc<sync_service::SyncService<TPlat>>,
127
    /// See [`Config::runtime_service`].
128
    runtime_service: Arc<runtime_service::RuntimeService<TPlat>>,
129
    /// See [`Config::transactions_service`].
130
    transactions_service: Arc<transactions_service::TransactionsService<TPlat>>,
131
132
    /// Tasks that are spawned by the service and running in the background.
133
    background_tasks:
134
        stream::FuturesUnordered<Pin<Box<dyn future::Future<Output = Event<TPlat>> + Send>>>,
135
136
    /// Channel where serialized JSON-RPC requests are pulled from.
137
    requests_rx: Pin<Box<async_channel::Receiver<String>>>,
138
    /// Channel to send serialized JSON-RPC responses and notifications to the foreground.
139
    responses_tx: async_channel::Sender<String>,
140
141
    /// State of each `chainHead_follow` subscription indexed by its ID.
142
    chain_head_follow_subscriptions:
143
        hashbrown::HashMap<String, ChainHeadFollow, fnv::FnvBuildHasher>,
144
145
    /// If `true`, we have already printed a warning about usage of the legacy JSON-RPC API. This
146
    /// flag prevents printing this message multiple times.
147
    printed_legacy_json_rpc_warning: bool,
148
149
    /// Next time to do some memory reclaims.
150
    next_garbage_collection: Pin<Box<TPlat::Delay>>,
151
152
    /// State of the runtime service subscription. Used for legacy JSON-RPC API subscriptions.
153
    runtime_service_subscription: RuntimeServiceSubscription<TPlat>,
154
    /// List of all active `chain_subscribeAllHeads` subscriptions, indexed by the subscription ID.
155
    all_heads_subscriptions: hashbrown::HashSet<String, fnv::FnvBuildHasher>,
156
    /// List of all active `chain_subscribeNewHeads` subscriptions, indexed by the subscription ID.
157
    new_heads_subscriptions: hashbrown::HashSet<String, fnv::FnvBuildHasher>,
158
    /// List of all active `chain_subscribeFinalizedHeads` subscriptions, indexed by the
159
    /// subscription ID.
160
    finalized_heads_subscriptions: hashbrown::HashSet<String, fnv::FnvBuildHasher>,
161
    /// List of all active `state_subscribeRuntimeVersion` subscriptions, indexed by the
162
    /// subscription ID.
163
    runtime_version_subscriptions: hashbrown::HashSet<String, fnv::FnvBuildHasher>,
164
    /// List of all active `author_submitAndWatchExtrinsic`, `transaction_v1_broadcast`, and
165
    /// `transactionWatch_v1_submitAndWatch` subscriptions, indexed by the subscription ID.
166
    /// When it comes to `author_submitAndWatchExtrinsic` and
167
    /// `transactionWatch_v1_submitAndWatch`, transactions are removed from this list when
168
    /// they are dropped from the transactions service. When it comes
169
    /// to  `transaction_v1_broadcast`, transactions are left forever until the API user
170
    /// unsubscribes.
171
    transactions_subscriptions: hashbrown::HashMap<String, TransactionWatch, fnv::FnvBuildHasher>,
172
173
    /// List of all active `state_subscribeStorage` subscriptions, indexed by the subscription ID.
174
    /// Values are the list of keys requested by this subscription.
175
    legacy_api_storage_subscriptions: BTreeSet<(Arc<str>, Vec<u8>)>,
176
    /// Identical to [`Background::legacy_api_storage_subscriptions`] but indexed by requested key.
177
    legacy_api_storage_subscriptions_by_key: BTreeSet<(Vec<u8>, Arc<str>)>,
178
    /// List of storage subscriptions whose latest sent notification isn't about the current
179
    /// best block.
180
    legacy_api_stale_storage_subscriptions: hashbrown::HashSet<Arc<str>, fnv::FnvBuildHasher>,
181
    /// `true` if there exists a background task in [`Background::background_tasks`] currently
182
    /// fetching storage items for storage subscriptions.
183
    legacy_api_storage_query_in_progress: bool,
184
185
    /// List of multi-stage requests (i.e. JSON-RPC requests that require multiple asynchronous
186
    /// operations) that are ready to make progress.
187
    multistage_requests_to_advance: VecDeque<(String, MultiStageRequestStage, MultiStageRequestTy)>,
188
    /// Multi-stage requests that are waiting for the best block hash to be known in order
189
    /// to progress.
190
    best_block_hash_pending: Vec<(String, MultiStageRequestTy)>,
191
    /// List of request IDs of `chain_getFinalizedHash` requests that are waiting for the
192
    /// finalized block hash to be known.
193
    pending_get_finalized_head: Vec<String>,
194
    /// Requests for blocks headers, state root hash and numbers that are still in progress.
195
    /// For each block hash, contains a list of multi-stage requests that are interested in the
196
    /// response. Once the operation has been finished, the value is inserted in
197
    /// [`Background::block_headers_cache`].
198
    block_headers_pending:
199
        hashbrown::HashMap<[u8; 32], Vec<(String, MultiStageRequestTy)>, fnv::FnvBuildHasher>,
200
    /// Requests for block runtimes that are still in progress.
201
    /// For each block hash, contains a list of requests that are interested in the response.
202
    /// Once the operation has been finished, the value is inserted in
203
    /// [`Background::block_runtimes_cache`].
204
    block_runtimes_pending:
205
        hashbrown::HashMap<[u8; 32], Vec<(String, MultiStageRequestTy)>, fnv::FnvBuildHasher>,
206
207
    /// Cache of known headers, state trie root hashes and numbers of blocks. Used only for the
208
    /// legacy JSON-RPC API.
209
    ///
210
    /// Can also be an `Err` if the header is in an invalid format.
211
    block_headers_cache: lru::LruCache<
212
        [u8; 32],
213
        Result<(Vec<u8>, [u8; 32], u64), header::Error>,
214
        fnv::FnvBuildHasher,
215
    >,
216
    /// Cache of known runtimes of blocks. Used only for the legacy JSON-RPC API.
217
    ///
218
    /// Note that runtimes that have failed to compile can be found here as well.
219
    block_runtimes_cache:
220
        lru::LruCache<[u8; 32], runtime_service::PinnedRuntime, fnv::FnvBuildHasher>,
221
    /// When `state_getKeysPaged` is called and the response is truncated, the response is
222
    /// inserted in this cache. The API user is likely to call `state_getKeysPaged` again with
223
    /// the same parameters, in which case we hit the cache and avoid the networking requests.
224
    /// The values are list of keys.
225
    state_get_keys_paged_cache:
226
        lru::LruCache<GetKeysPagedCacheKey, Vec<Vec<u8>>, util::SipHasherBuild>,
227
}
228
229
/// State of the subscription towards the runtime service.
230
/// See [`Background::runtime_service_subscription`].
231
enum RuntimeServiceSubscription<TPlat: PlatformRef> {
232
    /// Subscription is active.
233
    Active {
234
        /// Object representing the subscription.
235
        subscription: runtime_service::Subscription<TPlat>,
236
237
        /// Hash of the current best block. Guaranteed to be in
238
        /// [`RuntimeServiceSubscription::Active::pinned_blocks`].
239
        current_best_block: [u8; 32],
240
241
        /// If `Some`, the new heads and runtime version subscriptions haven't been updated about
242
        /// the new current best block yet. Contains the previous best block that the
243
        /// subscriptions are aware of. The previous best block is guaranteed to be in
244
        /// [`RuntimeServiceSubscription::Active::pinned_blocks`].
245
        new_heads_and_runtime_subscriptions_stale: Option<Option<[u8; 32]>>,
246
247
        /// Hash of the current finalized block. Guaranteed to be in
248
        /// [`RuntimeServiceSubscription::Active::pinned_blocks`].
249
        current_finalized_block: [u8; 32],
250
251
        /// If `true`, the finalized heads subscriptions haven't been updated about the new
252
        /// current finalized block yet.
253
        finalized_heads_subscriptions_stale: bool,
254
255
        /// When the runtime service reports a new block, it is kept pinned and inserted in this
256
        /// list.
257
        ///
258
        /// Blocks are removed from this container and unpinned when they leave
259
        /// [`RuntimeServiceSubscription::Active::finalized_and_pruned_lru`].
260
        ///
261
        /// JSON-RPC clients are more likely to ask for information about recent blocks and
262
        /// perform calls on them, hence a cache of recent blocks.
263
        pinned_blocks: hashbrown::HashMap<[u8; 32], RecentBlock, fnv::FnvBuildHasher>,
264
265
        /// When a block is finalized or pruned, it is inserted into this LRU cache. The least
266
        /// recently used blocks are removed and unpinned.
267
        finalized_and_pruned_lru: lru::LruCache<[u8; 32], (), fnv::FnvBuildHasher>,
268
    },
269
270
    /// Waiting for the runtime service to start the subscription. Can potentially take a long
271
    /// time.
272
    Pending(Pin<Box<dyn future::Future<Output = runtime_service::SubscribeAll<TPlat>> + Send>>),
273
274
    /// Subscription not requested yet. Should transition to
275
    /// [`RuntimeServiceSubscription::Pending`] as soon as possible.
276
    NotCreated,
277
}
278
279
struct RecentBlock {
280
    scale_encoded_header: Vec<u8>,
281
    // TODO: do we really need to keep the runtime version here, given that the block is still pinned in the runtime service?
282
    runtime_version: Arc<Result<smoldot::executor::CoreVersion, runtime_service::RuntimeError>>,
283
}
284
285
struct ChainHeadFollow {
286
    /// For each pinned block hash, the SCALE-encoded header of the block.
287
    pinned_blocks_headers: hashbrown::HashMap<[u8; 32], Vec<u8>, fnv::FnvBuildHasher>,
288
289
    /// List of body/call/storage operations currently in progress. Keys are operation IDs.
290
    operations_in_progress: hashbrown::HashMap<String, ChainHeadOperation, fnv::FnvBuildHasher>,
291
292
    /// Remaining number of operation slots that the JSON-RPC client can occupy.
293
    available_operation_slots: u32,
294
295
    /// If the subscription was created with `withRuntime: true`, contains the subscription ID
296
    /// according to the runtime service.
297
    ///
298
    /// Contains `None` if `withRuntime` was `false`, or if the subscription hasn't been
299
    /// initialized yet.
300
    runtime_service_subscription_id: Option<runtime_service::SubscriptionId>,
301
}
302
303
struct ChainHeadOperation {
304
    /// Number of slots that this operation occupies.
305
    /// See [`ChainHeadFollow::available_operation_slots`].
306
    occupied_slots: u32,
307
308
    /// Event connected to the background task in [`Background::background_tasks`] that is
309
    /// currently executing the operation. Cancels the task when notified.
310
    interrupt: event_listener::Event,
311
}
312
313
enum MultiStageRequestStage {
314
    BlockHashNotKnown,
315
    BlockHashKnown {
316
        block_hash: [u8; 32],
317
    },
318
    BlockInfoKnown {
319
        block_hash: [u8; 32],
320
        block_state_trie_root_hash: [u8; 32],
321
        block_number: u64,
322
    },
323
}
324
325
enum MultiStageRequestTy {
326
    ChainGetBestBlockHash,
327
    ChainGetBlock,
328
    ChainGetHeader,
329
    StateCall {
330
        name: String,
331
        parameters: Vec<u8>,
332
    },
333
    StateGetKeys {
334
        prefix: Vec<u8>,
335
    },
336
    StateGetKeysPaged {
337
        prefix: Vec<u8>,
338
        count: u32,
339
        start_key: Option<Vec<u8>>,
340
    },
341
    StateQueryStorageAt {
342
        keys: Vec<methods::HexString>,
343
    },
344
    StateGetMetadata,
345
    StateGetStorage {
346
        key: Vec<u8>,
347
    },
348
    StateGetRuntimeVersion,
349
    PaymentQueryInfo {
350
        extrinsic: Vec<u8>,
351
    },
352
    SystemAccountNextIndex {
353
        account_id: Vec<u8>,
354
    },
355
}
356
357
enum StorageRequestInProgress {
358
    StateGetKeys {
359
        in_progress_results: Vec<methods::HexString>,
360
    },
361
    StateGetKeysPaged {
362
        block_hash: [u8; 32],
363
        prefix: Vec<u8>,
364
        count: u32,
365
        start_key: Option<Vec<u8>>,
366
        in_progress_results: Vec<Vec<u8>>,
367
    },
368
    StateQueryStorageAt {
369
        block_hash: [u8; 32],
370
        in_progress_results: Vec<(methods::HexString, Option<methods::HexString>)>,
371
    },
372
    StateGetStorage,
373
}
374
375
enum RuntimeCallRequestInProgress {
376
    StateCall,
377
    StateGetMetadata,
378
    PaymentQueryInfo,
379
    SystemAccountNextIndex,
380
}
381
382
/// Event generated by a task in [`Background::background_tasks`] when it finishes.
383
enum Event<TPlat: PlatformRef> {
384
    TransactionEvent {
385
        subscription_id: String,
386
        event: transactions_service::TransactionStatus,
387
        watcher: Pin<Box<transactions_service::TransactionWatcher>>,
388
    },
389
    ChainGetBlockResult {
390
        request_id_json: String,
391
        result: Result<codec::BlockData, ()>,
392
        expected_block_hash: [u8; 32],
393
    },
394
    ChainHeadSubscriptionWithRuntimeReady {
395
        subscription_id: String,
396
        subscription: runtime_service::SubscribeAll<TPlat>,
397
    },
398
    ChainHeadSubscriptionWithRuntimeNotification {
399
        subscription_id: String,
400
        notification: runtime_service::Notification,
401
        stream: runtime_service::Subscription<TPlat>,
402
    },
403
    ChainHeadSubscriptionWithoutRuntimeReady {
404
        subscription_id: String,
405
        subscription: sync_service::SubscribeAll,
406
    },
407
    ChainHeadSubscriptionWithoutRuntimeNotification {
408
        subscription_id: String,
409
        notification: sync_service::Notification,
410
        stream: Pin<Box<async_channel::Receiver<sync_service::Notification>>>,
411
    },
412
    ChainHeadSubscriptionDeadSubcription {
413
        subscription_id: String,
414
    },
415
    ChainHeadStorageOperationProgress {
416
        subscription_id: String,
417
        operation_id: String,
418
        progress: sync_service::StorageQueryProgress<TPlat>,
419
    },
420
    ChainHeadCallOperationDone {
421
        subscription_id: String,
422
        operation_id: String,
423
        result: Result<runtime_service::RuntimeCallSuccess, runtime_service::RuntimeCallError>,
424
    },
425
    ChainHeadBodyOperationDone {
426
        subscription_id: String,
427
        operation_id: String,
428
        expected_extrinsics_root: [u8; 32],
429
        result: Result<codec::BlockData, ()>,
430
    },
431
    ChainHeadOperationCancelled,
432
    BlockInfoRetrieved {
433
        block_hash: [u8; 32],
434
        result: Result<Result<(Vec<u8>, [u8; 32], u64), header::Error>, ()>,
435
    },
436
    RuntimeDownloaded {
437
        block_hash: [u8; 32],
438
        result: Result<runtime_service::PinnedRuntime, String>,
439
    },
440
    LegacyApiFunctionStorageRequestProgress {
441
        request_id_json: String,
442
        request: StorageRequestInProgress,
443
        progress: sync_service::StorageQueryProgress<TPlat>,
444
    },
445
    LegacyApiFunctionRuntimeCallResult {
446
        request_id_json: String,
447
        request: RuntimeCallRequestInProgress,
448
        result: Result<runtime_service::RuntimeCallSuccess, runtime_service::RuntimeCallError>,
449
    },
450
    LegacyApiStorageSubscriptionsUpdate {
451
        block_hash: [u8; 32],
452
        result: Result<Vec<sync_service::StorageResultItem>, sync_service::StorageQueryError>,
453
    },
454
}
455
456
struct TransactionWatch {
457
    included_block: Option<[u8; 32]>,
458
    num_broadcasted_peers: usize,
459
    ty: TransactionWatchTy,
460
}
461
462
enum TransactionWatchTy {
463
    /// `author_submitAndWatchExtrinsic`.
464
    Legacy,
465
    /// `transaction_v1_broadcast`.
466
    NewApi {
467
        /// A copy of the body of the transaction is kept, as it might be necessary to re-insert
468
        /// it in the transactions service later, for example if it reports having crashed.
469
        transaction_bytes: Vec<u8>,
470
    },
471
    /// `transactionWatch_v1_submitAndWatch`.
472
    NewApiWatch,
473
}
474
475
/// See [`Background::state_get_keys_paged_cache`].
476
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
477
struct GetKeysPagedCacheKey {
478
    /// Value of the `hash` parameter of the call to `state_getKeysPaged`.
479
    hash: [u8; 32],
480
    /// Value of the `prefix` parameter of the call to `state_getKeysPaged`.
481
    prefix: Vec<u8>,
482
}
483
484
0
pub(super) async fn run<TPlat: PlatformRef>(
485
0
    log_target: String,
486
0
    config: Config<TPlat>,
487
0
    requests_rx: async_channel::Receiver<String>,
488
0
    responses_tx: async_channel::Sender<String>,
489
0
) {
Unexecuted instantiation: _RINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpEB6_
Unexecuted instantiation: _RINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefEB1b_
Unexecuted instantiation: _RINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpEB6_
490
0
    let mut me = Background {
491
0
        log_target,
492
0
        chain_name: config.chain_name,
493
0
        chain_ty: config.chain_ty,
494
0
        chain_is_live: config.chain_is_live,
495
0
        chain_properties_json: config.chain_properties_json,
496
0
        system_name: config.system_name.clone(),
497
0
        system_version: config.system_version.clone(),
498
0
        randomness: ChaCha20Rng::from_seed({
499
0
            let mut seed = [0; 32];
500
0
            config.platform.fill_random_bytes(&mut seed);
501
0
            seed
502
0
        }),
503
0
        next_garbage_collection: Box::pin(config.platform.sleep(Duration::new(0, 0))),
504
0
        network_service: config.network_service.clone(),
505
0
        sync_service: config.sync_service.clone(),
506
0
        runtime_service: config.runtime_service.clone(),
507
0
        transactions_service: config.transactions_service.clone(),
508
0
        background_tasks: stream::FuturesUnordered::new(),
509
0
        runtime_service_subscription: RuntimeServiceSubscription::NotCreated,
510
0
        all_heads_subscriptions: hashbrown::HashSet::with_capacity_and_hasher(
511
0
            2,
512
0
            Default::default(),
513
0
        ),
514
0
        new_heads_subscriptions: hashbrown::HashSet::with_capacity_and_hasher(
515
0
            2,
516
0
            Default::default(),
517
0
        ),
518
0
        finalized_heads_subscriptions: hashbrown::HashSet::with_capacity_and_hasher(
519
0
            2,
520
0
            Default::default(),
521
0
        ),
522
0
        runtime_version_subscriptions: hashbrown::HashSet::with_capacity_and_hasher(
523
0
            2,
524
0
            Default::default(),
525
0
        ),
526
0
        transactions_subscriptions: hashbrown::HashMap::with_capacity_and_hasher(
527
0
            2,
528
0
            Default::default(),
529
0
        ),
530
0
        chain_head_follow_subscriptions: hashbrown::HashMap::with_hasher(Default::default()),
531
0
        legacy_api_storage_subscriptions: BTreeSet::new(),
532
0
        legacy_api_storage_subscriptions_by_key: BTreeSet::new(),
533
0
        legacy_api_stale_storage_subscriptions: hashbrown::HashSet::with_capacity_and_hasher(
534
0
            0,
535
0
            Default::default(),
536
0
        ),
537
0
        legacy_api_storage_query_in_progress: false,
538
0
        requests_rx: Box::pin(requests_rx),
539
0
        responses_tx,
540
0
        multistage_requests_to_advance: VecDeque::new(),
541
0
        block_headers_cache: lru::LruCache::with_hasher(
542
0
            NonZeroUsize::new(32).unwrap_or_else(|| unreachable!()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE00Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE00B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE00Ba_
543
0
            Default::default(),
544
0
        ),
545
0
        best_block_hash_pending: Vec::new(),
546
0
        pending_get_finalized_head: Vec::new(),
547
0
        block_headers_pending: hashbrown::HashMap::with_capacity_and_hasher(0, Default::default()),
548
0
        block_runtimes_cache: lru::LruCache::with_hasher(
549
0
            NonZeroUsize::new(32).unwrap_or_else(|| unreachable!()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s_0Ba_
550
0
            Default::default(),
551
0
        ),
552
0
        block_runtimes_pending: hashbrown::HashMap::with_capacity_and_hasher(0, Default::default()),
553
0
        state_get_keys_paged_cache: lru::LruCache::with_hasher(
554
0
            NonZeroUsize::new(2).unwrap(),
555
0
            util::SipHasherBuild::new({
556
0
                let mut seed = [0; 16];
557
0
                config.platform.fill_random_bytes(&mut seed);
558
0
                seed
559
0
            }),
560
0
        ),
561
0
        genesis_block_hash: config.genesis_block_hash,
562
0
        printed_legacy_json_rpc_warning: false,
563
0
        platform: config.platform,
564
0
    };
565
566
    loop {
567
        // Yield at every loop in order to provide better tasks granularity.
568
0
        futures_lite::future::yield_now().await;
569
570
        enum WakeUpReason<'a, TPlat: PlatformRef> {
571
            ForegroundDead,
572
            GarbageCollection,
573
            IncomingJsonRpcRequest(String),
574
            AdvanceMultiStageRequest {
575
                request_id_json: String,
576
                stage: MultiStageRequestStage,
577
                request_ty: MultiStageRequestTy,
578
            },
579
            Event(Event<TPlat>),
580
            RuntimeServiceSubscriptionReady(runtime_service::SubscribeAll<TPlat>),
581
            RuntimeServiceSubscriptionNotification {
582
                notification: runtime_service::Notification,
583
                subscription: &'a mut runtime_service::Subscription<TPlat>,
584
                pinned_blocks:
585
                    &'a mut hashbrown::HashMap<[u8; 32], RecentBlock, fnv::FnvBuildHasher>,
586
                finalized_and_pruned_lru: &'a mut lru::LruCache<[u8; 32], (), fnv::FnvBuildHasher>,
587
                current_best_block: &'a mut [u8; 32],
588
                new_heads_and_runtime_subscriptions_stale: &'a mut Option<Option<[u8; 32]>>,
589
                current_finalized_block: &'a mut [u8; 32],
590
                finalized_heads_subscriptions_stale: &'a mut bool,
591
            },
592
            RuntimeServiceSubscriptionDead,
593
            StartStorageSubscriptionsUpdates,
594
            NotifyFinalizedHeads,
595
            NotifyNewHeadsRuntimeSubscriptions(Option<[u8; 32]>),
596
        }
597
598
        // Wait until there is something to do.
599
0
        let wake_up_reason = {
600
0
            async {
601
0
                match &mut me.runtime_service_subscription {
602
                    RuntimeServiceSubscription::NotCreated => {
603
                        // TODO: only do this if there is a need for the subscription
604
0
                        WakeUpReason::RuntimeServiceSubscriptionDead
605
                    }
606
                    RuntimeServiceSubscription::Active {
607
0
                        subscription,
608
0
                        pinned_blocks,
609
0
                        finalized_and_pruned_lru,
610
0
                        current_best_block,
611
0
                        new_heads_and_runtime_subscriptions_stale,
612
0
                        current_finalized_block,
613
0
                        finalized_heads_subscriptions_stale,
614
0
                    } => {
615
0
                        if !me.legacy_api_storage_query_in_progress
616
0
                            && !me.legacy_api_stale_storage_subscriptions.is_empty()
617
                        {
618
0
                            return WakeUpReason::StartStorageSubscriptionsUpdates;
619
0
                        }
620
0
621
0
                        if *finalized_heads_subscriptions_stale {
622
0
                            return WakeUpReason::NotifyFinalizedHeads;
623
0
                        }
624
625
0
                        if let Some(previous_best_block) =
626
0
                            new_heads_and_runtime_subscriptions_stale.take()
627
                        {
628
0
                            return WakeUpReason::NotifyNewHeadsRuntimeSubscriptions(
629
0
                                previous_best_block,
630
0
                            );
631
0
                        }
632
0
633
0
                        match subscription.next().await {
634
0
                            Some(notification) => {
635
0
                                WakeUpReason::RuntimeServiceSubscriptionNotification {
636
0
                                    notification,
637
0
                                    subscription,
638
0
                                    pinned_blocks,
639
0
                                    finalized_and_pruned_lru,
640
0
                                    current_best_block,
641
0
                                    new_heads_and_runtime_subscriptions_stale,
642
0
                                    current_finalized_block,
643
0
                                    finalized_heads_subscriptions_stale,
644
0
                                }
645
                            }
646
0
                            None => WakeUpReason::RuntimeServiceSubscriptionDead,
647
                        }
648
                    }
649
0
                    RuntimeServiceSubscription::Pending(pending) => {
650
0
                        WakeUpReason::RuntimeServiceSubscriptionReady(pending.await)
651
                    }
652
                }
653
0
            }
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s0_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s0_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s0_0Ba_
654
0
            .or(async {
655
0
                if let Some((request_id_json, stage, request_ty)) =
656
0
                    me.multistage_requests_to_advance.pop_front()
657
                {
658
0
                    WakeUpReason::AdvanceMultiStageRequest {
659
0
                        request_id_json,
660
0
                        stage,
661
0
                        request_ty,
662
0
                    }
663
                } else {
664
0
                    future::pending().await
665
                }
666
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s1_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s1_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s1_0Ba_
667
0
            .or(async {
668
0
                if let Some(event) = me.background_tasks.next().await {
669
0
                    WakeUpReason::Event(event)
670
                } else {
671
0
                    future::pending().await
672
                }
673
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s2_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s2_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s2_0Ba_
674
0
            .or(async {
675
0
                // Pulling new requests is one of the lowest priority tasks, in order to avoid
676
0
                // doing so if the task is overloaded.
677
0
                me.requests_rx.next().await.map_or(
678
0
                    WakeUpReason::ForegroundDead,
679
0
                    WakeUpReason::IncomingJsonRpcRequest,
680
0
                )
681
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s3_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s3_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s3_0Ba_
682
0
            .or(async {
683
0
                (&mut me.next_garbage_collection).await;
684
0
                me.next_garbage_collection = Box::pin(me.platform.sleep(Duration::from_secs(10)));
685
0
                WakeUpReason::GarbageCollection
686
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s4_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s4_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s4_0Ba_
687
0
            .await
688
        };
689
690
0
        match wake_up_reason {
691
            WakeUpReason::ForegroundDead => {
692
                // Service foreground has been destroyed. Stop the background task.
693
0
                return;
694
            }
695
696
0
            WakeUpReason::GarbageCollection => {
697
0
                // Periodically shrink all the shrinkable containers, in order to make sure that
698
0
                // a temporary peak in memory usage doesn't keep memory allocated forever.
699
0
                me.chain_head_follow_subscriptions.shrink_to_fit();
700
0
                me.all_heads_subscriptions.shrink_to_fit();
701
0
                me.new_heads_subscriptions.shrink_to_fit();
702
0
                me.finalized_heads_subscriptions.shrink_to_fit();
703
0
                me.runtime_version_subscriptions.shrink_to_fit();
704
0
                me.transactions_subscriptions.shrink_to_fit();
705
0
                me.legacy_api_stale_storage_subscriptions.shrink_to_fit();
706
0
                me.multistage_requests_to_advance.shrink_to_fit();
707
0
                me.block_headers_pending.shrink_to_fit();
708
0
                me.block_runtimes_pending.shrink_to_fit();
709
0
            }
710
711
0
            WakeUpReason::IncomingJsonRpcRequest(request_json) => {
712
                // New JSON-RPC request pulled from the channel.
713
0
                let Ok((request_id_json, request_parsed)) =
714
0
                    methods::parse_jsonrpc_client_to_server(&request_json)
715
                else {
716
                    // Request has failed to parse. Immediately return an answer.
717
0
                    let _ = me
718
0
                        .responses_tx
719
0
                        .send(parse::build_parse_error_response())
720
0
                        .await;
721
0
                    continue;
722
                };
723
724
                // Print a warning for legacy JSON-RPC API functions.
725
0
                match request_parsed {
726
                    // Legacy API functions.
727
                    methods::MethodCall::account_nextIndex { .. }
728
                    | methods::MethodCall::author_hasKey { .. }
729
                    | methods::MethodCall::author_hasSessionKeys { .. }
730
                    | methods::MethodCall::author_insertKey { .. }
731
                    | methods::MethodCall::author_pendingExtrinsics { .. }
732
                    | methods::MethodCall::author_removeExtrinsic { .. }
733
                    | methods::MethodCall::author_rotateKeys { .. }
734
                    | methods::MethodCall::author_submitAndWatchExtrinsic { .. }
735
                    | methods::MethodCall::author_submitExtrinsic { .. }
736
                    | methods::MethodCall::author_unwatchExtrinsic { .. }
737
                    | methods::MethodCall::babe_epochAuthorship { .. }
738
                    | methods::MethodCall::chain_getBlock { .. }
739
                    | methods::MethodCall::chain_getBlockHash { .. }
740
                    | methods::MethodCall::chain_getFinalizedHead { .. }
741
                    | methods::MethodCall::chain_getHeader { .. }
742
                    | methods::MethodCall::chain_subscribeAllHeads { .. }
743
                    | methods::MethodCall::chain_subscribeFinalizedHeads { .. }
744
                    | methods::MethodCall::chain_subscribeNewHeads { .. }
745
                    | methods::MethodCall::chain_unsubscribeAllHeads { .. }
746
                    | methods::MethodCall::chain_unsubscribeFinalizedHeads { .. }
747
                    | methods::MethodCall::chain_unsubscribeNewHeads { .. }
748
                    | methods::MethodCall::childstate_getKeys { .. }
749
                    | methods::MethodCall::childstate_getStorage { .. }
750
                    | methods::MethodCall::childstate_getStorageHash { .. }
751
                    | methods::MethodCall::childstate_getStorageSize { .. }
752
                    | methods::MethodCall::grandpa_roundState { .. }
753
                    | methods::MethodCall::offchain_localStorageGet { .. }
754
                    | methods::MethodCall::offchain_localStorageSet { .. }
755
                    | methods::MethodCall::payment_queryInfo { .. }
756
                    | methods::MethodCall::state_call { .. }
757
                    | methods::MethodCall::state_getKeys { .. }
758
                    | methods::MethodCall::state_getKeysPaged { .. }
759
                    | methods::MethodCall::state_getMetadata { .. }
760
                    | methods::MethodCall::state_getPairs { .. }
761
                    | methods::MethodCall::state_getReadProof { .. }
762
                    | methods::MethodCall::state_getRuntimeVersion { .. }
763
                    | methods::MethodCall::state_getStorage { .. }
764
                    | methods::MethodCall::state_getStorageHash { .. }
765
                    | methods::MethodCall::state_getStorageSize { .. }
766
                    | methods::MethodCall::state_queryStorage { .. }
767
                    | methods::MethodCall::state_queryStorageAt { .. }
768
                    | methods::MethodCall::state_subscribeRuntimeVersion { .. }
769
                    | methods::MethodCall::state_subscribeStorage { .. }
770
                    | methods::MethodCall::state_unsubscribeRuntimeVersion { .. }
771
                    | methods::MethodCall::state_unsubscribeStorage { .. }
772
                    | methods::MethodCall::system_accountNextIndex { .. }
773
                    | methods::MethodCall::system_addReservedPeer { .. }
774
                    | methods::MethodCall::system_chain { .. }
775
                    | methods::MethodCall::system_chainType { .. }
776
                    | methods::MethodCall::system_dryRun { .. }
777
                    | methods::MethodCall::system_health { .. }
778
                    | methods::MethodCall::system_localListenAddresses { .. }
779
                    | methods::MethodCall::system_localPeerId { .. }
780
                    | methods::MethodCall::system_name { .. }
781
                    | methods::MethodCall::system_networkState { .. }
782
                    | methods::MethodCall::system_nodeRoles { .. }
783
                    | methods::MethodCall::system_peers { .. }
784
                    | methods::MethodCall::system_properties { .. }
785
                    | methods::MethodCall::system_removeReservedPeer { .. }
786
                    | methods::MethodCall::system_version { .. } => {
787
0
                        if !me.printed_legacy_json_rpc_warning {
788
0
                            me.printed_legacy_json_rpc_warning = true;
789
0
                            log!(
790
0
                                &me.platform,
791
0
                                Warn,
792
0
                                &me.log_target,
793
0
                                format!(
794
0
                                    "The JSON-RPC client has just called a JSON-RPC function from \
795
0
                                    the legacy JSON-RPC API ({}). Legacy JSON-RPC functions have \
796
0
                                    loose semantics and cannot be properly implemented on a light \
797
0
                                    client. You are encouraged to use the new JSON-RPC API \
798
0
                                    <https://github.com/paritytech/json-rpc-interface-spec/> \
799
0
                                    instead. The legacy JSON-RPC API functions will be deprecated \
800
0
                                    and removed in the distant future.",
801
0
                                    request_parsed.name()
802
0
                                )
803
0
                            )
804
0
                        }
805
                    }
806
807
                    // Non-legacy-API functions.
808
                    methods::MethodCall::chainHead_v1_body { .. }
809
                    | methods::MethodCall::chainHead_v1_call { .. }
810
                    | methods::MethodCall::chainHead_v1_continue { .. }
811
                    | methods::MethodCall::chainHead_v1_follow { .. }
812
                    | methods::MethodCall::chainHead_v1_header { .. }
813
                    | methods::MethodCall::chainHead_v1_stopOperation { .. }
814
                    | methods::MethodCall::chainHead_v1_storage { .. }
815
                    | methods::MethodCall::chainHead_v1_unfollow { .. }
816
                    | methods::MethodCall::chainHead_v1_unpin { .. }
817
                    | methods::MethodCall::chainSpec_v1_chainName { .. }
818
                    | methods::MethodCall::chainSpec_v1_genesisHash { .. }
819
                    | methods::MethodCall::chainSpec_v1_properties { .. }
820
                    | methods::MethodCall::rpc_methods { .. }
821
                    | methods::MethodCall::sudo_unstable_p2pDiscover { .. }
822
                    | methods::MethodCall::sudo_unstable_version { .. }
823
                    | methods::MethodCall::transaction_v1_broadcast { .. }
824
                    | methods::MethodCall::transaction_v1_stop { .. }
825
                    | methods::MethodCall::transactionWatch_v1_submitAndWatch { .. }
826
                    | methods::MethodCall::transactionWatch_v1_unwatch { .. }
827
                    | methods::MethodCall::sudo_network_unstable_watch { .. }
828
                    | methods::MethodCall::sudo_network_unstable_unwatch { .. }
829
0
                    | methods::MethodCall::chainHead_unstable_finalizedDatabase { .. } => {}
830
                }
831
832
                // Actual requests handler.
833
0
                match request_parsed {
834
                    methods::MethodCall::author_pendingExtrinsics {} => {
835
                        // Because multiple different chains ("chain" in the context of the
836
                        // public API of smoldot) might share the same transactions service, it
837
                        // could be possible for chain A to submit a transaction and then for
838
                        // chain B to read it by calling `author_pendingExtrinsics`. This would
839
                        // make it possible for the API user of chain A to be able to communicate
840
                        // with the API user of chain B. While the implications of permitting
841
                        // this are unclear, it is not a bad idea to prevent this communication
842
                        // from happening. Consequently, we always return an empty list of
843
                        // pending extrinsics.
844
                        // TODO: could store the list of pending transactions in the JSON-RPC service instead
845
0
                        let _ = me
846
0
                            .responses_tx
847
0
                            .send(
848
0
                                methods::Response::author_pendingExtrinsics(Vec::new())
849
0
                                    .to_json_response(request_id_json),
850
0
                            )
851
0
                            .await;
852
                    }
853
854
0
                    methods::MethodCall::author_submitExtrinsic { transaction } => {
855
0
                        // Note that this function is misnamed. It should really be called
856
0
                        // "author_submitTransaction".
857
0
858
0
                        // In Substrate, `author_submitExtrinsic` returns the hash of the
859
0
                        // transaction. It is unclear whether it has to actually be the hash of
860
0
                        // the transaction or if it could be any opaque value. Additionally, there
861
0
                        // isn't any other JSON-RPC method that accepts as parameter the value
862
0
                        // returned here. When in doubt, we return the hash as well.
863
0
864
0
                        let mut hash_context = blake2_rfc::blake2b::Blake2b::new(32);
865
0
                        hash_context.update(&transaction.0);
866
0
                        let mut transaction_hash: [u8; 32] = Default::default();
867
0
                        transaction_hash.copy_from_slice(hash_context.finalize().as_bytes());
868
0
                        me.transactions_service
869
0
                            .submit_transaction(transaction.0)
870
0
                            .await;
871
0
                        let _ = me
872
0
                            .responses_tx
873
0
                            .send(
874
0
                                methods::Response::author_submitExtrinsic(methods::HashHexString(
875
0
                                    transaction_hash,
876
0
                                ))
877
0
                                .to_json_response(request_id_json),
878
0
                            )
879
0
                            .await;
880
                    }
881
882
0
                    methods::MethodCall::author_submitAndWatchExtrinsic { transaction } => {
883
0
                        let subscription_id = {
884
0
                            let mut subscription_id = [0u8; 32];
885
0
                            me.randomness.fill_bytes(&mut subscription_id);
886
0
                            bs58::encode(subscription_id).into_string()
887
                        };
888
889
0
                        let mut transaction_updates = Box::pin(
890
0
                            me.transactions_service
891
0
                                .submit_and_watch_transaction(transaction.0, 16, true)
892
0
                                .await,
893
                        );
894
895
0
                        let _prev_value = me.transactions_subscriptions.insert(
896
0
                            subscription_id.clone(),
897
0
                            TransactionWatch {
898
0
                                included_block: None,
899
0
                                num_broadcasted_peers: 0,
900
0
                                ty: TransactionWatchTy::Legacy,
901
0
                            },
902
0
                        );
903
0
                        debug_assert!(_prev_value.is_none());
904
905
0
                        let _ = me
906
0
                            .responses_tx
907
0
                            .send(
908
0
                                methods::Response::author_submitAndWatchExtrinsic(Cow::Borrowed(
909
0
                                    &subscription_id,
910
0
                                ))
911
0
                                .to_json_response(request_id_json),
912
0
                            )
913
0
                            .await;
914
915
                        // Push a task that will generate an event whenever the transactions
916
                        // service sends a notification.
917
0
                        me.background_tasks.push(Box::pin(async move {
918
0
                            let Some(status) = transaction_updates.as_mut().next().await else {
919
0
                                unreachable!()
920
                            };
921
0
                            Event::TransactionEvent {
922
0
                                subscription_id,
923
0
                                event: status,
924
0
                                watcher: transaction_updates,
925
0
                            }
926
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s5_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s5_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s5_0Ba_
927
                    }
928
929
0
                    methods::MethodCall::author_unwatchExtrinsic { subscription } => {
930
0
                        let exists = me
931
0
                            .transactions_subscriptions
932
0
                            .get(&*subscription)
933
0
                            .map_or(false, |sub| matches!(sub.ty, TransactionWatchTy::Legacy));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s6_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s6_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s6_0Ba_
934
0
                        if exists {
935
0
                            me.transactions_subscriptions.remove(&*subscription);
936
0
                        }
937
0
                        let _ = me
938
0
                            .responses_tx
939
0
                            .send(
940
0
                                methods::Response::author_unwatchExtrinsic(exists)
941
0
                                    .to_json_response(request_id_json),
942
0
                            )
943
0
                            .await;
944
945
                        // Note that this doesn't remove the transaction from the transactions
946
                        // service.
947
                        // We don't cancel the task in `background_tasks` that will
948
                        // generate events about this transaction. Instead, the task will stop
949
                        // renewing itself the next time it generates a notification.
950
                    }
951
952
0
                    methods::MethodCall::chain_getBlock { hash } => {
953
0
                        // Because this request requires asynchronous operations, we push it
954
0
                        // to a list of "multi-stage requests" that are processed later.
955
0
                        me.multistage_requests_to_advance.push_back((
956
0
                            request_id_json.to_owned(),
957
0
                            match hash {
958
0
                                Some(methods::HashHexString(block_hash)) => {
959
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
960
                                }
961
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
962
                            },
963
0
                            MultiStageRequestTy::ChainGetBlock,
964
                        ));
965
                    }
966
967
0
                    methods::MethodCall::chain_getBlockHash { height } => {
968
0
                        // TODO: maybe store values in cache?
969
0
                        match height {
970
                            Some(0) => {
971
                                // Block 0 is important for the JSON-RPC client to be able
972
                                // to generate transactions for the chain. Make sure that it is
973
                                // always queriable
974
0
                                let _ = me
975
0
                                    .responses_tx
976
0
                                    .send(
977
0
                                        methods::Response::chain_getBlockHash(
978
0
                                            methods::HashHexString(me.genesis_block_hash),
979
0
                                        )
980
0
                                        .to_json_response(request_id_json),
981
0
                                    )
982
0
                                    .await;
983
                            }
984
0
                            None => {
985
0
                                // Because finding the best block might require an asynchronous
986
0
                                // operation, we push it to a list of "multi-stage requests"
987
0
                                // that are processed later.
988
0
                                me.multistage_requests_to_advance.push_back((
989
0
                                    request_id_json.to_owned(),
990
0
                                    MultiStageRequestStage::BlockHashNotKnown,
991
0
                                    MultiStageRequestTy::ChainGetBestBlockHash,
992
0
                                ));
993
0
                            }
994
                            Some(_) => {
995
                                // TODO: look into some list of known blocks
996
997
                                // While could ask a full node for the block with a specific
998
                                // number, there is absolutely no way to verify the answer of
999
                                // the full node.
1000
0
                                let _ = me
1001
0
                                    .responses_tx
1002
0
                                    .send(parse::build_success_response(request_id_json, "null"))
1003
0
                                    .await;
1004
                            }
1005
                        }
1006
                    }
1007
1008
                    methods::MethodCall::chain_getFinalizedHead {} => {
1009
                        if let RuntimeServiceSubscription::Active {
1010
0
                            current_finalized_block,
1011
                            ..
1012
0
                        } = &me.runtime_service_subscription
1013
                        {
1014
                            // The finalized block hash is known. Send back an answer immediately.
1015
0
                            let _ = me
1016
0
                                .responses_tx
1017
0
                                .send(
1018
0
                                    methods::Response::chain_getFinalizedHead(
1019
0
                                        methods::HashHexString(*current_finalized_block),
1020
0
                                    )
1021
0
                                    .to_json_response(request_id_json),
1022
0
                                )
1023
0
                                .await;
1024
0
                        } else {
1025
0
                            // Finalized block hash not known yet. Push the request to a list of
1026
0
                            // requests that will be answered once it is known.
1027
0
                            me.pending_get_finalized_head
1028
0
                                .push(request_id_json.to_owned());
1029
0
                        }
1030
                    }
1031
1032
0
                    methods::MethodCall::chain_getHeader { hash } => {
1033
0
                        // Because this request requires asynchronous operations, we push it
1034
0
                        // to a list of "multi-stage requests" that are processed later.
1035
0
                        me.multistage_requests_to_advance.push_back((
1036
0
                            request_id_json.to_owned(),
1037
0
                            match hash {
1038
0
                                Some(methods::HashHexString(block_hash)) => {
1039
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1040
                                }
1041
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1042
                            },
1043
0
                            MultiStageRequestTy::ChainGetHeader,
1044
                        ));
1045
                    }
1046
1047
                    methods::MethodCall::chain_subscribeAllHeads {} => {
1048
0
                        let subscription_id = {
1049
0
                            let mut subscription_id = [0u8; 32];
1050
0
                            me.randomness.fill_bytes(&mut subscription_id);
1051
0
                            bs58::encode(subscription_id).into_string()
1052
0
                        };
1053
0
1054
0
                        let _ = me
1055
0
                            .responses_tx
1056
0
                            .send(
1057
0
                                methods::Response::chain_subscribeAllHeads(Cow::Borrowed(
1058
0
                                    &subscription_id,
1059
0
                                ))
1060
0
                                .to_json_response(request_id_json),
1061
0
                            )
1062
0
                            .await;
1063
1064
0
                        let _was_inserted = me.all_heads_subscriptions.insert(subscription_id);
1065
0
                        debug_assert!(_was_inserted);
1066
1067
                        // Note that, contrary to other similar subscriptions, we don't send
1068
                        // any notification immediately.
1069
                    }
1070
1071
                    methods::MethodCall::chain_subscribeFinalizedHeads {} => {
1072
0
                        let subscription_id = {
1073
0
                            let mut subscription_id = [0u8; 32];
1074
0
                            me.randomness.fill_bytes(&mut subscription_id);
1075
0
                            bs58::encode(subscription_id).into_string()
1076
0
                        };
1077
0
1078
0
                        let _ = me
1079
0
                            .responses_tx
1080
0
                            .send(
1081
0
                                methods::Response::chain_subscribeFinalizedHeads(Cow::Borrowed(
1082
0
                                    &subscription_id,
1083
0
                                ))
1084
0
                                .to_json_response(request_id_json),
1085
0
                            )
1086
0
                            .await;
1087
1088
                        // If the finalized block hash is known, send a notification immediately.
1089
                        // Otherwise, one will be sent once the finalized block hash is known.
1090
                        if let RuntimeServiceSubscription::Active {
1091
0
                            current_finalized_block,
1092
0
                            pinned_blocks,
1093
                            ..
1094
0
                        } = &me.runtime_service_subscription
1095
                        {
1096
0
                            match methods::Header::from_scale_encoded_header(
1097
0
                                &pinned_blocks
1098
0
                                    .get(current_finalized_block)
1099
0
                                    .unwrap()
1100
0
                                    .scale_encoded_header,
1101
0
                                me.runtime_service.block_number_bytes(),
1102
0
                            ) {
1103
0
                                Ok(h) => {
1104
0
                                    let _ = me
1105
0
                                        .responses_tx
1106
0
                                        .send(
1107
0
                                            methods::ServerToClient::chain_finalizedHead {
1108
0
                                                subscription: Cow::Borrowed(&subscription_id),
1109
0
                                                result: h,
1110
0
                                            }
1111
0
                                            .to_json_request_object_parameters(None),
1112
0
                                        )
1113
0
                                        .await;
1114
                                }
1115
0
                                Err(error) => {
1116
0
                                    log!(
1117
0
                                        &me.platform,
1118
0
                                        Warn,
1119
0
                                        &me.log_target,
1120
0
                                        format!(
1121
0
                                            "`chain_subscribeFinalizedHeads` subscription has \
1122
0
                                                skipped block due to undecodable header. Hash: {}. \
1123
0
                                                Error: {}",
1124
0
                                            HashDisplay(current_finalized_block),
1125
0
                                            error
1126
0
                                        )
1127
0
                                    );
1128
0
                                }
1129
                            }
1130
0
                        }
1131
1132
0
                        let _was_inserted =
1133
0
                            me.finalized_heads_subscriptions.insert(subscription_id);
1134
0
                        debug_assert!(_was_inserted);
1135
                    }
1136
1137
                    methods::MethodCall::chain_subscribeNewHeads {} => {
1138
0
                        let subscription_id = {
1139
0
                            let mut subscription_id = [0u8; 32];
1140
0
                            me.randomness.fill_bytes(&mut subscription_id);
1141
0
                            bs58::encode(subscription_id).into_string()
1142
0
                        };
1143
0
1144
0
                        let _ = me
1145
0
                            .responses_tx
1146
0
                            .send(
1147
0
                                methods::Response::chain_subscribeNewHeads(Cow::Borrowed(
1148
0
                                    &subscription_id,
1149
0
                                ))
1150
0
                                .to_json_response(request_id_json),
1151
0
                            )
1152
0
                            .await;
1153
1154
                        // If the best block hash is known, send a notification immediately.
1155
                        // Otherwise, one will be sent once the best block hash is known.
1156
                        if let RuntimeServiceSubscription::Active {
1157
0
                            current_best_block,
1158
0
                            pinned_blocks,
1159
                            ..
1160
0
                        } = &me.runtime_service_subscription
1161
                        {
1162
0
                            match methods::Header::from_scale_encoded_header(
1163
0
                                &pinned_blocks
1164
0
                                    .get(current_best_block)
1165
0
                                    .unwrap()
1166
0
                                    .scale_encoded_header,
1167
0
                                me.runtime_service.block_number_bytes(),
1168
0
                            ) {
1169
0
                                Ok(h) => {
1170
0
                                    let _ = me
1171
0
                                        .responses_tx
1172
0
                                        .send(
1173
0
                                            methods::ServerToClient::chain_newHead {
1174
0
                                                subscription: Cow::Borrowed(&subscription_id),
1175
0
                                                result: h,
1176
0
                                            }
1177
0
                                            .to_json_request_object_parameters(None),
1178
0
                                        )
1179
0
                                        .await;
1180
                                }
1181
0
                                Err(error) => {
1182
0
                                    log!(
1183
0
                                        &me.platform,
1184
0
                                        Warn,
1185
0
                                        &me.log_target,
1186
0
                                        format!(
1187
0
                                            "`chain_subscribeNewHeads` subscription has \
1188
0
                                                skipped block due to undecodable header. Hash: {}. \
1189
0
                                                Error: {}",
1190
0
                                            HashDisplay(current_best_block),
1191
0
                                            error
1192
0
                                        )
1193
0
                                    );
1194
0
                                }
1195
                            }
1196
0
                        }
1197
1198
0
                        let _was_inserted = me.new_heads_subscriptions.insert(subscription_id);
1199
0
                        debug_assert!(_was_inserted);
1200
                    }
1201
1202
0
                    methods::MethodCall::chain_unsubscribeAllHeads { subscription } => {
1203
0
                        let exists = me.all_heads_subscriptions.remove(&subscription);
1204
0
                        let _ = me
1205
0
                            .responses_tx
1206
0
                            .send(
1207
0
                                methods::Response::chain_unsubscribeAllHeads(exists)
1208
0
                                    .to_json_response(request_id_json),
1209
0
                            )
1210
0
                            .await;
1211
                    }
1212
1213
0
                    methods::MethodCall::chain_unsubscribeFinalizedHeads { subscription } => {
1214
0
                        let exists = me.finalized_heads_subscriptions.remove(&subscription);
1215
0
                        let _ = me
1216
0
                            .responses_tx
1217
0
                            .send(
1218
0
                                methods::Response::chain_unsubscribeFinalizedHeads(exists)
1219
0
                                    .to_json_response(request_id_json),
1220
0
                            )
1221
0
                            .await;
1222
                    }
1223
1224
0
                    methods::MethodCall::chain_unsubscribeNewHeads { subscription } => {
1225
0
                        let exists = me.new_heads_subscriptions.remove(&subscription);
1226
0
                        let _ = me
1227
0
                            .responses_tx
1228
0
                            .send(
1229
0
                                methods::Response::chain_unsubscribeNewHeads(exists)
1230
0
                                    .to_json_response(request_id_json),
1231
0
                            )
1232
0
                            .await;
1233
                    }
1234
1235
                    methods::MethodCall::payment_queryInfo {
1236
0
                        extrinsic: methods::HexString(extrinsic),
1237
0
                        hash,
1238
0
                    } => {
1239
0
                        // Because this request requires asynchronous operations, we push it
1240
0
                        // to a list of "multi-stage requests" that are processed later.
1241
0
                        me.multistage_requests_to_advance.push_back((
1242
0
                            request_id_json.to_owned(),
1243
0
                            match hash {
1244
0
                                Some(methods::HashHexString(block_hash)) => {
1245
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1246
                                }
1247
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1248
                            },
1249
0
                            MultiStageRequestTy::PaymentQueryInfo { extrinsic },
1250
                        ));
1251
                    }
1252
1253
                    methods::MethodCall::rpc_methods {} => {
1254
0
                        let _ = me
1255
0
                            .responses_tx
1256
0
                            .send(
1257
0
                                methods::Response::rpc_methods(methods::RpcMethods {
1258
0
                                    methods: methods::MethodCall::method_names()
1259
0
                                        .map(|n| n.into())
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s7_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s7_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s7_0Ba_
1260
0
                                        .collect(),
1261
0
                                })
1262
0
                                .to_json_response(request_id_json),
1263
0
                            )
1264
0
                            .await;
1265
                    }
1266
1267
                    methods::MethodCall::state_call {
1268
0
                        name,
1269
0
                        parameters,
1270
0
                        hash,
1271
0
                    } => {
1272
0
                        // Because this request requires asynchronous operations, we push it
1273
0
                        // to a list of "multi-stage requests" that are processed later.
1274
0
                        me.multistage_requests_to_advance.push_back((
1275
0
                            request_id_json.to_owned(),
1276
0
                            match hash {
1277
0
                                Some(methods::HashHexString(block_hash)) => {
1278
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1279
                                }
1280
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1281
                            },
1282
0
                            MultiStageRequestTy::StateCall {
1283
0
                                name: name.into_owned(),
1284
0
                                parameters: parameters.0,
1285
0
                            },
1286
                        ));
1287
                    }
1288
1289
                    methods::MethodCall::state_getKeys {
1290
0
                        prefix: methods::HexString(prefix),
1291
0
                        hash,
1292
0
                    } => {
1293
0
                        // Because this request requires asynchronous operations, we push it
1294
0
                        // to a list of "multi-stage requests" that are processed later.
1295
0
                        me.multistage_requests_to_advance.push_back((
1296
0
                            request_id_json.to_owned(),
1297
0
                            match hash {
1298
0
                                Some(methods::HashHexString(block_hash)) => {
1299
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1300
                                }
1301
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1302
                            },
1303
0
                            MultiStageRequestTy::StateGetKeys { prefix },
1304
                        ));
1305
                    }
1306
1307
                    methods::MethodCall::state_getKeysPaged {
1308
0
                        prefix,
1309
0
                        count,
1310
0
                        start_key,
1311
0
                        hash,
1312
0
                    } => {
1313
0
                        // Because this request requires asynchronous operations, we push it
1314
0
                        // to a list of "multi-stage requests" that are processed later.
1315
0
                        me.multistage_requests_to_advance.push_back((
1316
0
                            request_id_json.to_owned(),
1317
0
                            match hash {
1318
0
                                Some(methods::HashHexString(block_hash)) => {
1319
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1320
                                }
1321
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1322
                            },
1323
0
                            MultiStageRequestTy::StateGetKeysPaged {
1324
0
                                prefix: prefix.map_or(Vec::new(), |p| p.0),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s8_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s8_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s8_0Ba_
1325
0
                                count,
1326
0
                                start_key: start_key.map(|p| p.0),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s9_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s9_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s9_0Ba_
1327
0
                            },
1328
                        ));
1329
                    }
1330
1331
0
                    methods::MethodCall::state_queryStorageAt { keys, at } => {
1332
0
                        // Because this request requires asynchronous operations, we push it
1333
0
                        // to a list of "multi-stage requests" that are processed later.
1334
0
                        me.multistage_requests_to_advance.push_back((
1335
0
                            request_id_json.to_owned(),
1336
0
                            match at {
1337
0
                                Some(methods::HashHexString(block_hash)) => {
1338
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1339
                                }
1340
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1341
                            },
1342
0
                            MultiStageRequestTy::StateQueryStorageAt { keys },
1343
                        ));
1344
                    }
1345
1346
0
                    methods::MethodCall::state_getMetadata { hash } => {
1347
0
                        // Because this request requires asynchronous operations, we push it
1348
0
                        // to a list of "multi-stage requests" that are processed later.
1349
0
                        me.multistage_requests_to_advance.push_back((
1350
0
                            request_id_json.to_owned(),
1351
0
                            match hash {
1352
0
                                Some(methods::HashHexString(block_hash)) => {
1353
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1354
                                }
1355
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1356
                            },
1357
0
                            MultiStageRequestTy::StateGetMetadata,
1358
                        ));
1359
                    }
1360
1361
0
                    methods::MethodCall::state_getStorage { key, hash } => {
1362
0
                        // Because this request requires asynchronous operations, we push it
1363
0
                        // to a list of "multi-stage requests" that are processed later.
1364
0
                        me.multistage_requests_to_advance.push_back((
1365
0
                            request_id_json.to_owned(),
1366
0
                            match hash {
1367
0
                                Some(methods::HashHexString(block_hash)) => {
1368
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1369
                                }
1370
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1371
                            },
1372
0
                            MultiStageRequestTy::StateGetStorage { key: key.0 },
1373
                        ));
1374
                    }
1375
1376
0
                    methods::MethodCall::state_getRuntimeVersion { at } => {
1377
0
                        // Because this request requires asynchronous operations, we push it
1378
0
                        // to a list of "multi-stage requests" that are processed later.
1379
0
                        me.multistage_requests_to_advance.push_back((
1380
0
                            request_id_json.to_owned(),
1381
0
                            match at {
1382
0
                                Some(methods::HashHexString(block_hash)) => {
1383
0
                                    MultiStageRequestStage::BlockHashKnown { block_hash }
1384
                                }
1385
0
                                None => MultiStageRequestStage::BlockHashNotKnown,
1386
                            },
1387
0
                            MultiStageRequestTy::StateGetRuntimeVersion,
1388
                        ));
1389
                    }
1390
1391
                    methods::MethodCall::state_subscribeRuntimeVersion {} => {
1392
0
                        let subscription_id = {
1393
0
                            let mut subscription_id = [0u8; 32];
1394
0
                            me.randomness.fill_bytes(&mut subscription_id);
1395
0
                            bs58::encode(subscription_id).into_string()
1396
0
                        };
1397
0
1398
0
                        let _ = me
1399
0
                            .responses_tx
1400
0
                            .send(
1401
0
                                methods::Response::state_subscribeRuntimeVersion(Cow::Borrowed(
1402
0
                                    &subscription_id,
1403
0
                                ))
1404
0
                                .to_json_response(request_id_json),
1405
0
                            )
1406
0
                            .await;
1407
1408
                        // If the finalized block runtime is known, immediately send back
1409
                        // a notification.
1410
                        if let RuntimeServiceSubscription::Active {
1411
0
                            current_best_block,
1412
0
                            pinned_blocks,
1413
                            ..
1414
0
                        } = &me.runtime_service_subscription
1415
                        {
1416
                            // TODO: we don't send None in case of error; remove the Option altogether
1417
0
                            if let Ok(runtime_version) = &*pinned_blocks
1418
0
                                .get(current_best_block)
1419
0
                                .unwrap()
1420
0
                                .runtime_version
1421
                            {
1422
0
                                let _ = me
1423
0
                                    .responses_tx
1424
0
                                    .send(
1425
0
                                        methods::ServerToClient::state_runtimeVersion {
1426
0
                                            subscription: Cow::Borrowed(&subscription_id),
1427
0
                                            result: Some(convert_runtime_version_legacy(
1428
0
                                                runtime_version,
1429
0
                                            )),
1430
0
                                        }
1431
0
                                        .to_json_request_object_parameters(None),
1432
0
                                    )
1433
0
                                    .await;
1434
0
                            }
1435
0
                        }
1436
1437
0
                        let _was_inserted =
1438
0
                            me.runtime_version_subscriptions.insert(subscription_id);
1439
0
                        debug_assert!(_was_inserted);
1440
                    }
1441
1442
0
                    methods::MethodCall::state_subscribeStorage { list } => {
1443
0
                        // TODO: limit the size of `list` to avoid DoS attacks; this is out of scope of this module and should be done "externally"
1444
0
                        if list.is_empty() {
1445
                            // When the list of keys is empty, that means we want to subscribe
1446
                            // to *all* storage changes. It is not possible to reasonably
1447
                            // implement this in a light client.
1448
0
                            let _ = me
1449
0
                                .responses_tx
1450
0
                                .send(parse::build_error_response(
1451
0
                                    request_id_json,
1452
0
                                    parse::ErrorResponse::ServerError(
1453
0
                                        -32000,
1454
0
                                        "Subscribing to all storage changes isn't supported",
1455
0
                                    ),
1456
0
                                    None,
1457
0
                                ))
1458
0
                                .await;
1459
0
                            continue;
1460
0
                        }
1461
0
1462
0
                        let subscription_id = Arc::<str>::from({
1463
0
                            let mut subscription_id = [0u8; 32];
1464
0
                            me.randomness.fill_bytes(&mut subscription_id);
1465
0
                            bs58::encode(subscription_id).into_string()
1466
0
                        });
1467
1468
0
                        for key in list {
1469
0
                            let _was_inserted = me
1470
0
                                .legacy_api_storage_subscriptions_by_key
1471
0
                                .insert((key.0.clone(), subscription_id.clone()));
1472
0
                            debug_assert!(_was_inserted);
1473
0
                            let _was_inserted = me
1474
0
                                .legacy_api_storage_subscriptions
1475
0
                                .insert((subscription_id.clone(), key.0));
1476
0
                            debug_assert!(_was_inserted);
1477
                        }
1478
1479
                        // The subscription is inserted in a list of "stale" subscriptions.
1480
                        // It will be picked up as soon as possible.
1481
0
                        let _was_inserted = me
1482
0
                            .legacy_api_stale_storage_subscriptions
1483
0
                            .insert(subscription_id.clone());
1484
0
                        debug_assert!(_was_inserted);
1485
1486
0
                        let _ = me
1487
0
                            .responses_tx
1488
0
                            .send(
1489
0
                                methods::Response::state_subscribeStorage(Cow::Borrowed(
1490
0
                                    &*subscription_id,
1491
0
                                ))
1492
0
                                .to_json_response(request_id_json),
1493
0
                            )
1494
0
                            .await;
1495
                    }
1496
1497
0
                    methods::MethodCall::state_unsubscribeRuntimeVersion { subscription } => {
1498
0
                        let exists = me.runtime_version_subscriptions.remove(&*subscription);
1499
0
                        let _ = me
1500
0
                            .responses_tx
1501
0
                            .send(
1502
0
                                methods::Response::state_unsubscribeRuntimeVersion(exists)
1503
0
                                    .to_json_response(request_id_json),
1504
0
                            )
1505
0
                            .await;
1506
                    }
1507
1508
0
                    methods::MethodCall::state_unsubscribeStorage { subscription } => {
1509
0
                        let subscription = Arc::<str>::from(&*subscription);
1510
1511
                        // Remove the subscription from the state. This is a bit complicated due
1512
                        // to the use of `BTreeSet`s.
1513
0
                        let subscribed_keys = {
1514
0
                            let mut after = me
1515
0
                                .legacy_api_storage_subscriptions
1516
0
                                .split_off(&(subscription.clone(), Vec::new()));
1517
0
                            if let Some(first_entry_after) =
1518
0
                                after.iter().find(|(s, _)| *s != subscription).cloned()
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sa_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sa_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sa_0Ba_
1519
                            // TODO: O(n) ^
1520
0
                            {
1521
0
                                me.legacy_api_storage_subscriptions
1522
0
                                    .append(&mut after.split_off(&first_entry_after));
1523
0
                            }
1524
0
                            after
1525
0
                        };
1526
0
                        let exists = !subscribed_keys.is_empty();
1527
0
                        for (_, key) in subscribed_keys {
1528
0
                            let _was_removed = me
1529
0
                                .legacy_api_storage_subscriptions_by_key
1530
0
                                .remove(&(key, subscription.clone()));
1531
0
                            debug_assert!(_was_removed);
1532
                        }
1533
1534
0
                        let _ = me
1535
0
                            .legacy_api_stale_storage_subscriptions
1536
0
                            .remove(&subscription);
1537
0
1538
0
                        let _ = me
1539
0
                            .responses_tx
1540
0
                            .send(
1541
0
                                methods::Response::state_unsubscribeStorage(exists)
1542
0
                                    .to_json_response(request_id_json),
1543
0
                            )
1544
0
                            .await;
1545
                    }
1546
1547
0
                    methods::MethodCall::system_accountNextIndex { account } => {
1548
0
                        // Because this request requires asynchronous operations, we push it
1549
0
                        // to a list of "multi-stage requests" that are processed later.
1550
0
                        me.multistage_requests_to_advance.push_back((
1551
0
                            request_id_json.to_owned(),
1552
0
                            MultiStageRequestStage::BlockHashNotKnown,
1553
0
                            MultiStageRequestTy::SystemAccountNextIndex {
1554
0
                                account_id: account.0,
1555
0
                            },
1556
0
                        ));
1557
0
                    }
1558
1559
                    methods::MethodCall::system_chain {} => {
1560
0
                        let _ = me
1561
0
                            .responses_tx
1562
0
                            .send(
1563
0
                                methods::Response::system_chain((&me.chain_name).into())
1564
0
                                    .to_json_response(request_id_json),
1565
0
                            )
1566
0
                            .await;
1567
                    }
1568
1569
                    methods::MethodCall::system_chainType {} => {
1570
0
                        let _ = me
1571
0
                            .responses_tx
1572
0
                            .send(
1573
0
                                methods::Response::system_chainType((&me.chain_ty).into())
1574
0
                                    .to_json_response(request_id_json),
1575
0
                            )
1576
0
                            .await;
1577
                    }
1578
1579
                    methods::MethodCall::system_health {} => {
1580
0
                        let _ = me
1581
0
                            .responses_tx
1582
0
                            .send(
1583
0
                                methods::Response::system_health(methods::SystemHealth {
1584
0
                                    is_syncing: !me
1585
0
                                        .runtime_service
1586
0
                                        .is_near_head_of_chain_heuristic()
1587
0
                                        .await,
1588
                                    peers: u64::try_from(
1589
0
                                        me.sync_service.syncing_peers().await.len(),
1590
0
                                    )
1591
0
                                    .unwrap_or(u64::MAX),
1592
0
                                    should_have_peers: me.chain_is_live,
1593
0
                                })
1594
0
                                .to_json_response(request_id_json),
1595
                            )
1596
0
                            .await;
1597
                    }
1598
1599
                    methods::MethodCall::system_localListenAddresses {} => {
1600
                        // Light client never listens on any address.
1601
0
                        let _ = me
1602
0
                            .responses_tx
1603
0
                            .send(
1604
0
                                methods::Response::system_localListenAddresses(Vec::new())
1605
0
                                    .to_json_response(request_id_json),
1606
0
                            )
1607
0
                            .await;
1608
                    }
1609
1610
                    methods::MethodCall::system_name {} => {
1611
0
                        let _ = me
1612
0
                            .responses_tx
1613
0
                            .send(
1614
0
                                methods::Response::system_name((&me.system_name).into())
1615
0
                                    .to_json_response(request_id_json),
1616
0
                            )
1617
0
                            .await;
1618
                    }
1619
1620
                    methods::MethodCall::system_nodeRoles {} => {
1621
0
                        let _ = me
1622
0
                            .responses_tx
1623
0
                            .send(
1624
0
                                methods::Response::system_nodeRoles(Cow::Borrowed(&[
1625
0
                                    methods::NodeRole::Light,
1626
0
                                ]))
1627
0
                                .to_json_response(request_id_json),
1628
0
                            )
1629
0
                            .await;
1630
                    }
1631
1632
                    methods::MethodCall::system_peers {} => {
1633
0
                        let _ = me
1634
0
                            .responses_tx
1635
0
                            .send(
1636
0
                                methods::Response::system_peers(
1637
0
                                    me.sync_service
1638
0
                                        .syncing_peers()
1639
0
                                        .await
1640
0
                                        .map(|(peer_id, role, best_number, best_hash)| {
1641
0
                                            methods::SystemPeer {
1642
0
                                                peer_id: peer_id.to_string(),
1643
0
                                                roles: match role {
1644
                                                    sync_service::Role::Authority => {
1645
0
                                                        methods::SystemPeerRole::Authority
1646
                                                    }
1647
                                                    sync_service::Role::Full => {
1648
0
                                                        methods::SystemPeerRole::Full
1649
                                                    }
1650
                                                    sync_service::Role::Light => {
1651
0
                                                        methods::SystemPeerRole::Light
1652
                                                    }
1653
                                                },
1654
0
                                                best_hash: methods::HashHexString(best_hash),
1655
0
                                                best_number,
1656
0
                                            }
1657
0
                                        })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sb_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sb_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sb_0Ba_
1658
0
                                        .collect(),
1659
0
                                )
1660
0
                                .to_json_response(request_id_json),
1661
                            )
1662
0
                            .await;
1663
                    }
1664
1665
                    methods::MethodCall::system_properties {} => {
1666
0
                        let _ = me
1667
0
                            .responses_tx
1668
0
                            .send(
1669
0
                                methods::Response::system_properties(
1670
0
                                    serde_json::from_str(&me.chain_properties_json).unwrap(),
1671
0
                                )
1672
0
                                .to_json_response(request_id_json),
1673
0
                            )
1674
0
                            .await;
1675
                    }
1676
1677
                    methods::MethodCall::system_version {} => {
1678
0
                        let _ = me
1679
0
                            .responses_tx
1680
0
                            .send(
1681
0
                                methods::Response::system_version((&me.system_version).into())
1682
0
                                    .to_json_response(request_id_json),
1683
0
                            )
1684
0
                            .await;
1685
                    }
1686
1687
                    methods::MethodCall::chainHead_v1_body {
1688
0
                        follow_subscription,
1689
0
                        hash,
1690
                    } => {
1691
0
                        let Some(subscription) = me
1692
0
                            .chain_head_follow_subscriptions
1693
0
                            .get_mut(&*follow_subscription)
1694
                        else {
1695
                            // Subscription doesn't exist.
1696
0
                            let _ = me
1697
0
                                .responses_tx
1698
0
                                .send(
1699
0
                                    methods::Response::chainHead_v1_body(
1700
0
                                        methods::ChainHeadBodyCallReturn::LimitReached {},
1701
0
                                    )
1702
0
                                    .to_json_response(request_id_json),
1703
0
                                )
1704
0
                                .await;
1705
0
                            continue;
1706
                        };
1707
1708
                        // Determine whether the requested block hash is valid, and if yes its
1709
                        // number and extrinsics trie root. The extrinsics trie root is used to
1710
                        // verify whether the body we download is correct.
1711
0
                        let (block_number, extrinsics_root) = {
1712
0
                            if let Some(header) = subscription.pinned_blocks_headers.get(&hash.0) {
1713
0
                                let decoded =
1714
0
                                    header::decode(header, me.sync_service.block_number_bytes())
1715
0
                                        .unwrap(); // TODO: unwrap?
1716
0
                                (decoded.number, *decoded.extrinsics_root)
1717
                            } else {
1718
                                // Block isn't pinned. Request is invalid.
1719
0
                                let _ = me
1720
0
                                    .responses_tx
1721
0
                                    .send(parse::build_error_response(
1722
0
                                        request_id_json,
1723
0
                                        parse::ErrorResponse::ApplicationDefined(
1724
0
                                            -32801,
1725
0
                                            "unknown or unpinned block",
1726
0
                                        ),
1727
0
                                        None,
1728
0
                                    ))
1729
0
                                    .await;
1730
0
                                continue;
1731
                            }
1732
                        };
1733
1734
                        // Check whether there is an operation slot available.
1735
                        subscription.available_operation_slots =
1736
0
                            match subscription.available_operation_slots.checked_sub(1) {
1737
0
                                Some(s) => s,
1738
                                None => {
1739
0
                                    let _ = me
1740
0
                                        .responses_tx
1741
0
                                        .send(
1742
0
                                            methods::Response::chainHead_v1_body(
1743
0
                                                methods::ChainHeadBodyCallReturn::LimitReached {},
1744
0
                                            )
1745
0
                                            .to_json_response(request_id_json),
1746
0
                                        )
1747
0
                                        .await;
1748
0
                                    continue;
1749
                                }
1750
                            };
1751
1752
                        // Build the future that will grab the block body.
1753
0
                        let body_download_future = me.sync_service.clone().block_query(
1754
0
                            block_number,
1755
0
                            hash.0,
1756
0
                            codec::BlocksRequestFields {
1757
0
                                header: false,
1758
0
                                body: true,
1759
0
                                justifications: false,
1760
0
                            },
1761
0
                            3,
1762
0
                            Duration::from_secs(20),
1763
0
                            NonZeroU32::new(2).unwrap(),
1764
0
                        );
1765
0
1766
0
                        // Allocate an operation ID, update the local state, and notify the
1767
0
                        // JSON-RPC client.
1768
0
                        let operation_id = {
1769
0
                            let mut operation_id = [0u8; 32];
1770
0
                            me.randomness.fill_bytes(&mut operation_id);
1771
0
                            bs58::encode(operation_id).into_string()
1772
0
                        };
1773
0
                        let interrupt = event_listener::Event::new();
1774
0
                        let on_interrupt = interrupt.listen();
1775
0
                        let _was_in = subscription.operations_in_progress.insert(
1776
0
                            operation_id.clone(),
1777
0
                            ChainHeadOperation {
1778
0
                                occupied_slots: 1,
1779
0
                                interrupt,
1780
0
                            },
1781
0
                        );
1782
0
                        debug_assert!(_was_in.is_none());
1783
0
                        let _ = me
1784
0
                            .responses_tx
1785
0
                            .send(
1786
0
                                methods::Response::chainHead_v1_body(
1787
0
                                    methods::ChainHeadBodyCallReturn::Started {
1788
0
                                        operation_id: (&operation_id).into(),
1789
0
                                    },
1790
0
                                )
1791
0
                                .to_json_response(request_id_json),
1792
0
                            )
1793
0
                            .await;
1794
1795
                        // Finish the download asynchronously.
1796
0
                        let subscription_id = follow_subscription.into_owned();
1797
0
                        me.background_tasks.push(Box::pin(async move {
1798
0
                            async move {
1799
0
                                on_interrupt.await;
1800
                                // This event is necessary only because tasks can't finish without
1801
                                // generating an event.
1802
0
                                Event::ChainHeadOperationCancelled
1803
0
                            }
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sc_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sc_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sc_00Bc_
1804
0
                            .or(async move {
1805
0
                                Event::ChainHeadBodyOperationDone {
1806
0
                                    subscription_id,
1807
0
                                    operation_id,
1808
0
                                    expected_extrinsics_root: extrinsics_root,
1809
0
                                    result: body_download_future.await,
1810
                                }
1811
0
                            })
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sc_0s_0Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sc_0s_0B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sc_0s_0Bc_
1812
0
                            .await
1813
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sc_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sc_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sc_0Ba_
1814
                    }
1815
1816
                    methods::MethodCall::chainHead_v1_call {
1817
0
                        follow_subscription,
1818
0
                        hash,
1819
0
                        function,
1820
0
                        call_parameters: methods::HexString(call_parameters),
1821
                    } => {
1822
0
                        let Some(subscription) = me
1823
0
                            .chain_head_follow_subscriptions
1824
0
                            .get_mut(&*follow_subscription)
1825
                        else {
1826
                            // Subscription doesn't exist.
1827
0
                            let _ = me
1828
0
                                .responses_tx
1829
0
                                .send(
1830
0
                                    methods::Response::chainHead_v1_call(
1831
0
                                        methods::ChainHeadBodyCallReturn::LimitReached {},
1832
0
                                    )
1833
0
                                    .to_json_response(request_id_json),
1834
0
                                )
1835
0
                                .await;
1836
0
                            continue;
1837
                        };
1838
1839
                        // Determine whether the requested block hash is valid.
1840
0
                        if !subscription.pinned_blocks_headers.contains_key(&hash.0) {
1841
                            // Block isn't pinned. Request is invalid.
1842
0
                            let _ = me
1843
0
                                .responses_tx
1844
0
                                .send(parse::build_error_response(
1845
0
                                    request_id_json,
1846
0
                                    parse::ErrorResponse::ApplicationDefined(
1847
0
                                        -32801,
1848
0
                                        "unknown or unpinned block",
1849
0
                                    ),
1850
0
                                    None,
1851
0
                                ))
1852
0
                                .await;
1853
0
                            continue;
1854
0
                        }
1855
0
1856
0
                        // Check whether there is an operation slot available.
1857
0
                        subscription.available_operation_slots =
1858
0
                            match subscription.available_operation_slots.checked_sub(1) {
1859
0
                                Some(s) => s,
1860
                                None => {
1861
0
                                    let _ = me
1862
0
                                        .responses_tx
1863
0
                                        .send(
1864
0
                                            methods::Response::chainHead_v1_call(
1865
0
                                                methods::ChainHeadBodyCallReturn::LimitReached {},
1866
0
                                            )
1867
0
                                            .to_json_response(request_id_json),
1868
0
                                        )
1869
0
                                        .await;
1870
0
                                    continue;
1871
                                }
1872
                            };
1873
1874
                        // Make sure that the subscription is `withRuntime: true`.
1875
0
                        let Some(runtime_service_subscription_id) =
1876
0
                            subscription.runtime_service_subscription_id
1877
                        else {
1878
                            // Subscription is "without runtime".
1879
                            // This path is in principle also reachable if the subscription isn't
1880
                            // initialized yet, but in that case the block hash can't possibly be
1881
                            // pinned.
1882
0
                            let _ = me
1883
0
                                .responses_tx
1884
0
                                .send(parse::build_error_response(
1885
0
                                    request_id_json,
1886
0
                                    parse::ErrorResponse::InvalidParams,
1887
0
                                    None,
1888
0
                                ))
1889
0
                                .await;
1890
0
                            continue;
1891
                        };
1892
1893
                        // Extract information about the block.
1894
0
                        let (pinned_runtime, block_state_trie_root_hash, block_number) = match me
1895
0
                            .runtime_service
1896
0
                            .pin_pinned_block_runtime(runtime_service_subscription_id, hash.0)
1897
0
                            .await
1898
                        {
1899
0
                            Ok(info) => info,
1900
                            Err(runtime_service::PinPinnedBlockRuntimeError::BlockNotPinned) => {
1901
                                // This has been verified above.
1902
0
                                unreachable!()
1903
                            }
1904
                            Err(
1905
                                runtime_service::PinPinnedBlockRuntimeError::ObsoleteSubscription,
1906
                            ) => {
1907
                                // The runtime service subscription is dead.
1908
0
                                let _ = me
1909
0
                                    .responses_tx
1910
0
                                    .send(
1911
0
                                        methods::Response::chainHead_v1_call(
1912
0
                                            methods::ChainHeadBodyCallReturn::LimitReached {},
1913
0
                                        )
1914
0
                                        .to_json_response(request_id_json),
1915
0
                                    )
1916
0
                                    .await;
1917
0
                                continue;
1918
                            }
1919
                        };
1920
1921
                        // Create a future that will perform the runtime call.
1922
0
                        let runtime_call_future = {
1923
0
                            let runtime_service = me.runtime_service.clone();
1924
0
                            let function = function.into_owned();
1925
0
                            async move {
1926
0
                                runtime_service
1927
0
                                    .clone()
1928
0
                                    .runtime_call(
1929
0
                                        pinned_runtime,
1930
0
                                        hash.0,
1931
0
                                        block_number,
1932
0
                                        block_state_trie_root_hash,
1933
0
                                        function,
1934
0
                                        None,
1935
0
                                        call_parameters,
1936
0
                                        3,
1937
0
                                        Duration::from_secs(20),
1938
0
                                        NonZeroU32::new(2).unwrap(),
1939
0
                                    )
1940
0
                                    .await
1941
0
                            }
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sd_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sd_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sd_0Ba_
1942
                        };
1943
1944
                        // Allocate a new operation ID, update the local state, and send the
1945
                        // confirmation to the JSON-RPC client.
1946
0
                        let operation_id = {
1947
0
                            let mut operation_id = [0u8; 32];
1948
0
                            me.randomness.fill_bytes(&mut operation_id);
1949
0
                            bs58::encode(operation_id).into_string()
1950
0
                        };
1951
0
                        let interrupt = event_listener::Event::new();
1952
0
                        let on_interrupt = interrupt.listen();
1953
0
                        let _was_in = subscription.operations_in_progress.insert(
1954
0
                            operation_id.clone(),
1955
0
                            ChainHeadOperation {
1956
0
                                occupied_slots: 1,
1957
0
                                interrupt,
1958
0
                            },
1959
0
                        );
1960
0
                        debug_assert!(_was_in.is_none());
1961
0
                        let _ = me
1962
0
                            .responses_tx
1963
0
                            .send(
1964
0
                                methods::Response::chainHead_v1_call(
1965
0
                                    methods::ChainHeadBodyCallReturn::Started {
1966
0
                                        operation_id: (&operation_id).into(),
1967
0
                                    },
1968
0
                                )
1969
0
                                .to_json_response(request_id_json),
1970
0
                            )
1971
0
                            .await;
1972
1973
                        // Finish the call asynchronously.
1974
0
                        let subscription_id = follow_subscription.into_owned();
1975
0
                        me.background_tasks.push(Box::pin(async move {
1976
0
                            async move {
1977
0
                                on_interrupt.await;
1978
                                // This event is necessary only because tasks can't finish without
1979
                                // generating an event.
1980
0
                                Event::ChainHeadOperationCancelled
1981
0
                            }
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0se_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0se_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0se_00Bc_
1982
0
                            .or(async move {
1983
0
                                Event::ChainHeadCallOperationDone {
1984
0
                                    subscription_id,
1985
0
                                    operation_id,
1986
0
                                    result: runtime_call_future.await,
1987
                                }
1988
0
                            })
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0se_0s_0Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0se_0s_0B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0se_0s_0Bc_
1989
0
                            .await
1990
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0se_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0se_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0se_0Ba_
1991
                    }
1992
1993
                    methods::MethodCall::chainHead_v1_continue { .. } => {
1994
                        // TODO: not implemented properly
1995
0
                        let _ = me
1996
0
                            .responses_tx
1997
0
                            .send(
1998
0
                                methods::Response::chainHead_v1_continue(())
1999
0
                                    .to_json_response(request_id_json),
2000
0
                            )
2001
0
                            .await;
2002
                    }
2003
2004
                    methods::MethodCall::chainHead_v1_storage {
2005
0
                        follow_subscription,
2006
0
                        hash,
2007
0
                        items,
2008
0
                        child_trie,
2009
                    } => {
2010
0
                        let Some(subscription) = me
2011
0
                            .chain_head_follow_subscriptions
2012
0
                            .get_mut(&*follow_subscription)
2013
                        else {
2014
                            // Subscription doesn't exist.
2015
0
                            let _ = me
2016
0
                                .responses_tx
2017
0
                                .send(
2018
0
                                    methods::Response::chainHead_v1_storage(
2019
0
                                        methods::ChainHeadStorageReturn::LimitReached {},
2020
0
                                    )
2021
0
                                    .to_json_response(request_id_json),
2022
0
                                )
2023
0
                                .await;
2024
0
                            continue;
2025
                        };
2026
2027
                        // Determine whether the requested block hash is valid, and if yes its
2028
                        // number and state trie root. The extrinsics trie root is used to
2029
                        // verify whether the body we download is correct.
2030
0
                        let (block_number, block_state_trie_root) = {
2031
0
                            if let Some(header) = subscription.pinned_blocks_headers.get(&hash.0) {
2032
0
                                let decoded =
2033
0
                                    header::decode(header, me.sync_service.block_number_bytes())
2034
0
                                        .unwrap(); // TODO: unwrap?
2035
0
                                (decoded.number, *decoded.state_root)
2036
                            } else {
2037
                                // Block isn't pinned. Request is invalid.
2038
0
                                let _ = me
2039
0
                                    .responses_tx
2040
0
                                    .send(parse::build_error_response(
2041
0
                                        request_id_json,
2042
0
                                        parse::ErrorResponse::ApplicationDefined(
2043
0
                                            -32801,
2044
0
                                            "unknown or unpinned block",
2045
0
                                        ),
2046
0
                                        None,
2047
0
                                    ))
2048
0
                                    .await;
2049
0
                                continue;
2050
                            }
2051
                        };
2052
2053
0
                        if child_trie.is_some() {
2054
                            // TODO: implement this
2055
0
                            let _ = me
2056
0
                                .responses_tx
2057
0
                                .send(parse::build_error_response(
2058
0
                                    request_id_json,
2059
0
                                    parse::ErrorResponse::ServerError(
2060
0
                                        -32000,
2061
0
                                        "Child key storage queries not supported yet",
2062
0
                                    ),
2063
0
                                    None,
2064
0
                                ))
2065
0
                                .await;
2066
0
                            log!(
2067
0
                                &me.platform,
2068
0
                                Warn,
2069
0
                                &me.log_target,
2070
0
                                "chainHead_v1_storage has been called with a non-null childTrie. \
2071
0
                                This isn't supported by smoldot yet."
2072
0
                            );
2073
0
                            continue;
2074
0
                        }
2075
0
2076
0
                        // Build the list of storage operations that are effectively started.
2077
0
                        // This reads from the list that the API user requests, and stops if there
2078
0
                        // is no available operation slot.
2079
0
                        let mut storage_operations = Vec::with_capacity(items.len());
2080
0
                        let mut items = items.into_iter();
2081
                        loop {
2082
0
                            if subscription.available_operation_slots == 0 {
2083
0
                                break;
2084
0
                            }
2085
0
                            let Some(item) = items.next() else { break };
2086
0
                            subscription.available_operation_slots -= 1;
2087
0
                            storage_operations.push(sync_service::StorageRequestItem {
2088
0
                                    key: item.key.0,
2089
0
                                    ty: match item.ty {
2090
                                        methods::ChainHeadStorageType::Value => {
2091
0
                                            sync_service::StorageRequestItemTy::Value
2092
                                        }
2093
                                        methods::ChainHeadStorageType::Hash => {
2094
0
                                            sync_service::StorageRequestItemTy::Hash
2095
                                        }
2096
                                        methods::ChainHeadStorageType::ClosestDescendantMerkleValue => {
2097
0
                                            sync_service::StorageRequestItemTy::ClosestDescendantMerkleValue
2098
                                        }
2099
                                        methods::ChainHeadStorageType::DescendantsValues => {
2100
0
                                            sync_service::StorageRequestItemTy::DescendantsValues
2101
                                        }
2102
                                        methods::ChainHeadStorageType::DescendantsHashes => {
2103
0
                                            sync_service::StorageRequestItemTy::DescendantsHashes
2104
                                        }
2105
                                    },
2106
                                });
2107
                        }
2108
2109
                        // Abort immediately if nothing was started.
2110
0
                        if storage_operations.is_empty() {
2111
0
                            let _ = me
2112
0
                                .responses_tx
2113
0
                                .send(
2114
0
                                    methods::Response::chainHead_v1_storage(
2115
0
                                        methods::ChainHeadStorageReturn::LimitReached {},
2116
0
                                    )
2117
0
                                    .to_json_response(request_id_json),
2118
0
                                )
2119
0
                                .await;
2120
0
                            continue;
2121
0
                        }
2122
0
2123
0
                        // Initialize the storage query operation.
2124
0
                        let fetch_operation = me.sync_service.clone().storage_query(
2125
0
                            block_number,
2126
0
                            hash.0,
2127
0
                            block_state_trie_root,
2128
0
                            storage_operations.into_iter(),
2129
0
                            3,
2130
0
                            Duration::from_secs(20),
2131
0
                            NonZeroU32::new(2).unwrap(),
2132
0
                        );
2133
0
2134
0
                        let operation_id = {
2135
0
                            let mut operation_id = [0u8; 32];
2136
0
                            me.randomness.fill_bytes(&mut operation_id);
2137
0
                            bs58::encode(operation_id).into_string()
2138
0
                        };
2139
0
2140
0
                        let interrupt = event_listener::Event::new();
2141
0
                        let on_interrupt = interrupt.listen();
2142
0
2143
0
                        let _was_in = subscription.operations_in_progress.insert(
2144
0
                            operation_id.clone(),
2145
0
                            ChainHeadOperation {
2146
0
                                occupied_slots: 1,
2147
0
                                interrupt,
2148
0
                            },
2149
0
                        );
2150
0
                        debug_assert!(_was_in.is_none());
2151
0
                        let _ = me
2152
0
                            .responses_tx
2153
0
                            .send(
2154
0
                                methods::Response::chainHead_v1_storage(
2155
0
                                    methods::ChainHeadStorageReturn::Started {
2156
0
                                        operation_id: (&operation_id).into(),
2157
0
                                        discarded_items: items.len(),
2158
0
                                    },
2159
0
                                )
2160
0
                                .to_json_response(request_id_json),
2161
0
                            )
2162
0
                            .await;
2163
2164
0
                        let subscription_id = follow_subscription.into_owned();
2165
0
                        me.background_tasks.push(Box::pin(async move {
2166
0
                            async {
2167
0
                                on_interrupt.await;
2168
                                // This event is necessary only because tasks can't finish without
2169
                                // generating an event.
2170
0
                                Event::ChainHeadOperationCancelled
2171
0
                            }
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sf_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sf_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sf_00Bc_
2172
0
                            .or(async {
2173
0
                                Event::ChainHeadStorageOperationProgress {
2174
0
                                    subscription_id,
2175
0
                                    operation_id,
2176
0
                                    progress: fetch_operation.advance().await,
2177
                                }
2178
0
                            })
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sf_0s_0Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sf_0s_0B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sf_0s_0Bc_
2179
0
                            .await
2180
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sf_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sf_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sf_0Ba_
2181
                    }
2182
2183
                    methods::MethodCall::chainHead_v1_stopOperation {
2184
0
                        follow_subscription,
2185
0
                        operation_id,
2186
                    } => {
2187
                        // Stopping an operation is done by notifying an event so that the
2188
                        // background task stops.
2189
0
                        if let Some(subscription) = me
2190
0
                            .chain_head_follow_subscriptions
2191
0
                            .get_mut(&*follow_subscription)
2192
                        {
2193
0
                            if let Some(operation) =
2194
0
                                subscription.operations_in_progress.remove(&*operation_id)
2195
0
                            {
2196
0
                                operation.interrupt.notify(usize::MAX);
2197
0
                                subscription.available_operation_slots += operation.occupied_slots;
2198
0
                            }
2199
0
                        }
2200
2201
0
                        let _ = me
2202
0
                            .responses_tx
2203
0
                            .send(
2204
0
                                methods::Response::chainHead_v1_stopOperation(())
2205
0
                                    .to_json_response(request_id_json),
2206
0
                            )
2207
0
                            .await;
2208
                    }
2209
2210
0
                    methods::MethodCall::chainHead_v1_follow { with_runtime } => {
2211
0
                        // Check that the number of existing subscriptions is below the limit.
2212
0
                        // TODO: configurable limit
2213
0
                        if me.chain_head_follow_subscriptions.len() >= 2 {
2214
0
                            let _ = me
2215
0
                                .responses_tx
2216
0
                                .send(parse::build_error_response(
2217
0
                                    request_id_json,
2218
0
                                    parse::ErrorResponse::ApplicationDefined(
2219
0
                                        -32800,
2220
0
                                        "too many active follow subscriptions",
2221
0
                                    ),
2222
0
                                    None,
2223
0
                                ))
2224
0
                                .await;
2225
0
                            continue;
2226
0
                        }
2227
0
2228
0
                        let subscription_id = {
2229
0
                            let mut subscription_id = [0u8; 32];
2230
0
                            me.randomness.fill_bytes(&mut subscription_id);
2231
0
                            bs58::encode(subscription_id).into_string()
2232
0
                        };
2233
0
2234
0
                        let _prev_value = me.chain_head_follow_subscriptions.insert(
2235
0
                            subscription_id.clone(),
2236
0
                            ChainHeadFollow {
2237
0
                                pinned_blocks_headers: hashbrown::HashMap::with_capacity_and_hasher(
2238
0
                                    0,
2239
0
                                    Default::default(),
2240
0
                                ), // TODO: capacity?
2241
0
                                operations_in_progress:
2242
0
                                    hashbrown::HashMap::with_capacity_and_hasher(
2243
0
                                        32,
2244
0
                                        Default::default(),
2245
0
                                    ),
2246
0
                                available_operation_slots: 32, // TODO: make configurable? adjust dynamically?
2247
0
                                runtime_service_subscription_id: None,
2248
0
                            },
2249
0
                        );
2250
0
                        debug_assert!(_prev_value.is_none());
2251
2252
0
                        let _ = me
2253
0
                            .responses_tx
2254
0
                            .send(
2255
0
                                methods::Response::chainHead_v1_follow(Cow::Borrowed(
2256
0
                                    &subscription_id,
2257
0
                                ))
2258
0
                                .to_json_response(request_id_json),
2259
0
                            )
2260
0
                            .await;
2261
2262
                        // Subscription asynchronously either to the runtime service or the
2263
                        // sync service.
2264
0
                        if with_runtime {
2265
0
                            let runtime_service = me.runtime_service.clone();
2266
0
                            me.background_tasks.push(Box::pin(async move {
2267
0
                                Event::ChainHeadSubscriptionWithRuntimeReady {
2268
0
                                    subscription_id,
2269
0
                                    subscription: runtime_service
2270
0
                                        .subscribe_all(
2271
0
                                            32,
2272
0
                                            NonZeroUsize::new(32).unwrap_or_else(|| unreachable!()),
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sg_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sg_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sg_00Bc_
2273
0
                                        )
2274
0
                                        .await,
2275
                                }
2276
0
                            }))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sg_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sg_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sg_0Ba_
2277
                        } else {
2278
0
                            let sync_service = me.sync_service.clone();
2279
0
                            me.background_tasks.push(Box::pin(async move {
2280
0
                                Event::ChainHeadSubscriptionWithoutRuntimeReady {
2281
0
                                    subscription_id,
2282
0
                                    subscription: sync_service.subscribe_all(32, false).await,
2283
                                }
2284
0
                            }))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sh_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sh_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sh_0Ba_
2285
                        }
2286
                    }
2287
2288
                    methods::MethodCall::chainHead_v1_unfollow {
2289
0
                        follow_subscription,
2290
                    } => {
2291
0
                        if let Some(subscription) = me
2292
0
                            .chain_head_follow_subscriptions
2293
0
                            .remove(&*follow_subscription)
2294
                        {
2295
0
                            for (_, operation) in subscription.operations_in_progress {
2296
0
                                operation.interrupt.notify(usize::MAX);
2297
0
                            }
2298
0
                        };
2299
2300
0
                        let _ = me
2301
0
                            .responses_tx
2302
0
                            .send(
2303
0
                                methods::Response::chainHead_v1_unfollow(())
2304
0
                                    .to_json_response(request_id_json),
2305
0
                            )
2306
0
                            .await;
2307
                    }
2308
2309
                    methods::MethodCall::chainHead_v1_header {
2310
0
                        follow_subscription,
2311
0
                        hash,
2312
                    } => {
2313
0
                        let Some(subscription) = me
2314
0
                            .chain_head_follow_subscriptions
2315
0
                            .get_mut(&*follow_subscription)
2316
                        else {
2317
                            // Subscription doesn't exist.
2318
0
                            let _ = me
2319
0
                                .responses_tx
2320
0
                                .send(
2321
0
                                    methods::Response::chainHead_v1_header(None)
2322
0
                                        .to_json_response(request_id_json),
2323
0
                                )
2324
0
                                .await;
2325
0
                            continue;
2326
                        };
2327
2328
0
                        let Some(block) = subscription.pinned_blocks_headers.get(&hash.0) else {
2329
                            // Block isn't pinned.
2330
0
                            let _ = me
2331
0
                                .responses_tx
2332
0
                                .send(parse::build_error_response(
2333
0
                                    request_id_json,
2334
0
                                    parse::ErrorResponse::ApplicationDefined(
2335
0
                                        -32801,
2336
0
                                        "unknown or unpinned block",
2337
0
                                    ),
2338
0
                                    None,
2339
0
                                ))
2340
0
                                .await;
2341
0
                            continue;
2342
                        };
2343
2344
0
                        let _ = me
2345
0
                            .responses_tx
2346
0
                            .send(
2347
0
                                methods::Response::chainHead_v1_header(Some(methods::HexString(
2348
0
                                    block.clone(),
2349
0
                                )))
2350
0
                                .to_json_response(request_id_json),
2351
0
                            )
2352
0
                            .await;
2353
                    }
2354
2355
                    methods::MethodCall::chainHead_v1_unpin {
2356
0
                        follow_subscription,
2357
0
                        hash_or_hashes,
2358
                    } => {
2359
0
                        let Some(subscription) = me
2360
0
                            .chain_head_follow_subscriptions
2361
0
                            .get_mut(&*follow_subscription)
2362
                        else {
2363
                            // Subscription doesn't exist.
2364
0
                            let _ = me
2365
0
                                .responses_tx
2366
0
                                .send(
2367
0
                                    methods::Response::chainHead_v1_unpin(())
2368
0
                                        .to_json_response(request_id_json),
2369
0
                                )
2370
0
                                .await;
2371
0
                            continue;
2372
                        };
2373
2374
0
                        let all_hashes = match &hash_or_hashes {
2375
0
                            methods::HashHexStringSingleOrArray::Single(hash) => {
2376
0
                                either::Left(iter::once(&hash.0))
2377
                            }
2378
0
                            methods::HashHexStringSingleOrArray::Array(hashes) => {
2379
0
                                either::Right(hashes.iter().map(|h| &h.0))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0si_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0si_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0si_0Ba_
2380
                            }
2381
                        };
2382
2383
0
                        let checks_passed = {
2384
0
                            let mut dedup_check = hashbrown::HashSet::with_capacity_and_hasher(
2385
0
                                0,
2386
0
                                SipHasherBuild::new({
2387
0
                                    let mut seed = [0; 16];
2388
0
                                    me.randomness.fill_bytes(&mut seed);
2389
0
                                    seed
2390
0
                                }),
2391
0
                            );
2392
0
                            let mut all_hashes = all_hashes.clone();
2393
2394
                            loop {
2395
0
                                let Some(hash) = all_hashes.next() else {
2396
0
                                    break true;
2397
                                };
2398
2399
0
                                if !dedup_check.insert(hash) {
2400
0
                                    let _ = me
2401
0
                                        .responses_tx
2402
0
                                        .send(parse::build_error_response(
2403
0
                                            request_id_json,
2404
0
                                            parse::ErrorResponse::ApplicationDefined(
2405
0
                                                -32804,
2406
0
                                                "duplicate block hash",
2407
0
                                            ),
2408
0
                                            None,
2409
0
                                        ))
2410
0
                                        .await;
2411
0
                                    break false;
2412
0
                                }
2413
0
2414
0
                                if !subscription.pinned_blocks_headers.contains_key(hash) {
2415
0
                                    let _ = me
2416
0
                                        .responses_tx
2417
0
                                        .send(parse::build_error_response(
2418
0
                                            request_id_json,
2419
0
                                            parse::ErrorResponse::InvalidParams,
2420
0
                                            None,
2421
0
                                        ))
2422
0
                                        .await;
2423
0
                                    break false;
2424
0
                                }
2425
                            }
2426
                        };
2427
2428
0
                        if !checks_passed {
2429
0
                            continue;
2430
0
                        }
2431
2432
                        // The logic below assumes that all hashes are unique, which is ensured
2433
                        // above.
2434
0
                        for hash in all_hashes {
2435
0
                            subscription.pinned_blocks_headers.remove(hash);
2436
0
                            if let Some(subscription_id) =
2437
0
                                subscription.runtime_service_subscription_id
2438
                            {
2439
0
                                me.runtime_service.unpin_block(subscription_id, *hash).await;
2440
0
                            }
2441
                        }
2442
2443
0
                        let _ = me
2444
0
                            .responses_tx
2445
0
                            .send(
2446
0
                                methods::Response::chainHead_v1_unpin(())
2447
0
                                    .to_json_response(request_id_json),
2448
0
                            )
2449
0
                            .await;
2450
                    }
2451
2452
                    methods::MethodCall::chainHead_unstable_finalizedDatabase {
2453
0
                        max_size_bytes,
2454
                    } => {
2455
0
                        let response = crate::database::encode_database(
2456
0
                            &me.network_service,
2457
0
                            &me.sync_service,
2458
0
                            &me.runtime_service,
2459
0
                            &me.genesis_block_hash,
2460
0
                            usize::try_from(max_size_bytes.unwrap_or(u64::MAX))
2461
0
                                .unwrap_or(usize::MAX),
2462
0
                        )
2463
0
                        .await;
2464
2465
0
                        let _ = me
2466
0
                            .responses_tx
2467
0
                            .send(
2468
0
                                methods::Response::chainHead_unstable_finalizedDatabase(
2469
0
                                    response.into(),
2470
0
                                )
2471
0
                                .to_json_response(request_id_json),
2472
0
                            )
2473
0
                            .await;
2474
                    }
2475
2476
                    methods::MethodCall::chainSpec_v1_chainName {} => {
2477
0
                        let _ = me
2478
0
                            .responses_tx
2479
0
                            .send(
2480
0
                                methods::Response::chainSpec_v1_chainName((&me.chain_name).into())
2481
0
                                    .to_json_response(request_id_json),
2482
0
                            )
2483
0
                            .await;
2484
                    }
2485
2486
                    methods::MethodCall::chainSpec_v1_genesisHash {} => {
2487
0
                        let _ = me
2488
0
                            .responses_tx
2489
0
                            .send(
2490
0
                                methods::Response::chainSpec_v1_genesisHash(
2491
0
                                    methods::HashHexString(me.genesis_block_hash),
2492
0
                                )
2493
0
                                .to_json_response(request_id_json),
2494
0
                            )
2495
0
                            .await;
2496
                    }
2497
2498
                    methods::MethodCall::chainSpec_v1_properties {} => {
2499
0
                        let _ = me
2500
0
                            .responses_tx
2501
0
                            .send(
2502
0
                                methods::Response::chainSpec_v1_properties(
2503
0
                                    serde_json::from_str(&me.chain_properties_json).unwrap(),
2504
0
                                )
2505
0
                                .to_json_response(request_id_json),
2506
0
                            )
2507
0
                            .await;
2508
                    }
2509
2510
0
                    methods::MethodCall::sudo_unstable_p2pDiscover { multiaddr } => {
2511
0
                        match multiaddr.parse::<multiaddr::Multiaddr>() {
2512
0
                            Ok(mut addr)
2513
0
                                if matches!(
2514
0
                                    addr.iter().last(),
2515
                                    Some(multiaddr::Protocol::P2p(_))
2516
                                ) =>
2517
                            {
2518
0
                                let peer_id_bytes = match addr.iter().last() {
2519
0
                                    Some(multiaddr::Protocol::P2p(peer_id)) => {
2520
0
                                        peer_id.into_bytes().to_owned()
2521
                                    }
2522
0
                                    _ => unreachable!(),
2523
                                };
2524
0
                                addr.pop();
2525
0
2526
0
                                match PeerId::from_bytes(peer_id_bytes) {
2527
0
                                    Ok(peer_id) => {
2528
0
                                        me.network_service
2529
0
                                            .discover(
2530
0
                                                iter::once((peer_id, iter::once(addr))),
2531
0
                                                false,
2532
0
                                            )
2533
0
                                            .await;
2534
0
                                        let _ = me
2535
0
                                            .responses_tx
2536
0
                                            .send(
2537
0
                                                methods::Response::sudo_unstable_p2pDiscover(())
2538
0
                                                    .to_json_response(request_id_json),
2539
0
                                            )
2540
0
                                            .await;
2541
                                    }
2542
                                    Err(_) => {
2543
0
                                        let _ = me
2544
0
                                            .responses_tx
2545
0
                                            .send(parse::build_error_response(
2546
0
                                                request_id_json,
2547
0
                                                parse::ErrorResponse::InvalidParams,
2548
0
                                                Some(
2549
0
                                                    &serde_json::to_string(
2550
0
                                                        "multiaddr doesn't end with /p2p",
2551
0
                                                    )
2552
0
                                                    .unwrap_or_else(|_| unreachable!()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sj_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sj_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sj_0Ba_
2553
0
                                                ),
2554
0
                                            ))
2555
0
                                            .await;
2556
                                    }
2557
                                }
2558
                            }
2559
                            Ok(_) => {
2560
0
                                let _ = me
2561
0
                                    .responses_tx
2562
0
                                    .send(parse::build_error_response(
2563
0
                                        request_id_json,
2564
0
                                        parse::ErrorResponse::InvalidParams,
2565
0
                                        Some(
2566
0
                                            &serde_json::to_string(
2567
0
                                                "multiaddr doesn't end with /p2p",
2568
0
                                            )
2569
0
                                            .unwrap_or_else(|_| unreachable!()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sk_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sk_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sk_0Ba_
2570
0
                                        ),
2571
0
                                    ))
2572
0
                                    .await;
2573
                            }
2574
0
                            Err(err) => {
2575
0
                                let _ = me
2576
0
                                    .responses_tx
2577
0
                                    .send(parse::build_error_response(
2578
0
                                        request_id_json,
2579
0
                                        parse::ErrorResponse::InvalidParams,
2580
0
                                        Some(
2581
0
                                            &serde_json::to_string(&err.to_string())
2582
0
                                                .unwrap_or_else(|_| unreachable!()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sl_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sl_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sl_0Ba_
2583
0
                                        ),
2584
0
                                    ))
2585
0
                                    .await;
2586
                            }
2587
                        }
2588
                    }
2589
2590
                    methods::MethodCall::sudo_unstable_version {} => {
2591
0
                        let _ = me
2592
0
                            .responses_tx
2593
0
                            .send(
2594
0
                                methods::Response::sudo_unstable_version(
2595
0
                                    format!("{} {}", me.system_name, me.system_version).into(),
2596
0
                                )
2597
0
                                .to_json_response(request_id_json),
2598
0
                            )
2599
0
                            .await;
2600
                    }
2601
2602
0
                    request_parsed @ (methods::MethodCall::transaction_v1_broadcast { .. }
2603
                    | methods::MethodCall::transactionWatch_v1_submitAndWatch {
2604
                        ..
2605
                    }) => {
2606
0
                        let (transaction, watched) = match request_parsed {
2607
                            methods::MethodCall::transaction_v1_broadcast {
2608
0
                                transaction: methods::HexString(transaction),
2609
0
                            } => (transaction, false),
2610
                            methods::MethodCall::transactionWatch_v1_submitAndWatch {
2611
0
                                transaction: methods::HexString(transaction),
2612
0
                            } => (transaction, true),
2613
0
                            _ => unreachable!(),
2614
                        };
2615
2616
0
                        let subscription_id = {
2617
0
                            let mut subscription_id = [0u8; 32];
2618
0
                            me.randomness.fill_bytes(&mut subscription_id);
2619
0
                            bs58::encode(subscription_id).into_string()
2620
                        };
2621
2622
0
                        let _prev_value = me.transactions_subscriptions.insert(
2623
0
                            subscription_id.clone(),
2624
0
                            TransactionWatch {
2625
0
                                included_block: None,
2626
0
                                num_broadcasted_peers: 0,
2627
0
                                ty: if watched {
2628
0
                                    TransactionWatchTy::NewApiWatch
2629
                                } else {
2630
0
                                    TransactionWatchTy::NewApi {
2631
0
                                        transaction_bytes: transaction.clone(),
2632
0
                                    }
2633
                                },
2634
                            },
2635
                        );
2636
0
                        debug_assert!(_prev_value.is_none());
2637
2638
0
                        let mut transaction_updates = Box::pin(
2639
0
                            me.transactions_service
2640
0
                                .submit_and_watch_transaction(transaction, 16, watched)
2641
0
                                .await,
2642
                        );
2643
2644
0
                        let _ = me
2645
0
                            .responses_tx
2646
0
                            .send(
2647
0
                                if watched {
2648
0
                                    methods::Response::transactionWatch_v1_submitAndWatch(
2649
0
                                        Cow::Borrowed(&subscription_id),
2650
0
                                    )
2651
                                } else {
2652
0
                                    methods::Response::transaction_v1_broadcast(Cow::Borrowed(
2653
0
                                        &subscription_id,
2654
0
                                    ))
2655
                                }
2656
0
                                .to_json_response(request_id_json),
2657
                            )
2658
0
                            .await;
2659
2660
                        // A task is started that will yield when the transactions service
2661
                        // generates a notification.
2662
                        // Note that we do that even for `transaction_v1_broadcast`, as it is
2663
                        // important to pull notifications from the channel in order to not
2664
                        // clog it.
2665
0
                        me.background_tasks.push(Box::pin(async move {
2666
0
                            let Some(status) = transaction_updates.as_mut().next().await else {
2667
0
                                unreachable!()
2668
                            };
2669
0
                            Event::TransactionEvent {
2670
0
                                subscription_id,
2671
0
                                event: status,
2672
0
                                watcher: transaction_updates,
2673
0
                            }
2674
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sm_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sm_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sm_0Ba_
2675
                    }
2676
2677
0
                    methods::MethodCall::transaction_v1_stop { operation_id } => {
2678
0
                        let exists = me
2679
0
                            .transactions_subscriptions
2680
0
                            .get(&*operation_id)
2681
0
                            .map_or(false, |sub| {
2682
0
                                matches!(sub.ty, TransactionWatchTy::NewApi { .. })
2683
0
                            });
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sn_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sn_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sn_0Ba_
2684
0
                        if exists {
2685
0
                            me.transactions_subscriptions.remove(&*operation_id);
2686
0
                            let _ = me
2687
0
                                .responses_tx
2688
0
                                .send(
2689
0
                                    methods::Response::transaction_v1_stop(())
2690
0
                                        .to_json_response(request_id_json),
2691
0
                                )
2692
0
                                .await;
2693
                        } else {
2694
0
                            let _ = me
2695
0
                                .responses_tx
2696
0
                                .send(parse::build_error_response(
2697
0
                                    request_id_json,
2698
0
                                    json_rpc::parse::ErrorResponse::InvalidParams,
2699
0
                                    None,
2700
0
                                ))
2701
0
                                .await;
2702
                        }
2703
                    }
2704
2705
0
                    methods::MethodCall::transactionWatch_v1_unwatch { subscription } => {
2706
0
                        let exists = me
2707
0
                            .transactions_subscriptions
2708
0
                            .get(&*subscription)
2709
0
                            .map_or(false, |sub| {
2710
0
                                matches!(sub.ty, TransactionWatchTy::NewApiWatch)
2711
0
                            });
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0so_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0so_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0so_0Ba_
2712
0
                        if exists {
2713
0
                            me.transactions_subscriptions.remove(&*subscription);
2714
0
                        }
2715
0
                        let _ = me
2716
0
                            .responses_tx
2717
0
                            .send(
2718
0
                                methods::Response::transactionWatch_v1_unwatch(())
2719
0
                                    .to_json_response(request_id_json),
2720
0
                            )
2721
0
                            .await;
2722
                    }
2723
2724
0
                    _method @ (methods::MethodCall::account_nextIndex { .. }
2725
                    | methods::MethodCall::author_hasKey { .. }
2726
                    | methods::MethodCall::author_hasSessionKeys { .. }
2727
                    | methods::MethodCall::author_insertKey { .. }
2728
                    | methods::MethodCall::author_removeExtrinsic { .. }
2729
                    | methods::MethodCall::author_rotateKeys { .. }
2730
                    | methods::MethodCall::babe_epochAuthorship { .. }
2731
                    | methods::MethodCall::childstate_getKeys { .. }
2732
                    | methods::MethodCall::childstate_getStorage { .. }
2733
                    | methods::MethodCall::childstate_getStorageHash { .. }
2734
                    | methods::MethodCall::childstate_getStorageSize { .. }
2735
                    | methods::MethodCall::grandpa_roundState { .. }
2736
                    | methods::MethodCall::offchain_localStorageGet { .. }
2737
                    | methods::MethodCall::offchain_localStorageSet { .. }
2738
                    | methods::MethodCall::state_getPairs { .. }
2739
                    | methods::MethodCall::state_getReadProof { .. }
2740
                    | methods::MethodCall::state_getStorageHash { .. }
2741
                    | methods::MethodCall::state_getStorageSize { .. }
2742
                    | methods::MethodCall::state_queryStorage { .. }
2743
                    | methods::MethodCall::system_addReservedPeer { .. }
2744
                    | methods::MethodCall::system_dryRun { .. }
2745
                    | methods::MethodCall::system_localPeerId { .. }
2746
                    | methods::MethodCall::system_networkState { .. }
2747
                    | methods::MethodCall::system_removeReservedPeer { .. }
2748
                    | methods::MethodCall::sudo_network_unstable_watch { .. }
2749
                    | methods::MethodCall::sudo_network_unstable_unwatch { .. }) => {
2750
                        // TODO: implement the ones that make sense to implement ^
2751
0
                        log!(
2752
0
                            &me.platform,
2753
0
                            Warn,
2754
0
                            &me.log_target,
2755
0
                            format!("JSON-RPC call not supported yet: {:?}", _method)
2756
0
                        );
2757
0
                        let _ = me
2758
0
                            .responses_tx
2759
0
                            .send(parse::build_error_response(
2760
0
                                request_id_json,
2761
0
                                json_rpc::parse::ErrorResponse::ServerError(
2762
0
                                    -32000,
2763
0
                                    "Not implemented in smoldot yet",
2764
0
                                ),
2765
0
                                None,
2766
0
                            ))
2767
0
                            .await;
2768
                    }
2769
                }
2770
            }
2771
2772
            WakeUpReason::AdvanceMultiStageRequest {
2773
0
                request_id_json,
2774
0
                stage: MultiStageRequestStage::BlockHashNotKnown,
2775
0
                request_ty,
2776
0
            } => {
2777
0
                // A "multi-stage" request needs to know the best block hash.
2778
0
                // If it is known, we switch it to the next stage, otherwise we push it in a
2779
0
                // different list.
2780
0
                match me.runtime_service_subscription {
2781
                    RuntimeServiceSubscription::Pending { .. }
2782
0
                    | RuntimeServiceSubscription::NotCreated => {
2783
0
                        me.best_block_hash_pending
2784
0
                            .push((request_id_json, request_ty));
2785
0
                    }
2786
                    RuntimeServiceSubscription::Active {
2787
0
                        current_best_block, ..
2788
                    } => {
2789
                        // We special-case `state_getKeysPaged` as the results of previous similar
2790
                        // requests are put in a cache. Perform a cache lookup now.
2791
                        if let MultiStageRequestTy::StateGetKeysPaged {
2792
0
                            prefix,
2793
0
                            start_key,
2794
0
                            count,
2795
0
                        } = &request_ty
2796
                        {
2797
0
                            if let Some(cache_entry) =
2798
0
                                me.state_get_keys_paged_cache.get(&GetKeysPagedCacheKey {
2799
0
                                    hash: current_best_block,
2800
0
                                    prefix: prefix.clone(),
2801
0
                                })
2802
                            {
2803
                                // Cache hit!
2804
                                // Filter by start key and count.
2805
0
                                let results_to_client = cache_entry
2806
0
                                    .iter()
2807
0
                                    .cloned()
2808
0
                                    .filter(|k| start_key.as_ref().map_or(true, |s| *k > *s))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sp_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sp_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sp_0Ba_
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sp_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sp_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sp_00Bc_
2809
0
                                    .map(methods::HexString)
2810
0
                                    .take(usize::try_from(*count).unwrap_or(usize::MAX))
2811
0
                                    .collect::<Vec<_>>();
2812
0
                                let _ = me
2813
0
                                    .responses_tx
2814
0
                                    .send(
2815
0
                                        methods::Response::state_getKeysPaged(results_to_client)
2816
0
                                            .to_json_response(&request_id_json),
2817
0
                                    )
2818
0
                                    .await;
2819
0
                                continue;
2820
0
                            }
2821
0
                        }
2822
2823
0
                        me.multistage_requests_to_advance.push_back((
2824
0
                            request_id_json,
2825
0
                            MultiStageRequestStage::BlockHashKnown {
2826
0
                                block_hash: current_best_block,
2827
0
                            },
2828
0
                            request_ty,
2829
0
                        ));
2830
                    }
2831
                }
2832
            }
2833
2834
            WakeUpReason::AdvanceMultiStageRequest {
2835
0
                request_id_json,
2836
0
                stage:
2837
0
                    MultiStageRequestStage::BlockHashKnown { block_hash, .. }
2838
0
                    | MultiStageRequestStage::BlockInfoKnown { block_hash, .. },
2839
                request_ty: MultiStageRequestTy::ChainGetBestBlockHash,
2840
            } => {
2841
                // Handling `chain_getBlockHash` for the best block.
2842
0
                let _ = me
2843
0
                    .responses_tx
2844
0
                    .send(
2845
0
                        methods::Response::chain_getBlockHash(methods::HashHexString(block_hash))
2846
0
                            .to_json_response(&request_id_json),
2847
0
                    )
2848
0
                    .await;
2849
            }
2850
2851
            WakeUpReason::AdvanceMultiStageRequest {
2852
0
                request_id_json,
2853
0
                stage:
2854
0
                    MultiStageRequestStage::BlockHashKnown { block_hash, .. }
2855
0
                    | MultiStageRequestStage::BlockInfoKnown { block_hash, .. },
2856
                request_ty: MultiStageRequestTy::ChainGetBlock,
2857
0
            } => {
2858
0
                // Handling `chain_getBlock`.
2859
0
2860
0
                // Try to determine the block number by looking for the block in cache.
2861
0
                // The request can be fulfilled no matter whether the block number is
2862
0
                // known or not, but knowing it will lead to a better selection of peers,
2863
0
                // and thus increase the chances of the requests succeeding.
2864
0
                let block_number = me
2865
0
                    .block_headers_cache
2866
0
                    .get(&block_hash)
2867
0
                    .and_then(|result| result.as_ref().ok().map(|(_, _, n)| *n));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sq_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sq_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sq_0Ba_
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sq_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sq_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sq_00Bc_
2868
0
2869
0
                // Block bodies and headers aren't stored locally. Ask the network.
2870
0
                me.background_tasks.push({
2871
0
                    let sync_service = me.sync_service.clone();
2872
0
                    let request_id_json = request_id_json.to_owned();
2873
0
                    Box::pin(async move {
2874
0
                        let result = if let Some(block_number) = block_number {
2875
0
                            sync_service
2876
0
                                .block_query(
2877
0
                                    block_number,
2878
0
                                    block_hash,
2879
0
                                    codec::BlocksRequestFields {
2880
0
                                        header: true,
2881
0
                                        body: true,
2882
0
                                        justifications: false,
2883
0
                                    },
2884
0
                                    3,
2885
0
                                    Duration::from_secs(8),
2886
0
                                    NonZeroU32::new(1).unwrap(),
2887
0
                                )
2888
0
                                .await
2889
                        } else {
2890
0
                            sync_service
2891
0
                                .block_query_unknown_number(
2892
0
                                    block_hash,
2893
0
                                    codec::BlocksRequestFields {
2894
0
                                        header: true,
2895
0
                                        body: true,
2896
0
                                        justifications: false,
2897
0
                                    },
2898
0
                                    3,
2899
0
                                    Duration::from_secs(8),
2900
0
                                    NonZeroU32::new(1).unwrap(),
2901
0
                                )
2902
0
                                .await
2903
                        };
2904
0
                        Event::ChainGetBlockResult {
2905
0
                            request_id_json,
2906
0
                            result,
2907
0
                            expected_block_hash: block_hash,
2908
0
                        }
2909
0
                    })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sr_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sr_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sr_0Ba_
2910
0
                });
2911
0
            }
2912
2913
            WakeUpReason::AdvanceMultiStageRequest {
2914
0
                request_id_json: request_id,
2915
0
                stage: MultiStageRequestStage::BlockHashKnown { block_hash },
2916
0
                request_ty,
2917
            } => {
2918
                // A "multi-stage request" needs to know the information about the block with
2919
                // the given hash.
2920
2921
                // If the block's information is available in cache, switch it to the next stage.
2922
0
                if let Some(in_cache) = me.block_headers_cache.get(&block_hash) {
2923
0
                    let &Ok((ref scale_encoded_header, block_state_trie_root_hash, block_number)) =
2924
0
                        in_cache
2925
                    else {
2926
                        // Block is known to not be decodable.
2927
0
                        let _ = me
2928
0
                            .responses_tx
2929
0
                            .send(parse::build_error_response(
2930
0
                                &request_id,
2931
0
                                parse::ErrorResponse::ServerError(-32000, "invalid block header"),
2932
0
                                None,
2933
0
                            ))
2934
0
                            .await;
2935
0
                        continue;
2936
                    };
2937
2938
                    // Special-case `chain_getHeader`, as it is only needs to know the header
2939
                    // of the block and doesn't need to be switched to a next stage.
2940
0
                    if matches!(request_ty, MultiStageRequestTy::ChainGetHeader) {
2941
0
                        match methods::Header::from_scale_encoded_header(
2942
0
                            scale_encoded_header,
2943
0
                            me.runtime_service.block_number_bytes(),
2944
0
                        ) {
2945
0
                            Ok(header) => {
2946
0
                                let _ = me
2947
0
                                    .responses_tx
2948
0
                                    .send(
2949
0
                                        methods::Response::chain_getHeader(header)
2950
0
                                            .to_json_response(&request_id),
2951
0
                                    )
2952
0
                                    .await;
2953
                            }
2954
0
                            Err(error) => {
2955
0
                                let _ = me
2956
0
                                    .responses_tx
2957
0
                                    .send(parse::build_error_response(
2958
0
                                        &request_id,
2959
0
                                        json_rpc::parse::ErrorResponse::ServerError(
2960
0
                                            -32000,
2961
0
                                            &format!("Failed to decode block header: {error}"),
2962
0
                                        ),
2963
0
                                        None,
2964
0
                                    ))
2965
0
                                    .await;
2966
                            }
2967
                        }
2968
0
                        continue;
2969
0
                    }
2970
0
2971
0
                    me.multistage_requests_to_advance.push_back((
2972
0
                        request_id,
2973
0
                        MultiStageRequestStage::BlockInfoKnown {
2974
0
                            block_hash,
2975
0
                            block_state_trie_root_hash,
2976
0
                            block_number,
2977
0
                        },
2978
0
                        request_ty,
2979
0
                    ));
2980
0
                    continue;
2981
0
                }
2982
0
2983
0
                // Value is not available in cache.
2984
0
                match me.block_headers_pending.entry(block_hash) {
2985
0
                    hashbrown::hash_map::Entry::Occupied(entry) => {
2986
0
                        // We are already in the process of asking the networking service for
2987
0
                        // the block information.
2988
0
                        // Keep track of the request.
2989
0
                        debug_assert!(!entry.get().is_empty());
2990
0
                        entry.into_mut().push((request_id, request_ty));
2991
                    }
2992
0
                    hashbrown::hash_map::Entry::Vacant(entry) => {
2993
0
                        // No network request is in progress yet. Start one.
2994
0
                        me.background_tasks.push({
2995
0
                            let block_info_retrieve_future =
2996
0
                                me.sync_service.clone().block_query_unknown_number(
2997
0
                                    block_hash,
2998
0
                                    codec::BlocksRequestFields {
2999
0
                                        header: true,
3000
0
                                        body: false,
3001
0
                                        justifications: false,
3002
0
                                    },
3003
0
                                    3,
3004
0
                                    Duration::from_secs(5),
3005
0
                                    NonZeroU32::new(1).unwrap_or_else(|| unreachable!()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0ss_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0ss_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0ss_0Ba_
3006
0
                                );
3007
0
                            let block_number_bytes = me.runtime_service.block_number_bytes();
3008
0
                            Box::pin(async move {
3009
0
                                let result = match block_info_retrieve_future.await {
3010
0
                                    Ok(result) => match result.header {
3011
0
                                        Some(scale_header) => {
3012
0
                                            if header::hash_from_scale_encoded_header(&scale_header)
3013
0
                                                == block_hash
3014
                                            {
3015
0
                                                Ok(header::decode(
3016
0
                                                    &scale_header,
3017
0
                                                    block_number_bytes,
3018
0
                                                )
3019
0
                                                .map(|header| {
3020
0
                                                    (
3021
0
                                                        scale_header.clone(),
3022
0
                                                        *header.state_root,
3023
0
                                                        header.number,
3024
0
                                                    )
3025
0
                                                }))
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0st_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0st_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0st_00Bc_
3026
                                            } else {
3027
0
                                                Err(())
3028
                                            }
3029
                                        }
3030
0
                                        None => Err(()),
3031
                                    },
3032
0
                                    Err(()) => Err(()),
3033
                                };
3034
0
                                Event::BlockInfoRetrieved { block_hash, result }
3035
0
                            })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0st_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0st_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0st_0Ba_
3036
0
                        });
3037
0
3038
0
                        // Keep track of the request.
3039
0
                        let mut list = Vec::with_capacity(4);
3040
0
                        list.push((request_id, request_ty));
3041
0
                        entry.insert(list);
3042
0
                    }
3043
                }
3044
            }
3045
3046
            WakeUpReason::AdvanceMultiStageRequest {
3047
                stage: MultiStageRequestStage::BlockInfoKnown { .. },
3048
                request_ty: MultiStageRequestTy::ChainGetHeader,
3049
                ..
3050
            } => {
3051
                // `chain_getHeader` should never reach this stage.
3052
0
                unreachable!()
3053
            }
3054
3055
            WakeUpReason::AdvanceMultiStageRequest {
3056
0
                request_id_json,
3057
                stage:
3058
                    MultiStageRequestStage::BlockInfoKnown {
3059
0
                        block_hash,
3060
0
                        block_state_trie_root_hash,
3061
0
                        block_number,
3062
                    },
3063
                request_ty:
3064
0
                    request_ty @ (MultiStageRequestTy::StateGetRuntimeVersion
3065
                    | MultiStageRequestTy::StateCall { .. }
3066
                    | MultiStageRequestTy::StateGetMetadata
3067
                    | MultiStageRequestTy::PaymentQueryInfo { .. }
3068
                    | MultiStageRequestTy::SystemAccountNextIndex { .. }),
3069
            } => {
3070
                // A runtime-related JSON-RPC function needs access to the runtime of the
3071
                // given block.
3072
3073
                // If the value is available in cache, do the runtime call.
3074
0
                if let Some(in_cache) = me.block_runtimes_cache.get(&block_hash) {
3075
                    // Special-case `state_getRuntimeVersion` as it only needs access to the
3076
                    // runtime but not do any call.
3077
0
                    if let MultiStageRequestTy::StateGetRuntimeVersion = &request_ty {
3078
0
                        match me
3079
0
                            .runtime_service
3080
0
                            .pinned_runtime_specification(in_cache.clone())
3081
0
                            .await
3082
                        {
3083
0
                            Ok(spec) => {
3084
0
                                let _ = me
3085
0
                                    .responses_tx
3086
0
                                    .send(
3087
0
                                        methods::Response::state_getRuntimeVersion(
3088
0
                                            convert_runtime_version_legacy(&spec),
3089
0
                                        )
3090
0
                                        .to_json_response(&request_id_json),
3091
0
                                    )
3092
0
                                    .await;
3093
                            }
3094
0
                            Err(error) => {
3095
0
                                let _ = me
3096
0
                                    .responses_tx
3097
0
                                    .send(parse::build_error_response(
3098
0
                                        &request_id_json,
3099
0
                                        json_rpc::parse::ErrorResponse::ServerError(
3100
0
                                            -32000,
3101
0
                                            &error.to_string(),
3102
0
                                        ),
3103
0
                                        None,
3104
0
                                    ))
3105
0
                                    .await;
3106
                            }
3107
                        }
3108
0
                        continue;
3109
0
                    }
3110
3111
                    // Determine the parameters of the runtime call to start.
3112
0
                    let (function_name, required_api_version, parameters_vectored, request_update) =
3113
0
                        match request_ty {
3114
0
                            MultiStageRequestTy::StateCall { name, parameters } => (
3115
0
                                name,
3116
0
                                None,
3117
0
                                parameters,
3118
0
                                RuntimeCallRequestInProgress::StateCall,
3119
0
                            ),
3120
0
                            MultiStageRequestTy::StateGetMetadata => (
3121
0
                                "Metadata_metadata".to_owned(),
3122
0
                                Some(("Metadata".to_owned(), 1..=2)),
3123
0
                                Vec::new(),
3124
0
                                RuntimeCallRequestInProgress::StateGetMetadata,
3125
0
                            ),
3126
0
                            MultiStageRequestTy::PaymentQueryInfo { extrinsic } => {
3127
0
                                (
3128
0
                                    json_rpc::payment_info::PAYMENT_FEES_FUNCTION_NAME.to_owned(),
3129
0
                                    Some(("TransactionPaymentApi".to_owned(), 1..=2)),
3130
0
                                    json_rpc::payment_info::payment_info_parameters(&extrinsic)
3131
0
                                        .fold(Vec::new(), |mut a, b| {
3132
0
                                            a.extend_from_slice(b.as_ref());
3133
0
                                            a
3134
0
                                        }),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0su_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0su_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0su_0Ba_
3135
0
                                    RuntimeCallRequestInProgress::PaymentQueryInfo,
3136
0
                                )
3137
                            }
3138
0
                            MultiStageRequestTy::SystemAccountNextIndex { account_id } => (
3139
0
                                "AccountNonceApi_account_nonce".to_owned(),
3140
0
                                Some(("AccountNonceApi".to_owned(), 1..=1)),
3141
0
                                account_id,
3142
0
                                RuntimeCallRequestInProgress::SystemAccountNextIndex,
3143
0
                            ),
3144
0
                            _ => unreachable!(),
3145
                        };
3146
3147
                    // Start the runtime call in the background.
3148
0
                    let runtime_service = me.runtime_service.clone();
3149
0
                    let in_cache = in_cache.clone();
3150
0
                    me.background_tasks.push(Box::pin(async move {
3151
0
                        Event::LegacyApiFunctionRuntimeCallResult {
3152
0
                            request_id_json,
3153
0
                            request: request_update,
3154
0
                            result: runtime_service
3155
0
                                .runtime_call(
3156
0
                                    in_cache,
3157
0
                                    block_hash,
3158
0
                                    block_number,
3159
0
                                    block_state_trie_root_hash,
3160
0
                                    function_name,
3161
0
                                    required_api_version,
3162
0
                                    parameters_vectored,
3163
0
                                    3,
3164
0
                                    Duration::from_secs(5),
3165
0
                                    NonZeroU32::new(1).unwrap_or_else(|| unreachable!()),
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sv_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sv_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sv_00Bc_
3166
0
                                )
3167
0
                                .await,
3168
                        }
3169
0
                    }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sv_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sv_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sv_0Ba_
3170
0
                    continue;
3171
0
                }
3172
0
3173
0
                // Runtime is not available in cache. Download it from the network.
3174
0
                match me.block_runtimes_pending.entry(block_hash) {
3175
0
                    hashbrown::hash_map::Entry::Occupied(entry) => {
3176
0
                        // We are already in the process of asking the networking service for
3177
0
                        // the runtime.
3178
0
                        // Keep track of the request.
3179
0
                        debug_assert!(!entry.get().is_empty());
3180
0
                        entry.into_mut().push((request_id_json, request_ty));
3181
                    }
3182
0
                    hashbrown::hash_map::Entry::Vacant(entry) => {
3183
0
                        // No network request is in progress yet. Start one.
3184
0
                        me.background_tasks.push(Box::pin({
3185
0
                            let sync_service = me.sync_service.clone();
3186
0
                            let runtime_service = me.runtime_service.clone();
3187
0
                            // TODO: move to separate function
3188
0
                            async move {
3189
                                let (
3190
0
                                    storage_code,
3191
0
                                    storage_heap_pages,
3192
0
                                    code_merkle_value,
3193
0
                                    code_closest_ancestor_excluding,
3194
                                ) = {
3195
0
                                    let mut storage_code = None;
3196
0
                                    let mut storage_heap_pages = None;
3197
0
                                    let mut code_merkle_value = None;
3198
0
                                    let mut code_closest_ancestor_excluding = None;
3199
3200
0
                                    let mut query =
3201
0
                                        sync_service
3202
0
                                        .storage_query(
3203
0
                                            block_number,
3204
0
                                            block_hash,
3205
0
                                            block_state_trie_root_hash,
3206
0
                                            [
3207
0
                                                sync_service::StorageRequestItem {
3208
0
                                                    key: b":code".to_vec(),
3209
0
                                                    ty: sync_service::StorageRequestItemTy::ClosestDescendantMerkleValue,
3210
0
                                                },
3211
0
                                                sync_service::StorageRequestItem {
3212
0
                                                    key: b":code".to_vec(),
3213
0
                                                    ty: sync_service::StorageRequestItemTy::Value,
3214
0
                                                },
3215
0
                                                sync_service::StorageRequestItem {
3216
0
                                                    key: b":heappages".to_vec(),
3217
0
                                                    ty: sync_service::StorageRequestItemTy::Value,
3218
0
                                                },
3219
0
                                            ]
3220
0
                                            .into_iter(),
3221
0
                                            3,
3222
0
                                            Duration::from_secs(20),
3223
0
                                            NonZeroU32::new(1).unwrap(),
3224
0
                                        )
3225
0
                                        .advance()
3226
0
                                        .await;
3227
3228
                                    loop {
3229
0
                                        match query {
3230
                                            sync_service::StorageQueryProgress::Finished => {
3231
0
                                                break (
3232
0
                                                    storage_code,
3233
0
                                                    storage_heap_pages,
3234
0
                                                    code_merkle_value,
3235
0
                                                    code_closest_ancestor_excluding,
3236
0
                                                )
3237
                                            }
3238
                                            sync_service::StorageQueryProgress::Progress {
3239
                                                request_index: 0,
3240
                                                item:
3241
                                                    sync_service::StorageResultItem::ClosestDescendantMerkleValue {
3242
0
                                                        closest_descendant_merkle_value,
3243
0
                                                        found_closest_ancestor_excluding,
3244
0
                                                        ..
3245
0
                                                    },
3246
0
                                                query: next,
3247
0
                                            } => {
3248
0
                                                code_merkle_value = closest_descendant_merkle_value;
3249
0
                                                code_closest_ancestor_excluding = found_closest_ancestor_excluding;
3250
0
                                                query = next.advance().await;
3251
                                            }
3252
                                            sync_service::StorageQueryProgress::Progress {
3253
                                                request_index: 1,
3254
0
                                                item: sync_service::StorageResultItem::Value { value, .. },
3255
0
                                                query: next,
3256
0
                                            } => {
3257
0
                                                storage_code = value;
3258
0
                                                query = next.advance().await;
3259
                                            }
3260
                                            sync_service::StorageQueryProgress::Progress {
3261
                                                request_index: 2,
3262
0
                                                item: sync_service::StorageResultItem::Value { value, .. },
3263
0
                                                query: next,
3264
0
                                            } => {
3265
0
                                                storage_heap_pages = value;
3266
0
                                                query = next.advance().await;
3267
                                            }
3268
0
                                            sync_service::StorageQueryProgress::Progress { .. } => unreachable!(),
3269
0
                                            sync_service::StorageQueryProgress::Error(error) => {
3270
0
                                                return Event::RuntimeDownloaded {
3271
0
                                                    block_hash,
3272
0
                                                    result: Err(error.to_string()),
3273
0
                                                }
3274
                                            }
3275
                                        }
3276
                                    }
3277
                                };
3278
3279
                                // Give the code and heap pages to the runtime service. The runtime service will
3280
                                // try to find any similar runtime it might have, and if not will compile it.
3281
0
                                let pinned_runtime = runtime_service
3282
0
                                    .compile_and_pin_runtime(
3283
0
                                        storage_code,
3284
0
                                        storage_heap_pages,
3285
0
                                        code_merkle_value,
3286
0
                                        code_closest_ancestor_excluding,
3287
0
                                    )
3288
0
                                    .await;
3289
3290
0
                                Event::RuntimeDownloaded {
3291
0
                                    block_hash,
3292
0
                                    result: pinned_runtime.map_err(|error| error.to_string()),
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sw_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sw_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sw_00Bc_
3293
0
                                }
3294
0
                            }
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sw_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sw_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sw_0Ba_
3295
0
                        }));
3296
0
3297
0
                        // Keep track of the request.
3298
0
                        let mut list = Vec::with_capacity(4);
3299
0
                        list.push((request_id_json, request_ty));
3300
0
                        entry.insert(list);
3301
0
                    }
3302
                }
3303
            }
3304
3305
            WakeUpReason::Event(Event::LegacyApiFunctionRuntimeCallResult {
3306
0
                request_id_json,
3307
0
                request,
3308
0
                result,
3309
0
            }) => {
3310
0
                // A runtime-call-related JSON-RPC API has finished its runtime call.
3311
0
                match (result, request) {
3312
0
                    (Ok(result), RuntimeCallRequestInProgress::StateCall) => {
3313
0
                        let _ = me
3314
0
                            .responses_tx
3315
0
                            .send(
3316
0
                                methods::Response::state_call(methods::HexString(result.output))
3317
0
                                    .to_json_response(&request_id_json),
3318
0
                            )
3319
0
                            .await;
3320
                    }
3321
0
                    (Ok(result), RuntimeCallRequestInProgress::StateGetMetadata) => {
3322
0
                        match methods::remove_metadata_length_prefix(&result.output) {
3323
0
                            Ok(metadata) => {
3324
0
                                let _ = me
3325
0
                                    .responses_tx
3326
0
                                    .send(
3327
0
                                        methods::Response::state_getMetadata(methods::HexString(
3328
0
                                            metadata.to_owned(),
3329
0
                                        ))
3330
0
                                        .to_json_response(&request_id_json),
3331
0
                                    )
3332
0
                                    .await;
3333
                            }
3334
0
                            Err(error) => {
3335
0
                                log!(
3336
0
                                    &me.platform,
3337
0
                                    Warn,
3338
0
                                    &me.log_target,
3339
0
                                    format!("Failed to decode metadata. Error: {error}")
3340
0
                                );
3341
0
                                let _ = me
3342
0
                                    .responses_tx
3343
0
                                    .send(parse::build_error_response(
3344
0
                                        &request_id_json,
3345
0
                                        parse::ErrorResponse::ServerError(
3346
0
                                            -32000,
3347
0
                                            &error.to_string(),
3348
0
                                        ),
3349
0
                                        None,
3350
0
                                    ))
3351
0
                                    .await;
3352
                            }
3353
                        }
3354
                    }
3355
0
                    (Ok(result), RuntimeCallRequestInProgress::PaymentQueryInfo) => {
3356
0
                        match json_rpc::payment_info::decode_payment_info(
3357
0
                            &result.output,
3358
0
                            // `api_version` is guaranteed to be `Some` if we passed an API
3359
0
                            // requirement when calling `runtime_call`, which we always do.
3360
0
                            result.api_version.unwrap(),
3361
0
                        ) {
3362
0
                            Ok(info) => {
3363
0
                                let _ = me
3364
0
                                    .responses_tx
3365
0
                                    .send(
3366
0
                                        methods::Response::payment_queryInfo(info)
3367
0
                                            .to_json_response(&request_id_json),
3368
0
                                    )
3369
0
                                    .await;
3370
                            }
3371
0
                            Err(error) => {
3372
0
                                let _ = me
3373
0
                                    .responses_tx
3374
0
                                    .send(parse::build_error_response(
3375
0
                                        &request_id_json,
3376
0
                                        parse::ErrorResponse::ServerError(
3377
0
                                            -32000,
3378
0
                                            &format!("Failed to decode runtime output: {error}"),
3379
0
                                        ),
3380
0
                                        None,
3381
0
                                    ))
3382
0
                                    .await;
3383
                            }
3384
                        }
3385
                    }
3386
0
                    (Ok(result), RuntimeCallRequestInProgress::SystemAccountNextIndex) => {
3387
0
                        // TODO: we get a u32 when expecting a u64; figure out problem
3388
0
                        match <[u8; 4]>::try_from(&result.output[..]) {
3389
0
                            Ok(index) => {
3390
0
                                let _ = me
3391
0
                                    .responses_tx
3392
0
                                    .send(
3393
0
                                        methods::Response::system_accountNextIndex(u64::from(
3394
0
                                            u32::from_le_bytes(index),
3395
0
                                        ))
3396
0
                                        .to_json_response(&request_id_json),
3397
0
                                    )
3398
0
                                    .await;
3399
                            }
3400
                            Err(_) => {
3401
0
                                let _ = me
3402
0
                                    .responses_tx
3403
0
                                    .send(parse::build_error_response(
3404
0
                                        &request_id_json,
3405
0
                                        parse::ErrorResponse::ServerError(
3406
0
                                            -32000,
3407
0
                                            &format!("Failed to decode runtime output"),
3408
0
                                        ),
3409
0
                                        None,
3410
0
                                    ))
3411
0
                                    .await;
3412
                            }
3413
                        }
3414
                    }
3415
0
                    (Err(error), request) => {
3416
0
                        if matches!(request, RuntimeCallRequestInProgress::StateGetMetadata) {
3417
0
                            log!(
3418
0
                                &me.platform,
3419
0
                                Warn,
3420
0
                                &me.log_target,
3421
0
                                format!(
3422
0
                                    "Returning error from `state_getMetadata`. API user might \
3423
0
                                    not function properly. Error: {error}"
3424
0
                                )
3425
0
                            );
3426
0
                        }
3427
3428
0
                        let _ = me
3429
0
                            .responses_tx
3430
0
                            .send(parse::build_error_response(
3431
0
                                &request_id_json,
3432
0
                                parse::ErrorResponse::ServerError(-32000, &error.to_string()),
3433
0
                                None,
3434
0
                            ))
3435
0
                            .await;
3436
                    }
3437
                }
3438
            }
3439
3440
            WakeUpReason::AdvanceMultiStageRequest {
3441
0
                request_id_json,
3442
                stage:
3443
                    MultiStageRequestStage::BlockInfoKnown {
3444
0
                        block_hash,
3445
0
                        block_state_trie_root_hash,
3446
0
                        block_number,
3447
                    },
3448
                request_ty:
3449
0
                    request_ty @ (MultiStageRequestTy::StateGetKeys { .. }
3450
                    | MultiStageRequestTy::StateGetKeysPaged { .. }
3451
                    | MultiStageRequestTy::StateQueryStorageAt { .. }
3452
                    | MultiStageRequestTy::StateGetStorage { .. }),
3453
0
            } => {
3454
0
                // A storage-related JSON-RPC function can make progress.
3455
0
                // Build and start a background task that performs the actual storage request.
3456
0
                let (request, storage_request) = match request_ty {
3457
0
                    MultiStageRequestTy::StateGetKeys { prefix } => (
3458
0
                        StorageRequestInProgress::StateGetKeys {
3459
0
                            in_progress_results: Vec::with_capacity(32),
3460
0
                        },
3461
0
                        either::Left(iter::once(sync_service::StorageRequestItem {
3462
0
                            key: prefix.clone(),
3463
0
                            ty: sync_service::StorageRequestItemTy::DescendantsHashes,
3464
0
                        })),
3465
0
                    ),
3466
                    MultiStageRequestTy::StateGetKeysPaged {
3467
0
                        prefix,
3468
0
                        start_key,
3469
0
                        count,
3470
0
                    } => (
3471
0
                        StorageRequestInProgress::StateGetKeysPaged {
3472
0
                            in_progress_results: Vec::with_capacity(32),
3473
0
                            block_hash,
3474
0
                            prefix: prefix.clone(),
3475
0
                            start_key,
3476
0
                            count,
3477
0
                        },
3478
0
                        either::Left(iter::once(sync_service::StorageRequestItem {
3479
0
                            key: prefix,
3480
0
                            ty: sync_service::StorageRequestItemTy::DescendantsHashes,
3481
0
                        })),
3482
0
                    ),
3483
0
                    MultiStageRequestTy::StateQueryStorageAt { keys } => (
3484
0
                        StorageRequestInProgress::StateQueryStorageAt {
3485
0
                            block_hash,
3486
0
                            in_progress_results: Vec::with_capacity(keys.len()),
3487
0
                        },
3488
0
                        either::Right(keys.into_iter().map(|key| {
3489
0
                            sync_service::StorageRequestItem {
3490
0
                                key: key.0,
3491
0
                                ty: sync_service::StorageRequestItemTy::Value,
3492
0
                            }
3493
0
                        })),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sx_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sx_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sx_0Ba_
3494
0
                    ),
3495
0
                    MultiStageRequestTy::StateGetStorage { key } => (
3496
0
                        StorageRequestInProgress::StateGetStorage {},
3497
0
                        either::Left(iter::once(sync_service::StorageRequestItem {
3498
0
                            key,
3499
0
                            ty: sync_service::StorageRequestItemTy::Value,
3500
0
                        })),
3501
0
                    ),
3502
0
                    _ => unreachable!(),
3503
                };
3504
3505
0
                let storage_query = me.sync_service.clone().storage_query(
3506
0
                    block_number,
3507
0
                    block_hash,
3508
0
                    block_state_trie_root_hash,
3509
0
                    storage_request,
3510
0
                    3,
3511
0
                    Duration::from_secs(10),
3512
0
                    NonZeroU32::new(1).unwrap_or_else(|| unreachable!()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sy_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sy_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sy_0Ba_
3513
0
                );
3514
0
3515
0
                me.background_tasks.push(Box::pin(async move {
3516
0
                    Event::LegacyApiFunctionStorageRequestProgress {
3517
0
                        request_id_json,
3518
0
                        request,
3519
0
                        progress: storage_query.advance().await,
3520
                    }
3521
0
                }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sz_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sz_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sz_0Ba_
3522
            }
3523
3524
            WakeUpReason::Event(Event::LegacyApiFunctionStorageRequestProgress {
3525
0
                request_id_json,
3526
0
                request,
3527
0
                progress,
3528
0
            }) => {
3529
0
                // The background task of a storage-related JSON-RPC function has made progress.
3530
0
                match (progress, request) {
3531
                    (
3532
                        sync_service::StorageQueryProgress::Progress {
3533
0
                            item: sync_service::StorageResultItem::DescendantHash { key, .. },
3534
0
                            query: next,
3535
0
                            ..
3536
0
                        },
3537
0
                        StorageRequestInProgress::StateGetKeys {
3538
0
                            mut in_progress_results,
3539
0
                        },
3540
0
                    ) => {
3541
0
                        // Continue finding descendants.
3542
0
                        in_progress_results.push(methods::HexString(key));
3543
0
                        me.background_tasks.push(Box::pin(async move {
3544
0
                            Event::LegacyApiFunctionStorageRequestProgress {
3545
0
                                request_id_json,
3546
0
                                request: StorageRequestInProgress::StateGetKeys {
3547
0
                                    in_progress_results,
3548
0
                                },
3549
0
                                progress: next.advance().await,
3550
                            }
3551
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sA_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sA_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sA_0Ba_
3552
0
                    }
3553
                    (
3554
                        sync_service::StorageQueryProgress::Finished,
3555
                        StorageRequestInProgress::StateGetKeys {
3556
0
                            in_progress_results,
3557
0
                        },
3558
0
                    ) => {
3559
0
                        // Finished.
3560
0
                        let _ = me
3561
0
                            .responses_tx
3562
0
                            .send(
3563
0
                                methods::Response::state_getKeys(in_progress_results)
3564
0
                                    .to_json_response(&request_id_json),
3565
0
                            )
3566
0
                            .await;
3567
                    }
3568
                    (
3569
                        sync_service::StorageQueryProgress::Progress {
3570
0
                            item: sync_service::StorageResultItem::DescendantHash { key, .. },
3571
0
                            query: next,
3572
0
                            ..
3573
0
                        },
3574
0
                        StorageRequestInProgress::StateGetKeysPaged {
3575
0
                            mut in_progress_results,
3576
0
                            block_hash,
3577
0
                            prefix,
3578
0
                            start_key,
3579
0
                            count,
3580
0
                        },
3581
0
                    ) => {
3582
0
                        // Continue finding descendants.
3583
0
                        in_progress_results.push(key);
3584
0
                        me.background_tasks.push(Box::pin(async move {
3585
0
                            Event::LegacyApiFunctionStorageRequestProgress {
3586
0
                                request_id_json,
3587
0
                                request: StorageRequestInProgress::StateGetKeysPaged {
3588
0
                                    in_progress_results,
3589
0
                                    block_hash,
3590
0
                                    prefix,
3591
0
                                    start_key,
3592
0
                                    count,
3593
0
                                },
3594
0
                                progress: next.advance().await,
3595
                            }
3596
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sB_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sB_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sB_0Ba_
3597
0
                    }
3598
                    (
3599
                        sync_service::StorageQueryProgress::Finished,
3600
                        StorageRequestInProgress::StateGetKeysPaged {
3601
0
                            block_hash,
3602
0
                            in_progress_results: final_results,
3603
0
                            prefix,
3604
0
                            start_key,
3605
0
                            count,
3606
0
                        },
3607
0
                    ) => {
3608
0
                        // Finished.
3609
0
3610
0
                        // Filter by start key and count.
3611
0
                        let results_to_client = final_results
3612
0
                            .iter()
3613
0
                            .cloned()
3614
0
                            .filter(|k| start_key.as_ref().map_or(true, |s| *k > *s))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sC_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sC_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sC_0Ba_
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sC_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sC_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sC_00Bc_
3615
0
                            .map(methods::HexString)
3616
0
                            .take(usize::try_from(count).unwrap_or(usize::MAX))
3617
0
                            .collect::<Vec<_>>();
3618
0
3619
0
                        // If the returned response is somehow truncated, it is very likely that the
3620
0
                        // JSON-RPC client will call the function again with the exact same parameters.
3621
0
                        // Thus, store the results in a cache.
3622
0
                        if results_to_client.len() != final_results.len() {
3623
0
                            me.state_get_keys_paged_cache.push(
3624
0
                                GetKeysPagedCacheKey {
3625
0
                                    hash: block_hash,
3626
0
                                    prefix,
3627
0
                                },
3628
0
                                final_results,
3629
0
                            );
3630
0
                        }
3631
3632
0
                        let _ = me
3633
0
                            .responses_tx
3634
0
                            .send(
3635
0
                                methods::Response::state_getKeysPaged(results_to_client)
3636
0
                                    .to_json_response(&request_id_json),
3637
0
                            )
3638
0
                            .await;
3639
                    }
3640
                    (
3641
                        sync_service::StorageQueryProgress::Progress {
3642
0
                            item: sync_service::StorageResultItem::Value { key, value },
3643
0
                            query: next,
3644
0
                            ..
3645
0
                        },
3646
0
                        StorageRequestInProgress::StateQueryStorageAt {
3647
0
                            block_hash,
3648
0
                            mut in_progress_results,
3649
0
                        },
3650
0
                    ) => {
3651
0
                        // Continue finding keys.
3652
0
                        in_progress_results
3653
0
                            .push((methods::HexString(key), value.map(methods::HexString)));
3654
0
                        me.background_tasks.push(Box::pin(async move {
3655
0
                            Event::LegacyApiFunctionStorageRequestProgress {
3656
0
                                request_id_json,
3657
0
                                request: StorageRequestInProgress::StateQueryStorageAt {
3658
0
                                    block_hash,
3659
0
                                    in_progress_results,
3660
0
                                },
3661
0
                                progress: next.advance().await,
3662
                            }
3663
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sD_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sD_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sD_0Ba_
3664
0
                    }
3665
                    (
3666
                        sync_service::StorageQueryProgress::Finished,
3667
                        StorageRequestInProgress::StateQueryStorageAt {
3668
0
                            block_hash,
3669
0
                            in_progress_results,
3670
0
                        },
3671
0
                    ) => {
3672
0
                        // Finished.
3673
0
                        let _ = me
3674
0
                            .responses_tx
3675
0
                            .send(
3676
0
                                methods::Response::state_queryStorageAt(vec![
3677
0
                                    methods::StorageChangeSet {
3678
0
                                        block: methods::HashHexString(block_hash),
3679
0
                                        changes: in_progress_results,
3680
0
                                    },
3681
0
                                ])
3682
0
                                .to_json_response(&request_id_json),
3683
0
                            )
3684
0
                            .await;
3685
                    }
3686
                    (
3687
                        sync_service::StorageQueryProgress::Progress {
3688
                            item:
3689
                                sync_service::StorageResultItem::Value {
3690
0
                                    value: Some(value), ..
3691
0
                                },
3692
0
                            ..
3693
0
                        },
3694
0
                        StorageRequestInProgress::StateGetStorage {},
3695
0
                    ) => {
3696
0
                        // Finished. We throw away the object that continues the request, as we
3697
0
                        // know that nothing else will come after.
3698
0
                        let _ = me
3699
0
                            .responses_tx
3700
0
                            .send(
3701
0
                                methods::Response::state_getStorage(methods::HexString(value))
3702
0
                                    .to_json_response(&request_id_json),
3703
0
                            )
3704
0
                            .await;
3705
                    }
3706
                    (
3707
                        sync_service::StorageQueryProgress::Progress {
3708
                            item: sync_service::StorageResultItem::Value { value: None, .. },
3709
                            ..
3710
                        },
3711
                        StorageRequestInProgress::StateGetStorage {},
3712
                    ) => {
3713
                        // Finished. We throw away the object that continues the request, as we
3714
                        // know that nothing else will come after.
3715
0
                        let _ = me
3716
0
                            .responses_tx
3717
0
                            .send(parse::build_success_response(&request_id_json, "null"))
3718
0
                            .await;
3719
                    }
3720
0
                    (sync_service::StorageQueryProgress::Error(error), _) => {
3721
0
                        // All errors are sent back the same way.
3722
0
                        let _ = me
3723
0
                            .responses_tx
3724
0
                            .send(parse::build_error_response(
3725
0
                                &request_id_json,
3726
0
                                parse::ErrorResponse::ServerError(-32000, &error.to_string()),
3727
0
                                None,
3728
0
                            ))
3729
0
                            .await;
3730
                    }
3731
0
                    _ => unreachable!(),
3732
                }
3733
            }
3734
3735
            WakeUpReason::Event(
3736
0
                event @ (Event::ChainHeadSubscriptionWithRuntimeReady { .. }
3737
                | Event::ChainHeadSubscriptionWithoutRuntimeReady { .. }),
3738
            ) => {
3739
                // A `chainHead_follow` subscription has finished subscribing to either the
3740
                // runtime service or the sync service.
3741
3742
                // Both "with runtime" and "without runtime" events are handled together here,
3743
                // but they use different types.
3744
                // Extract the event information.
3745
                let (
3746
0
                    subscription_id,
3747
0
                    new_blocks,
3748
0
                    finalized_block_scale_encoded_header,
3749
0
                    finalized_block_runtime,
3750
0
                    non_finalized_blocks_ancestry_order,
3751
0
                ) = match event {
3752
                    Event::ChainHeadSubscriptionWithRuntimeReady {
3753
0
                        subscription_id,
3754
0
                        subscription,
3755
0
                    } => (
3756
0
                        subscription_id,
3757
0
                        either::Left(subscription.new_blocks),
3758
0
                        subscription.finalized_block_scale_encoded_header,
3759
0
                        Some(subscription.finalized_block_runtime),
3760
0
                        either::Left(
3761
0
                            subscription
3762
0
                                .non_finalized_blocks_ancestry_order
3763
0
                                .into_iter()
3764
0
                                .map(either::Left),
3765
0
                        ),
3766
0
                    ),
3767
                    Event::ChainHeadSubscriptionWithoutRuntimeReady {
3768
0
                        subscription_id,
3769
0
                        subscription,
3770
0
                    } => (
3771
0
                        subscription_id,
3772
0
                        either::Right(Box::pin(subscription.new_blocks)),
3773
0
                        subscription.finalized_block_scale_encoded_header,
3774
0
                        None,
3775
0
                        either::Right(
3776
0
                            subscription
3777
0
                                .non_finalized_blocks_ancestry_order
3778
0
                                .into_iter()
3779
0
                                .map(either::Right),
3780
0
                        ),
3781
0
                    ),
3782
0
                    _ => unreachable!(),
3783
                };
3784
3785
                // It might be that the JSON-RPC client has unsubscribed before the subscription
3786
                // was initialized.
3787
0
                let Some(subscription_info) =
3788
0
                    me.chain_head_follow_subscriptions.get_mut(&subscription_id)
3789
                else {
3790
0
                    continue;
3791
                };
3792
3793
                // Store the subscription ID in the subscription.
3794
0
                if let either::Left(new_blocks) = &new_blocks {
3795
0
                    subscription_info.runtime_service_subscription_id = Some(new_blocks.id());
3796
0
                }
3797
3798
                // Send the `initialized` event and pin the finalized block.
3799
0
                let finalized_block_hash =
3800
0
                    header::hash_from_scale_encoded_header(&finalized_block_scale_encoded_header); // TODO: indicate hash in subscription?
3801
0
                let _ = me
3802
0
                    .responses_tx
3803
0
                    .send(
3804
0
                        methods::ServerToClient::chainHead_v1_followEvent {
3805
0
                            subscription: Cow::Borrowed(&subscription_id),
3806
0
                            result: methods::FollowEvent::Initialized {
3807
0
                                finalized_block_hashes: vec![methods::HashHexString(
3808
0
                                    finalized_block_hash,
3809
0
                                )],
3810
0
                                finalized_block_runtime: finalized_block_runtime.as_ref().map(
3811
0
                                    |runtime| match runtime {
3812
0
                                        Ok(rt) => methods::MaybeRuntimeSpec::Valid {
3813
0
                                            spec: convert_runtime_version(&rt),
3814
0
                                        },
3815
0
                                        Err(error) => methods::MaybeRuntimeSpec::Invalid {
3816
0
                                            error: error.to_string(),
3817
0
                                        },
3818
0
                                    },
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sE_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sE_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sE_0Ba_
3819
0
                                ),
3820
0
                            },
3821
0
                        }
3822
0
                        .to_json_request_object_parameters(None),
3823
0
                    )
3824
0
                    .await;
3825
0
                subscription_info
3826
0
                    .pinned_blocks_headers
3827
0
                    .insert(finalized_block_hash, finalized_block_scale_encoded_header);
3828
3829
                // Send an event for each non-finalized block.
3830
0
                for block in non_finalized_blocks_ancestry_order {
3831
0
                    let parent_block_hash = match &block {
3832
0
                        either::Left(b) => b.parent_hash,
3833
0
                        either::Right(b) => b.parent_hash,
3834
                    };
3835
0
                    let hash = header::hash_from_scale_encoded_header(match &block {
3836
0
                        either::Left(b) => &b.scale_encoded_header,
3837
0
                        either::Right(b) => &b.scale_encoded_header,
3838
                    }); // TODO: indicate hash in subscription?
3839
0
                    let _ = me
3840
0
                        .responses_tx
3841
0
                        .send(
3842
0
                            methods::ServerToClient::chainHead_v1_followEvent {
3843
0
                                subscription: Cow::Borrowed(&subscription_id),
3844
0
                                result: methods::FollowEvent::NewBlock {
3845
0
                                    block_hash: methods::HashHexString(hash),
3846
0
                                    parent_block_hash: methods::HashHexString(parent_block_hash),
3847
0
                                    new_runtime: if let either::Left(block) = &block {
3848
0
                                        if let Some(rt) = &block.new_runtime {
3849
0
                                            match rt {
3850
0
                                                Ok(spec) => {
3851
0
                                                    Some(methods::MaybeRuntimeSpec::Valid {
3852
0
                                                        spec: convert_runtime_version(spec),
3853
0
                                                    })
3854
                                                }
3855
0
                                                Err(error) => {
3856
0
                                                    Some(methods::MaybeRuntimeSpec::Invalid {
3857
0
                                                        error: error.to_string(),
3858
0
                                                    })
3859
                                                }
3860
                                            }
3861
                                        } else {
3862
0
                                            None
3863
                                        }
3864
                                    } else {
3865
0
                                        None
3866
                                    },
3867
                                },
3868
                            }
3869
0
                            .to_json_request_object_parameters(None),
3870
                        )
3871
0
                        .await;
3872
0
                    if match &block {
3873
0
                        either::Left(b) => b.is_new_best,
3874
0
                        either::Right(b) => b.is_new_best,
3875
                    } {
3876
0
                        let _ = me
3877
0
                            .responses_tx
3878
0
                            .send(
3879
0
                                methods::ServerToClient::chainHead_v1_followEvent {
3880
0
                                    subscription: Cow::Borrowed(&subscription_id),
3881
0
                                    result: methods::FollowEvent::BestBlockChanged {
3882
0
                                        best_block_hash: methods::HashHexString(hash),
3883
0
                                    },
3884
0
                                }
3885
0
                                .to_json_request_object_parameters(None),
3886
0
                            )
3887
0
                            .await;
3888
0
                    }
3889
0
                    subscription_info.pinned_blocks_headers.insert(
3890
0
                        hash,
3891
0
                        match block {
3892
0
                            either::Left(b) => b.scale_encoded_header,
3893
0
                            either::Right(b) => b.scale_encoded_header,
3894
                        },
3895
                    );
3896
                }
3897
3898
                // Push a new background task that will yield an event when the newly-created
3899
                // susbcription generates its first event.
3900
0
                me.background_tasks.push({
3901
0
                    match new_blocks {
3902
0
                        either::Left(mut new_blocks) => Box::pin(async move {
3903
0
                            if let Some(notification) = new_blocks.next().await {
3904
0
                                Event::ChainHeadSubscriptionWithRuntimeNotification {
3905
0
                                    subscription_id,
3906
0
                                    notification,
3907
0
                                    stream: new_blocks,
3908
0
                                }
3909
                            } else {
3910
0
                                Event::ChainHeadSubscriptionDeadSubcription { subscription_id }
3911
                            }
3912
0
                        }),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sF_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sF_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sF_0Ba_
3913
0
                        either::Right(mut new_blocks) => Box::pin(async move {
3914
0
                            if let Some(notification) = new_blocks.next().await {
3915
0
                                Event::ChainHeadSubscriptionWithoutRuntimeNotification {
3916
0
                                    subscription_id,
3917
0
                                    notification,
3918
0
                                    stream: new_blocks,
3919
0
                                }
3920
                            } else {
3921
0
                                Event::ChainHeadSubscriptionDeadSubcription { subscription_id }
3922
                            }
3923
0
                        }),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sG_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sG_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sG_0Ba_
3924
                    }
3925
                });
3926
            }
3927
3928
            WakeUpReason::Event(Event::ChainHeadSubscriptionWithRuntimeNotification {
3929
0
                subscription_id,
3930
0
                notification,
3931
0
                mut stream,
3932
            }) => {
3933
                // It might be that the JSON-RPC client has unsubscribed.
3934
0
                let Some(subscription_info) =
3935
0
                    me.chain_head_follow_subscriptions.get_mut(&subscription_id)
3936
                else {
3937
0
                    continue;
3938
                };
3939
3940
0
                match notification {
3941
                    runtime_service::Notification::Finalized {
3942
0
                        hash,
3943
0
                        best_block_hash_if_changed,
3944
0
                        pruned_blocks,
3945
                    } => {
3946
0
                        if let Some(new_best_block_hash) = best_block_hash_if_changed {
3947
0
                            let _ = me
3948
0
                                .responses_tx
3949
0
                                .send(
3950
0
                                    methods::ServerToClient::chainHead_v1_followEvent {
3951
0
                                        subscription: Cow::Borrowed(&subscription_id),
3952
0
                                        result: methods::FollowEvent::BestBlockChanged {
3953
0
                                            best_block_hash: methods::HashHexString(
3954
0
                                                new_best_block_hash,
3955
0
                                            ),
3956
0
                                        },
3957
0
                                    }
3958
0
                                    .to_json_request_object_parameters(None),
3959
0
                                )
3960
0
                                .await;
3961
0
                        }
3962
3963
0
                        let _ = me
3964
0
                            .responses_tx
3965
0
                            .send(
3966
0
                                methods::ServerToClient::chainHead_v1_followEvent {
3967
0
                                    subscription: Cow::Borrowed(&subscription_id),
3968
0
                                    result: methods::FollowEvent::Finalized {
3969
0
                                        finalized_blocks_hashes: vec![methods::HashHexString(hash)],
3970
0
                                        pruned_blocks_hashes: pruned_blocks
3971
0
                                            .into_iter()
3972
0
                                            .map(methods::HashHexString)
3973
0
                                            .collect(),
3974
0
                                    },
3975
0
                                }
3976
0
                                .to_json_request_object_parameters(None),
3977
0
                            )
3978
0
                            .await;
3979
                    }
3980
0
                    runtime_service::Notification::BestBlockChanged { hash } => {
3981
0
                        let _ = me
3982
0
                            .responses_tx
3983
0
                            .send(
3984
0
                                methods::ServerToClient::chainHead_v1_followEvent {
3985
0
                                    subscription: Cow::Borrowed(&subscription_id),
3986
0
                                    result: methods::FollowEvent::BestBlockChanged {
3987
0
                                        best_block_hash: methods::HashHexString(hash),
3988
0
                                    },
3989
0
                                }
3990
0
                                .to_json_request_object_parameters(None),
3991
0
                            )
3992
0
                            .await;
3993
                    }
3994
0
                    runtime_service::Notification::Block(block) => {
3995
0
                        // TODO: pass hash through notification
3996
0
                        let block_hash =
3997
0
                            header::hash_from_scale_encoded_header(&block.scale_encoded_header);
3998
0
                        subscription_info
3999
0
                            .pinned_blocks_headers
4000
0
                            .insert(block_hash, block.scale_encoded_header);
4001
0
4002
0
                        let _ = me
4003
0
                            .responses_tx
4004
0
                            .send(
4005
0
                                methods::ServerToClient::chainHead_v1_followEvent {
4006
0
                                    subscription: Cow::Borrowed(&subscription_id),
4007
0
                                    result: methods::FollowEvent::NewBlock {
4008
0
                                        block_hash: methods::HashHexString(block_hash),
4009
0
                                        parent_block_hash: methods::HashHexString(
4010
0
                                            block.parent_hash,
4011
0
                                        ),
4012
0
                                        new_runtime: match &block.new_runtime {
4013
0
                                            Some(Ok(rt)) => {
4014
0
                                                Some(methods::MaybeRuntimeSpec::Valid {
4015
0
                                                    spec: convert_runtime_version(&rt),
4016
0
                                                })
4017
                                            }
4018
0
                                            Some(Err(error)) => {
4019
0
                                                Some(methods::MaybeRuntimeSpec::Invalid {
4020
0
                                                    error: error.to_string(),
4021
0
                                                })
4022
                                            }
4023
0
                                            None => None,
4024
                                        },
4025
                                    },
4026
                                }
4027
0
                                .to_json_request_object_parameters(None),
4028
                            )
4029
0
                            .await;
4030
4031
0
                        if block.is_new_best {
4032
0
                            let _ = me
4033
0
                                .responses_tx
4034
0
                                .send(
4035
0
                                    methods::ServerToClient::chainHead_v1_followEvent {
4036
0
                                        subscription: Cow::Borrowed(&subscription_id),
4037
0
                                        result: methods::FollowEvent::BestBlockChanged {
4038
0
                                            best_block_hash: methods::HashHexString(block_hash),
4039
0
                                        },
4040
0
                                    }
4041
0
                                    .to_json_request_object_parameters(None),
4042
0
                                )
4043
0
                                .await;
4044
0
                        }
4045
                    }
4046
                }
4047
4048
                // Push a new task that will yield when the runtime service subscription generates
4049
                // the next notification.
4050
0
                me.background_tasks.push(Box::pin(async move {
4051
0
                    if let Some(notification) = stream.next().await {
4052
0
                        Event::ChainHeadSubscriptionWithRuntimeNotification {
4053
0
                            subscription_id,
4054
0
                            notification,
4055
0
                            stream,
4056
0
                        }
4057
                    } else {
4058
0
                        Event::ChainHeadSubscriptionDeadSubcription { subscription_id }
4059
                    }
4060
0
                }))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sH_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sH_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sH_0Ba_
4061
            }
4062
4063
            WakeUpReason::Event(Event::ChainHeadSubscriptionWithoutRuntimeNotification {
4064
0
                subscription_id,
4065
0
                notification,
4066
0
                mut stream,
4067
            }) => {
4068
                // It might be that the JSON-RPC client has unsubscribed.
4069
0
                let Some(subscription_info) =
4070
0
                    me.chain_head_follow_subscriptions.get_mut(&subscription_id)
4071
                else {
4072
0
                    continue;
4073
                };
4074
4075
0
                match notification {
4076
                    sync_service::Notification::Finalized {
4077
0
                        hash,
4078
0
                        best_block_hash_if_changed,
4079
0
                        pruned_blocks,
4080
                    } => {
4081
0
                        if let Some(new_best_block_hash) = best_block_hash_if_changed {
4082
0
                            let _ = me
4083
0
                                .responses_tx
4084
0
                                .send(
4085
0
                                    methods::ServerToClient::chainHead_v1_followEvent {
4086
0
                                        subscription: Cow::Borrowed(&subscription_id),
4087
0
                                        result: methods::FollowEvent::BestBlockChanged {
4088
0
                                            best_block_hash: methods::HashHexString(
4089
0
                                                new_best_block_hash,
4090
0
                                            ),
4091
0
                                        },
4092
0
                                    }
4093
0
                                    .to_json_request_object_parameters(None),
4094
0
                                )
4095
0
                                .await;
4096
0
                        }
4097
4098
0
                        let _ = me
4099
0
                            .responses_tx
4100
0
                            .send(
4101
0
                                methods::ServerToClient::chainHead_v1_followEvent {
4102
0
                                    subscription: Cow::Borrowed(&subscription_id),
4103
0
                                    result: methods::FollowEvent::Finalized {
4104
0
                                        finalized_blocks_hashes: vec![methods::HashHexString(hash)],
4105
0
                                        pruned_blocks_hashes: pruned_blocks
4106
0
                                            .into_iter()
4107
0
                                            .map(methods::HashHexString)
4108
0
                                            .collect(),
4109
0
                                    },
4110
0
                                }
4111
0
                                .to_json_request_object_parameters(None),
4112
0
                            )
4113
0
                            .await;
4114
                    }
4115
0
                    sync_service::Notification::BestBlockChanged { hash } => {
4116
0
                        let _ = me
4117
0
                            .responses_tx
4118
0
                            .send(
4119
0
                                methods::ServerToClient::chainHead_v1_followEvent {
4120
0
                                    subscription: Cow::Borrowed(&subscription_id),
4121
0
                                    result: methods::FollowEvent::BestBlockChanged {
4122
0
                                        best_block_hash: methods::HashHexString(hash),
4123
0
                                    },
4124
0
                                }
4125
0
                                .to_json_request_object_parameters(None),
4126
0
                            )
4127
0
                            .await;
4128
                    }
4129
0
                    sync_service::Notification::Block(block) => {
4130
0
                        // TODO: pass hash through notification
4131
0
                        let block_hash =
4132
0
                            header::hash_from_scale_encoded_header(&block.scale_encoded_header);
4133
0
                        subscription_info
4134
0
                            .pinned_blocks_headers
4135
0
                            .insert(block_hash, block.scale_encoded_header);
4136
0
4137
0
                        let _ = me
4138
0
                            .responses_tx
4139
0
                            .send(
4140
0
                                methods::ServerToClient::chainHead_v1_followEvent {
4141
0
                                    subscription: Cow::Borrowed(&subscription_id),
4142
0
                                    result: methods::FollowEvent::NewBlock {
4143
0
                                        block_hash: methods::HashHexString(block_hash),
4144
0
                                        parent_block_hash: methods::HashHexString(
4145
0
                                            block.parent_hash,
4146
0
                                        ),
4147
0
                                        new_runtime: None,
4148
0
                                    },
4149
0
                                }
4150
0
                                .to_json_request_object_parameters(None),
4151
0
                            )
4152
0
                            .await;
4153
4154
0
                        if block.is_new_best {
4155
0
                            let _ = me
4156
0
                                .responses_tx
4157
0
                                .send(
4158
0
                                    methods::ServerToClient::chainHead_v1_followEvent {
4159
0
                                        subscription: Cow::Borrowed(&subscription_id),
4160
0
                                        result: methods::FollowEvent::BestBlockChanged {
4161
0
                                            best_block_hash: methods::HashHexString(block_hash),
4162
0
                                        },
4163
0
                                    }
4164
0
                                    .to_json_request_object_parameters(None),
4165
0
                                )
4166
0
                                .await;
4167
0
                        }
4168
                    }
4169
                }
4170
4171
                // Push a new task that will yield when the sync service subscription generates
4172
                // the next notification.
4173
0
                me.background_tasks.push(Box::pin(async move {
4174
0
                    if let Some(notification) = stream.next().await {
4175
0
                        Event::ChainHeadSubscriptionWithoutRuntimeNotification {
4176
0
                            subscription_id,
4177
0
                            notification,
4178
0
                            stream,
4179
0
                        }
4180
                    } else {
4181
0
                        Event::ChainHeadSubscriptionDeadSubcription { subscription_id }
4182
                    }
4183
0
                }))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sI_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sI_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sI_0Ba_
4184
            }
4185
4186
            WakeUpReason::Event(Event::ChainHeadCallOperationDone {
4187
0
                subscription_id,
4188
0
                operation_id,
4189
0
                result,
4190
            }) => {
4191
                // A `chainHead_call` operation has finished.
4192
4193
0
                let Some(subscription_info) =
4194
0
                    me.chain_head_follow_subscriptions.get_mut(&subscription_id)
4195
                else {
4196
0
                    unreachable!()
4197
                };
4198
0
                let Some(operation_info) = subscription_info
4199
0
                    .operations_in_progress
4200
0
                    .remove(&operation_id)
4201
                else {
4202
                    // If the operation was cancelled, then a `ChainHeadOperationCancelled`
4203
                    // event should have been generated instead.
4204
0
                    unreachable!()
4205
                };
4206
4207
0
                subscription_info.available_operation_slots += operation_info.occupied_slots;
4208
4209
0
                let result = match result {
4210
0
                    Ok(success) => methods::FollowEvent::OperationCallDone {
4211
0
                        operation_id: operation_id.clone().into(),
4212
0
                        output: methods::HexString(success.output),
4213
0
                    },
4214
0
                    Err(runtime_service::RuntimeCallError::InvalidRuntime(error)) => {
4215
0
                        methods::FollowEvent::OperationError {
4216
0
                            operation_id: operation_id.clone().into(),
4217
0
                            error: error.to_string().into(),
4218
0
                        }
4219
                    }
4220
                    Err(runtime_service::RuntimeCallError::ApiVersionRequirementUnfulfilled) => {
4221
                        // We pass `None` for the API requirement, thus this error can never happen.
4222
0
                        unreachable!()
4223
                    }
4224
                    Err(
4225
                        runtime_service::RuntimeCallError::Crash
4226
                        | runtime_service::RuntimeCallError::Inaccessible(_),
4227
0
                    ) => methods::FollowEvent::OperationInaccessible {
4228
0
                        operation_id: operation_id.clone().into(),
4229
0
                    },
4230
                    Err(runtime_service::RuntimeCallError::Execution(
4231
                        runtime_service::RuntimeCallExecutionError::ForbiddenHostFunction,
4232
0
                    )) => methods::FollowEvent::OperationError {
4233
0
                        operation_id: operation_id.clone().into(),
4234
0
                        error: "Runtime has called an offchain host function"
4235
0
                            .to_string()
4236
0
                            .into(),
4237
0
                    },
4238
                    Err(runtime_service::RuntimeCallError::Execution(
4239
0
                        runtime_service::RuntimeCallExecutionError::Start(error),
4240
0
                    )) => methods::FollowEvent::OperationError {
4241
0
                        operation_id: operation_id.clone().into(),
4242
0
                        error: error.to_string().into(),
4243
0
                    },
4244
                    Err(runtime_service::RuntimeCallError::Execution(
4245
0
                        runtime_service::RuntimeCallExecutionError::Execution(error),
4246
0
                    )) => methods::FollowEvent::OperationError {
4247
0
                        operation_id: operation_id.clone().into(),
4248
0
                        error: error.to_string().into(),
4249
0
                    },
4250
                };
4251
4252
0
                let _ = me
4253
0
                    .responses_tx
4254
0
                    .send(
4255
0
                        methods::ServerToClient::chainHead_v1_followEvent {
4256
0
                            subscription: Cow::Borrowed(&subscription_id),
4257
0
                            result,
4258
0
                        }
4259
0
                        .to_json_request_object_parameters(None),
4260
0
                    )
4261
0
                    .await;
4262
            }
4263
4264
            WakeUpReason::Event(Event::ChainHeadBodyOperationDone {
4265
0
                subscription_id,
4266
0
                operation_id,
4267
0
                expected_extrinsics_root,
4268
0
                result,
4269
            }) => {
4270
                // A `chainHead_body` operation has finished.
4271
4272
0
                let Some(subscription_info) =
4273
0
                    me.chain_head_follow_subscriptions.get_mut(&subscription_id)
4274
                else {
4275
0
                    unreachable!()
4276
                };
4277
0
                let Some(operation_info) = subscription_info
4278
0
                    .operations_in_progress
4279
0
                    .remove(&operation_id)
4280
                else {
4281
                    // If the operation was cancelled, then a `ChainHeadOperationCancelled`
4282
                    // event should have been generated instead.
4283
0
                    unreachable!()
4284
                };
4285
4286
0
                subscription_info.available_operation_slots += operation_info.occupied_slots;
4287
4288
                // We must check whether the body is present in the response and valid.
4289
                // TODO: should try the request again with a different peer instead of failing immediately
4290
0
                let body = match result {
4291
0
                    Ok(result) => {
4292
0
                        if let Some(body) = result.body {
4293
0
                            if header::extrinsics_root(&body) == expected_extrinsics_root {
4294
0
                                Ok(body)
4295
                            } else {
4296
0
                                Err(())
4297
                            }
4298
                        } else {
4299
0
                            Err(())
4300
                        }
4301
                    }
4302
0
                    Err(err) => Err(err),
4303
                };
4304
4305
                // Send back the response.
4306
0
                match body {
4307
0
                    Ok(body) => {
4308
0
                        let _ = me
4309
0
                            .responses_tx
4310
0
                            .send(
4311
0
                                methods::ServerToClient::chainHead_v1_followEvent {
4312
0
                                    subscription: Cow::Borrowed(&subscription_id),
4313
0
                                    result: methods::FollowEvent::OperationBodyDone {
4314
0
                                        operation_id: operation_id.clone().into(),
4315
0
                                        value: body.into_iter().map(methods::HexString).collect(),
4316
0
                                    },
4317
0
                                }
4318
0
                                .to_json_request_object_parameters(None),
4319
0
                            )
4320
0
                            .await;
4321
                    }
4322
                    Err(()) => {
4323
0
                        let _ = me
4324
0
                            .responses_tx
4325
0
                            .send(
4326
0
                                methods::ServerToClient::chainHead_v1_followEvent {
4327
0
                                    subscription: Cow::Borrowed(&subscription_id),
4328
0
                                    result: methods::FollowEvent::OperationInaccessible {
4329
0
                                        operation_id: operation_id.clone().into(),
4330
0
                                    },
4331
0
                                }
4332
0
                                .to_json_request_object_parameters(None),
4333
0
                            )
4334
0
                            .await;
4335
                    }
4336
                }
4337
            }
4338
4339
            WakeUpReason::Event(Event::ChainHeadStorageOperationProgress {
4340
0
                subscription_id,
4341
0
                operation_id,
4342
0
                progress:
4343
0
                    sync_service::StorageQueryProgress::Progress {
4344
0
                        request_index,
4345
0
                        item,
4346
0
                        mut query,
4347
0
                    },
4348
0
            }) => {
4349
0
                // A `chainHead_storage` operation has made progress.
4350
0
                let mut items_chunk = Vec::with_capacity(16);
4351
4352
0
                for (_, item) in
4353
0
                    iter::once((request_index, item)).chain(iter::from_fn(|| query.try_advance()))
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sJ_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sJ_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sJ_0Ba_
4354
                {
4355
                    // Perform some API conversion.
4356
0
                    let item = match item {
4357
                        sync_service::StorageResultItem::Value {
4358
0
                            key,
4359
0
                            value: Some(value),
4360
0
                        } => Some(methods::ChainHeadStorageResponseItem {
4361
0
                            key: methods::HexString(key),
4362
0
                            value: Some(methods::HexString(value)),
4363
0
                            hash: None,
4364
0
                            closest_descendant_merkle_value: None,
4365
0
                        }),
4366
0
                        sync_service::StorageResultItem::Value { value: None, .. } => None,
4367
                        sync_service::StorageResultItem::Hash {
4368
0
                            key,
4369
0
                            hash: Some(hash),
4370
0
                        } => Some(methods::ChainHeadStorageResponseItem {
4371
0
                            key: methods::HexString(key),
4372
0
                            value: None,
4373
0
                            hash: Some(methods::HexString(hash.to_vec())),
4374
0
                            closest_descendant_merkle_value: None,
4375
0
                        }),
4376
0
                        sync_service::StorageResultItem::Hash { hash: None, .. } => None,
4377
0
                        sync_service::StorageResultItem::DescendantValue { key, value, .. } => {
4378
0
                            Some(methods::ChainHeadStorageResponseItem {
4379
0
                                key: methods::HexString(key),
4380
0
                                value: Some(methods::HexString(value)),
4381
0
                                hash: None,
4382
0
                                closest_descendant_merkle_value: None,
4383
0
                            })
4384
                        }
4385
0
                        sync_service::StorageResultItem::DescendantHash { key, hash, .. } => {
4386
0
                            Some(methods::ChainHeadStorageResponseItem {
4387
0
                                key: methods::HexString(key),
4388
0
                                value: None,
4389
0
                                hash: Some(methods::HexString(hash.to_vec())),
4390
0
                                closest_descendant_merkle_value: None,
4391
0
                            })
4392
                        }
4393
                        sync_service::StorageResultItem::ClosestDescendantMerkleValue {
4394
0
                            requested_key,
4395
0
                            closest_descendant_merkle_value: Some(merkle_value),
4396
0
                            ..
4397
0
                        } => Some(methods::ChainHeadStorageResponseItem {
4398
0
                            key: methods::HexString(requested_key),
4399
0
                            value: None,
4400
0
                            hash: None,
4401
0
                            closest_descendant_merkle_value: Some(methods::HexString(merkle_value)),
4402
0
                        }),
4403
                        sync_service::StorageResultItem::ClosestDescendantMerkleValue {
4404
                            closest_descendant_merkle_value: None,
4405
                            ..
4406
0
                        } => None,
4407
                    };
4408
4409
0
                    if let Some(item) = item {
4410
0
                        items_chunk.push(item);
4411
0
                    }
4412
                }
4413
4414
                // Send the gathered items to the JSON-RPC client.
4415
0
                if !items_chunk.is_empty() {
4416
0
                    let _ = me
4417
0
                        .responses_tx
4418
0
                        .send(
4419
0
                            methods::ServerToClient::chainHead_v1_followEvent {
4420
0
                                subscription: Cow::Borrowed(&subscription_id),
4421
0
                                result: methods::FollowEvent::OperationStorageItems {
4422
0
                                    operation_id: Cow::Borrowed(&operation_id),
4423
0
                                    items: items_chunk,
4424
0
                                },
4425
0
                            }
4426
0
                            .to_json_request_object_parameters(None),
4427
0
                        )
4428
0
                        .await;
4429
0
                }
4430
4431
                // TODO: generate a waitingForContinue here and wait for user to continue
4432
4433
                // Re-queue the operation for the follow-up items.
4434
0
                let on_interrupt = me
4435
0
                    .chain_head_follow_subscriptions
4436
0
                    .get(&subscription_id)
4437
0
                    .unwrap_or_else(|| unreachable!())
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sK_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sK_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sK_0Ba_
4438
0
                    .operations_in_progress
4439
0
                    .get(&operation_id)
4440
0
                    .unwrap_or_else(|| unreachable!())
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sL_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sL_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sL_0Ba_
4441
0
                    .interrupt
4442
0
                    .listen();
4443
0
                me.background_tasks.push(Box::pin(async move {
4444
0
                    async {
4445
0
                        on_interrupt.await;
4446
                        // This event is necessary only because tasks can't finish without
4447
                        // generating an event.
4448
0
                        Event::ChainHeadOperationCancelled
4449
0
                    }
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sM_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sM_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sM_00Bc_
4450
0
                    .or(async {
4451
0
                        Event::ChainHeadStorageOperationProgress {
4452
0
                            subscription_id,
4453
0
                            operation_id,
4454
0
                            progress: query.advance().await,
4455
                        }
4456
0
                    })
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sM_0s_0Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sM_0s_0B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sM_0s_0Bc_
4457
0
                    .await
4458
0
                }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sM_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sM_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sM_0Ba_
4459
            }
4460
4461
            WakeUpReason::Event(Event::ChainHeadStorageOperationProgress {
4462
0
                subscription_id,
4463
0
                operation_id,
4464
                progress: sync_service::StorageQueryProgress::Finished,
4465
            }) => {
4466
                // A `chainHead_storage` operation has finished successfully.
4467
4468
0
                let Some(subscription_info) =
4469
0
                    me.chain_head_follow_subscriptions.get_mut(&subscription_id)
4470
                else {
4471
0
                    unreachable!()
4472
                };
4473
0
                let Some(operation_info) = subscription_info
4474
0
                    .operations_in_progress
4475
0
                    .remove(&operation_id)
4476
                else {
4477
                    // If the operation was cancelled, then a `ChainHeadOperationCancelled`
4478
                    // event should have been generated instead.
4479
0
                    unreachable!()
4480
                };
4481
4482
0
                subscription_info.available_operation_slots += operation_info.occupied_slots;
4483
0
4484
0
                let _ = me
4485
0
                    .responses_tx
4486
0
                    .send(
4487
0
                        methods::ServerToClient::chainHead_v1_followEvent {
4488
0
                            subscription: Cow::Borrowed(&subscription_id),
4489
0
                            result: methods::FollowEvent::OperationStorageDone {
4490
0
                                operation_id: Cow::Borrowed(&operation_id),
4491
0
                            },
4492
0
                        }
4493
0
                        .to_json_request_object_parameters(None),
4494
0
                    )
4495
0
                    .await;
4496
            }
4497
4498
            WakeUpReason::Event(Event::ChainHeadStorageOperationProgress {
4499
0
                subscription_id,
4500
0
                operation_id,
4501
                progress: sync_service::StorageQueryProgress::Error(_),
4502
            }) => {
4503
                // A `chainHead_storage` operation has finished failed.
4504
4505
0
                let Some(subscription_info) =
4506
0
                    me.chain_head_follow_subscriptions.get_mut(&subscription_id)
4507
                else {
4508
0
                    unreachable!()
4509
                };
4510
0
                let Some(operation_info) = subscription_info
4511
0
                    .operations_in_progress
4512
0
                    .remove(&operation_id)
4513
                else {
4514
                    // If the operation was cancelled, then a `ChainHeadOperationCancelled`
4515
                    // event should have been generated instead.
4516
0
                    unreachable!()
4517
                };
4518
4519
0
                subscription_info.available_operation_slots += operation_info.occupied_slots;
4520
0
4521
0
                let _ = me
4522
0
                    .responses_tx
4523
0
                    .send(
4524
0
                        methods::ServerToClient::chainHead_v1_followEvent {
4525
0
                            subscription: Cow::Borrowed(&subscription_id),
4526
0
                            result: methods::FollowEvent::OperationInaccessible {
4527
0
                                operation_id: Cow::Borrowed(&operation_id),
4528
0
                            },
4529
0
                        }
4530
0
                        .to_json_request_object_parameters(None),
4531
0
                    )
4532
0
                    .await;
4533
            }
4534
4535
            WakeUpReason::Event(Event::ChainHeadSubscriptionDeadSubcription {
4536
0
                subscription_id,
4537
            }) => {
4538
                // The runtime service or sync service subscription of a `chainHead_follow`
4539
                // subscription has died.
4540
4541
                // It might be that the JSON-RPC client has already unsubscribed.
4542
0
                let Some(subscription_info) =
4543
0
                    me.chain_head_follow_subscriptions.remove(&subscription_id)
4544
                else {
4545
0
                    continue;
4546
                };
4547
4548
                // Cancel operations isn't necessary, but is also not a bad idea, to
4549
                // save resources.
4550
0
                for (_, operation) in subscription_info.operations_in_progress {
4551
0
                    operation.interrupt.notify(usize::MAX);
4552
0
                }
4553
4554
                // Send a stop event.
4555
0
                let _ = me
4556
0
                    .responses_tx
4557
0
                    .send(
4558
0
                        methods::ServerToClient::chainHead_v1_followEvent {
4559
0
                            subscription: Cow::Borrowed(&subscription_id),
4560
0
                            result: methods::FollowEvent::Stop {},
4561
0
                        }
4562
0
                        .to_json_request_object_parameters(None),
4563
0
                    )
4564
0
                    .await;
4565
            }
4566
4567
0
            WakeUpReason::Event(Event::ChainHeadOperationCancelled) => {
4568
0
                // Nothing to do.
4569
0
            }
4570
4571
0
            WakeUpReason::RuntimeServiceSubscriptionReady(subscribe_all) => {
4572
0
                // Runtime service is now ready to give us blocks.
4573
0
                // This only relates to the legacy JSON-RPC API.
4574
0
4575
0
                // Transition to `RuntimeServiceSubscription::Active`.
4576
0
                let mut pinned_blocks =
4577
0
                    hashbrown::HashMap::with_capacity_and_hasher(32, Default::default());
4578
0
                let mut finalized_and_pruned_lru = lru::LruCache::with_hasher(
4579
0
                    NonZeroUsize::new(32).unwrap(),
4580
0
                    fnv::FnvBuildHasher::default(),
4581
0
                );
4582
0
4583
0
                let finalized_block_hash = header::hash_from_scale_encoded_header(
4584
0
                    &subscribe_all.finalized_block_scale_encoded_header,
4585
0
                );
4586
0
                pinned_blocks.insert(
4587
0
                    finalized_block_hash,
4588
0
                    RecentBlock {
4589
0
                        scale_encoded_header: subscribe_all.finalized_block_scale_encoded_header,
4590
0
                        runtime_version: Arc::new(subscribe_all.finalized_block_runtime),
4591
0
                    },
4592
0
                );
4593
0
                finalized_and_pruned_lru.put(finalized_block_hash, ());
4594
0
4595
0
                let mut current_best_block = finalized_block_hash;
4596
4597
0
                for block in subscribe_all.non_finalized_blocks_ancestry_order {
4598
0
                    let hash = header::hash_from_scale_encoded_header(&block.scale_encoded_header);
4599
0
                    pinned_blocks.insert(
4600
0
                        hash,
4601
0
                        RecentBlock {
4602
0
                            scale_encoded_header: block.scale_encoded_header,
4603
0
                            runtime_version: match block.new_runtime {
4604
0
                                Some(r) => Arc::new(r),
4605
0
                                None => pinned_blocks
4606
0
                                    .get(&block.parent_hash)
4607
0
                                    .unwrap()
4608
0
                                    .runtime_version
4609
0
                                    .clone(),
4610
                            },
4611
                        },
4612
                    );
4613
4614
0
                    if block.is_new_best {
4615
0
                        current_best_block = hash;
4616
0
                    }
4617
                }
4618
4619
0
                me.runtime_service_subscription = RuntimeServiceSubscription::Active {
4620
0
                    subscription: subscribe_all.new_blocks,
4621
0
                    pinned_blocks,
4622
0
                    finalized_and_pruned_lru,
4623
0
                    current_best_block,
4624
0
                    new_heads_and_runtime_subscriptions_stale: Some(None),
4625
0
                    current_finalized_block: finalized_block_hash,
4626
0
                    finalized_heads_subscriptions_stale: true,
4627
0
                };
4628
4629
                // Advance all the requests that are waiting for the best block hash to be known.
4630
                // We use `mem::take` as this de-allocates the memory of the `Vec`.
4631
0
                for (request_id, request_ty) in mem::take(&mut me.best_block_hash_pending) {
4632
0
                    me.multistage_requests_to_advance.push_back((
4633
0
                        request_id,
4634
0
                        MultiStageRequestStage::BlockHashKnown {
4635
0
                            block_hash: current_best_block,
4636
0
                        },
4637
0
                        request_ty,
4638
0
                    ));
4639
0
                }
4640
4641
                // Answer all the pending `chain_getFinalizedHash` requests.
4642
                // We use `mem::take` as this de-allocates the memory of the `Vec`.
4643
0
                for request_id in mem::take(&mut me.pending_get_finalized_head) {
4644
0
                    let _ = me
4645
0
                        .responses_tx
4646
0
                        .send(
4647
0
                            methods::Response::chain_getFinalizedHead(methods::HashHexString(
4648
0
                                finalized_block_hash,
4649
0
                            ))
4650
0
                            .to_json_response(&request_id),
4651
0
                        )
4652
0
                        .await;
4653
                }
4654
            }
4655
4656
0
            WakeUpReason::RuntimeServiceSubscriptionDead => {
4657
0
                // The subscription towards the runtime service needs to be renewed.
4658
0
4659
0
                // The buffer size should be large enough so that, if the CPU is busy, it
4660
0
                // doesn't become full before the execution of this task resumes.
4661
0
                // The maximum number of pinned block is ignored, as this maximum is a way to
4662
0
                // avoid malicious behaviors. This code is by definition not considered
4663
0
                // malicious.
4664
0
                let runtime_service = me.runtime_service.clone();
4665
0
                me.runtime_service_subscription =
4666
0
                    RuntimeServiceSubscription::Pending(Box::pin(async move {
4667
0
                        runtime_service
4668
0
                            .subscribe_all(
4669
0
                                32,
4670
0
                                NonZeroUsize::new(usize::MAX).unwrap_or_else(|| unreachable!()),
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sN_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sN_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sN_00Bc_
4671
0
                            )
4672
0
                            .await
4673
0
                    }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sN_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sN_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sN_0Ba_
4674
0
            }
4675
4676
            WakeUpReason::RuntimeServiceSubscriptionNotification {
4677
                notification:
4678
                    runtime_service::Notification::BestBlockChanged {
4679
0
                        hash: new_best_hash,
4680
0
                        ..
4681
0
                    },
4682
0
                current_best_block,
4683
0
                new_heads_and_runtime_subscriptions_stale,
4684
0
                ..
4685
0
            } => {
4686
0
                // Runtime service has notified that the best block has changed.
4687
0
                // This only relates to the legacy JSON-RPC API.
4688
0
                // This is handled by marking subscriptions as stale.
4689
0
                *new_heads_and_runtime_subscriptions_stale = Some(Some(*current_best_block));
4690
0
                *current_best_block = new_best_hash;
4691
0
            }
4692
4693
            WakeUpReason::RuntimeServiceSubscriptionNotification {
4694
0
                notification: runtime_service::Notification::Block(block),
4695
0
                pinned_blocks,
4696
0
                current_best_block,
4697
0
                new_heads_and_runtime_subscriptions_stale,
4698
                ..
4699
            } => {
4700
                // Runtime service has notified of a new best block.
4701
                // This only relates to the legacy JSON-RPC API.
4702
0
                let json_rpc_header = match methods::Header::from_scale_encoded_header(
4703
0
                    &block.scale_encoded_header,
4704
0
                    me.runtime_service.block_number_bytes(),
4705
0
                ) {
4706
0
                    Ok(h) => h,
4707
0
                    Err(error) => {
4708
0
                        log!(
4709
0
                            &me.platform,
4710
0
                            Warn,
4711
0
                            &me.log_target,
4712
0
                            format!(
4713
0
                                "`chain_subscribeAllHeads` subscription has skipped block \
4714
0
                                due to undecodable header. Hash: {}. Error: {}",
4715
0
                                HashDisplay(&header::hash_from_scale_encoded_header(
4716
0
                                    &block.scale_encoded_header
4717
0
                                )),
4718
0
                                error
4719
0
                            )
4720
0
                        );
4721
0
                        continue;
4722
                    }
4723
                };
4724
4725
0
                let hash = header::hash_from_scale_encoded_header(&block.scale_encoded_header);
4726
0
4727
0
                // The JSON-RPC client is likely to query things about the new block. We thus
4728
0
                // put it in cache.
4729
0
                me.block_headers_cache.put(
4730
0
                    hash,
4731
0
                    Ok((
4732
0
                        block.scale_encoded_header.clone(),
4733
0
                        json_rpc_header.state_root.0,
4734
0
                        json_rpc_header.number,
4735
0
                    )),
4736
0
                );
4737
4738
0
                let _was_in = pinned_blocks.insert(
4739
0
                    hash,
4740
0
                    RecentBlock {
4741
0
                        scale_encoded_header: block.scale_encoded_header,
4742
0
                        runtime_version: match block.new_runtime {
4743
0
                            Some(r) => Arc::new(r),
4744
0
                            None => pinned_blocks
4745
0
                                .get(&block.parent_hash)
4746
0
                                .unwrap()
4747
0
                                .runtime_version
4748
0
                                .clone(),
4749
                        },
4750
                    },
4751
                );
4752
0
                debug_assert!(_was_in.is_none());
4753
4754
0
                for subscription_id in &me.all_heads_subscriptions {
4755
0
                    let _ = me
4756
0
                        .responses_tx
4757
0
                        .send(
4758
0
                            methods::ServerToClient::chain_allHead {
4759
0
                                subscription: subscription_id.as_str().into(),
4760
0
                                result: json_rpc_header.clone(),
4761
0
                            }
4762
0
                            .to_json_request_object_parameters(None),
4763
0
                        )
4764
0
                        .await;
4765
                }
4766
4767
0
                if block.is_new_best {
4768
0
                    *new_heads_and_runtime_subscriptions_stale = Some(Some(*current_best_block));
4769
0
                    *current_best_block = hash;
4770
0
                }
4771
            }
4772
4773
            WakeUpReason::RuntimeServiceSubscriptionNotification {
4774
                notification:
4775
                    runtime_service::Notification::Finalized {
4776
0
                        hash: finalized_hash,
4777
0
                        pruned_blocks,
4778
0
                        best_block_hash_if_changed,
4779
0
                    },
4780
0
                pinned_blocks,
4781
0
                finalized_and_pruned_lru,
4782
0
                subscription,
4783
0
                current_best_block,
4784
0
                new_heads_and_runtime_subscriptions_stale,
4785
0
                current_finalized_block,
4786
0
                finalized_heads_subscriptions_stale,
4787
0
            } => {
4788
0
                // Runtime service has notified a new finalized block.
4789
0
                // This only relates to the legacy JSON-RPC API.
4790
0
4791
0
                *current_finalized_block = finalized_hash;
4792
0
                *finalized_heads_subscriptions_stale = true;
4793
0
4794
0
                debug_assert!(pruned_blocks
4795
0
                    .iter()
4796
0
                    .all(|hash| pinned_blocks.contains_key(hash)));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s12_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s12_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s12_0Ba_
4797
4798
                // Add the pruned and finalized blocks to the LRU cache. The least-recently used
4799
                // entries in the cache are unpinned and no longer tracked.
4800
                //
4801
                // An important detail here is that the newly-finalized block is added to the list
4802
                // at the end, in order to guarantee that it doesn't get removed. This is
4803
                // necessary in order to guarantee that the current finalized (and current best,
4804
                // if the best block is also the finalized block) remains pinned until at least
4805
                // a different block gets finalized.
4806
0
                for block_hash in pruned_blocks.into_iter().chain(iter::once(finalized_hash)) {
4807
0
                    if finalized_and_pruned_lru.len() == finalized_and_pruned_lru.cap().get() {
4808
0
                        let (hash_to_unpin, _) = finalized_and_pruned_lru.pop_lru().unwrap();
4809
0
                        subscription.unpin_block(hash_to_unpin).await;
4810
0
                        pinned_blocks.remove(&hash_to_unpin).unwrap();
4811
0
                    }
4812
0
                    finalized_and_pruned_lru.put(block_hash, ());
4813
                }
4814
4815
0
                if let Some(new_best_block_hash) = best_block_hash_if_changed {
4816
0
                    *new_heads_and_runtime_subscriptions_stale = Some(Some(*current_best_block));
4817
0
                    *current_best_block = new_best_block_hash;
4818
0
                }
4819
            }
4820
4821
            WakeUpReason::Event(Event::BlockInfoRetrieved {
4822
0
                block_hash,
4823
0
                result: Ok(result),
4824
0
            }) => {
4825
0
                // A block header necessary for a "multi-stage request" has successfully been
4826
0
                // retrieved.
4827
0
4828
0
                me.block_headers_cache.put(block_hash, result);
4829
4830
0
                for (request_id, request) in me
4831
0
                    .block_headers_pending
4832
0
                    .remove(&block_hash)
4833
0
                    .into_iter()
4834
0
                    .flat_map(|l| l)
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sO_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sO_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sO_0Ba_
4835
0
                {
4836
0
                    // Note that we push_front in order to guarantee that the information is
4837
0
                    // not removed from cache before the request is processed.
4838
0
                    me.multistage_requests_to_advance.push_front((
4839
0
                        request_id,
4840
0
                        MultiStageRequestStage::BlockHashKnown { block_hash },
4841
0
                        request,
4842
0
                    ));
4843
0
                }
4844
            }
4845
4846
            WakeUpReason::Event(Event::BlockInfoRetrieved {
4847
0
                block_hash,
4848
                result: Err(()),
4849
            }) => {
4850
                // A block header necessary for a "multi-stage request" has failed to be
4851
                // retrieved.
4852
0
                for (request_id, _) in me
4853
0
                    .block_headers_pending
4854
0
                    .remove(&block_hash)
4855
0
                    .into_iter()
4856
0
                    .flat_map(|l| l)
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sP_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sP_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sP_0Ba_
4857
                {
4858
0
                    let _ = me
4859
0
                        .responses_tx
4860
0
                        .send(parse::build_error_response(
4861
0
                            &request_id,
4862
0
                            parse::ErrorResponse::ApplicationDefined(
4863
0
                                -32800,
4864
0
                                "Failed to retrieve block information from the network",
4865
0
                            ),
4866
0
                            None,
4867
0
                        ))
4868
0
                        .await;
4869
                }
4870
            }
4871
4872
            WakeUpReason::Event(Event::RuntimeDownloaded {
4873
0
                block_hash,
4874
0
                result: Ok(result),
4875
0
            }) => {
4876
0
                // A block runtime necessary for a "multi-stage request" has successfully been
4877
0
                // retrieved.
4878
0
4879
0
                me.block_runtimes_cache.put(block_hash, result);
4880
4881
0
                for (request_id, request) in me
4882
0
                    .block_runtimes_pending
4883
0
                    .remove(&block_hash)
4884
0
                    .into_iter()
4885
0
                    .flat_map(|l| l)
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sQ_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sQ_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sQ_0Ba_
4886
0
                {
4887
0
                    // Note that we push_front in order to guarantee that the information is
4888
0
                    // not removed from cache before the request is processed.
4889
0
                    me.multistage_requests_to_advance.push_front((
4890
0
                        request_id,
4891
0
                        MultiStageRequestStage::BlockHashKnown { block_hash },
4892
0
                        request,
4893
0
                    ));
4894
0
                }
4895
            }
4896
4897
            WakeUpReason::Event(Event::RuntimeDownloaded {
4898
0
                block_hash,
4899
0
                result: Err(error_message),
4900
            }) => {
4901
                // A block runtime necessary for a "multi-stage request" has failed to be
4902
                // retrieved.
4903
0
                for (request_id, _) in me
4904
0
                    .block_runtimes_pending
4905
0
                    .remove(&block_hash)
4906
0
                    .into_iter()
4907
0
                    .flat_map(|l| l)
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sR_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sR_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sR_0Ba_
4908
                {
4909
0
                    let _ = me
4910
0
                        .responses_tx
4911
0
                        .send(parse::build_error_response(
4912
0
                            &request_id,
4913
0
                            parse::ErrorResponse::ApplicationDefined(
4914
0
                                -32800,
4915
0
                                &format!(
4916
0
                                    "Failed to retrieve runtime from the \
4917
0
                                    network: {error_message}"
4918
0
                                ),
4919
0
                            ),
4920
0
                            None,
4921
0
                        ))
4922
0
                        .await;
4923
                }
4924
            }
4925
4926
            WakeUpReason::Event(Event::TransactionEvent {
4927
0
                subscription_id,
4928
0
                event: transactions_service::TransactionStatus::Dropped(drop_reason),
4929
                ..
4930
            }) => {
4931
                // Transactions service has notified that a transaction has left its pool.
4932
0
                let Some(transaction_watch) =
4933
0
                    me.transactions_subscriptions.remove(&subscription_id)
4934
                else {
4935
                    // JSON-RPC client has unsubscribed from this transaction and is no longer
4936
                    // interested in events.
4937
0
                    continue;
4938
                };
4939
4940
0
                match (drop_reason, &transaction_watch.ty) {
4941
                    (
4942
                        transactions_service::DropReason::GapInChain
4943
                        | transactions_service::DropReason::Crashed,
4944
0
                        TransactionWatchTy::NewApi { transaction_bytes },
4945
                    ) => {
4946
                        // In case of `transaction_v1_broadcast`, we re-submit the transaction
4947
                        // if it was dropped for a temporary reasons.
4948
0
                        let mut new_watcher = Box::pin(
4949
0
                            me.transactions_service
4950
0
                                .submit_and_watch_transaction(transaction_bytes.clone(), 16, false)
4951
0
                                .await,
4952
                        );
4953
4954
0
                        let _prev_value = me
4955
0
                            .transactions_subscriptions
4956
0
                            .insert(subscription_id.clone(), transaction_watch);
4957
0
                        debug_assert!(_prev_value.is_none());
4958
4959
                        // Push a new background task that waits for the next notification.
4960
0
                        me.background_tasks.push(Box::pin(async move {
4961
0
                            let Some(status) = new_watcher.as_mut().next().await else {
4962
0
                                unreachable!()
4963
                            };
4964
0
                            Event::TransactionEvent {
4965
0
                                subscription_id,
4966
0
                                event: status,
4967
0
                                watcher: new_watcher,
4968
0
                            }
4969
0
                        }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sS_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sS_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sS_0Ba_
4970
                    }
4971
4972
                    (
4973
                        transactions_service::DropReason::Finalized { .. }
4974
                        | transactions_service::DropReason::Invalid(_)
4975
                        | transactions_service::DropReason::MaxPendingTransactionsReached
4976
                        | transactions_service::DropReason::ValidateError(_),
4977
                        TransactionWatchTy::NewApi { .. },
4978
                    ) => {
4979
                        // In case of `transaction_v1_broadcast`, the transaction is re-inserted
4980
                        // in the list, but no new notification-generating task is pushed, making
4981
                        // the transaction effectively dead and waiting for `transaction_v1_stop`
4982
                        // to be called to remove it.
4983
0
                        let _prev_value = me
4984
0
                            .transactions_subscriptions
4985
0
                            .insert(subscription_id.clone(), transaction_watch);
4986
0
                        debug_assert!(_prev_value.is_none());
4987
                    }
4988
4989
                    (transactions_service::DropReason::GapInChain, TransactionWatchTy::Legacy)
4990
                    | (
4991
                        transactions_service::DropReason::MaxPendingTransactionsReached,
4992
                        TransactionWatchTy::Legacy,
4993
                    )
4994
                    | (transactions_service::DropReason::Invalid(_), TransactionWatchTy::Legacy)
4995
                    | (
4996
                        transactions_service::DropReason::ValidateError(_),
4997
                        TransactionWatchTy::Legacy,
4998
                    )
4999
                    | (transactions_service::DropReason::Crashed, TransactionWatchTy::Legacy) => {
5000
0
                        let _ = me
5001
0
                            .responses_tx
5002
0
                            .send(
5003
0
                                methods::ServerToClient::author_extrinsicUpdate {
5004
0
                                    subscription: Cow::Borrowed(&subscription_id),
5005
0
                                    result: methods::TransactionStatus::Dropped,
5006
0
                                }
5007
0
                                .to_json_request_object_parameters(None),
5008
0
                            )
5009
0
                            .await;
5010
                    }
5011
                    (
5012
                        transactions_service::DropReason::GapInChain,
5013
                        TransactionWatchTy::NewApiWatch,
5014
                    ) => {
5015
0
                        let _ = me
5016
0
                            .responses_tx
5017
0
                            .send(
5018
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5019
0
                                    subscription: Cow::Borrowed(&subscription_id),
5020
0
                                    result: methods::TransactionWatchEvent::Dropped {
5021
0
                                        error: "gap in chain of blocks".into(),
5022
0
                                        broadcasted: transaction_watch.num_broadcasted_peers != 0,
5023
0
                                    },
5024
0
                                }
5025
0
                                .to_json_request_object_parameters(None),
5026
0
                            )
5027
0
                            .await;
5028
                    }
5029
                    (
5030
                        transactions_service::DropReason::MaxPendingTransactionsReached,
5031
                        TransactionWatchTy::NewApiWatch,
5032
                    ) => {
5033
0
                        let _ = me
5034
0
                            .responses_tx
5035
0
                            .send(
5036
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5037
0
                                    subscription: Cow::Borrowed(&subscription_id),
5038
0
                                    result: methods::TransactionWatchEvent::Dropped {
5039
0
                                        error: "transactions pool full".into(),
5040
0
                                        broadcasted: transaction_watch.num_broadcasted_peers != 0,
5041
0
                                    },
5042
0
                                }
5043
0
                                .to_json_request_object_parameters(None),
5044
0
                            )
5045
0
                            .await;
5046
                    }
5047
                    (
5048
0
                        transactions_service::DropReason::Invalid(error),
5049
0
                        TransactionWatchTy::NewApiWatch,
5050
0
                    ) => {
5051
0
                        let _ = me
5052
0
                            .responses_tx
5053
0
                            .send(
5054
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5055
0
                                    subscription: Cow::Borrowed(&subscription_id),
5056
0
                                    result: methods::TransactionWatchEvent::Invalid {
5057
0
                                        error: error.to_string().into(),
5058
0
                                    },
5059
0
                                }
5060
0
                                .to_json_request_object_parameters(None),
5061
0
                            )
5062
0
                            .await;
5063
                    }
5064
                    (
5065
0
                        transactions_service::DropReason::ValidateError(error),
5066
0
                        TransactionWatchTy::NewApiWatch,
5067
0
                    ) => {
5068
0
                        let _ = me
5069
0
                            .responses_tx
5070
0
                            .send(
5071
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5072
0
                                    subscription: Cow::Borrowed(&subscription_id),
5073
0
                                    result: methods::TransactionWatchEvent::Error {
5074
0
                                        error: error.to_string().into(),
5075
0
                                    },
5076
0
                                }
5077
0
                                .to_json_request_object_parameters(None),
5078
0
                            )
5079
0
                            .await;
5080
                    }
5081
                    (
5082
                        transactions_service::DropReason::Crashed,
5083
                        TransactionWatchTy::NewApiWatch,
5084
                    ) => {
5085
0
                        let _ = me
5086
0
                            .responses_tx
5087
0
                            .send(
5088
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5089
0
                                    subscription: Cow::Borrowed(&subscription_id),
5090
0
                                    result: methods::TransactionWatchEvent::Error {
5091
0
                                        error: "transactions service has crashed".into(),
5092
0
                                    },
5093
0
                                }
5094
0
                                .to_json_request_object_parameters(None),
5095
0
                            )
5096
0
                            .await;
5097
                    }
5098
5099
                    (
5100
0
                        transactions_service::DropReason::Finalized { block_hash, .. },
5101
0
                        TransactionWatchTy::Legacy,
5102
0
                    ) => {
5103
0
                        let _ = me
5104
0
                            .responses_tx
5105
0
                            .send(
5106
0
                                methods::ServerToClient::author_extrinsicUpdate {
5107
0
                                    subscription: Cow::Borrowed(&subscription_id),
5108
0
                                    result: methods::TransactionStatus::Finalized(
5109
0
                                        methods::HashHexString(block_hash),
5110
0
                                    ),
5111
0
                                }
5112
0
                                .to_json_request_object_parameters(None),
5113
0
                            )
5114
0
                            .await;
5115
                    }
5116
                    (
5117
0
                        transactions_service::DropReason::Finalized { block_hash, index },
5118
0
                        TransactionWatchTy::NewApiWatch,
5119
0
                    ) => {
5120
0
                        let _ = me
5121
0
                            .responses_tx
5122
0
                            .send(
5123
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5124
0
                                    subscription: Cow::Borrowed(&subscription_id),
5125
0
                                    result: methods::TransactionWatchEvent::Finalized {
5126
0
                                        block: methods::TransactionWatchEventBlock {
5127
0
                                            hash: methods::HashHexString(block_hash),
5128
0
                                            index,
5129
0
                                        },
5130
0
                                    },
5131
0
                                }
5132
0
                                .to_json_request_object_parameters(None),
5133
0
                            )
5134
0
                            .await;
5135
                    }
5136
                }
5137
            }
5138
5139
            WakeUpReason::Event(Event::TransactionEvent {
5140
0
                subscription_id,
5141
0
                event,
5142
0
                mut watcher,
5143
            }) => {
5144
                // Event (other than `Dropped`, as it's handled above) from the
5145
                // transactions service.
5146
0
                let Some(transaction_watch) =
5147
0
                    me.transactions_subscriptions.get_mut(&subscription_id)
5148
                else {
5149
                    // JSON-RPC client has unsubscribed from this transaction and is no longer
5150
                    // interested in events.
5151
0
                    continue;
5152
                };
5153
5154
0
                match (event, &transaction_watch.ty) {
5155
0
                    (_, TransactionWatchTy::NewApi { .. }) => {
5156
0
                        // Events are ignored when it comes to `transaction_v1_broadcast`.
5157
0
                    }
5158
5159
                    (
5160
0
                        transactions_service::TransactionStatus::Broadcast(peers),
5161
0
                        TransactionWatchTy::Legacy,
5162
0
                    ) => {
5163
0
                        let _ = me
5164
0
                            .responses_tx
5165
0
                            .send(
5166
0
                                methods::ServerToClient::author_extrinsicUpdate {
5167
0
                                    subscription: Cow::Borrowed(&subscription_id),
5168
0
                                    result: methods::TransactionStatus::Broadcast(
5169
0
                                        peers.into_iter().map(|peer| peer.to_base58()).collect(),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sT_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sT_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sT_0Ba_
5170
0
                                    ),
5171
0
                                }
5172
0
                                .to_json_request_object_parameters(None),
5173
0
                            )
5174
0
                            .await;
5175
                    }
5176
                    (
5177
0
                        transactions_service::TransactionStatus::Broadcast(peers),
5178
0
                        TransactionWatchTy::NewApiWatch,
5179
0
                    ) => {
5180
0
                        transaction_watch.num_broadcasted_peers += peers.len();
5181
0
                        let _ = me
5182
0
                            .responses_tx
5183
0
                            .send(
5184
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5185
0
                                    subscription: Cow::Borrowed(&subscription_id),
5186
0
                                    result: methods::TransactionWatchEvent::Broadcasted {
5187
0
                                        num_peers: u32::try_from(
5188
0
                                            transaction_watch.num_broadcasted_peers,
5189
0
                                        )
5190
0
                                        .unwrap_or(u32::MAX),
5191
0
                                    },
5192
0
                                }
5193
0
                                .to_json_request_object_parameters(None),
5194
0
                            )
5195
0
                            .await;
5196
                    }
5197
5198
                    (
5199
                        transactions_service::TransactionStatus::Validated,
5200
                        TransactionWatchTy::Legacy,
5201
0
                    ) => {
5202
0
                        // Nothing to do.
5203
0
                    }
5204
                    (
5205
                        transactions_service::TransactionStatus::Validated,
5206
                        TransactionWatchTy::NewApiWatch,
5207
                    ) => {
5208
0
                        let _ = me
5209
0
                            .responses_tx
5210
0
                            .send(
5211
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5212
0
                                    subscription: Cow::Borrowed(&subscription_id),
5213
0
                                    result: methods::TransactionWatchEvent::Validated {},
5214
0
                                }
5215
0
                                .to_json_request_object_parameters(None),
5216
0
                            )
5217
0
                            .await;
5218
                    }
5219
5220
                    (
5221
                        transactions_service::TransactionStatus::IncludedBlockUpdate {
5222
0
                            block_hash: Some((block_hash, _)),
5223
0
                        },
5224
0
                        TransactionWatchTy::Legacy,
5225
0
                    ) => {
5226
0
                        transaction_watch.included_block = Some(block_hash);
5227
0
                        let _ = me
5228
0
                            .responses_tx
5229
0
                            .send(
5230
0
                                methods::ServerToClient::author_extrinsicUpdate {
5231
0
                                    subscription: Cow::Borrowed(&subscription_id),
5232
0
                                    result: methods::TransactionStatus::InBlock(
5233
0
                                        methods::HashHexString(block_hash),
5234
0
                                    ),
5235
0
                                }
5236
0
                                .to_json_request_object_parameters(None),
5237
0
                            )
5238
0
                            .await;
5239
                    }
5240
                    (
5241
                        transactions_service::TransactionStatus::IncludedBlockUpdate {
5242
                            block_hash: None,
5243
                        },
5244
                        TransactionWatchTy::Legacy,
5245
                    ) => {
5246
0
                        if let Some(block_hash) = transaction_watch.included_block.take() {
5247
0
                            let _ = me
5248
0
                                .responses_tx
5249
0
                                .send(
5250
0
                                    methods::ServerToClient::author_extrinsicUpdate {
5251
0
                                        subscription: Cow::Borrowed(&subscription_id),
5252
0
                                        result: methods::TransactionStatus::Retracted(
5253
0
                                            methods::HashHexString(block_hash),
5254
0
                                        ),
5255
0
                                    }
5256
0
                                    .to_json_request_object_parameters(None),
5257
0
                                )
5258
0
                                .await;
5259
0
                        }
5260
                    }
5261
                    (
5262
                        transactions_service::TransactionStatus::IncludedBlockUpdate {
5263
0
                            block_hash: Some((block_hash, index)),
5264
0
                        },
5265
0
                        TransactionWatchTy::NewApiWatch,
5266
0
                    ) => {
5267
0
                        transaction_watch.included_block = Some(block_hash);
5268
0
                        let _ = me
5269
0
                            .responses_tx
5270
0
                            .send(
5271
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5272
0
                                    subscription: Cow::Borrowed(&subscription_id),
5273
0
                                    result:
5274
0
                                        methods::TransactionWatchEvent::BestChainBlockIncluded {
5275
0
                                            block: Some(methods::TransactionWatchEventBlock {
5276
0
                                                hash: methods::HashHexString(block_hash),
5277
0
                                                index,
5278
0
                                            }),
5279
0
                                        },
5280
0
                                }
5281
0
                                .to_json_request_object_parameters(None),
5282
0
                            )
5283
0
                            .await;
5284
                    }
5285
                    (
5286
                        transactions_service::TransactionStatus::IncludedBlockUpdate {
5287
                            block_hash: None,
5288
                        },
5289
                        TransactionWatchTy::NewApiWatch,
5290
                    ) => {
5291
0
                        let _ = me
5292
0
                            .responses_tx
5293
0
                            .send(
5294
0
                                methods::ServerToClient::transactionWatch_v1_watchEvent {
5295
0
                                    subscription: Cow::Borrowed(&subscription_id),
5296
0
                                    result:
5297
0
                                        methods::TransactionWatchEvent::BestChainBlockIncluded {
5298
0
                                            block: None,
5299
0
                                        },
5300
0
                                }
5301
0
                                .to_json_request_object_parameters(None),
5302
0
                            )
5303
0
                            .await;
5304
                    }
5305
5306
                    // `Dropped` was handle above separately.
5307
0
                    (transactions_service::TransactionStatus::Dropped(_), _) => unreachable!(),
5308
                }
5309
5310
                // Push a new background task that waits for the next notification.
5311
0
                me.background_tasks.push(Box::pin(async move {
5312
0
                    let Some(status) = watcher.as_mut().next().await else {
5313
0
                        unreachable!()
5314
                    };
5315
0
                    Event::TransactionEvent {
5316
0
                        subscription_id,
5317
0
                        event: status,
5318
0
                        watcher,
5319
0
                    }
5320
0
                }));
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sU_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sU_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sU_0Ba_
5321
            }
5322
5323
            WakeUpReason::Event(Event::ChainGetBlockResult {
5324
0
                request_id_json,
5325
0
                mut result,
5326
0
                expected_block_hash,
5327
            }) => {
5328
                // A network request necessary to fulfill `chain_getBlock` has finished.
5329
5330
                // Check whether the header and body are present and valid.
5331
                // TODO: try the request again with a different peerin case the response is invalid, instead of returning null
5332
0
                if let Ok(block) = &result {
5333
0
                    if let (Some(header), Some(body)) = (&block.header, &block.body) {
5334
0
                        if header::hash_from_scale_encoded_header(header) == expected_block_hash {
5335
0
                            if let Ok(decoded) =
5336
0
                                header::decode(header, me.sync_service.block_number_bytes())
5337
                            {
5338
0
                                if header::extrinsics_root(body) != *decoded.extrinsics_root {
5339
0
                                    result = Err(());
5340
0
                                }
5341
0
                            } else {
5342
0
                                // Note that if the header is undecodable it doesn't necessarily mean
5343
0
                                // that the header and/or body is bad, but given that we have no way to
5344
0
                                // check this we return an error.
5345
0
                                result = Err(());
5346
0
                            }
5347
0
                        } else {
5348
0
                            result = Err(());
5349
0
                        }
5350
0
                    } else {
5351
0
                        result = Err(());
5352
0
                    }
5353
0
                }
5354
5355
                // Send the response.
5356
0
                if let Ok(block) = result {
5357
0
                    let _ = me
5358
0
                        .responses_tx
5359
0
                        .send(
5360
0
                            methods::Response::chain_getBlock(methods::Block {
5361
0
                                extrinsics: block
5362
0
                                    .body
5363
0
                                    .unwrap()
5364
0
                                    .into_iter()
5365
0
                                    .map(methods::HexString)
5366
0
                                    .collect(),
5367
0
                                header: methods::Header::from_scale_encoded_header(
5368
0
                                    &block.header.unwrap(),
5369
0
                                    me.sync_service.block_number_bytes(),
5370
0
                                )
5371
0
                                .unwrap(),
5372
0
                                // There's no way to verify the correctness of the justifications, consequently
5373
0
                                // we always return an empty list.
5374
0
                                justifications: None,
5375
0
                            })
5376
0
                            .to_json_response(&request_id_json),
5377
0
                        )
5378
0
                        .await;
5379
                } else {
5380
0
                    let _ = me
5381
0
                        .responses_tx
5382
0
                        .send(parse::build_success_response(&request_id_json, "null"))
5383
0
                        .await;
5384
                }
5385
            }
5386
5387
            WakeUpReason::StartStorageSubscriptionsUpdates => {
5388
                // Some existing `state_storageSubscribe` haven't been notified of subscription
5389
                // changes of the latest best block. Start storage requests on the network.
5390
5391
                let RuntimeServiceSubscription::Active {
5392
0
                    pinned_blocks,
5393
0
                    current_best_block,
5394
                    ..
5395
0
                } = &mut me.runtime_service_subscription
5396
                else {
5397
0
                    unreachable!()
5398
                };
5399
5400
                // If the header of the current best block can't be decoded, we don't do anything.
5401
0
                let (block_number, state_trie_root) = match header::decode(
5402
0
                    &pinned_blocks
5403
0
                        .get(current_best_block)
5404
0
                        .unwrap()
5405
0
                        .scale_encoded_header,
5406
0
                    me.runtime_service.block_number_bytes(),
5407
0
                ) {
5408
0
                    Ok(header) => (header.number, *header.state_root),
5409
                    Err(_) => {
5410
                        // Can't decode the header of the current best block.
5411
                        // All the subscriptions are marked as non-stale, since they are up-to-date
5412
                        // with the current best block.
5413
                        // TODO: print warning?
5414
0
                        me.legacy_api_stale_storage_subscriptions.clear();
5415
0
                        continue;
5416
                    }
5417
                };
5418
5419
                // Build the list of keys that must be requested by aggregating the keys requested
5420
                // by all stale storage subscriptions.
5421
0
                let mut keys = hashbrown::HashSet::with_hasher(SipHasherBuild::new({
5422
0
                    let mut seed = [0; 16];
5423
0
                    me.platform.fill_random_bytes(&mut seed);
5424
0
                    seed
5425
0
                }));
5426
0
                keys.extend(
5427
0
                    me.legacy_api_stale_storage_subscriptions
5428
0
                        .iter()
5429
0
                        .map(|s_id| {
5430
0
                            me.legacy_api_storage_subscriptions
5431
0
                                .range((s_id.clone(), Vec::new())..)
5432
0
                                .take_while(move |(s, _)| s == s_id)
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sV_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sV_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sV_00Bc_
5433
0
                                .map(|(_, key)| key)
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sV_0s_0Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sV_0s_0B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sV_0s_0Bc_
5434
0
                        })
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sV_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sV_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sV_0Ba_
5435
0
                        .flat_map(|keys_list| keys_list.cloned()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sW_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sW_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sW_0Ba_
5436
0
                );
5437
0
5438
0
                // If the list of keys to query is empty, we mark all subscriptions as no longer
5439
0
                // stale and loop again. This is necessary in order to prevent infinite loops if
5440
0
                // the JSON-RPC client subscribes to an empty list of items.
5441
0
                if keys.is_empty() {
5442
0
                    me.legacy_api_stale_storage_subscriptions.clear();
5443
0
                    continue;
5444
0
                }
5445
0
5446
0
                // Start the task in the background.
5447
0
                // The task will generate a
5448
0
                // `Event::LegacyApiStorageSubscriptionsUpdate` once it is done.
5449
0
                me.legacy_api_storage_query_in_progress = true;
5450
0
                me.background_tasks.push(Box::pin({
5451
0
                    let block_hash = *current_best_block;
5452
0
                    let sync_service = me.sync_service.clone();
5453
0
                    async move {
5454
0
                        let mut out = Vec::with_capacity(keys.len());
5455
0
                        let mut query = sync_service
5456
0
                            .storage_query(
5457
0
                                block_number,
5458
0
                                block_hash,
5459
0
                                state_trie_root,
5460
0
                                keys.into_iter()
5461
0
                                    .map(|key| sync_service::StorageRequestItem {
5462
0
                                        key,
5463
0
                                        ty: sync_service::StorageRequestItemTy::Value,
5464
0
                                    }),
Unexecuted instantiation: _RNCNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sX_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sX_00B1h_
Unexecuted instantiation: _RNCNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sX_00Bc_
5465
0
                                4,
5466
0
                                Duration::from_secs(12),
5467
0
                                NonZeroU32::new(2).unwrap(),
5468
0
                            )
5469
0
                            .advance()
5470
0
                            .await;
5471
0
                        loop {
5472
0
                            match query {
5473
                                sync_service::StorageQueryProgress::Progress {
5474
0
                                    item,
5475
0
                                    query: next,
5476
0
                                    ..
5477
0
                                } => {
5478
0
                                    out.push(item);
5479
0
                                    query = next.advance().await;
5480
                                }
5481
                                sync_service::StorageQueryProgress::Finished => {
5482
0
                                    break Event::LegacyApiStorageSubscriptionsUpdate {
5483
0
                                        block_hash,
5484
0
                                        result: Ok(out),
5485
0
                                    };
5486
                                }
5487
0
                                sync_service::StorageQueryProgress::Error(error) => {
5488
0
                                    break Event::LegacyApiStorageSubscriptionsUpdate {
5489
0
                                        block_hash,
5490
0
                                        result: Err(error),
5491
0
                                    };
5492
                                }
5493
                            }
5494
                        }
5495
0
                    }
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sX_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sX_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sX_0Ba_
5496
0
                }));
5497
            }
5498
5499
            WakeUpReason::Event(Event::LegacyApiStorageSubscriptionsUpdate {
5500
0
                block_hash,
5501
0
                result: Ok(result),
5502
0
            }) => {
5503
0
                // Background task dedicated to performing a storage query for the storage
5504
0
                // subscriptions has finished.
5505
0
5506
0
                debug_assert!(me.legacy_api_storage_query_in_progress);
5507
0
                me.legacy_api_storage_query_in_progress = false;
5508
5509
                // Determine whether another storage query targeting a more up-to-date block
5510
                // must be started afterwards.
5511
0
                let is_up_to_date = match me.runtime_service_subscription {
5512
                    RuntimeServiceSubscription::Active {
5513
0
                        current_best_block, ..
5514
0
                    } => current_best_block == block_hash,
5515
                    RuntimeServiceSubscription::NotCreated
5516
0
                    | RuntimeServiceSubscription::Pending(_) => true,
5517
                };
5518
5519
                // Because all the keys of all the subscriptions are merged into one network
5520
                // request, we must now attribute each item in the result back to its subscription.
5521
                // While this solution is a bit CPU-heavy, it is a more elegant solution than
5522
                // keeping track of subscription in the background task.
5523
0
                let mut notifications_to_send = hashbrown::HashMap::<
5524
0
                    Arc<str>,
5525
0
                    Vec<(methods::HexString, Option<methods::HexString>)>,
5526
0
                    _,
5527
0
                >::with_capacity_and_hasher(
5528
0
                    me.legacy_api_storage_subscriptions.len(),
5529
0
                    fnv::FnvBuildHasher::default(),
5530
0
                );
5531
0
                for item in result {
5532
0
                    let sync_service::StorageResultItem::Value { key, value } = item else {
5533
0
                        unreachable!()
5534
                    };
5535
0
                    for subscription_id in me
5536
0
                        .legacy_api_storage_subscriptions_by_key
5537
0
                        .range((key.clone(), Arc::from(String::new()))..)
5538
0
                        .take_while(|(k, _)| *k == key)
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sY_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sY_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sY_0Ba_
5539
0
                        .map(|(_, s_id)| s_id.clone())
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0sZ_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sZ_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0sZ_0Ba_
5540
0
                    {
5541
0
                        notifications_to_send
5542
0
                            .entry(subscription_id)
5543
0
                            .or_insert_with(Vec::new)
5544
0
                            .push((
5545
0
                                methods::HexString(key.clone()),
5546
0
                                value.clone().map(methods::HexString),
5547
0
                            ));
5548
0
                    }
5549
                }
5550
5551
                // Send the notifications and mark the subscriptions as no longer stale if
5552
                // relevant.
5553
0
                for (subscription_id, changes) in notifications_to_send {
5554
0
                    if is_up_to_date {
5555
0
                        me.legacy_api_stale_storage_subscriptions
5556
0
                            .remove(&subscription_id);
5557
0
                    }
5558
0
                    let _ = me
5559
0
                        .responses_tx
5560
0
                        .send(
5561
0
                            methods::ServerToClient::state_storage {
5562
0
                                subscription: Cow::Borrowed(&*subscription_id),
5563
0
                                result: methods::StorageChangeSet {
5564
0
                                    block: methods::HashHexString(block_hash),
5565
0
                                    changes,
5566
0
                                },
5567
0
                            }
5568
0
                            .to_json_request_object_parameters(None),
5569
0
                        )
5570
0
                        .await;
5571
                }
5572
            }
5573
5574
            // Background task dedicated to performing a storage query for the storage
5575
            // subscription has finished but was unsuccessful.
5576
            WakeUpReason::Event(Event::LegacyApiStorageSubscriptionsUpdate {
5577
                result: Err(_),
5578
                ..
5579
            }) => {
5580
                // Background task dedicated to performing a storage query for the storage
5581
                // subscriptions has failed.
5582
0
                debug_assert!(me.legacy_api_storage_query_in_progress);
5583
0
                me.legacy_api_storage_query_in_progress = false;
5584
                // TODO: add a delay or something?
5585
            }
5586
5587
            WakeUpReason::NotifyFinalizedHeads => {
5588
                // All `chain_subscribeFinalizedHeads` subscriptions must be notified of the
5589
                // latest finalized block.
5590
5591
                let RuntimeServiceSubscription::Active {
5592
0
                    pinned_blocks,
5593
0
                    current_finalized_block,
5594
0
                    finalized_heads_subscriptions_stale,
5595
                    ..
5596
0
                } = &mut me.runtime_service_subscription
5597
                else {
5598
0
                    unreachable!()
5599
                };
5600
5601
0
                let finalized_block_header = &pinned_blocks
5602
0
                    .get(current_finalized_block)
5603
0
                    .unwrap()
5604
0
                    .scale_encoded_header;
5605
0
                let finalized_block_json_rpc_header =
5606
0
                    match methods::Header::from_scale_encoded_header(
5607
0
                        finalized_block_header,
5608
0
                        me.runtime_service.block_number_bytes(),
5609
0
                    ) {
5610
0
                        Ok(h) => h,
5611
0
                        Err(error) => {
5612
0
                            log!(
5613
0
                                &me.platform,
5614
0
                                Warn,
5615
0
                                &me.log_target,
5616
0
                                format!(
5617
0
                                    "`chain_subscribeFinalizedHeads` subscription has skipped \
5618
0
                                    block due to undecodable header. Hash: {}. Error: {}",
5619
0
                                    HashDisplay(current_finalized_block),
5620
0
                                    error,
5621
0
                                )
5622
0
                            );
5623
0
                            continue;
5624
                        }
5625
                    };
5626
5627
0
                for subscription_id in &me.finalized_heads_subscriptions {
5628
0
                    let _ = me
5629
0
                        .responses_tx
5630
0
                        .send(
5631
0
                            methods::ServerToClient::chain_finalizedHead {
5632
0
                                subscription: Cow::Borrowed(subscription_id),
5633
0
                                result: finalized_block_json_rpc_header.clone(),
5634
0
                            }
5635
0
                            .to_json_request_object_parameters(None),
5636
0
                        )
5637
0
                        .await;
5638
                }
5639
5640
0
                *finalized_heads_subscriptions_stale = false;
5641
            }
5642
5643
0
            WakeUpReason::NotifyNewHeadsRuntimeSubscriptions(previous_best_block) => {
5644
                // All `chain_subscribeNewHeads` subscriptions must be notified of the
5645
                // latest best block.
5646
5647
                let RuntimeServiceSubscription::Active {
5648
0
                    pinned_blocks,
5649
0
                    current_best_block,
5650
                    ..
5651
0
                } = &mut me.runtime_service_subscription
5652
                else {
5653
0
                    unreachable!()
5654
                };
5655
5656
0
                let best_block_header = &pinned_blocks
5657
0
                    .get(current_best_block)
5658
0
                    .unwrap()
5659
0
                    .scale_encoded_header;
5660
0
                let best_block_json_rpc_header = match methods::Header::from_scale_encoded_header(
5661
0
                    best_block_header,
5662
0
                    me.runtime_service.block_number_bytes(),
5663
0
                ) {
5664
0
                    Ok(h) => h,
5665
0
                    Err(error) => {
5666
0
                        log!(
5667
0
                            &me.platform,
5668
0
                            Warn,
5669
0
                            &me.log_target,
5670
0
                            format!(
5671
0
                                "`chain_subscribeNewHeads` subscription has skipped block due to \
5672
0
                                undecodable header. Hash: {}. Error: {}",
5673
0
                                HashDisplay(current_best_block),
5674
0
                                error
5675
0
                            )
5676
0
                        );
5677
0
                        continue;
5678
                    }
5679
                };
5680
5681
0
                for subscription_id in &me.new_heads_subscriptions {
5682
0
                    let _ = me
5683
0
                        .responses_tx
5684
0
                        .send(
5685
0
                            methods::ServerToClient::chain_newHead {
5686
0
                                subscription: Cow::Borrowed(subscription_id),
5687
0
                                result: best_block_json_rpc_header.clone(),
5688
0
                            }
5689
0
                            .to_json_request_object_parameters(None),
5690
0
                        )
5691
0
                        .await;
5692
                }
5693
5694
0
                let new_best_runtime = &pinned_blocks
5695
0
                    .get(current_best_block)
5696
0
                    .unwrap()
5697
0
                    .runtime_version;
5698
0
                if previous_best_block.map_or(true, |prev_best_block| {
5699
0
                    !Arc::ptr_eq(
5700
0
                        new_best_runtime,
5701
0
                        &pinned_blocks.get(&prev_best_block).unwrap().runtime_version,
5702
0
                    )
5703
0
                }) {
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s10_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s10_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s10_0Ba_
5704
0
                    if let Ok(new_best_runtime) = &**new_best_runtime {
5705
0
                        for subscription_id in &me.runtime_version_subscriptions {
5706
0
                            let _ = me
5707
0
                                .responses_tx
5708
0
                                .send(
5709
0
                                    methods::ServerToClient::state_runtimeVersion {
5710
0
                                        subscription: subscription_id.as_str().into(),
5711
0
                                        result: Some(convert_runtime_version_legacy(
5712
0
                                            new_best_runtime,
5713
0
                                        )),
5714
0
                                    }
5715
0
                                    .to_json_request_object_parameters(None),
5716
0
                                )
5717
0
                                .await;
5718
                        }
5719
0
                    }
5720
0
                }
5721
5722
                // The `state_subscribeStorage` subscriptions are marked as stale after sending
5723
                // out the notifications.
5724
0
                me.legacy_api_stale_storage_subscriptions.extend(
5725
0
                    me.legacy_api_storage_subscriptions
5726
0
                        .iter()
5727
0
                        .map(|(s_id, _)| s_id.clone()),
Unexecuted instantiation: _RNCNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0s11_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s11_0B1f_
Unexecuted instantiation: _RNCNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0s11_0Ba_
5728
0
                );
5729
            }
5730
        }
5731
    }
5732
0
}
Unexecuted instantiation: _RNCINvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background3runpE0B8_
Unexecuted instantiation: _RNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0B1d_
Unexecuted instantiation: _RNCINvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background3runpE0B8_
5733
5734
0
fn convert_runtime_version_legacy(
5735
0
    runtime_spec: &smoldot::executor::CoreVersion,
5736
0
) -> methods::RuntimeVersion {
5737
0
    let runtime_spec = runtime_spec.decode();
5738
0
    methods::RuntimeVersion {
5739
0
        spec_name: runtime_spec.spec_name.into(),
5740
0
        impl_name: runtime_spec.impl_name.into(),
5741
0
        authoring_version: u64::from(runtime_spec.authoring_version),
5742
0
        spec_version: u64::from(runtime_spec.spec_version),
5743
0
        impl_version: u64::from(runtime_spec.impl_version),
5744
0
        transaction_version: runtime_spec.transaction_version.map(u64::from),
5745
0
        state_version: runtime_spec.state_version.map(u8::from).map(u64::from),
5746
0
        apis: runtime_spec
5747
0
            .apis
5748
0
            .map(|api| (methods::HexString(api.name_hash.to_vec()), api.version))
Unexecuted instantiation: _RNCNvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background30convert_runtime_version_legacy0B7_
Unexecuted instantiation: _RNCNvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background30convert_runtime_version_legacy0B7_
5749
0
            .collect(),
5750
0
    }
5751
0
}
Unexecuted instantiation: _RNvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background30convert_runtime_version_legacy
Unexecuted instantiation: _RNvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background30convert_runtime_version_legacy
5752
5753
0
fn convert_runtime_version(runtime_spec: &smoldot::executor::CoreVersion) -> methods::RuntimeSpec {
5754
0
    let runtime_spec = runtime_spec.decode();
5755
0
    methods::RuntimeSpec {
5756
0
        spec_name: runtime_spec.spec_name.into(),
5757
0
        impl_name: runtime_spec.impl_name.into(),
5758
0
        spec_version: runtime_spec.spec_version,
5759
0
        impl_version: runtime_spec.impl_version,
5760
0
        transaction_version: runtime_spec.transaction_version,
5761
0
        apis: runtime_spec
5762
0
            .apis
5763
0
            .map(|api| (methods::HexString(api.name_hash.to_vec()), api.version))
Unexecuted instantiation: _RNCNvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background23convert_runtime_version0B7_
Unexecuted instantiation: _RNCNvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background23convert_runtime_version0B7_
5764
0
            .collect(),
5765
0
    }
5766
0
}
Unexecuted instantiation: _RNvNtNtCsiGub1lfKphe_13smoldot_light16json_rpc_service10background23convert_runtime_version
Unexecuted instantiation: _RNvNtNtCsih6EgvAwZF2_13smoldot_light16json_rpc_service10background23convert_runtime_version