Skip to content

Commit

Permalink
[RPC-Spec-V2] chainHead: use integer for block index and adjust Runti…
Browse files Browse the repository at this point in the history
…meVersion JSON format (paritytech#1666)

This PR adjusts the serialized format of the the returned RuntimeVersion
in the rpc-spec-v2 methods. This is done to match the format defined
here:
https://paritytech.github.io/json-rpc-interface-spec/api/chainHead_unstable_follow.html#about-the-runtime

- ##### `apis` field as object
`apis` field of `RuntimeVersion` is now returned as an object, e.g. 
```
"apis": {
      "0xdf6acb689907609b": 3,
      "0x37e397fc7c91f5e4": 1,
}
```
instead of 
```
"apis": [
      ["0xdf6acb689907609b", 3],
      ["0x37e397fc7c91f5e4", 1],
]
```
- ##### removed `stateVersion` and `authoringVersion`
`stateVersion` and `authoringVersion` are no longer returned in the
`RuntimeVersion` JSON Object.

- ##### block index in chain head events as integer

### Related Issues

Closes: paritytech#1507
Closes: paritytech#1146

### Testing Done
Adjusted existing tests to make sure data is returned in the correct
format.
  • Loading branch information
tadeohepperle authored Sep 29, 2023
1 parent 6936565 commit 2985373
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 37 deletions.
1 change: 0 additions & 1 deletion substrate/client/rpc-spec-v2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ tokio = { version = "1.22.0", features = ["sync"] }
array-bytes = "6.1"
log = "0.4.17"
futures-util = { version = "0.3.19", default-features = false }

[dev-dependencies]
serde_json = "1.0"
tokio = { version = "1.22.0", features = ["macros"] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ where
let parent = match parent {
Some(parent) => parent,
// Nothing to compare against, always report.
None => return Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt })),
None => return Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt.into() })),
};

let parent_rt = match self.client.runtime_version_at(parent) {
Expand All @@ -168,7 +168,7 @@ where

// Report the runtime version change.
if block_rt != parent_rt {
Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt }))
Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: block_rt.into() }))
} else {
None
}
Expand Down
1 change: 0 additions & 1 deletion substrate/client/rpc-spec-v2/src/chain_head/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ impl From<Error> for ErrorObject<'static> {
Error::InvalidSubscriptionID => ErrorObject::owned(INVALID_SUB_ID, msg, None::<()>),
Error::InvalidContinue => ErrorObject::owned(INVALID_CONTINUE, msg, None::<()>),
}
.into()
}
}

Expand Down
54 changes: 46 additions & 8 deletions substrate/client/rpc-spec-v2/src/chain_head/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use sp_api::ApiError;
use sp_version::RuntimeVersion;
use std::collections::BTreeMap;

/// The operation could not be processed due to an error.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand All @@ -35,11 +36,47 @@ pub struct ErrorEvent {
/// This event is generated for:
/// - the first announced block by the follow subscription
/// - blocks that suffered a change in runtime compared with their parents
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeVersionEvent {
/// The runtime version.
pub spec: RuntimeVersion,
pub spec: ChainHeadRuntimeVersion,
}

/// Simplified type clone of `sp_version::RuntimeVersion`. Used instead of
/// `sp_version::RuntimeVersion` to conform to RPC spec V2.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ChainHeadRuntimeVersion {
/// Identifies the different Substrate runtimes.
pub spec_name: String,
/// Name of the implementation of the spec.
pub impl_name: String,
/// Version of the runtime specification.
pub spec_version: u32,
/// Version of the implementation of the specification.
pub impl_version: u32,
/// Map of all supported API "features" and their versions.
pub apis: BTreeMap<String, u32>,
/// Transaction version.
pub transaction_version: u32,
}

impl From<RuntimeVersion> for ChainHeadRuntimeVersion {
fn from(val: RuntimeVersion) -> Self {
Self {
spec_name: val.spec_name.into(),
impl_name: val.impl_name.into(),
spec_version: val.spec_version,
impl_version: val.impl_version,
apis: val
.apis
.into_iter()
.map(|(api, version)| (sp_core::bytes::to_hex(api, false), *version))
.collect(),
transaction_version: val.transaction_version,
}
}
}

/// The runtime event generated if the `follow` subscription
Expand Down Expand Up @@ -380,7 +417,7 @@ mod tests {
..Default::default()
};

let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime });
let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.into() });
let mut initialized = Initialized {
finalized_block_hash: "0x1".into(),
finalized_block_runtime: Some(runtime_event),
Expand All @@ -391,8 +428,8 @@ mod tests {
let ser = serde_json::to_string(&event).unwrap();
let exp = concat!(
r#"{"event":"initialized","finalizedBlockHash":"0x1","#,
r#""finalizedBlockRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","authoringVersion":0,"#,
r#""specVersion":1,"implVersion":0,"apis":[],"transactionVersion":0,"stateVersion":0}}}"#,
r#""finalizedBlockRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","#,
r#""specVersion":1,"implVersion":0,"apis":{},"transactionVersion":0}}}"#,
);
assert_eq!(ser, exp);

Expand Down Expand Up @@ -429,10 +466,11 @@ mod tests {
spec_name: "ABC".into(),
impl_name: "Impl".into(),
spec_version: 1,
apis: vec![([0, 0, 0, 0, 0, 0, 0, 0], 2), ([1, 0, 0, 0, 0, 0, 0, 0], 3)].into(),
..Default::default()
};

let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime });
let runtime_event = RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.into() });
let mut new_block = NewBlock {
block_hash: "0x1".into(),
parent_block_hash: "0x2".into(),
Expand All @@ -445,8 +483,8 @@ mod tests {
let ser = serde_json::to_string(&event).unwrap();
let exp = concat!(
r#"{"event":"newBlock","blockHash":"0x1","parentBlockHash":"0x2","#,
r#""newRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","authoringVersion":0,"#,
r#""specVersion":1,"implVersion":0,"apis":[],"transactionVersion":0,"stateVersion":0}}}"#,
r#""newRuntime":{"type":"valid","spec":{"specName":"ABC","implName":"Impl","#,
r#""specVersion":1,"implVersion":0,"apis":{"0x0000000000000000":2,"0x0100000000000000":3},"transactionVersion":0}}}"#,
);
assert_eq!(ser, exp);

Expand Down
9 changes: 5 additions & 4 deletions substrate/client/rpc-spec-v2/src/chain_head/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,17 +234,17 @@ async fn follow_with_runtime() {
let event: FollowEvent<String> = get_next_event(&mut sub).await;

// it is basically json-encoded substrate_test_runtime_client::runtime::VERSION
let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":0,\
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\
[\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\
[\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\
[\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\
[\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":1}";
[\"0xed99c5acb25eedf5\",3],[\"0xfbc577b9d747efd6\",1]],\"transactionVersion\":1,\"stateVersion\":0}";

let runtime: RuntimeVersion = serde_json::from_str(runtime_str).unwrap();

let finalized_block_runtime =
Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone() }));
Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone().into() }));
// Runtime must always be reported with the first event.
let expected = FollowEvent::Initialized(Initialized {
finalized_block_hash: format!("{:?}", finalized_hash),
Expand Down Expand Up @@ -308,7 +308,8 @@ async fn follow_with_runtime() {
let best_hash = block.header.hash();
client.import(BlockOrigin::Own, block.clone()).await.unwrap();

let new_runtime = Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone() }));
let new_runtime =
Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec: runtime.clone().into() }));
let event: FollowEvent<String> = get_next_event(&mut sub).await;
let expected = FollowEvent::NewBlock(NewBlock {
block_hash: format!("{:?}", best_hash),
Expand Down
24 changes: 3 additions & 21 deletions substrate/client/rpc-spec-v2/src/transaction/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use serde::{Deserialize, Serialize};
#[serde(rename_all = "camelCase")]
pub struct TransactionBroadcasted {
/// The number of peers the transaction was broadcasted to.
#[serde(with = "as_string")]
pub num_peers: usize,
}

Expand All @@ -45,7 +44,6 @@ pub struct TransactionBlock<Hash> {
/// The hash of the block the transaction was included into.
pub hash: Hash,
/// The index (zero-based) of the transaction within the body of the block.
#[serde(with = "as_string")]
pub index: usize,
}

Expand Down Expand Up @@ -224,22 +222,6 @@ impl<Hash> From<TransactionEventIR<Hash>> for TransactionEvent<Hash> {
}
}

/// Serialize and deserialize helper as string.
mod as_string {
use super::*;
use serde::{Deserializer, Serializer};

pub fn serialize<S: Serializer>(data: &usize, serializer: S) -> Result<S::Ok, S::Error> {
data.to_string().serialize(serializer)
}

pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<usize, D::Error> {
String::deserialize(deserializer)?
.parse()
.map_err(|e| serde::de::Error::custom(format!("Parsing failed: {}", e)))
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -263,7 +245,7 @@ mod tests {
TransactionEvent::Broadcasted(TransactionBroadcasted { num_peers: 2 });
let ser = serde_json::to_string(&event).unwrap();

let exp = r#"{"event":"broadcasted","numPeers":"2"}"#;
let exp = r#"{"event":"broadcasted","numPeers":2}"#;
assert_eq!(ser, exp);

let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap();
Expand All @@ -288,7 +270,7 @@ mod tests {
}));
let ser = serde_json::to_string(&event).unwrap();

let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"2"}}"#;
let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":2}}"#;
assert_eq!(ser, exp);

let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
Expand All @@ -303,7 +285,7 @@ mod tests {
});
let ser = serde_json::to_string(&event).unwrap();

let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"10"}}"#;
let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":10}}"#;
assert_eq!(ser, exp);

let event_dec: TransactionEvent<H256> = serde_json::from_str(exp).unwrap();
Expand Down

0 comments on commit 2985373

Please sign in to comment.