Skip to content

Commit 79cdb2b

Browse files
committed
fixup! feat(truapi-server): add Rust host runtime
1 parent 94e0bd0 commit 79cdb2b

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

  • rust/crates/truapi-server/src/host_logic/statement_store
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//! Statement-store JSON-RPC shapes mirrored from `sp_statement_store`.
2+
//!
3+
//! See the upstream RPC methods plus `TopicFilter` / `StatementEvent` types:
4+
//! <https://github.com/paritytech/polkadot-sdk/blob/f2f3aa6a8fda8ea52282da9711b3c5da4ba82529/substrate/client/rpc-api/src/statement/mod.rs#L19-L117>
5+
//! <https://github.com/paritytech/polkadot-sdk/blob/f2f3aa6a8fda8ea52282da9711b3c5da4ba82529/substrate/primitives/statement-store/src/store_api.rs#L41-L54>
6+
//! <https://github.com/paritytech/polkadot-sdk/blob/f2f3aa6a8fda8ea52282da9711b3c5da4ba82529/substrate/primitives/statement-store/src/store_api.rs#L204-L221>
7+
8+
use serde_json::Value;
9+
10+
use super::StatementStoreParseError;
11+
12+
/// Statement-store RPC method used to open a topic subscription.
13+
pub const SUBSCRIBE_STATEMENT_METHOD: &str = "statement_subscribeStatement";
14+
/// Statement-store RPC method used to close a topic subscription.
15+
pub const UNSUBSCRIBE_STATEMENT_METHOD: &str = "statement_unsubscribeStatement";
16+
/// Statement-store RPC method used to submit a signed statement.
17+
pub const SUBMIT_STATEMENT_METHOD: &str = "statement_submit";
18+
/// Maximum `matchAll` topic count accepted by the statement-store RPC.
19+
pub const MAX_MATCH_ALL_TOPICS: usize = 4;
20+
/// Maximum `matchAny` topic count accepted by the statement-store RPC.
21+
pub const MAX_MATCH_ANY_TOPICS: usize = 128;
22+
23+
/// Decoded `newStatements` subscription notification.
24+
#[derive(Debug, Clone, PartialEq, Eq)]
25+
pub struct NewStatements {
26+
/// Remote subscription id included in the notification.
27+
pub remote_subscription_id: String,
28+
/// SCALE-encoded signed statements carried by the notification.
29+
pub statements: Vec<Vec<u8>>,
30+
/// Optional server-side backlog count.
31+
pub remaining: Option<u64>,
32+
}
33+
34+
/// Topic filter flavor used by statement-store subscribe requests.
35+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36+
pub enum TopicFilterKind {
37+
/// Require every listed topic to match.
38+
MatchAll,
39+
/// Accept any listed topic match.
40+
MatchAny,
41+
}
42+
43+
/// Parse a statement-store subscription result value.
44+
pub fn parse_new_statements_result(
45+
remote_subscription_id: String,
46+
result: &Value,
47+
) -> Result<NewStatements, StatementStoreParseError> {
48+
if result.get("event").and_then(Value::as_str) != Some("newStatements") {
49+
return Err(StatementStoreParseError::Malformed(
50+
"result is not a newStatements event".to_string(),
51+
));
52+
}
53+
let data = result
54+
.get("data")
55+
.ok_or_else(|| StatementStoreParseError::Malformed("missing data".to_string()))?;
56+
let statement_values = data
57+
.get("statements")
58+
.and_then(Value::as_array)
59+
.ok_or_else(|| StatementStoreParseError::Malformed("missing statements".to_string()))?;
60+
let statements = statement_values
61+
.iter()
62+
.map(|value| {
63+
let Some(hex) = value.as_str() else {
64+
return Err(StatementStoreParseError::Malformed(
65+
"statement is not a hex string".to_string(),
66+
));
67+
};
68+
decode_hex(hex)
69+
})
70+
.collect::<Result<Vec<_>, _>>()?;
71+
let remaining = data
72+
.get("remaining")
73+
.map(|value| {
74+
value.as_u64().ok_or_else(|| {
75+
StatementStoreParseError::Malformed("remaining is not an integer".to_string())
76+
})
77+
})
78+
.transpose()?;
79+
80+
Ok(NewStatements {
81+
remote_subscription_id,
82+
statements,
83+
remaining,
84+
})
85+
}
86+
87+
fn decode_hex(value: &str) -> Result<Vec<u8>, StatementStoreParseError> {
88+
hex::decode(value.strip_prefix("0x").unwrap_or(value))
89+
.map_err(|error| StatementStoreParseError::InvalidStatementHex(error.to_string()))
90+
}
91+
92+
#[cfg(test)]
93+
mod tests {
94+
use super::*;
95+
96+
#[test]
97+
fn parses_dotli_sdk_new_statements_result() {
98+
let result = serde_json::json!({
99+
"event": "newStatements",
100+
"data": {
101+
"statements": ["0xdeadbeef", "0xcafe"],
102+
"remaining": 0,
103+
},
104+
});
105+
106+
assert_eq!(
107+
parse_new_statements_result("remote-sub".to_string(), &result).unwrap(),
108+
NewStatements {
109+
remote_subscription_id: "remote-sub".to_string(),
110+
statements: vec![vec![0xde, 0xad, 0xbe, 0xef], vec![0xca, 0xfe]],
111+
remaining: Some(0),
112+
}
113+
);
114+
}
115+
}

0 commit comments

Comments
 (0)