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:
Alexandru Vasile
2023-07-21 19:56:40 +03:00
committed by GitHub
parent 649be3aaaa
commit 1fef5ee4a4
7 changed files with 703 additions and 110 deletions
@@ -241,6 +241,85 @@ pub enum ChainHeadEvent<T> {
Disjoint,
}
/// The storage item received as paramter.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StorageQuery<Key> {
/// The provided key.
pub key: Key,
/// The type of the storage query.
#[serde(rename = "type")]
pub queue_type: StorageQueryType,
}
/// The type of the storage query.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum StorageQueryType {
/// Fetch the value of the provided key.
Value,
/// Fetch the hash of the value of the provided key.
Hash,
/// Fetch the closest descendant merkle value.
ClosestDescendantMerkleValue,
/// Fetch the values of all descendants of they provided key.
DescendantsValues,
/// Fetch the hashes of the values of all descendants of they provided key.
DescendantsHashes,
}
/// The storage result.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StorageResult<T> {
/// The hex-encoded key of the result.
pub key: String,
/// The result of the query.
#[serde(flatten)]
pub result: StorageResultType<T>,
}
/// The type of the storage query.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum StorageResultType<T> {
/// Fetch the value of the provided key.
Value(T),
/// Fetch the hash of the value of the provided key.
Hash(T),
/// Fetch the closest descendant merkle value.
ClosestDescendantMerkleValue(T),
}
/// The event generated by storage method.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[serde(tag = "event")]
pub enum ChainHeadStorageEvent<T> {
/// The request produced multiple result items.
Items(ItemsEvent<T>),
/// The request produced multiple result items.
WaitForContinue,
/// The request completed successfully and all the results were provided.
Done,
/// The resources requested are inaccessible.
///
/// Resubmitting the request later might succeed.
Inaccessible,
/// An error occurred. This is definitive.
Error(ErrorEvent),
/// The provided subscription ID is stale or invalid.
Disjoint,
}
/// The request produced multiple result items.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ItemsEvent<T> {
/// The resulting items.
pub items: Vec<StorageResult<T>>,
}
#[cfg(test)]
mod tests {
use super::*;
@@ -475,4 +554,152 @@ mod tests {
let conf_dec: NetworkConfig = serde_json::from_str(exp).unwrap();
assert_eq!(conf_dec, conf);
}
#[test]
fn chain_head_storage_query() {
// Item with Value.
let item = StorageQuery { key: "0x1", queue_type: StorageQueryType::Value };
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","type":"value"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageQuery<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
// Item with Hash.
let item = StorageQuery { key: "0x1", queue_type: StorageQueryType::Hash };
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","type":"hash"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageQuery<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
// Item with DescendantsValues.
let item = StorageQuery { key: "0x1", queue_type: StorageQueryType::DescendantsValues };
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","type":"descendants-values"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageQuery<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
// Item with DescendantsHashes.
let item = StorageQuery { key: "0x1", queue_type: StorageQueryType::DescendantsHashes };
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","type":"descendants-hashes"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageQuery<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
// Item with Merkle.
let item =
StorageQuery { key: "0x1", queue_type: StorageQueryType::ClosestDescendantMerkleValue };
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","type":"closest-descendant-merkle-value"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageQuery<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
}
#[test]
fn chain_head_storage_result() {
// Item with Value.
let item = StorageResult { key: "0x1".into(), result: StorageResultType::Value("res") };
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","value":"res"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageResult<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
// Item with Hash.
let item = StorageResult { key: "0x1".into(), result: StorageResultType::Hash("res") };
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","hash":"res"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageResult<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
// Item with DescendantsValues.
let item = StorageResult {
key: "0x1".into(),
result: StorageResultType::ClosestDescendantMerkleValue("res"),
};
// Encode
let ser = serde_json::to_string(&item).unwrap();
let exp = r#"{"key":"0x1","closest-descendant-merkle-value":"res"}"#;
assert_eq!(ser, exp);
// Decode
let dec: StorageResult<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, item);
}
#[test]
fn chain_head_storage_event() {
// Event with Items.
let event = ChainHeadStorageEvent::Items(ItemsEvent {
items: vec![
StorageResult { key: "0x1".into(), result: StorageResultType::Value("first") },
StorageResult { key: "0x2".into(), result: StorageResultType::Hash("second") },
],
});
// Encode
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"items","items":[{"key":"0x1","value":"first"},{"key":"0x2","hash":"second"}]}"#;
assert_eq!(ser, exp);
// Decode
let dec: ChainHeadStorageEvent<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, event);
// Event with WaitForContinue.
let event = ChainHeadStorageEvent::WaitForContinue;
// Encode
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"wait-for-continue"}"#;
assert_eq!(ser, exp);
// Decode
let dec: ChainHeadStorageEvent<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, event);
// Event with Done.
let event = ChainHeadStorageEvent::Done;
// Encode
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"done"}"#;
assert_eq!(ser, exp);
// Decode
let dec: ChainHeadStorageEvent<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, event);
// Event with Inaccessible.
let event = ChainHeadStorageEvent::Inaccessible;
// Encode
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"inaccessible"}"#;
assert_eq!(ser, exp);
// Decode
let dec: ChainHeadStorageEvent<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, event);
// Event with Inaccessible.
let event = ChainHeadStorageEvent::Error(ErrorEvent { error: "reason".into() });
// Encode
let ser = serde_json::to_string(&event).unwrap();
let exp = r#"{"event":"error","error":"reason"}"#;
assert_eq!(ser, exp);
// Decode
let dec: ChainHeadStorageEvent<&str> = serde_json::from_str(exp).unwrap();
assert_eq!(dec, event);
}
}