subxt_rpcs/methods/
chain_head.rs

1// Copyright 2019-2025 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5//! An interface to call the  API methods. See
6//! <https://github.com/paritytech/json-rpc-interface-spec/> for details of the API
7//! methods exposed here.
8
9use crate::Hash;
10use crate::client::{RpcClient, RpcSubscription, rpc_params};
11use crate::{Error, RpcConfig};
12use derive_where::derive_where;
13use futures::{Stream, StreamExt};
14use serde::{Deserialize, Deserializer, Serialize};
15use std::collections::{HashMap, VecDeque};
16use std::task::Poll;
17
18/// An interface to call the unstable RPC methods. This interface is instantiated with
19/// some `T: Config` trait which determines some of the types that the RPC methods will
20/// take or hand back.
21#[derive_where(Clone, Debug)]
22pub struct ChainHeadRpcMethods<T> {
23    client: RpcClient,
24    _marker: std::marker::PhantomData<T>,
25}
26
27impl<T: RpcConfig> ChainHeadRpcMethods<T> {
28    /// Instantiate the legacy RPC method interface.
29    pub fn new(client: RpcClient) -> Self {
30        ChainHeadRpcMethods {
31            client,
32            _marker: std::marker::PhantomData,
33        }
34    }
35
36    /// Subscribe to `chainHead_v1_follow` to obtain all reported blocks by the chain.
37    ///
38    /// The subscription ID can be used to make queries for the
39    /// block's body ([`chainHead_v1_body`](ChainHeadRpcMethods::chainhead_v1_follow)),
40    /// block's header ([`chainHead_v1_header`](ChainHeadRpcMethods::chainhead_v1_header)),
41    /// block's storage ([`chainHead_v1_storage`](ChainHeadRpcMethods::chainhead_v1_storage)) and submitting
42    /// runtime API calls at this block ([`chainHead_v1_call`](ChainHeadRpcMethods::chainhead_v1_call)).
43    ///
44    /// # Note
45    ///
46    /// When the user is no longer interested in a block, the user is responsible
47    /// for calling the [`chainHead_v1_unpin`](ChainHeadRpcMethods::chainhead_v1_unpin) method.
48    /// Failure to do so will result in the subscription being stopped by generating the `Stop` event.
49    pub async fn chainhead_v1_follow(
50        &self,
51        with_runtime: bool,
52    ) -> Result<FollowSubscription<T::Hash>, Error> {
53        let sub = self
54            .client
55            .subscribe(
56                "chainHead_v1_follow",
57                rpc_params![with_runtime],
58                "chainHead_v1_unfollow",
59            )
60            .await?;
61
62        Ok(FollowSubscription { sub, done: false })
63    }
64
65    /// Resumes a storage fetch started with chainHead_v1_storage after it has generated an
66    /// `operationWaitingForContinue` event.
67    ///
68    /// Has no effect if the operationId is invalid or refers to an operation that has emitted a
69    /// `{"event": "operationInaccessible"` event, or if the followSubscription is invalid or stale.
70    pub async fn chainhead_v1_continue(
71        &self,
72        follow_subscription: &str,
73        operation_id: &str,
74    ) -> Result<(), Error> {
75        self.client
76            .request(
77                "chainHead_v1_continue",
78                rpc_params![follow_subscription, operation_id],
79            )
80            .await
81    }
82
83    /// Stops an operation started with `chainHead_v1_body`, `chainHead_v1_call`, or
84    /// `chainHead_v1_storage¦. If the operation was still in progress, this interrupts it.
85    /// If the operation was already finished, this call has no effect.
86    ///
87    /// Has no effect if the `followSubscription` is invalid or stale.
88    pub async fn chainhead_v1_stop_operation(
89        &self,
90        follow_subscription: &str,
91        operation_id: &str,
92    ) -> Result<(), Error> {
93        self.client
94            .request(
95                "chainHead_v1_stopOperation",
96                rpc_params![follow_subscription, operation_id],
97            )
98            .await
99    }
100
101    /// Call the `chainHead_v1_body` method and return an operation ID to obtain the block's body.
102    ///
103    /// The response events are provided on the `chainHead_follow` subscription and identified by
104    /// the returned operation ID.
105    ///
106    /// # Note
107    ///
108    /// The subscription ID is obtained from an open subscription created by
109    /// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
110    pub async fn chainhead_v1_body(
111        &self,
112        subscription_id: &str,
113        hash: T::Hash,
114    ) -> Result<MethodResponse, Error> {
115        let response = self
116            .client
117            .request("chainHead_v1_body", rpc_params![subscription_id, hash])
118            .await?;
119
120        Ok(response)
121    }
122
123    /// Get the block's header using the `chainHead_v1_header` method.
124    ///
125    /// # Note
126    ///
127    /// The subscription ID is obtained from an open subscription created by
128    /// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
129    pub async fn chainhead_v1_header(
130        &self,
131        subscription_id: &str,
132        hash: T::Hash,
133    ) -> Result<Option<T::Header>, Error> {
134        // header returned as hex encoded SCALE encoded bytes.
135        let header: Option<Bytes> = self
136            .client
137            .request("chainHead_v1_header", rpc_params![subscription_id, hash])
138            .await?;
139
140        let header = header
141            .map(|h| codec::Decode::decode(&mut &*h.0))
142            .transpose()
143            .map_err(Error::Decode)?;
144        Ok(header)
145    }
146
147    /// Call the `chainHead_v1_storage` method and return an operation ID to obtain the block's storage.
148    ///
149    /// The response events are provided on the `chainHead_follow` subscription and identified by
150    /// the returned operation ID.
151    ///
152    /// # Note
153    ///
154    /// The subscription ID is obtained from an open subscription created by
155    /// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
156    pub async fn chainhead_v1_storage(
157        &self,
158        subscription_id: &str,
159        hash: T::Hash,
160        items: impl IntoIterator<Item = StorageQuery<&[u8]>>,
161        child_key: Option<&[u8]>,
162    ) -> Result<MethodResponse, Error> {
163        let items: Vec<StorageQuery<String>> = items
164            .into_iter()
165            .map(|item| StorageQuery {
166                key: to_hex(item.key),
167                query_type: item.query_type,
168            })
169            .collect();
170
171        let response = self
172            .client
173            .request(
174                "chainHead_v1_storage",
175                rpc_params![subscription_id, hash, items, child_key.map(to_hex)],
176            )
177            .await?;
178
179        Ok(response)
180    }
181
182    /// Call the `chainHead_v1_call` method and return an operation ID to obtain the runtime API result.
183    ///
184    /// The response events are provided on the `chainHead_follow` subscription and identified by
185    /// the returned operation ID.
186    ///
187    /// # Note
188    ///
189    /// The subscription ID is obtained from an open subscription created by
190    /// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
191    pub async fn chainhead_v1_call(
192        &self,
193        subscription_id: &str,
194        hash: T::Hash,
195        function: &str,
196        call_parameters: &[u8],
197    ) -> Result<MethodResponse, Error> {
198        let response = self
199            .client
200            .request(
201                "chainHead_v1_call",
202                rpc_params![subscription_id, hash, function, to_hex(call_parameters)],
203            )
204            .await?;
205
206        Ok(response)
207    }
208
209    /// Unpin a block reported by the `chainHead_follow` subscription.
210    ///
211    /// # Note
212    ///
213    /// The subscription ID is obtained from an open subscription created by
214    /// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
215    pub async fn chainhead_v1_unpin(
216        &self,
217        subscription_id: &str,
218        hash: T::Hash,
219    ) -> Result<(), Error> {
220        self.client
221            .request("chainHead_v1_unpin", rpc_params![subscription_id, hash])
222            .await
223    }
224
225    /// Return the genesis hash.
226    pub async fn chainspec_v1_genesis_hash(&self) -> Result<T::Hash, Error> {
227        self.client
228            .request("chainSpec_v1_genesisHash", rpc_params![])
229            .await
230    }
231
232    /// Return a string containing the human-readable name of the chain.
233    pub async fn chainspec_v1_chain_name(&self) -> Result<String, Error> {
234        self.client
235            .request("chainSpec_v1_chainName", rpc_params![])
236            .await
237    }
238
239    /// Returns the JSON payload found in the chain specification under the key properties.
240    /// No guarantee is offered about the content of this object, and so it's up to the caller
241    /// to decide what to deserialize it into.
242    pub async fn chainspec_v1_properties<Props: serde::de::DeserializeOwned>(
243        &self,
244    ) -> Result<Props, Error> {
245        self.client
246            .request("chainSpec_v1_properties", rpc_params![])
247            .await
248    }
249
250    /// Returns an array of strings indicating the names of all the JSON-RPC functions supported by
251    /// the JSON-RPC server.
252    pub async fn rpc_methods(&self) -> Result<Vec<String>, Error> {
253        self.client.request("rpc_methods", rpc_params![]).await
254    }
255
256    /// Attempt to submit a transaction, returning events about its progress.
257    pub async fn transactionwatch_v1_submit_and_watch(
258        &self,
259        tx: &[u8],
260    ) -> Result<TransactionSubscription<T::Hash>, Error> {
261        let sub = self
262            .client
263            .subscribe(
264                "transactionWatch_v1_submitAndWatch",
265                rpc_params![to_hex(tx)],
266                "transactionWatch_v1_unwatch",
267            )
268            .await?;
269
270        Ok(TransactionSubscription { sub, done: false })
271    }
272
273    /// Broadcast the transaction on the p2p network until the
274    /// [`Self::transaction_v1_stop`] is called.
275    ///
276    /// Returns an operation ID that can be used to stop the broadcasting process.
277    /// Returns `None` if the server cannot handle the request at the moment.
278    pub async fn transaction_v1_broadcast(&self, tx: &[u8]) -> Result<Option<String>, Error> {
279        self.client
280            .request("transaction_v1_broadcast", rpc_params![to_hex(tx)])
281            .await
282    }
283
284    /// Stop the broadcasting process of the transaction.
285    ///
286    /// The operation ID is obtained from the [`Self::transaction_v1_broadcast`] method.
287    ///
288    /// Returns an error if the operation ID does not correspond to any active transaction for this connection.
289    pub async fn transaction_v1_stop(&self, operation_id: &str) -> Result<(), Error> {
290        self.client
291            .request("transaction_v1_stop", rpc_params![operation_id])
292            .await
293    }
294
295    /// Fetch the block body (ie the extrinsics in the block) given its hash.
296    ///
297    /// Returns an array of the hexadecimal-encoded scale-encoded extrinsics found in the block,
298    /// or `None` if the block wasn't found.
299    pub async fn archive_v1_body(&self, block_hash: T::Hash) -> Result<Option<Vec<Bytes>>, Error> {
300        self.client
301            .request("archive_v1_body", rpc_params![block_hash])
302            .await
303    }
304
305    /// Call the `archive_v1_call` method and return the response.
306    pub async fn archive_v1_call(
307        &self,
308        block_hash: T::Hash,
309        function: &str,
310        call_parameters: &[u8],
311    ) -> Result<ArchiveCallResult, Error> {
312        use serde::de::Error as _;
313
314        // We deserialize to this intermediate shape, since
315        // we can't have a boolean tag to denote variants.
316        #[derive(Deserialize)]
317        struct Response {
318            success: bool,
319            value: Option<Bytes>,
320            error: Option<String>,
321            // This was accidentally used instead of value in Substrate,
322            // so to support those impls we try it here if needed:
323            result: Option<Bytes>,
324        }
325
326        let res: Response = self
327            .client
328            .request(
329                "archive_v1_call",
330                rpc_params![block_hash, function, to_hex(call_parameters)],
331            )
332            .await?;
333
334        let value = res.value.or(res.result);
335        match (res.success, value, res.error) {
336            (true, Some(value), _) => Ok(ArchiveCallResult::Success(value)),
337            (false, _, err) => Ok(ArchiveCallResult::Error(err.unwrap_or(String::new()))),
338            (true, None, _) => {
339                let m = "archive_v1_call: 'success: true' response should have `value: 0x1234` alongside it";
340                Err(Error::Deserialization(serde_json::Error::custom(m)))
341            }
342        }
343    }
344
345    /// Return the finalized block height of the chain.
346    pub async fn archive_v1_finalized_height(&self) -> Result<usize, Error> {
347        self.client
348            .request("archive_v1_finalizedHeight", rpc_params![])
349            .await
350    }
351
352    /// Return the genesis hash.
353    pub async fn archive_v1_genesis_hash(&self) -> Result<T::Hash, Error> {
354        self.client
355            .request("archive_v1_genesisHash", rpc_params![])
356            .await
357    }
358
359    /// Given a block height, return the hashes of the zero or more blocks at that height.
360    /// For blocks older than the latest finalized block, only one entry will be returned. For blocks
361    /// newer than the latest finalized block, it's possible to have 0, 1 or multiple blocks at
362    /// that height given that forks could occur.
363    pub async fn archive_v1_hash_by_height(&self, height: usize) -> Result<Vec<T::Hash>, Error> {
364        self.client
365            .request("archive_v1_hashByHeight", rpc_params![height])
366            .await
367    }
368
369    /// Fetch the header for a block with the given hash, or `None` if no block with that hash exists.
370    pub async fn archive_v1_header(&self, block_hash: T::Hash) -> Result<Option<T::Header>, Error> {
371        let maybe_encoded_header: Option<Bytes> = self
372            .client
373            .request("archive_v1_header", rpc_params![block_hash])
374            .await?;
375
376        let Some(encoded_header) = maybe_encoded_header else {
377            return Ok(None);
378        };
379
380        let header =
381            <T::Header as codec::Decode>::decode(&mut &*encoded_header.0).map_err(Error::Decode)?;
382        Ok(Some(header))
383    }
384
385    /// Query the node storage and return a subscription which streams corresponding storage events back.
386    pub async fn archive_v1_storage(
387        &self,
388        block_hash: T::Hash,
389        items: impl IntoIterator<Item = StorageQuery<&[u8]>>,
390        child_key: Option<&[u8]>,
391    ) -> Result<ArchiveStorageSubscription<T::Hash>, Error> {
392        let items: Vec<StorageQuery<String>> = items
393            .into_iter()
394            .map(|item| StorageQuery {
395                key: to_hex(item.key),
396                query_type: item.query_type,
397            })
398            .collect();
399
400        let sub = self
401            .client
402            .subscribe(
403                "archive_v1_storage",
404                rpc_params![block_hash, items, child_key.map(to_hex)],
405                "archive_v1_stopStorage",
406            )
407            .await?;
408
409        Ok(ArchiveStorageSubscription { sub, done: false })
410    }
411
412    // Dev note: we continue to support the latest "unstable" archive methods because
413    // they will be around for a while before the stable ones make it into a release.
414    // The below are just a copy-paste of the v1 methods, above, but calling the
415    // "unstable" RPCs instead. Eventually we'll remove them.
416
417    /// Fetch the block body (ie the extrinsics in the block) given its hash.
418    ///
419    /// Returns an array of the hexadecimal-encoded scale-encoded extrinsics found in the block,
420    /// or `None` if the block wasn't found.
421    pub async fn archive_unstable_body(
422        &self,
423        block_hash: T::Hash,
424    ) -> Result<Option<Vec<Bytes>>, Error> {
425        self.client
426            .request("archive_unstable_body", rpc_params![block_hash])
427            .await
428    }
429
430    /// Call the `archive_unstable_call` method and return the response.
431    pub async fn archive_unstable_call(
432        &self,
433        block_hash: T::Hash,
434        function: &str,
435        call_parameters: &[u8],
436    ) -> Result<ArchiveCallResult, Error> {
437        use serde::de::Error as _;
438
439        // We deserialize to this intermediate shape, since
440        // we can't have a boolean tag to denote variants.
441        #[derive(Deserialize)]
442        struct Response {
443            success: bool,
444            value: Option<Bytes>,
445            error: Option<String>,
446            // This was accidentally used instead of value in Substrate,
447            // so to support those impls we try it here if needed:
448            result: Option<Bytes>,
449        }
450
451        let res: Response = self
452            .client
453            .request(
454                "archive_unstable_call",
455                rpc_params![block_hash, function, to_hex(call_parameters)],
456            )
457            .await?;
458
459        let value = res.value.or(res.result);
460        match (res.success, value, res.error) {
461            (true, Some(value), _) => Ok(ArchiveCallResult::Success(value)),
462            (false, _, err) => Ok(ArchiveCallResult::Error(err.unwrap_or(String::new()))),
463            (true, None, _) => {
464                let m = "archive_unstable_call: 'success: true' response should have `value: 0x1234` alongside it";
465                Err(Error::Deserialization(serde_json::Error::custom(m)))
466            }
467        }
468    }
469
470    /// Return the finalized block height of the chain.
471    pub async fn archive_unstable_finalized_height(&self) -> Result<usize, Error> {
472        self.client
473            .request("archive_unstable_finalizedHeight", rpc_params![])
474            .await
475    }
476
477    /// Return the genesis hash.
478    pub async fn archive_unstable_genesis_hash(&self) -> Result<T::Hash, Error> {
479        self.client
480            .request("archive_unstable_genesisHash", rpc_params![])
481            .await
482    }
483
484    /// Given a block height, return the hashes of the zero or more blocks at that height.
485    /// For blocks older than the latest finalized block, only one entry will be returned. For blocks
486    /// newer than the latest finalized block, it's possible to have 0, 1 or multiple blocks at
487    /// that height given that forks could occur.
488    pub async fn archive_unstable_hash_by_height(
489        &self,
490        height: usize,
491    ) -> Result<Vec<T::Hash>, Error> {
492        self.client
493            .request("archive_unstable_hashByHeight", rpc_params![height])
494            .await
495    }
496
497    /// Fetch the header for a block with the given hash, or `None` if no block with that hash exists.
498    pub async fn archive_unstable_header(
499        &self,
500        block_hash: T::Hash,
501    ) -> Result<Option<T::Header>, Error> {
502        let maybe_encoded_header: Option<Bytes> = self
503            .client
504            .request("archive_unstable_header", rpc_params![block_hash])
505            .await?;
506
507        let Some(encoded_header) = maybe_encoded_header else {
508            return Ok(None);
509        };
510
511        let header =
512            <T::Header as codec::Decode>::decode(&mut &*encoded_header.0).map_err(Error::Decode)?;
513        Ok(Some(header))
514    }
515
516    /// Query the node storage and return a subscription which streams corresponding storage events back.
517    pub async fn archive_unstable_storage(
518        &self,
519        block_hash: T::Hash,
520        items: impl IntoIterator<Item = StorageQuery<&[u8]>>,
521        child_key: Option<&[u8]>,
522    ) -> Result<ArchiveStorageSubscription<T::Hash>, Error> {
523        let items: Vec<StorageQuery<String>> = items
524            .into_iter()
525            .map(|item| StorageQuery {
526                key: to_hex(item.key),
527                query_type: item.query_type,
528            })
529            .collect();
530
531        let sub = self
532            .client
533            .subscribe(
534                "archive_unstable_storage",
535                rpc_params![block_hash, items, child_key.map(to_hex)],
536                "archive_unstable_stopStorage",
537            )
538            .await?;
539
540        Ok(ArchiveStorageSubscription { sub, done: false })
541    }
542}
543
544/// This represents events generated by the `follow` method.
545///
546/// The block events are generated in the following order:
547/// 1. Initialized - generated only once to signal the latest finalized block
548/// 2. NewBlock - a new block was added.
549/// 3. BestBlockChanged - indicate that the best block is now the one from this event. The block was
550///    announced priorly with the `NewBlock` event.
551/// 4. Finalized - State the finalized and pruned blocks.
552///
553/// The following events are related to operations:
554/// - OperationBodyDone: The response of the `chainHead_body`
555/// - OperationCallDone: The response of the `chainHead_call`
556/// - OperationStorageItems: Items produced by the `chainHead_storage`
557/// - OperationWaitingForContinue: Generated after OperationStorageItems and requires the user to
558///   call `chainHead_continue`
559/// - OperationStorageDone: The `chainHead_storage` method has produced all the results
560/// - OperationInaccessible: The server was unable to provide the result, retries might succeed in
561///   the future
562/// - OperationError: The server encountered an error, retries will not succeed
563///
564/// The stop event indicates that the JSON-RPC server was unable to provide a consistent list of
565/// the blocks at the head of the chain.
566#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
567#[serde(rename_all = "camelCase")]
568#[serde(tag = "event")]
569pub enum FollowEvent<Hash> {
570    /// The latest finalized block.
571    ///
572    /// This event is generated only once.
573    Initialized(Initialized<Hash>),
574    /// A new non-finalized block was added.
575    NewBlock(NewBlock<Hash>),
576    /// The best block of the chain.
577    BestBlockChanged(BestBlockChanged<Hash>),
578    /// A list of finalized and pruned blocks.
579    Finalized(Finalized<Hash>),
580    /// The response of the `chainHead_body` method.
581    OperationBodyDone(OperationBodyDone),
582    /// The response of the `chainHead_call` method.
583    OperationCallDone(OperationCallDone),
584    /// Yield one or more items found in the storage.
585    OperationStorageItems(OperationStorageItems),
586    /// Ask the user to call `chainHead_continue` to produce more events
587    /// regarding the operation id.
588    OperationWaitingForContinue(OperationId),
589    /// The responses of the `chainHead_storage` method have been produced.
590    OperationStorageDone(OperationId),
591    /// The RPC server was unable to provide the response of the following operation id.
592    ///
593    /// Repeating the same operation in the future might succeed.
594    OperationInaccessible(OperationId),
595    /// The RPC server encountered an error while processing an operation id.
596    ///
597    /// Repeating the same operation in the future will not succeed.
598    OperationError(OperationError),
599    /// The subscription is dropped and no further events
600    /// will be generated.
601    Stop,
602}
603
604/// Contain information about the latest finalized block.
605///
606/// # Note
607///
608/// This is the first event generated by the `follow` subscription
609/// and is submitted only once.
610#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
611#[serde(rename_all = "camelCase")]
612pub struct Initialized<Hash> {
613    /// The hashes of the last finalized blocks.
614    pub finalized_block_hashes: Vec<Hash>,
615    /// The runtime version of the finalized block.
616    ///
617    /// # Note
618    ///
619    /// This is present only if the `with_runtime` flag is set for
620    /// the `follow` subscription.
621    pub finalized_block_runtime: Option<RuntimeEvent>,
622}
623
624impl<'de, Hash: Deserialize<'de>> Deserialize<'de> for Initialized<Hash> {
625    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
626        // Custom struct that can deserialize both `finalizedBlockHash` and `finalizedBlockHashes`.
627        #[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
628        #[serde(rename_all = "camelCase")]
629        struct InitializedIR<Hash> {
630            finalized_block_hashes: Option<Vec<Hash>>,
631            finalized_block_hash: Option<Hash>,
632            finalized_block_runtime: Option<RuntimeEvent>,
633        }
634
635        let ir = InitializedIR::deserialize(deserializer)?;
636        let finalized_block_hashes = ir
637            .finalized_block_hashes
638            .or_else(|| ir.finalized_block_hash.map(|hash| vec![hash]))
639            .ok_or_else(|| serde::de::Error::custom("Missing finalized block hashes"))?;
640
641        Ok(Initialized {
642            finalized_block_hashes,
643            finalized_block_runtime: ir.finalized_block_runtime,
644        })
645    }
646}
647
648/// The runtime event generated if the `follow` subscription
649/// has set the `with_runtime` flag.
650#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
651#[serde(rename_all = "camelCase")]
652#[serde(tag = "type")]
653pub enum RuntimeEvent {
654    /// The runtime version of this block.
655    Valid(RuntimeVersionEvent),
656    /// The runtime could not be obtained due to an error.
657    Invalid(ErrorEvent),
658}
659
660/// The runtime specification of the current block.
661///
662/// This event is generated for:
663///   - the first announced block by the follow subscription
664///   - blocks that suffered a change in runtime compared with their parents
665#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
666#[serde(rename_all = "camelCase")]
667pub struct RuntimeVersionEvent {
668    /// Details about this runtime.
669    pub spec: RuntimeSpec,
670}
671
672/// This contains the runtime version information necessary to make transactions, and is obtained from
673/// the "initialized" event of `chainHead_follow` if the `withRuntime` flag is set.
674#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
675#[serde(rename_all = "camelCase")]
676pub struct RuntimeSpec {
677    /// Opaque string indicating the name of the chain.
678    pub spec_name: String,
679
680    /// Opaque string indicating the name of the implementation of the chain.
681    pub impl_name: String,
682
683    /// Opaque integer. The JSON-RPC client can assume that the Runtime API call to `Metadata_metadata`
684    /// will always produce the same output as long as the specVersion is the same.
685    pub spec_version: u32,
686
687    /// Opaque integer. Whenever the runtime code changes in a backwards-compatible way, the implVersion
688    /// is modified while the specVersion is left untouched.
689    pub impl_version: u32,
690
691    /// Opaque integer. Necessary when building the bytes of a transaction. Transactions that have been
692    /// generated with a different `transaction_version` are incompatible.
693    pub transaction_version: u32,
694
695    /// Object containing a list of "entry point APIs" supported by the runtime. Each key is an opaque string
696    /// indicating the API, and each value is an integer version number. Before making a runtime call (using
697    /// chainHead_call), you should make sure that this list contains the entry point API corresponding to the
698    /// call and with a known version number.
699    ///
700    /// **Note:** In Substrate, the keys in the apis field consists of the hexadecimal-encoded 8-bytes blake2
701    /// hash of the name of the API. For example, the `TaggedTransactionQueue` API is 0xd2bc9897eed08f15.
702    #[serde(with = "hashmap_as_tuple_list")]
703    pub apis: HashMap<String, u32>,
704}
705
706/// The operation could not be processed due to an error.
707#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
708#[serde(rename_all = "camelCase")]
709pub struct ErrorEvent {
710    /// Reason of the error.
711    pub error: String,
712}
713
714/// Indicate a new non-finalized block.
715#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
716#[serde(rename_all = "camelCase")]
717pub struct NewBlock<Hash> {
718    /// The hash of the new block.
719    pub block_hash: Hash,
720    /// The parent hash of the new block.
721    pub parent_block_hash: Hash,
722    /// The runtime version of the new block.
723    ///
724    /// # Note
725    ///
726    /// This is present only if the `with_runtime` flag is set for
727    /// the `follow` subscription.
728    pub new_runtime: Option<RuntimeEvent>,
729}
730
731/// Indicate the block hash of the new best block.
732#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
733#[serde(rename_all = "camelCase")]
734pub struct BestBlockChanged<Hash> {
735    /// The block hash of the new best block.
736    pub best_block_hash: Hash,
737}
738
739/// Indicate the finalized and pruned block hashes.
740#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
741#[serde(rename_all = "camelCase")]
742pub struct Finalized<Hash> {
743    /// Block hashes that are finalized.
744    pub finalized_block_hashes: Vec<Hash>,
745    /// Block hashes that are pruned (removed).
746    pub pruned_block_hashes: Vec<Hash>,
747}
748
749/// Indicate the operation id of the event.
750#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
751#[serde(rename_all = "camelCase")]
752pub struct OperationId {
753    /// The operation id of the event.
754    pub operation_id: String,
755}
756
757/// The response of the `chainHead_body` method.
758#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
759#[serde(rename_all = "camelCase")]
760pub struct OperationBodyDone {
761    /// The operation id of the event.
762    pub operation_id: String,
763    /// Array of hexadecimal-encoded scale-encoded extrinsics found in the block.
764    pub value: Vec<Bytes>,
765}
766
767/// The response of the `chainHead_call` method.
768#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
769#[serde(rename_all = "camelCase")]
770pub struct OperationCallDone {
771    /// The operation id of the event.
772    pub operation_id: String,
773    /// Hexadecimal-encoded output of the runtime function call.
774    pub output: Bytes,
775}
776
777/// The response of the `chainHead_call` method.
778#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
779#[serde(rename_all = "camelCase")]
780pub struct OperationStorageItems {
781    /// The operation id of the event.
782    pub operation_id: String,
783    /// The resulting items.
784    pub items: VecDeque<StorageResult>,
785}
786
787/// Indicate a problem during the operation.
788#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
789#[serde(rename_all = "camelCase")]
790pub struct OperationError {
791    /// The operation id of the event.
792    pub operation_id: String,
793    /// The reason of the error.
794    pub error: String,
795}
796
797/// The storage result.
798#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
799#[serde(rename_all = "camelCase")]
800pub struct StorageResult {
801    /// The hex-encoded key of the result.
802    pub key: Bytes,
803    /// The result of the query.
804    #[serde(flatten)]
805    pub result: StorageResultType,
806}
807
808/// The type of the storage query.
809#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
810#[serde(rename_all = "camelCase")]
811pub enum StorageResultType {
812    /// Fetch the value of the provided key.
813    Value(Bytes),
814    /// Fetch the hash of the value of the provided key.
815    Hash(Bytes),
816    /// Fetch the closest descendant merkle value.
817    ClosestDescendantMerkleValue(Bytes),
818}
819
820/// The method response of `chainHead_body`, `chainHead_call` and `chainHead_storage`.
821#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
822#[serde(rename_all = "camelCase")]
823#[serde(tag = "result")]
824pub enum MethodResponse {
825    /// The method has started.
826    Started(MethodResponseStarted),
827    /// The RPC server cannot handle the request at the moment.
828    LimitReached,
829}
830
831/// The `started` result of a method.
832#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
833#[serde(rename_all = "camelCase")]
834pub struct MethodResponseStarted {
835    /// The operation id of the response.
836    pub operation_id: String,
837    /// The number of items from the back of the `chainHead_storage` that have been discarded.
838    pub discarded_items: Option<usize>,
839}
840
841/// The storage item received as parameter.
842#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
843#[serde(rename_all = "camelCase")]
844pub struct StorageQuery<Key> {
845    /// The provided key.
846    pub key: Key,
847    /// The type of the storage query.
848    #[serde(rename = "type")]
849    pub query_type: StorageQueryType,
850}
851
852/// The type of the storage query.
853#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
854#[serde(rename_all = "camelCase")]
855pub enum StorageQueryType {
856    /// Fetch the value of the provided key.
857    Value,
858    /// Fetch the hash of the value of the provided key.
859    Hash,
860    /// Fetch the closest descendant merkle value.
861    ClosestDescendantMerkleValue,
862    /// Fetch the values of all descendants of they provided key.
863    DescendantsValues,
864    /// Fetch the hashes of the values of all descendants of they provided key.
865    DescendantsHashes,
866}
867
868/// A subscription which returns follow events, and ends when a Stop event occurs.
869pub struct FollowSubscription<Hash> {
870    sub: RpcSubscription<FollowEvent<Hash>>,
871    done: bool,
872}
873
874impl<H: Hash> FollowSubscription<H> {
875    /// Fetch the next item in the stream.
876    pub async fn next(&mut self) -> Option<<Self as Stream>::Item> {
877        <Self as StreamExt>::next(self).await
878    }
879    /// Fetch the subscription ID for the stream.
880    pub fn subscription_id(&self) -> Option<&str> {
881        self.sub.subscription_id()
882    }
883}
884
885impl<H: Hash> Stream for FollowSubscription<H> {
886    type Item = <RpcSubscription<FollowEvent<H>> as Stream>::Item;
887    fn poll_next(
888        mut self: std::pin::Pin<&mut Self>,
889        cx: &mut std::task::Context<'_>,
890    ) -> std::task::Poll<Option<Self::Item>> {
891        if self.done {
892            return Poll::Ready(None);
893        }
894
895        let res = self.sub.poll_next_unpin(cx);
896
897        if let Poll::Ready(Some(Ok(FollowEvent::Stop))) = &res {
898            // No more events will occur after this one.
899            self.done = true;
900        }
901
902        res
903    }
904}
905
906/// A subscription which returns transaction status events, stopping
907/// when no more events will be sent.
908pub struct TransactionSubscription<Hash> {
909    sub: RpcSubscription<TransactionStatus<Hash>>,
910    done: bool,
911}
912
913impl<H: Hash> TransactionSubscription<H> {
914    /// Fetch the next item in the stream.
915    pub async fn next(&mut self) -> Option<<Self as Stream>::Item> {
916        <Self as StreamExt>::next(self).await
917    }
918}
919
920impl<H: Hash> Stream for TransactionSubscription<H> {
921    type Item = <RpcSubscription<TransactionStatus<H>> as Stream>::Item;
922    fn poll_next(
923        mut self: std::pin::Pin<&mut Self>,
924        cx: &mut std::task::Context<'_>,
925    ) -> std::task::Poll<Option<Self::Item>> {
926        if self.done {
927            return Poll::Ready(None);
928        }
929
930        let res = self.sub.poll_next_unpin(cx);
931
932        if let Poll::Ready(Some(Ok(res))) = &res {
933            if matches!(
934                res,
935                TransactionStatus::Dropped { .. }
936                    | TransactionStatus::Error { .. }
937                    | TransactionStatus::Invalid { .. }
938                    | TransactionStatus::Finalized { .. }
939            ) {
940                // No more events will occur after these ones.
941                self.done = true
942            }
943        }
944
945        res
946    }
947}
948
949/// Transaction progress events
950#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
951#[serde(rename_all = "camelCase")]
952#[serde(tag = "event")]
953pub enum TransactionStatus<Hash> {
954    /// Transaction is part of the future queue.
955    Validated,
956    /// The transaction has been broadcast to other nodes.
957    ///
958    /// Note: This event is no longer expected to be returned as of
959    /// the chainHead_v1 spec, but we do so for compatibility with
960    /// older versions of Smoldot, which do return it.
961    Broadcasted,
962    /// Transaction has been included in block with given details.
963    /// Null is returned if the transaction is no longer in any block
964    /// of the best chain.
965    BestChainBlockIncluded {
966        /// Details of the block it's been seen in.
967        block: Option<TransactionBlockDetails<Hash>>,
968    },
969    /// The transaction is in a block that's been finalized.
970    Finalized {
971        /// Details of the block it's been seen in.
972        block: TransactionBlockDetails<Hash>,
973    },
974    /// Something went wrong in the node.
975    Error {
976        /// Human readable message; what went wrong.
977        error: String,
978    },
979    /// Transaction is invalid (bad nonce, signature etc).
980    Invalid {
981        /// Human readable message; why was it invalid.
982        error: String,
983    },
984    /// The transaction was dropped.
985    Dropped {
986        /// Human readable message; why was it dropped.
987        error: String,
988    },
989}
990
991/// Details of a block that a transaction is seen in.
992#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
993pub struct TransactionBlockDetails<Hash> {
994    /// The block hash.
995    pub hash: Hash,
996    /// The index of the transaction in the block.
997    #[serde(with = "unsigned_number_as_string")]
998    pub index: u64,
999}
1000
1001/// The response from calling `archive_call`.
1002#[derive(Debug, Clone, PartialEq, Eq)]
1003pub enum ArchiveCallResult {
1004    /// The bytes returned from successfully making a call
1005    Success(Bytes),
1006    /// An error returned if the call was not successful.
1007    Error(String),
1008}
1009
1010impl ArchiveCallResult {
1011    /// Return the bytes on success, or `None` if not an [`ArchiveCallResult::Success`].
1012    pub fn as_success(self) -> Option<Bytes> {
1013        match self {
1014            ArchiveCallResult::Success(bytes) => Some(bytes),
1015            _ => None,
1016        }
1017    }
1018
1019    /// Return the error message on call failure, or `None` if not an [`ArchiveCallResult::Error`].
1020    pub fn as_error(self) -> Option<String> {
1021        match self {
1022            ArchiveCallResult::Success(_) => None,
1023            ArchiveCallResult::Error(e) => Some(e),
1024        }
1025    }
1026}
1027
1028/// A subscription which returns follow events, and ends when a Stop event occurs.
1029pub struct ArchiveStorageSubscription<Hash> {
1030    sub: RpcSubscription<ArchiveStorageEvent<Hash>>,
1031    done: bool,
1032}
1033
1034impl<H: Hash> ArchiveStorageSubscription<H> {
1035    /// Fetch the next item in the stream.
1036    pub async fn next(&mut self) -> Option<<Self as Stream>::Item> {
1037        <Self as StreamExt>::next(self).await
1038    }
1039    /// Fetch the subscription ID for the stream.
1040    pub fn subscription_id(&self) -> Option<&str> {
1041        self.sub.subscription_id()
1042    }
1043}
1044
1045impl<H: Hash> Stream for ArchiveStorageSubscription<H> {
1046    type Item = <RpcSubscription<ArchiveStorageEvent<H>> as Stream>::Item;
1047    fn poll_next(
1048        mut self: std::pin::Pin<&mut Self>,
1049        cx: &mut std::task::Context<'_>,
1050    ) -> std::task::Poll<Option<Self::Item>> {
1051        if self.done {
1052            return Poll::Ready(None);
1053        }
1054
1055        let res = self.sub.poll_next_unpin(cx);
1056
1057        if let Poll::Ready(Some(Ok(ArchiveStorageEvent::Done | ArchiveStorageEvent::Error(..)))) =
1058            &res
1059        {
1060            // No more events will occur after "done" or "error" events.
1061            self.done = true;
1062        }
1063
1064        res
1065    }
1066}
1067
1068/// Responses returned from [`ArchiveStorageSubscription`].
1069#[derive(Debug, Deserialize)]
1070#[serde(tag = "event")]
1071pub enum ArchiveStorageEvent<Hash> {
1072    /// A storage response for one of the requested items.
1073    #[serde(rename = "storage")]
1074    Item(ArchiveStorageEventItem<Hash>),
1075    /// A human-readable error indicating what went wrong. No more storage events
1076    /// will be emitted after this.
1077    #[serde(rename = "storageError")]
1078    Error(ArchiveStorageEventError),
1079    /// No more storage events will be emitted after this.
1080    #[serde(rename = "storageDone")]
1081    Done,
1082}
1083
1084impl<Hash> ArchiveStorageEvent<Hash> {
1085    /// Return a storage item or `None` if not an [`ArchiveStorageEvent::Item`].
1086    pub fn as_item(self) -> Option<ArchiveStorageEventItem<Hash>> {
1087        match self {
1088            ArchiveStorageEvent::Item(item) => Some(item),
1089            _ => None,
1090        }
1091    }
1092
1093    /// Return a storage error or `None` if not an [`ArchiveStorageEvent::Error`].
1094    pub fn as_error(self) -> Option<ArchiveStorageEventError> {
1095        match self {
1096            ArchiveStorageEvent::Error(e) => Some(e),
1097            _ => None,
1098        }
1099    }
1100
1101    /// Is this an [`ArchiveStorageEvent::Done`].
1102    pub fn is_done(self) -> bool {
1103        matches!(self, ArchiveStorageEvent::Done)
1104    }
1105}
1106
1107/// Something went wrong during the [`ChainHeadRpcMethods::archive_unstable_storage()`] subscription.
1108#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
1109#[serde(rename_all = "camelCase")]
1110pub struct ArchiveStorageEventError {
1111    /// The human readable error message indicating what went wrong.
1112    pub error: String,
1113}
1114
1115/// A storage item returned from the [`ChainHeadRpcMethods::archive_unstable_storage()`] subscription.
1116#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
1117#[serde(rename_all = "camelCase")]
1118pub struct ArchiveStorageEventItem<Hash> {
1119    /// String containing the hexadecimal-encoded key of the storage entry.
1120    pub key: Bytes,
1121    /// String containing the hexadecimal-encoded value of the storage entry.
1122    /// Returned when the request type is [`StorageQueryType::Value`] or [`StorageQueryType::DescendantsValues`].
1123    pub value: Option<Bytes>,
1124    /// String containing the hexadecimal-encoded hash of the storage entry.
1125    /// Returned when the request type is [`StorageQueryType::Hash`] or [`StorageQueryType::DescendantsHashes`].
1126    pub hash: Option<Hash>,
1127    /// String containing the hexadecimal-encoded Merkle value of the closest descendant of key (including branch nodes).
1128    /// Returned when the request type is [`StorageQueryType::ClosestDescendantMerkleValue`].
1129    pub closest_descendant_merkle_value: Option<Bytes>,
1130    /// String containing the hexadecimal-encoded key of the child trie of the "default" namespace if the storage entry
1131    /// is part of a child trie. If the storage entry is part of the main trie, this field is not present.
1132    pub child_trie_key: Option<Bytes>,
1133}
1134
1135/// Hex-serialized shim for `Vec<u8>`.
1136#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Hash, PartialOrd, Ord, Debug)]
1137pub struct Bytes(#[serde(with = "impl_serde::serialize")] pub Vec<u8>);
1138impl std::ops::Deref for Bytes {
1139    type Target = [u8];
1140    fn deref(&self) -> &[u8] {
1141        &self.0[..]
1142    }
1143}
1144impl From<Vec<u8>> for Bytes {
1145    fn from(s: Vec<u8>) -> Self {
1146        Bytes(s)
1147    }
1148}
1149
1150fn to_hex(bytes: impl AsRef<[u8]>) -> String {
1151    format!("0x{}", hex::encode(bytes.as_ref()))
1152}
1153
1154/// Attempt to deserialize either a string or integer into an integer.
1155/// See <https://github.com/paritytech/json-rpc-interface-spec/issues/83>
1156pub(crate) mod unsigned_number_as_string {
1157    use serde::de::{Deserializer, Visitor};
1158    use std::fmt;
1159
1160    /// Deserialize a number from a string or number.
1161    pub fn deserialize<'de, N: From<u64>, D>(deserializer: D) -> Result<N, D::Error>
1162    where
1163        D: Deserializer<'de>,
1164    {
1165        deserializer.deserialize_any(NumberVisitor(std::marker::PhantomData))
1166    }
1167
1168    struct NumberVisitor<N>(std::marker::PhantomData<N>);
1169
1170    impl<N: From<u64>> Visitor<'_> for NumberVisitor<N> {
1171        type Value = N;
1172
1173        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1174            formatter.write_str("an unsigned integer or a string containing one")
1175        }
1176
1177        fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
1178            let n: u64 = v.parse().map_err(serde::de::Error::custom)?;
1179            Ok(n.into())
1180        }
1181
1182        fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
1183            Ok(v.into())
1184        }
1185    }
1186
1187    use serde::ser::Serializer;
1188
1189    /// Serialize a number as string
1190    pub fn serialize<S>(item: &u64, serializer: S) -> Result<S::Ok, S::Error>
1191    where
1192        S: Serializer,
1193    {
1194        serializer.serialize_str(&item.to_string())
1195    }
1196}
1197
1198/// A temporary shim to decode "spec.apis" if it comes back as an array like:
1199///
1200/// ```text
1201/// [["0xABC", 1], ["0xCDE", 2]]
1202/// ```
1203///
1204/// The expected format (which this also supports deserializing from) is:
1205///
1206/// ```text
1207/// { "0xABC": 1, "0xCDE": 2 }
1208/// ```
1209///
1210/// We can delete this when the correct format is being returned.
1211///
1212/// Adapted from <https://tikv.github.io/doc/serde_with/rust/hashmap_as_tuple_list>
1213pub(crate) mod hashmap_as_tuple_list {
1214    use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
1215    use std::collections::HashMap;
1216    use std::fmt;
1217    use std::hash::{BuildHasher, Hash};
1218    use std::marker::PhantomData;
1219
1220    /// Deserialize a [`HashMap`] from a list of tuples or object
1221    pub fn deserialize<'de, K, V, BH, D>(deserializer: D) -> Result<HashMap<K, V, BH>, D::Error>
1222    where
1223        D: Deserializer<'de>,
1224        K: Eq + Hash + Deserialize<'de>,
1225        V: Deserialize<'de>,
1226        BH: BuildHasher + Default,
1227    {
1228        deserializer.deserialize_any(HashMapVisitor(PhantomData))
1229    }
1230
1231    #[allow(clippy::type_complexity)]
1232    struct HashMapVisitor<K, V, BH>(PhantomData<fn() -> HashMap<K, V, BH>>);
1233
1234    impl<'de, K, V, BH> Visitor<'de> for HashMapVisitor<K, V, BH>
1235    where
1236        K: Deserialize<'de> + Eq + Hash,
1237        V: Deserialize<'de>,
1238        BH: BuildHasher + Default,
1239    {
1240        type Value = HashMap<K, V, BH>;
1241
1242        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1243            formatter.write_str("a list of key-value pairs")
1244        }
1245
1246        // Work with maps too:
1247        fn visit_map<A>(self, mut m: A) -> Result<Self::Value, A::Error>
1248        where
1249            A: serde::de::MapAccess<'de>,
1250        {
1251            let mut map =
1252                HashMap::with_capacity_and_hasher(m.size_hint().unwrap_or(0), BH::default());
1253            while let Some((key, value)) = m.next_entry()? {
1254                map.insert(key, value);
1255            }
1256            Ok(map)
1257        }
1258
1259        // The shim to also work with sequences of tuples.
1260        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1261        where
1262            A: SeqAccess<'de>,
1263        {
1264            let mut map =
1265                HashMap::with_capacity_and_hasher(seq.size_hint().unwrap_or(0), BH::default());
1266            while let Some((key, value)) = seq.next_element()? {
1267                map.insert(key, value);
1268            }
1269            Ok(map)
1270        }
1271    }
1272
1273    use serde::ser::{Serialize, SerializeSeq, Serializer};
1274
1275    /// Serialize hashmap as list of tuples
1276    pub fn serialize<S, K: Eq + Hash + Serialize, V: Serialize>(
1277        item: &HashMap<K, V>,
1278        serializer: S,
1279    ) -> Result<S::Ok, S::Error>
1280    where
1281        S: Serializer,
1282    {
1283        let mut seq = serializer.serialize_seq(None)?;
1284        for i in item {
1285            seq.serialize_element(&i)?;
1286        }
1287        seq.end()
1288    }
1289}
1290
1291#[cfg(test)]
1292mod test {
1293    use super::*;
1294
1295    #[test]
1296    fn can_deserialize_apis_from_tuple_or_object() {
1297        let old_response = serde_json::json!({
1298            "authoringVersion": 10,
1299            "specName": "westend",
1300            "implName": "parity-westend",
1301            "specVersion": 9122,
1302            "implVersion": 0,
1303            "stateVersion": 1,
1304            "transactionVersion": 7,
1305            "apis": [
1306                ["0xdf6acb689907609b", 3],
1307                ["0x37e397fc7c91f5e4", 1],
1308                ["0x40fe3ad401f8959a", 5],
1309                ["0xd2bc9897eed08f15", 3],
1310                ["0xf78b278be53f454c", 2],
1311                ["0xaf2c0297a23e6d3d", 1],
1312                ["0x49eaaf1b548a0cb0", 1],
1313                ["0x91d5df18b0d2cf58", 1],
1314                ["0xed99c5acb25eedf5", 3],
1315                ["0xcbca25e39f142387", 2],
1316                ["0x687ad44ad37f03c2", 1],
1317                ["0xab3c0572291feb8b", 1],
1318                ["0xbc9d89904f5b923f", 1],
1319                ["0x37c8bb1350a9a2a8", 1]
1320            ]
1321        });
1322        let old_spec: RuntimeSpec = serde_json::from_value(old_response).unwrap();
1323
1324        let new_response = serde_json::json!({
1325            "specName": "westend",
1326            "implName": "parity-westend",
1327            "specVersion": 9122,
1328            "implVersion": 0,
1329            "transactionVersion": 7,
1330            "apis": {
1331                "0xdf6acb689907609b": 3,
1332                "0x37e397fc7c91f5e4": 1,
1333                "0x40fe3ad401f8959a": 5,
1334                "0xd2bc9897eed08f15": 3,
1335                "0xf78b278be53f454c": 2,
1336                "0xaf2c0297a23e6d3d": 1,
1337                "0x49eaaf1b548a0cb0": 1,
1338                "0x91d5df18b0d2cf58": 1,
1339                "0xed99c5acb25eedf5": 3,
1340                "0xcbca25e39f142387": 2,
1341                "0x687ad44ad37f03c2": 1,
1342                "0xab3c0572291feb8b": 1,
1343                "0xbc9d89904f5b923f": 1,
1344                "0x37c8bb1350a9a2a8": 1
1345            }
1346        });
1347        let new_spec: RuntimeSpec = serde_json::from_value(new_response).unwrap();
1348
1349        assert_eq!(old_spec, new_spec);
1350    }
1351
1352    #[test]
1353    fn can_deserialize_from_number_or_string() {
1354        #[derive(Debug, Deserialize)]
1355        struct Foo64 {
1356            #[serde(with = "super::unsigned_number_as_string")]
1357            num: u64,
1358        }
1359        #[derive(Debug, Deserialize)]
1360        struct Foo32 {
1361            #[serde(with = "super::unsigned_number_as_string")]
1362            num: u128,
1363        }
1364
1365        let from_string = serde_json::json!({
1366            "num": "123"
1367        });
1368        let from_num = serde_json::json!({
1369            "num": 123
1370        });
1371        let from_err = serde_json::json!({
1372            "num": "123a"
1373        });
1374
1375        let f1: Foo64 =
1376            serde_json::from_value(from_string.clone()).expect("can deser string into u64");
1377        let f2: Foo32 = serde_json::from_value(from_string).expect("can deser string into u32");
1378        let f3: Foo64 = serde_json::from_value(from_num.clone()).expect("can deser num into u64");
1379        let f4: Foo32 = serde_json::from_value(from_num).expect("can deser num into u32");
1380
1381        assert_eq!(f1.num, 123);
1382        assert_eq!(f2.num, 123);
1383        assert_eq!(f3.num, 123);
1384        assert_eq!(f4.num, 123);
1385
1386        // Invalid things should lead to an error:
1387        let _ = serde_json::from_value::<Foo32>(from_err)
1388            .expect_err("can't deser invalid num into u32");
1389    }
1390
1391    #[test]
1392    fn chain_head_initialized() {
1393        // Latest format version.
1394        let event = serde_json::json!({
1395            "finalizedBlockHashes": ["0x1", "0x2"],
1396        });
1397        let decoded: Initialized<String> = serde_json::from_value(event).unwrap();
1398        assert_eq!(
1399            decoded.finalized_block_hashes,
1400            vec!["0x1".to_string(), "0x2".to_string()]
1401        );
1402
1403        // Old format.
1404        let event = serde_json::json!({
1405            "finalizedBlockHash": "0x1",
1406        });
1407        let decoded: Initialized<String> = serde_json::from_value(event).unwrap();
1408        assert_eq!(decoded.finalized_block_hashes, vec!["0x1".to_string()]);
1409
1410        // Wrong format.
1411        let event = serde_json::json!({
1412            "finalizedBlockHash": ["0x1"],
1413        });
1414        let _ = serde_json::from_value::<Initialized<String>>(event).unwrap_err();
1415    }
1416}