mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 06:51:07 +00:00
chainHead_storage: Backport queries for value types (#14551)
* chainHead/events: Add storage params and events Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/tests: Check storage events serialization / deserialization Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/error: Add error for invalid WaitForContinue storage call Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/storage: Use new items params Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/tests: Adjust storage tests to the new API Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/events: Generalize StorageQuery by provided key Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chain_head: Add dedicated ChainHeadStorage client for queries Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/storage: Implement queries for hashes of values Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/tests: Check storage queries for hashes of values Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead: Improve API documentation wrt multiple entries Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead/event: Rename StorageQueue ty to queue_ty Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chianHead: Add helper to encode chainHead results as hex str Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update client/rpc-spec-v2/src/chain_head/error.rs Co-authored-by: Sebastian Kunert <skunert49@gmail.com> * chainHead: Change the `queryResult` to a plain `Result` Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead: Stop producing events after the first error Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * chainHead: Change child_key to child_trie API param Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: Sebastian Kunert <skunert49@gmail.com>
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
use crate::chain_head::test_utils::ChainHeadMockClient;
|
||||
use crate::chain_head::{
|
||||
event::{ChainHeadStorageEvent, StorageQuery, StorageQueryType, StorageResultType},
|
||||
test_utils::ChainHeadMockClient,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use assert_matches::assert_matches;
|
||||
@@ -6,6 +9,7 @@ use codec::{Decode, Encode};
|
||||
use futures::Future;
|
||||
use jsonrpsee::{
|
||||
core::{error::Error, server::rpc_module::Subscription as RpcSubscription},
|
||||
rpc_params,
|
||||
types::{error::CallError, EmptyServerParams as EmptyParams},
|
||||
RpcModule,
|
||||
};
|
||||
@@ -16,9 +20,9 @@ use sp_api::BlockT;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::{
|
||||
hexdisplay::HexDisplay,
|
||||
storage::well_known_keys::{self, CODE},
|
||||
testing::TaskExecutor,
|
||||
Blake2Hasher, Hasher,
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
@@ -288,14 +292,14 @@ async fn get_genesis() {
|
||||
|
||||
let genesis: String =
|
||||
api.call("chainHead_unstable_genesisHash", EmptyParams::new()).await.unwrap();
|
||||
assert_eq!(genesis, format!("0x{}", HexDisplay::from(&CHAIN_GENESIS)));
|
||||
assert_eq!(genesis, hex_string(&CHAIN_GENESIS));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_header() {
|
||||
let (_client, api, _sub, sub_id, block) = setup_api().await;
|
||||
let block_hash = format!("{:?}", block.header.hash());
|
||||
let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH));
|
||||
let invalid_hash = hex_string(&INVALID_HASH);
|
||||
|
||||
// Invalid subscription ID must produce no results.
|
||||
let res: Option<String> = api
|
||||
@@ -324,7 +328,7 @@ async fn get_header() {
|
||||
async fn get_body() {
|
||||
let (mut client, api, mut block_sub, sub_id, block) = setup_api().await;
|
||||
let block_hash = format!("{:?}", block.header.hash());
|
||||
let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH));
|
||||
let invalid_hash = hex_string(&INVALID_HASH);
|
||||
|
||||
// Subscription ID is stale the disjoint event is emitted.
|
||||
let mut sub = api
|
||||
@@ -377,7 +381,7 @@ async fn get_body() {
|
||||
let mut sub = api.subscribe("chainHead_unstable_body", [&sub_id, &block_hash]).await.unwrap();
|
||||
let event: ChainHeadEvent<String> = get_next_event(&mut sub).await;
|
||||
// Hex encoded scale encoded string for the vector of extrinsics.
|
||||
let expected = format!("0x{:?}", HexDisplay::from(&block.extrinsics.encode()));
|
||||
let expected = hex_string(&block.extrinsics.encode());
|
||||
assert_matches!(event,
|
||||
ChainHeadEvent::Done(done) if done.result == expected
|
||||
);
|
||||
@@ -387,7 +391,7 @@ async fn get_body() {
|
||||
async fn call_runtime() {
|
||||
let (_client, api, _sub, sub_id, block) = setup_api().await;
|
||||
let block_hash = format!("{:?}", block.header.hash());
|
||||
let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH));
|
||||
let invalid_hash = hex_string(&INVALID_HASH);
|
||||
|
||||
// Subscription ID is stale the disjoint event is emitted.
|
||||
let mut sub = api
|
||||
@@ -426,7 +430,7 @@ async fn call_runtime() {
|
||||
|
||||
let alice_id = AccountKeyring::Alice.to_account_id();
|
||||
// Hex encoded scale encoded bytes representing the call parameters.
|
||||
let call_parameters = format!("0x{:?}", HexDisplay::from(&alice_id.encode()));
|
||||
let call_parameters = hex_string(&alice_id.encode());
|
||||
let mut sub = api
|
||||
.subscribe(
|
||||
"chainHead_unstable_call",
|
||||
@@ -495,7 +499,7 @@ async fn call_runtime_without_flag() {
|
||||
|
||||
// Valid runtime call on a subscription started with `with_runtime` false.
|
||||
let alice_id = AccountKeyring::Alice.to_account_id();
|
||||
let call_parameters = format!("0x{:?}", HexDisplay::from(&alice_id.encode()));
|
||||
let call_parameters = hex_string(&alice_id.encode());
|
||||
let err = api
|
||||
.subscribe(
|
||||
"chainHead_unstable_call",
|
||||
@@ -510,23 +514,37 @@ async fn call_runtime_without_flag() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_storage() {
|
||||
async fn get_storage_hash() {
|
||||
let (mut client, api, mut block_sub, sub_id, block) = setup_api().await;
|
||||
let block_hash = format!("{:?}", block.header.hash());
|
||||
let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH));
|
||||
let key = format!("0x{:?}", HexDisplay::from(&KEY));
|
||||
let invalid_hash = hex_string(&INVALID_HASH);
|
||||
let key = hex_string(&KEY);
|
||||
|
||||
// Subscription ID is stale the disjoint event is emitted.
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", ["invalid_sub_id", &invalid_hash, &key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
"invalid_sub_id",
|
||||
&invalid_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Hash }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_eq!(event, ChainHeadEvent::<String>::Disjoint);
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_eq!(event, ChainHeadStorageEvent::<String>::Disjoint);
|
||||
|
||||
// Valid subscription ID with invalid block hash will error.
|
||||
let err = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &invalid_hash, &key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&invalid_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Hash }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert_matches!(err,
|
||||
@@ -535,11 +553,19 @@ async fn get_storage() {
|
||||
|
||||
// Valid call without storage at the key.
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Hash }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<Option<String>> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadEvent::<Option<String>>::Done(done) if done.result.is_none());
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
// The `Done` event is generated directly since the key does not have any value associated.
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
|
||||
// Import a new block with storage changes.
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
@@ -559,75 +585,236 @@ async fn get_storage() {
|
||||
);
|
||||
|
||||
// Valid call with storage at the key.
|
||||
let expected_value = Some(format!("0x{:?}", HexDisplay::from(&VALUE)));
|
||||
let expected_hash = format!("{:?}", Blake2Hasher::hash(&VALUE));
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Hash }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<Option<String>> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadEvent::<Option<String>>::Done(done) if done.result == expected_value);
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::<String>::Items(res) if res.items.len() == 1 && res.items[0].key == key && res.items[0].result == StorageResultType::Hash(expected_hash));
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
|
||||
// Child value set in `setup_api`.
|
||||
let child_info = format!("0x{:?}", HexDisplay::from(b"child"));
|
||||
let child_info = hex_string(&CHILD_STORAGE_KEY);
|
||||
let genesis_hash = format!("{:?}", client.genesis_hash());
|
||||
let expected_value = Some(format!("0x{:?}", HexDisplay::from(&CHILD_VALUE)));
|
||||
let expected_hash = format!("{:?}", Blake2Hasher::hash(&CHILD_VALUE));
|
||||
println!("Expe: {:?}", expected_hash);
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &genesis_hash, &key, &child_info])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&genesis_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Hash }],
|
||||
&child_info
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<Option<String>> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadEvent::<Option<String>>::Done(done) if done.result == expected_value);
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::<String>::Items(res) if res.items.len() == 1 && res.items[0].key == key && res.items[0].result == StorageResultType::Hash(expected_hash));
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_storage_value() {
|
||||
let (mut client, api, mut block_sub, sub_id, block) = setup_api().await;
|
||||
let block_hash = format!("{:?}", block.header.hash());
|
||||
let invalid_hash = hex_string(&INVALID_HASH);
|
||||
let key = hex_string(&KEY);
|
||||
|
||||
// Subscription ID is stale the disjoint event is emitted.
|
||||
let mut sub = api
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
"invalid_sub_id",
|
||||
&invalid_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Value }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_eq!(event, ChainHeadStorageEvent::<String>::Disjoint);
|
||||
|
||||
// Valid subscription ID with invalid block hash will error.
|
||||
let err = api
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&invalid_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Value }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert_matches!(err,
|
||||
Error::Call(CallError::Custom(ref err)) if err.code() == 2001 && err.message() == "Invalid block hash"
|
||||
);
|
||||
|
||||
// Valid call without storage at the key.
|
||||
let mut sub = api
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Value }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
// The `Done` event is generated directly since the key does not have any value associated.
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
|
||||
// Import a new block with storage changes.
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
builder.push_storage_change(KEY.to_vec(), Some(VALUE.to_vec())).unwrap();
|
||||
let block = builder.build().unwrap().block;
|
||||
let block_hash = format!("{:?}", block.header.hash());
|
||||
client.import(BlockOrigin::Own, block.clone()).await.unwrap();
|
||||
|
||||
// Ensure the imported block is propagated and pinned for this subscription.
|
||||
assert_matches!(
|
||||
get_next_event::<FollowEvent<String>>(&mut block_sub).await,
|
||||
FollowEvent::NewBlock(_)
|
||||
);
|
||||
assert_matches!(
|
||||
get_next_event::<FollowEvent<String>>(&mut block_sub).await,
|
||||
FollowEvent::BestBlockChanged(_)
|
||||
);
|
||||
|
||||
// Valid call with storage at the key.
|
||||
let expected_value = hex_string(&VALUE);
|
||||
let mut sub = api
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Value }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::<String>::Items(res) if res.items.len() == 1 && res.items[0].key == key && res.items[0].result == StorageResultType::Value(expected_value));
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
|
||||
// Child value set in `setup_api`.
|
||||
let child_info = hex_string(b"child");
|
||||
let genesis_hash = format!("{:?}", client.genesis_hash());
|
||||
let expected_value = hex_string(&CHILD_VALUE);
|
||||
let mut sub = api
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&genesis_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Value }],
|
||||
&child_info
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::<String>::Items(res) if res.items.len() == 1 && res.items[0].key == key && res.items[0].result == StorageResultType::Value(expected_value));
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_storage_wrong_key() {
|
||||
let (mut _client, api, mut _block_sub, sub_id, block) = setup_api().await;
|
||||
let block_hash = format!("{:?}", block.header.hash());
|
||||
let key = format!("0x{:?}", HexDisplay::from(&KEY));
|
||||
let key = hex_string(&KEY);
|
||||
|
||||
// Key is prefixed by CHILD_STORAGE_KEY_PREFIX.
|
||||
let mut prefixed_key = well_known_keys::CHILD_STORAGE_KEY_PREFIX.to_vec();
|
||||
prefixed_key.extend_from_slice(&KEY);
|
||||
let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key));
|
||||
let prefixed_key = hex_string(&prefixed_key);
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &prefixed_key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key: prefixed_key, queue_type: StorageQueryType::Value }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<Option<String>> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadEvent::<Option<String>>::Done(done) if done.result.is_none());
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
|
||||
// Key is prefixed by DEFAULT_CHILD_STORAGE_KEY_PREFIX.
|
||||
let mut prefixed_key = well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.to_vec();
|
||||
prefixed_key.extend_from_slice(&KEY);
|
||||
let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key));
|
||||
let prefixed_key = hex_string(&prefixed_key);
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &prefixed_key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key: prefixed_key, queue_type: StorageQueryType::Value }]
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<Option<String>> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadEvent::<Option<String>>::Done(done) if done.result.is_none());
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
|
||||
// Child key is prefixed by CHILD_STORAGE_KEY_PREFIX.
|
||||
let mut prefixed_key = well_known_keys::CHILD_STORAGE_KEY_PREFIX.to_vec();
|
||||
prefixed_key.extend_from_slice(b"child");
|
||||
let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key));
|
||||
let prefixed_key = hex_string(&prefixed_key);
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key, &prefixed_key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key: key.clone(), queue_type: StorageQueryType::Value }],
|
||||
&prefixed_key
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<Option<String>> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadEvent::<Option<String>>::Done(done) if done.result.is_none());
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
|
||||
// Child key is prefixed by DEFAULT_CHILD_STORAGE_KEY_PREFIX.
|
||||
let mut prefixed_key = well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.to_vec();
|
||||
prefixed_key.extend_from_slice(b"child");
|
||||
let prefixed_key = format!("0x{:?}", HexDisplay::from(&prefixed_key));
|
||||
let prefixed_key = hex_string(&prefixed_key);
|
||||
let mut sub = api
|
||||
.subscribe("chainHead_unstable_storage", [&sub_id, &block_hash, &key, &prefixed_key])
|
||||
.subscribe(
|
||||
"chainHead_unstable_storage",
|
||||
rpc_params![
|
||||
&sub_id,
|
||||
&block_hash,
|
||||
vec![StorageQuery { key, queue_type: StorageQueryType::Value }],
|
||||
&prefixed_key
|
||||
],
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let event: ChainHeadEvent<Option<String>> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadEvent::<Option<String>>::Done(done) if done.result.is_none());
|
||||
let event: ChainHeadStorageEvent<String> = get_next_event(&mut sub).await;
|
||||
assert_matches!(event, ChainHeadStorageEvent::Done);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -848,14 +1035,14 @@ async fn follow_with_unpin() {
|
||||
);
|
||||
|
||||
// Unpin an invalid subscription ID must return Ok(()).
|
||||
let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH));
|
||||
let invalid_hash = hex_string(&INVALID_HASH);
|
||||
let _res: () = api
|
||||
.call("chainHead_unstable_unpin", ["invalid_sub_id", &invalid_hash])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Valid subscription with invalid block hash.
|
||||
let invalid_hash = format!("0x{:?}", HexDisplay::from(&INVALID_HASH));
|
||||
let invalid_hash = hex_string(&INVALID_HASH);
|
||||
let err = api
|
||||
.call::<_, serde_json::Value>("chainHead_unstable_unpin", [&sub_id, &invalid_hash])
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user