1use crate::codec::*;
13
14pub const TAG_HANDSHAKE_REQ: u8 = 0;
20pub const TAG_HANDSHAKE_RESP: u8 = 1;
21pub const TAG_FEATURE_SUPPORTED_REQ: u8 = 2;
22pub const TAG_FEATURE_SUPPORTED_RESP: u8 = 3;
23pub const TAG_PUSH_NOTIFICATION_REQ: u8 = 4;
24pub const TAG_PUSH_NOTIFICATION_RESP: u8 = 5;
25pub const TAG_NAVIGATE_TO_REQ: u8 = 6;
26pub const TAG_NAVIGATE_TO_RESP: u8 = 7;
27pub const TAG_DEVICE_PERMISSION_REQ: u8 = 8;
28pub const TAG_DEVICE_PERMISSION_RESP: u8 = 9;
29pub const TAG_REMOTE_PERMISSION_REQ: u8 = 10;
30pub const TAG_REMOTE_PERMISSION_RESP: u8 = 11;
31pub const TAG_LOCAL_STORAGE_READ_REQ: u8 = 12;
32pub const TAG_LOCAL_STORAGE_READ_RESP: u8 = 13;
33pub const TAG_LOCAL_STORAGE_WRITE_REQ: u8 = 14;
34pub const TAG_LOCAL_STORAGE_WRITE_RESP: u8 = 15;
35pub const TAG_LOCAL_STORAGE_CLEAR_REQ: u8 = 16;
36pub const TAG_LOCAL_STORAGE_CLEAR_RESP: u8 = 17;
37pub const TAG_ACCOUNT_STATUS_START: u8 = 18;
39pub const TAG_ACCOUNT_STATUS_STOP: u8 = 19;
40pub const TAG_ACCOUNT_STATUS_INTERRUPT: u8 = 20;
41pub const TAG_ACCOUNT_STATUS_RECEIVE: u8 = 21;
42pub const TAG_ACCOUNT_GET_REQ: u8 = 22;
43pub const TAG_ACCOUNT_GET_RESP: u8 = 23;
44pub const TAG_ACCOUNT_GET_ALIAS_REQ: u8 = 24;
45pub const TAG_ACCOUNT_GET_ALIAS_RESP: u8 = 25;
46pub const TAG_ACCOUNT_CREATE_PROOF_REQ: u8 = 26;
47pub const TAG_ACCOUNT_CREATE_PROOF_RESP: u8 = 27;
48pub const TAG_GET_NON_PRODUCT_ACCOUNTS_REQ: u8 = 28;
49pub const TAG_GET_NON_PRODUCT_ACCOUNTS_RESP: u8 = 29;
50pub const TAG_CREATE_TRANSACTION_REQ: u8 = 30;
51pub const TAG_CREATE_TRANSACTION_RESP: u8 = 31;
52pub const TAG_CREATE_TX_NON_PRODUCT_REQ: u8 = 32;
53pub const TAG_CREATE_TX_NON_PRODUCT_RESP: u8 = 33;
54pub const TAG_SIGN_RAW_REQ: u8 = 34;
55pub const TAG_SIGN_RAW_RESP: u8 = 35;
56pub const TAG_SIGN_PAYLOAD_REQ: u8 = 36;
57pub const TAG_SIGN_PAYLOAD_RESP: u8 = 37;
58pub const TAG_CHAT_CREATE_ROOM_REQ: u8 = 38;
59pub const TAG_CHAT_CREATE_ROOM_RESP: u8 = 39;
60pub const TAG_CHAT_REGISTER_BOT_REQ: u8 = 40;
61pub const TAG_CHAT_REGISTER_BOT_RESP: u8 = 41;
62pub const TAG_CHAT_LIST_START: u8 = 42;
63pub const TAG_CHAT_LIST_STOP: u8 = 43;
64pub const TAG_CHAT_LIST_INTERRUPT: u8 = 44;
65pub const TAG_CHAT_LIST_RECEIVE: u8 = 45;
66pub const TAG_CHAT_POST_MSG_REQ: u8 = 46;
67pub const TAG_CHAT_POST_MSG_RESP: u8 = 47;
68pub const TAG_CHAT_ACTION_START: u8 = 48;
69pub const TAG_CHAT_ACTION_STOP: u8 = 49;
70pub const TAG_CHAT_ACTION_INTERRUPT: u8 = 50;
71pub const TAG_CHAT_ACTION_RECEIVE: u8 = 51;
72pub const TAG_CHAT_CUSTOM_MSG_START: u8 = 52;
73pub const TAG_CHAT_CUSTOM_MSG_STOP: u8 = 53;
74pub const TAG_CHAT_CUSTOM_MSG_INTERRUPT: u8 = 54;
75pub const TAG_CHAT_CUSTOM_MSG_RECEIVE: u8 = 55;
76pub const TAG_STATEMENT_STORE_START: u8 = 56;
77pub const TAG_STATEMENT_STORE_STOP: u8 = 57;
78pub const TAG_STATEMENT_STORE_INTERRUPT: u8 = 58;
79pub const TAG_STATEMENT_STORE_RECEIVE: u8 = 59;
80pub const TAG_STATEMENT_PROOF_REQ: u8 = 60;
81pub const TAG_STATEMENT_PROOF_RESP: u8 = 61;
82pub const TAG_STATEMENT_SUBMIT_REQ: u8 = 62;
83pub const TAG_STATEMENT_SUBMIT_RESP: u8 = 63;
84pub const TAG_PREIMAGE_LOOKUP_START: u8 = 64;
85pub const TAG_PREIMAGE_LOOKUP_STOP: u8 = 65;
86pub const TAG_PREIMAGE_LOOKUP_INTERRUPT: u8 = 66;
87pub const TAG_PREIMAGE_LOOKUP_RECEIVE: u8 = 67;
88pub const TAG_PREIMAGE_SUBMIT_REQ: u8 = 68;
89pub const TAG_PREIMAGE_SUBMIT_RESP: u8 = 69;
90pub const TAG_JSONRPC_SEND_REQ: u8 = 70;
91pub const TAG_JSONRPC_SEND_RESP: u8 = 71;
92pub const TAG_JSONRPC_SUB_START: u8 = 72;
93pub const TAG_JSONRPC_SUB_STOP: u8 = 73;
94pub const TAG_JSONRPC_SUB_INTERRUPT: u8 = 74;
95pub const TAG_JSONRPC_SUB_RECEIVE: u8 = 75;
96pub const TAG_CHAIN_HEAD_FOLLOW_START: u8 = 76;
98pub const TAG_CHAIN_HEAD_FOLLOW_STOP: u8 = 77;
99pub const TAG_CHAIN_HEAD_FOLLOW_INTERRUPT: u8 = 78;
100pub const TAG_CHAIN_HEAD_FOLLOW_RECEIVE: u8 = 79;
101pub const TAG_CHAIN_HEAD_HEADER_REQ: u8 = 80;
103pub const TAG_CHAIN_HEAD_HEADER_RESP: u8 = 81;
104pub const TAG_CHAIN_HEAD_BODY_REQ: u8 = 82;
106pub const TAG_CHAIN_HEAD_BODY_RESP: u8 = 83;
107pub const TAG_CHAIN_HEAD_STORAGE_REQ: u8 = 84;
109pub const TAG_CHAIN_HEAD_STORAGE_RESP: u8 = 85;
110pub const TAG_CHAIN_HEAD_CALL_REQ: u8 = 86;
112pub const TAG_CHAIN_HEAD_CALL_RESP: u8 = 87;
113pub const TAG_CHAIN_HEAD_UNPIN_REQ: u8 = 88;
115pub const TAG_CHAIN_HEAD_UNPIN_RESP: u8 = 89;
116pub const TAG_CHAIN_HEAD_CONTINUE_REQ: u8 = 90;
118pub const TAG_CHAIN_HEAD_CONTINUE_RESP: u8 = 91;
119pub const TAG_CHAIN_HEAD_STOP_OP_REQ: u8 = 92;
121pub const TAG_CHAIN_HEAD_STOP_OP_RESP: u8 = 93;
122pub const TAG_CHAIN_SPEC_GENESIS_REQ: u8 = 94;
124pub const TAG_CHAIN_SPEC_GENESIS_RESP: u8 = 95;
125pub const TAG_CHAIN_SPEC_NAME_REQ: u8 = 96;
127pub const TAG_CHAIN_SPEC_NAME_RESP: u8 = 97;
128pub const TAG_CHAIN_SPEC_PROPS_REQ: u8 = 98;
130pub const TAG_CHAIN_SPEC_PROPS_RESP: u8 = 99;
131pub const TAG_CHAIN_TX_BROADCAST_REQ: u8 = 100;
133pub const TAG_CHAIN_TX_BROADCAST_RESP: u8 = 101;
134pub const TAG_CHAIN_TX_STOP_REQ: u8 = 102;
136pub const TAG_CHAIN_TX_STOP_RESP: u8 = 103;
137
138pub const PROTOCOL_VERSION: u8 = 1;
140
141pub const PROTOCOL_DISCRIMINATOR: u8 = 0x01;
152
153pub fn is_host_sdk_message(data: &[u8]) -> bool {
159 data.first() == Some(&PROTOCOL_DISCRIMINATOR)
160}
161
162#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
168pub struct Account {
169 pub public_key: Vec<u8>,
171 pub name: Option<String>,
173}
174
175#[derive(Debug)]
177pub enum HostRequest {
178 Handshake {
179 version: u8,
180 },
181 GetNonProductAccounts,
182 FeatureSupported {
183 feature_data: Vec<u8>,
184 },
185 LocalStorageRead {
186 key: String,
187 },
188 LocalStorageWrite {
189 key: String,
190 value: Vec<u8>,
191 },
192 LocalStorageClear {
193 key: String,
194 },
195 SignPayload {
196 public_key: Vec<u8>,
197 payload: Vec<u8>,
198 },
199 SignRaw {
200 public_key: Vec<u8>,
201 data: Vec<u8>,
202 },
203 CreateTransaction {
204 payload: Vec<u8>,
205 },
206 NavigateTo {
207 url: String,
208 },
209 PushNotification {
210 text: String,
211 deeplink: Option<String>,
212 },
213 AccountConnectionStatusStart,
214 JsonRpcSend {
215 data: Vec<u8>,
216 },
217 JsonRpcSubscribeStart {
218 data: Vec<u8>,
219 },
220 ChainHeadFollowStart {
222 genesis_hash: Vec<u8>,
223 with_runtime: bool,
224 },
225 ChainHeadRequest {
228 tag: u8,
229 genesis_hash: Vec<u8>,
230 follow_sub_id: String,
231 data: serde_json::Value,
232 },
233 ChainSpecRequest {
235 tag: u8,
236 genesis_hash: Vec<u8>,
237 },
238 ChainTxBroadcast {
240 genesis_hash: Vec<u8>,
241 transaction: Vec<u8>,
242 },
243 ChainTxStop {
245 genesis_hash: Vec<u8>,
246 operation_id: String,
247 },
248 Unimplemented {
250 tag: u8,
251 },
252 Unknown {
254 tag: u8,
255 },
256}
257
258#[derive(Debug)]
260pub enum HostResponse {
261 HandshakeOk,
262 AccountList(Vec<Account>),
263 Error(String),
264}
265
266fn bytes_to_hex(bytes: &[u8]) -> String {
272 let mut s = String::with_capacity(2 + bytes.len() * 2);
273 s.push_str("0x");
274 for b in bytes {
275 s.push_str(&format!("{b:02x}"));
276 }
277 s
278}
279
280fn begin_message(buf: &mut Vec<u8>, request_id: &str) {
285 buf.push(PROTOCOL_DISCRIMINATOR);
286 encode_string(buf, request_id);
287}
288
289pub fn decode_message(data: &[u8]) -> Result<(String, u8, HostRequest), DecodeErr> {
294 let mut r = Reader::new(data);
295
296 let disc = r.read_u8()?;
298 if disc != PROTOCOL_DISCRIMINATOR {
299 return Err(DecodeErr::UnknownProtocol);
300 }
301
302 let request_id = r.read_string()?;
304
305 let tag = r.read_u8()?;
307
308 let req = match tag {
309 TAG_HANDSHAKE_REQ => {
310 let _version_tag = r.read_u8()?; let version = r.read_u8()?;
313 HostRequest::Handshake { version }
314 }
315 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ => {
316 let _version_tag = r.read_u8()?;
318 HostRequest::GetNonProductAccounts
320 }
321 TAG_FEATURE_SUPPORTED_REQ => {
322 let _version_tag = r.read_u8()?;
323 let rest = r.remaining().to_vec();
324 r.skip_rest();
325 HostRequest::FeatureSupported { feature_data: rest }
326 }
327 TAG_LOCAL_STORAGE_READ_REQ => {
328 let _version_tag = r.read_u8()?;
329 let key = r.read_string()?;
330 HostRequest::LocalStorageRead { key }
331 }
332 TAG_LOCAL_STORAGE_WRITE_REQ => {
333 let _version_tag = r.read_u8()?;
334 let key = r.read_string()?;
335 let value = r.read_var_bytes()?;
336 HostRequest::LocalStorageWrite { key, value }
337 }
338 TAG_LOCAL_STORAGE_CLEAR_REQ => {
339 let _version_tag = r.read_u8()?;
340 let key = r.read_string()?;
341 HostRequest::LocalStorageClear { key }
342 }
343 TAG_SIGN_PAYLOAD_REQ => {
344 let _version_tag = r.read_u8()?;
345 let public_key = r.read_var_bytes()?;
346 let payload = r.remaining().to_vec();
347 r.skip_rest();
348 HostRequest::SignPayload {
349 public_key,
350 payload,
351 }
352 }
353 TAG_SIGN_RAW_REQ => {
354 let _version_tag = r.read_u8()?;
355 let public_key = r.read_var_bytes()?;
356 let data = r.remaining().to_vec();
357 r.skip_rest();
358 HostRequest::SignRaw { public_key, data }
359 }
360 TAG_CREATE_TRANSACTION_REQ => {
361 let _version_tag = r.read_u8()?;
362 let rest = r.remaining().to_vec();
363 r.skip_rest();
364 HostRequest::CreateTransaction { payload: rest }
365 }
366 TAG_NAVIGATE_TO_REQ => {
367 let _version_tag = r.read_u8()?;
368 let url = r.read_string()?;
369 HostRequest::NavigateTo { url }
370 }
371 TAG_PUSH_NOTIFICATION_REQ => {
372 let _version_tag = r.read_u8()?;
373 let text = r.read_string()?;
374 let deeplink = r.read_option(|r| r.read_string())?;
375 HostRequest::PushNotification { text, deeplink }
376 }
377 TAG_ACCOUNT_STATUS_START => {
378 let _version_tag = r.read_u8()?;
379 HostRequest::AccountConnectionStatusStart
380 }
381 TAG_JSONRPC_SEND_REQ => {
382 let _version_tag = r.read_u8()?;
383 let rest = r.remaining().to_vec();
384 r.skip_rest();
385 HostRequest::JsonRpcSend { data: rest }
386 }
387 TAG_JSONRPC_SUB_START => {
388 let _version_tag = r.read_u8()?;
389 let rest = r.remaining().to_vec();
390 r.skip_rest();
391 HostRequest::JsonRpcSubscribeStart { data: rest }
392 }
393 TAG_CHAIN_HEAD_FOLLOW_START => {
394 let _version_tag = r.read_u8()?;
395 let genesis_hash = r.read_var_bytes()?;
396 let with_runtime = r.read_u8()? != 0;
397 HostRequest::ChainHeadFollowStart {
398 genesis_hash,
399 with_runtime,
400 }
401 }
402 TAG_CHAIN_HEAD_HEADER_REQ => {
403 let _version_tag = r.read_u8()?;
404 let genesis_hash = r.read_var_bytes()?;
405 let follow_sub_id = r.read_string()?;
406 let hash = r.read_var_bytes()?;
407 let hash_hex = bytes_to_hex(&hash);
408 HostRequest::ChainHeadRequest {
409 tag,
410 genesis_hash,
411 follow_sub_id,
412 data: serde_json::json!([hash_hex]),
413 }
414 }
415 TAG_CHAIN_HEAD_BODY_REQ => {
416 let _version_tag = r.read_u8()?;
417 let genesis_hash = r.read_var_bytes()?;
418 let follow_sub_id = r.read_string()?;
419 let hash = r.read_var_bytes()?;
420 let hash_hex = bytes_to_hex(&hash);
421 HostRequest::ChainHeadRequest {
422 tag,
423 genesis_hash,
424 follow_sub_id,
425 data: serde_json::json!([hash_hex]),
426 }
427 }
428 TAG_CHAIN_HEAD_STORAGE_REQ => {
429 let _version_tag = r.read_u8()?;
430 let genesis_hash = r.read_var_bytes()?;
431 let follow_sub_id = r.read_string()?;
432 let hash = r.read_var_bytes()?;
433 let hash_hex = bytes_to_hex(&hash);
434 let item_count = r.read_compact_u32()?;
436 let mut items = Vec::new();
437 for _ in 0..item_count {
438 let key = r.read_var_bytes()?;
439 let storage_type = r.read_u8()?; let type_str = match storage_type {
441 0 => "value",
442 1 => "hash",
443 2 => "closestDescendantMerkleValue",
444 3 => "descendantsValues",
445 4 => "descendantsHashes",
446 _ => "value",
447 };
448 items.push(serde_json::json!({
449 "key": bytes_to_hex(&key),
450 "type": type_str,
451 }));
452 }
453 let child_trie = r.read_option(|r| r.read_var_bytes())?;
455 let child_trie_hex = child_trie.map(|b| bytes_to_hex(&b));
456 HostRequest::ChainHeadRequest {
457 tag,
458 genesis_hash,
459 follow_sub_id,
460 data: serde_json::json!([hash_hex, items, child_trie_hex]),
461 }
462 }
463 TAG_CHAIN_HEAD_CALL_REQ => {
464 let _version_tag = r.read_u8()?;
465 let genesis_hash = r.read_var_bytes()?;
466 let follow_sub_id = r.read_string()?;
467 let hash = r.read_var_bytes()?;
468 let function = r.read_string()?;
469 let call_params = r.read_var_bytes()?;
470 HostRequest::ChainHeadRequest {
471 tag,
472 genesis_hash,
473 follow_sub_id,
474 data: serde_json::json!([
475 bytes_to_hex(&hash),
476 function,
477 bytes_to_hex(&call_params)
478 ]),
479 }
480 }
481 TAG_CHAIN_HEAD_UNPIN_REQ => {
482 let _version_tag = r.read_u8()?;
483 let genesis_hash = r.read_var_bytes()?;
484 let follow_sub_id = r.read_string()?;
485 let count = r.read_compact_u32()?;
487 let mut hashes = Vec::new();
488 for _ in 0..count {
489 let h = r.read_var_bytes()?;
490 hashes.push(serde_json::Value::String(bytes_to_hex(&h)));
491 }
492 HostRequest::ChainHeadRequest {
493 tag,
494 genesis_hash,
495 follow_sub_id,
496 data: serde_json::json!([hashes]),
497 }
498 }
499 TAG_CHAIN_HEAD_CONTINUE_REQ | TAG_CHAIN_HEAD_STOP_OP_REQ => {
500 let _version_tag = r.read_u8()?;
501 let genesis_hash = r.read_var_bytes()?;
502 let follow_sub_id = r.read_string()?;
503 let operation_id = r.read_string()?;
504 HostRequest::ChainHeadRequest {
505 tag,
506 genesis_hash,
507 follow_sub_id,
508 data: serde_json::json!([operation_id]),
509 }
510 }
511 TAG_CHAIN_SPEC_GENESIS_REQ | TAG_CHAIN_SPEC_NAME_REQ | TAG_CHAIN_SPEC_PROPS_REQ => {
512 let _version_tag = r.read_u8()?;
513 let genesis_hash = r.read_var_bytes()?;
514 HostRequest::ChainSpecRequest { tag, genesis_hash }
515 }
516 TAG_CHAIN_TX_BROADCAST_REQ => {
517 let _version_tag = r.read_u8()?;
518 let genesis_hash = r.read_var_bytes()?;
519 let transaction = r.read_var_bytes()?;
520 HostRequest::ChainTxBroadcast {
521 genesis_hash,
522 transaction,
523 }
524 }
525 TAG_CHAIN_TX_STOP_REQ => {
526 let _version_tag = r.read_u8()?;
527 let genesis_hash = r.read_var_bytes()?;
528 let operation_id = r.read_string()?;
529 HostRequest::ChainTxStop {
530 genesis_hash,
531 operation_id,
532 }
533 }
534 TAG_PUSH_NOTIFICATION_REQ => {
535 let _version_tag = r.read_u8()?;
536 let text = r.read_string()?;
537 let deeplink = r.read_option(|r| r.read_string())?;
538 HostRequest::PushNotification { text, deeplink }
539 }
540 TAG_DEVICE_PERMISSION_REQ
542 | TAG_REMOTE_PERMISSION_REQ
543 | TAG_ACCOUNT_GET_REQ
544 | TAG_ACCOUNT_GET_ALIAS_REQ
545 | TAG_ACCOUNT_CREATE_PROOF_REQ
546 | TAG_CREATE_TX_NON_PRODUCT_REQ
547 | TAG_CHAT_CREATE_ROOM_REQ
548 | TAG_CHAT_REGISTER_BOT_REQ
549 | TAG_CHAT_POST_MSG_REQ
550 | TAG_STATEMENT_PROOF_REQ
551 | TAG_STATEMENT_SUBMIT_REQ
552 | TAG_PREIMAGE_SUBMIT_REQ => HostRequest::Unimplemented { tag },
553 TAG_ACCOUNT_STATUS_STOP
555 | TAG_ACCOUNT_STATUS_INTERRUPT
556 | TAG_CHAT_LIST_STOP
557 | TAG_CHAT_LIST_INTERRUPT
558 | TAG_CHAT_ACTION_STOP
559 | TAG_CHAT_ACTION_INTERRUPT
560 | TAG_CHAT_CUSTOM_MSG_STOP
561 | TAG_CHAT_CUSTOM_MSG_INTERRUPT
562 | TAG_STATEMENT_STORE_STOP
563 | TAG_STATEMENT_STORE_INTERRUPT
564 | TAG_PREIMAGE_LOOKUP_STOP
565 | TAG_PREIMAGE_LOOKUP_INTERRUPT
566 | TAG_JSONRPC_SUB_STOP
567 | TAG_JSONRPC_SUB_INTERRUPT
568 | TAG_CHAIN_HEAD_FOLLOW_STOP
569 | TAG_CHAIN_HEAD_FOLLOW_INTERRUPT => HostRequest::Unimplemented { tag },
570 _ => HostRequest::Unknown { tag },
571 };
572
573 Ok((request_id, tag, req))
574}
575
576pub fn encode_response(request_id: &str, request_tag: u8, response: &HostResponse) -> Vec<u8> {
578 let mut buf = Vec::with_capacity(128);
579 begin_message(&mut buf, request_id);
580
581 match response {
582 HostResponse::HandshakeOk => {
583 encode_tag(&mut buf, TAG_HANDSHAKE_RESP);
585 encode_tag(&mut buf, 0);
587 encode_result_ok_void(&mut buf);
589 }
590
591 HostResponse::AccountList(accounts) => {
592 encode_tag(&mut buf, TAG_GET_NON_PRODUCT_ACCOUNTS_RESP);
594 encode_tag(&mut buf, 0);
596 encode_result_ok(&mut buf);
598 encode_vector_len(&mut buf, accounts.len() as u32);
600 for account in accounts {
601 encode_var_bytes(&mut buf, &account.public_key);
604 match &account.name {
606 None => encode_option_none(&mut buf),
607 Some(name) => {
608 encode_option_some(&mut buf);
609 encode_string(&mut buf, name);
610 }
611 }
612 }
613 }
614
615 HostResponse::Error(_reason) => {
616 let resp_tag = response_tag_for(request_tag);
617 encode_tag(&mut buf, resp_tag);
618 encode_tag(&mut buf, 0); encode_result_err(&mut buf);
620 encode_tag(&mut buf, 0);
625 }
626 }
627
628 buf
629}
630
631fn response_tag_for(request_tag: u8) -> u8 {
635 assert!(
636 !matches!(
637 request_tag,
638 TAG_ACCOUNT_STATUS_START
639 | TAG_CHAT_LIST_START
640 | TAG_CHAT_ACTION_START
641 | TAG_CHAT_CUSTOM_MSG_START
642 | TAG_STATEMENT_STORE_START
643 | TAG_PREIMAGE_LOOKUP_START
644 | TAG_JSONRPC_SUB_START
645 | TAG_CHAIN_HEAD_FOLLOW_START
646 ),
647 "response_tag_for called with subscription start tag {request_tag}"
648 );
649 request_tag + 1
650}
651
652pub fn encode_feature_response(request_id: &str, supported: bool) -> Vec<u8> {
654 let mut buf = Vec::with_capacity(32);
655 begin_message(&mut buf, request_id);
656 encode_tag(&mut buf, TAG_FEATURE_SUPPORTED_RESP);
657 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
659 buf.push(if supported { 1 } else { 0 }); buf
661}
662
663pub fn encode_account_status(request_id: &str, connected: bool) -> Vec<u8> {
665 let mut buf = Vec::with_capacity(32);
666 begin_message(&mut buf, request_id);
667 encode_tag(&mut buf, TAG_ACCOUNT_STATUS_RECEIVE);
668 encode_tag(&mut buf, 0); encode_tag(&mut buf, if connected { 1 } else { 0 });
671 buf
672}
673
674pub fn encode_storage_read_response(request_id: &str, value: Option<&[u8]>) -> Vec<u8> {
676 let mut buf = Vec::with_capacity(64);
677 begin_message(&mut buf, request_id);
678 encode_tag(&mut buf, TAG_LOCAL_STORAGE_READ_RESP);
679 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
681 match value {
682 None => encode_option_none(&mut buf),
683 Some(v) => {
684 encode_option_some(&mut buf);
685 encode_var_bytes(&mut buf, v);
686 }
687 }
688 buf
689}
690
691pub fn encode_storage_write_response(request_id: &str, is_clear: bool) -> Vec<u8> {
693 let mut buf = Vec::with_capacity(32);
694 begin_message(&mut buf, request_id);
695 let tag = if is_clear {
696 TAG_LOCAL_STORAGE_CLEAR_RESP
697 } else {
698 TAG_LOCAL_STORAGE_WRITE_RESP
699 };
700 encode_tag(&mut buf, tag);
701 encode_tag(&mut buf, 0); encode_result_ok_void(&mut buf);
703 buf
704}
705
706pub fn encode_navigate_response(request_id: &str) -> Vec<u8> {
708 let mut buf = Vec::with_capacity(32);
709 begin_message(&mut buf, request_id);
710 encode_tag(&mut buf, TAG_NAVIGATE_TO_RESP);
711 encode_tag(&mut buf, 0); encode_result_ok_void(&mut buf);
713 buf
714}
715
716pub fn encode_push_notification_response(request_id: &str) -> Vec<u8> {
718 let mut buf = Vec::with_capacity(32);
719 begin_message(&mut buf, request_id);
720 encode_tag(&mut buf, TAG_PUSH_NOTIFICATION_RESP);
721 encode_tag(&mut buf, 0); encode_result_ok_void(&mut buf);
723 buf
724}
725
726pub fn encode_sign_response(request_id: &str, is_raw: bool, signature: &[u8]) -> Vec<u8> {
729 let mut buf = Vec::with_capacity(128);
730 begin_message(&mut buf, request_id);
731 encode_tag(
732 &mut buf,
733 if is_raw {
734 TAG_SIGN_RAW_RESP
735 } else {
736 TAG_SIGN_PAYLOAD_RESP
737 },
738 );
739 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
741 encode_compact_u32(&mut buf, 0); encode_var_bytes(&mut buf, signature);
743 buf
744}
745
746pub fn encode_jsonrpc_send_response(request_id: &str, json_rpc_result: &str) -> Vec<u8> {
751 let mut buf = Vec::with_capacity(64 + json_rpc_result.len());
752 begin_message(&mut buf, request_id);
753 encode_tag(&mut buf, TAG_JSONRPC_SEND_RESP);
754 encode_tag(&mut buf, 0); encode_result_ok(&mut buf);
756 encode_string(&mut buf, json_rpc_result);
757 buf
758}
759
760pub fn encode_jsonrpc_send_error(request_id: &str) -> Vec<u8> {
762 let mut buf = Vec::with_capacity(32);
763 begin_message(&mut buf, request_id);
764 encode_tag(&mut buf, TAG_JSONRPC_SEND_RESP);
765 encode_tag(&mut buf, 0); encode_result_err(&mut buf);
767 encode_tag(&mut buf, 0); buf
769}
770
771pub fn encode_jsonrpc_sub_receive(request_id: &str, json_rpc_msg: &str) -> Vec<u8> {
777 let mut buf = Vec::with_capacity(64 + json_rpc_msg.len());
778 begin_message(&mut buf, request_id);
779 encode_tag(&mut buf, TAG_JSONRPC_SUB_RECEIVE);
780 encode_tag(&mut buf, 0); encode_string(&mut buf, json_rpc_msg);
782 buf
783}
784
785pub fn encode_sign_error(request_id: &str, is_raw: bool) -> Vec<u8> {
787 let mut buf = Vec::with_capacity(32);
788 begin_message(&mut buf, request_id);
789 encode_tag(
790 &mut buf,
791 if is_raw {
792 TAG_SIGN_RAW_RESP
793 } else {
794 TAG_SIGN_PAYLOAD_RESP
795 },
796 );
797 encode_tag(&mut buf, 0); encode_result_err(&mut buf);
799 encode_tag(&mut buf, 0); buf
801}
802
803#[cfg(test)]
804mod tests {
805 use super::*;
806
807 #[test]
808 fn decode_handshake_request() {
809 let mut msg = Vec::new();
811 msg.push(PROTOCOL_DISCRIMINATOR);
812 encode_string(&mut msg, "test");
813 msg.push(TAG_HANDSHAKE_REQ); msg.push(0); msg.push(PROTOCOL_VERSION); let (id, tag, req) = decode_message(&msg).unwrap();
818 assert_eq!(id, "test");
819 assert_eq!(tag, TAG_HANDSHAKE_REQ);
820 match req {
821 HostRequest::Handshake { version } => assert_eq!(version, 1),
822 _ => panic!("expected Handshake"),
823 }
824 }
825
826 #[test]
827 fn encode_handshake_response() {
828 let resp = encode_response("test", TAG_HANDSHAKE_REQ, &HostResponse::HandshakeOk);
829
830 let mut r = Reader::new(&resp);
832 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
833 let id = r.read_string().unwrap();
834 assert_eq!(id, "test");
835 let tag = r.read_u8().unwrap();
836 assert_eq!(tag, TAG_HANDSHAKE_RESP);
837 let v1_tag = r.read_u8().unwrap();
838 assert_eq!(v1_tag, 0);
839 let result_ok = r.read_u8().unwrap();
840 assert_eq!(result_ok, 0x00); assert_eq!(r.pos, resp.len()); }
843
844 #[test]
845 fn decode_get_non_product_accounts() {
846 let mut msg = Vec::new();
847 msg.push(PROTOCOL_DISCRIMINATOR);
848 encode_string(&mut msg, "req-42");
849 msg.push(TAG_GET_NON_PRODUCT_ACCOUNTS_REQ);
850 msg.push(0); let (id, tag, req) = decode_message(&msg).unwrap();
853 assert_eq!(id, "req-42");
854 assert_eq!(tag, TAG_GET_NON_PRODUCT_ACCOUNTS_REQ);
855 assert!(matches!(req, HostRequest::GetNonProductAccounts));
856 }
857
858 #[test]
859 fn encode_account_list_response() {
860 let accounts = vec![
861 Account {
862 public_key: vec![0xd4; 32],
863 name: Some("Alice".into()),
864 },
865 Account {
866 public_key: vec![0x8e; 32],
867 name: None,
868 },
869 ];
870 let resp = encode_response(
871 "req-42",
872 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ,
873 &HostResponse::AccountList(accounts),
874 );
875
876 let mut r = Reader::new(&resp);
878 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
879 let id = r.read_string().unwrap();
880 assert_eq!(id, "req-42");
881 let tag = r.read_u8().unwrap();
882 assert_eq!(tag, TAG_GET_NON_PRODUCT_ACCOUNTS_RESP);
883 let v1 = r.read_u8().unwrap();
884 assert_eq!(v1, 0); let result = r.read_u8().unwrap();
886 assert_eq!(result, 0x00); let count = r.read_compact_u32().unwrap();
888 assert_eq!(count, 2);
889
890 let pk1 = r.read_var_bytes().unwrap();
892 assert_eq!(pk1.len(), 32);
893 assert_eq!(pk1[0], 0xd4);
894 let name1 = r.read_option(|r| r.read_string()).unwrap();
895 assert_eq!(name1.as_deref(), Some("Alice"));
896
897 let pk2 = r.read_var_bytes().unwrap();
899 assert_eq!(pk2.len(), 32);
900 assert_eq!(pk2[0], 0x8e);
901 let name2 = r.read_option(|r| r.read_string()).unwrap();
902 assert!(name2.is_none());
903
904 assert_eq!(r.pos, resp.len());
905 }
906
907 #[test]
908 fn handshake_round_trip() {
909 let mut req_msg = Vec::new();
911 req_msg.push(PROTOCOL_DISCRIMINATOR);
912 encode_string(&mut req_msg, "hsk-1");
913 req_msg.push(TAG_HANDSHAKE_REQ);
914 req_msg.push(0); req_msg.push(PROTOCOL_VERSION);
916
917 let (id, tag, req) = decode_message(&req_msg).unwrap();
918 assert!(matches!(req, HostRequest::Handshake { version: 1 }));
919
920 let resp_bytes = encode_response(&id, tag, &HostResponse::HandshakeOk);
921
922 let mut r = Reader::new(&resp_bytes);
924 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
925 assert_eq!(r.read_string().unwrap(), "hsk-1");
926 assert_eq!(r.read_u8().unwrap(), TAG_HANDSHAKE_RESP);
927 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); }
930
931 #[test]
939 fn golden_handshake_request() {
940 let expected: &[u8] = &[
942 0x01, 0x08, b't', b'1', 0x00, 0x00, 0x01, ];
948 let mut built = Vec::new();
949 built.push(PROTOCOL_DISCRIMINATOR);
950 encode_string(&mut built, "t1");
951 built.push(TAG_HANDSHAKE_REQ);
952 built.push(0);
953 built.push(PROTOCOL_VERSION);
954 assert_eq!(built, expected);
955 }
956
957 #[test]
958 fn golden_handshake_response_ok() {
959 let resp = encode_response("t1", TAG_HANDSHAKE_REQ, &HostResponse::HandshakeOk);
960 let expected: &[u8] = &[
961 0x01, 0x08, b't', b'1', 0x01, 0x00, 0x00, ];
967 assert_eq!(resp, expected);
968 }
969
970 #[test]
971 fn golden_get_accounts_request() {
972 let expected: &[u8] = &[
973 0x01, 0x08, b'a', b'1', 28, 0x00, ];
978 let mut built = Vec::new();
979 built.push(PROTOCOL_DISCRIMINATOR);
980 encode_string(&mut built, "a1");
981 built.push(TAG_GET_NON_PRODUCT_ACCOUNTS_REQ);
982 built.push(0);
983 assert_eq!(built, expected);
984 }
985
986 #[test]
987 fn golden_get_accounts_response_empty() {
988 let resp = encode_response(
989 "a1",
990 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ,
991 &HostResponse::AccountList(vec![]),
992 );
993 let expected: &[u8] = &[
994 0x01, 0x08, b'a', b'1', 29, 0x00, 0x00, 0x00, ];
1001 assert_eq!(resp, expected);
1002 }
1003
1004 #[test]
1005 fn golden_storage_write_response() {
1006 let resp = encode_storage_write_response("s1", false);
1007 let expected: &[u8] = &[
1008 0x01, 0x08, b's', b'1', 15, 0x00, 0x00, ];
1014 assert_eq!(resp, expected);
1015 }
1016
1017 #[test]
1018 fn golden_storage_clear_response() {
1019 let resp = encode_storage_write_response("s1", true);
1020 let expected: &[u8] = &[
1021 0x01, 0x08, b's', b'1', 17, 0x00, 0x00, ];
1027 assert_eq!(resp, expected);
1028 }
1029
1030 #[test]
1031 fn golden_feature_supported_response() {
1032 let resp = encode_feature_response("f1", false);
1033 let expected: &[u8] = &[
1034 0x01, 0x08, b'f', b'1', 3, 0x00, 0x00, 0x00, ];
1041 assert_eq!(resp, expected);
1042 }
1043
1044 #[test]
1045 fn golden_account_status_receive() {
1046 let resp = encode_account_status("c1", true);
1047 let expected: &[u8] = &[
1048 0x01, 0x08, b'c', b'1', 21, 0x00, 0x01, ];
1054 assert_eq!(resp, expected);
1055 }
1056
1057 #[test]
1058 fn golden_sign_payload_response_ok() {
1059 let sig = [0xAB; 64];
1060 let resp = encode_sign_response("s1", false, &sig);
1061 let mut r = Reader::new(&resp);
1062 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1063 assert_eq!(r.read_string().unwrap(), "s1");
1064 assert_eq!(r.read_u8().unwrap(), TAG_SIGN_PAYLOAD_RESP);
1065 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_compact_u32().unwrap(), 0); let sig_bytes = r.read_var_bytes().unwrap();
1069 assert_eq!(sig_bytes, vec![0xAB; 64]);
1070 assert_eq!(r.pos, resp.len());
1071 }
1072
1073 #[test]
1074 fn golden_sign_raw_response_ok() {
1075 let sig = [0xCD; 64];
1076 let resp = encode_sign_response("s2", true, &sig);
1077 let mut r = Reader::new(&resp);
1078 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1079 assert_eq!(r.read_string().unwrap(), "s2");
1080 assert_eq!(r.read_u8().unwrap(), TAG_SIGN_RAW_RESP);
1081 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_compact_u32().unwrap(), 0); let sig_bytes = r.read_var_bytes().unwrap();
1085 assert_eq!(sig_bytes, vec![0xCD; 64]);
1086 }
1087
1088 #[test]
1089 fn golden_sign_error_response() {
1090 let resp = encode_sign_error("s3", false);
1091 let expected: &[u8] = &[
1092 0x01, 0x08, b's', b'3', 37, 0x00, 0x01, 0x00, ];
1099 assert_eq!(resp, expected);
1100 }
1101
1102 #[test]
1103 fn decode_sign_payload_request() {
1104 let mut msg = Vec::new();
1105 msg.push(PROTOCOL_DISCRIMINATOR);
1106 encode_string(&mut msg, "sign-1");
1107 msg.push(TAG_SIGN_PAYLOAD_REQ);
1108 msg.push(0); encode_var_bytes(&mut msg, &[0xAA; 32]); msg.extend_from_slice(b"extrinsic-payload"); let (id, tag, req) = decode_message(&msg).unwrap();
1112 assert_eq!(id, "sign-1");
1113 assert_eq!(tag, TAG_SIGN_PAYLOAD_REQ);
1114 match req {
1115 HostRequest::SignPayload {
1116 public_key,
1117 payload,
1118 } => {
1119 assert_eq!(public_key, vec![0xAA; 32]);
1120 assert_eq!(payload, b"extrinsic-payload");
1121 }
1122 _ => panic!("expected SignPayload"),
1123 }
1124 }
1125
1126 #[test]
1127 fn decode_sign_raw_request() {
1128 let mut msg = Vec::new();
1129 msg.push(PROTOCOL_DISCRIMINATOR);
1130 encode_string(&mut msg, "sign-2");
1131 msg.push(TAG_SIGN_RAW_REQ);
1132 msg.push(0); encode_var_bytes(&mut msg, &[0xBB; 32]); msg.extend_from_slice(b"raw-data"); let (id, tag, req) = decode_message(&msg).unwrap();
1136 assert_eq!(id, "sign-2");
1137 assert_eq!(tag, TAG_SIGN_RAW_REQ);
1138 match req {
1139 HostRequest::SignRaw { public_key, data } => {
1140 assert_eq!(public_key, vec![0xBB; 32]);
1141 assert_eq!(data, b"raw-data");
1142 }
1143 _ => panic!("expected SignRaw"),
1144 }
1145 }
1146
1147 #[test]
1150 fn decode_push_notification_request_with_deeplink() {
1151 let mut msg = Vec::new();
1152 msg.push(PROTOCOL_DISCRIMINATOR);
1153 encode_string(&mut msg, "pn-1");
1154 msg.push(TAG_PUSH_NOTIFICATION_REQ);
1155 msg.push(0); encode_string(&mut msg, "Transfer complete");
1157 msg.push(0x01); encode_string(&mut msg, "https://app.example/tx/123");
1159
1160 let (id, tag, req) = decode_message(&msg).unwrap();
1161 assert_eq!(id, "pn-1");
1162 assert_eq!(tag, TAG_PUSH_NOTIFICATION_REQ);
1163 match req {
1164 HostRequest::PushNotification { text, deeplink } => {
1165 assert_eq!(text, "Transfer complete");
1166 assert_eq!(deeplink.as_deref(), Some("https://app.example/tx/123"));
1167 }
1168 _ => panic!("expected PushNotification"),
1169 }
1170 }
1171
1172 #[test]
1173 fn decode_push_notification_request_without_deeplink() {
1174 let mut msg = Vec::new();
1175 msg.push(PROTOCOL_DISCRIMINATOR);
1176 encode_string(&mut msg, "pn-2");
1177 msg.push(TAG_PUSH_NOTIFICATION_REQ);
1178 msg.push(0); encode_string(&mut msg, "Hello world");
1180 msg.push(0x00); let (id, tag, req) = decode_message(&msg).unwrap();
1183 assert_eq!(id, "pn-2");
1184 assert_eq!(tag, TAG_PUSH_NOTIFICATION_REQ);
1185 match req {
1186 HostRequest::PushNotification { text, deeplink } => {
1187 assert_eq!(text, "Hello world");
1188 assert!(deeplink.is_none());
1189 }
1190 _ => panic!("expected PushNotification"),
1191 }
1192 }
1193
1194 #[test]
1195 fn encode_push_notification_response_produces_ok() {
1196 let resp = encode_push_notification_response("pn-1");
1197 let mut r = Reader::new(&resp);
1198 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1199 assert_eq!(r.read_string().unwrap(), "pn-1");
1200 assert_eq!(r.read_u8().unwrap(), TAG_PUSH_NOTIFICATION_RESP);
1201 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.pos, resp.len());
1204 }
1205
1206 #[test]
1207 fn golden_push_notification_response_ok() {
1208 let resp = encode_push_notification_response("t1");
1209 let expected: &[u8] = &[
1210 0x01, 0x08, b't', b'1', 0x05, 0x00, 0x00, ];
1216 assert_eq!(resp, expected);
1217 }
1218
1219 #[test]
1220 fn push_notification_round_trip() {
1221 let mut req_msg = Vec::new();
1222 req_msg.push(PROTOCOL_DISCRIMINATOR);
1223 encode_string(&mut req_msg, "pn-rt");
1224 req_msg.push(TAG_PUSH_NOTIFICATION_REQ);
1225 req_msg.push(0); encode_string(&mut req_msg, "Test notification");
1227 req_msg.push(0x00); let (id, _tag, req) = decode_message(&req_msg).unwrap();
1230 assert!(matches!(req, HostRequest::PushNotification { .. }));
1231
1232 let resp_bytes = encode_push_notification_response(&id);
1233
1234 let mut r = Reader::new(&resp_bytes);
1235 assert_eq!(r.read_u8().unwrap(), PROTOCOL_DISCRIMINATOR);
1236 assert_eq!(r.read_string().unwrap(), "pn-rt");
1237 assert_eq!(r.read_u8().unwrap(), TAG_PUSH_NOTIFICATION_RESP);
1238 assert_eq!(r.read_u8().unwrap(), 0); assert_eq!(r.read_u8().unwrap(), 0); }
1241
1242 #[test]
1243 fn golden_storage_read_response_some() {
1244 let resp = encode_storage_read_response("s1", Some(b"hi"));
1245 let expected: &[u8] = &[
1246 PROTOCOL_DISCRIMINATOR,
1247 0x08,
1248 b's',
1249 b'1', 13, 0x00, 0x00, 0x01, 0x08,
1255 b'h',
1256 b'i', ];
1258 assert_eq!(resp, expected);
1259 }
1260
1261 #[test]
1262 fn golden_storage_read_response_none() {
1263 let resp = encode_storage_read_response("s1", None);
1264 let expected: &[u8] = &[
1265 PROTOCOL_DISCRIMINATOR,
1266 0x08,
1267 b's',
1268 b'1', 13, 0x00, 0x00, 0x00, ];
1274 assert_eq!(resp, expected);
1275 }
1276
1277 #[test]
1278 fn test_decode_rejects_missing_discriminator() {
1279 let mut msg = Vec::new();
1281 encode_string(&mut msg, "t1");
1282 msg.push(TAG_HANDSHAKE_REQ);
1283 msg.push(0);
1284 msg.push(PROTOCOL_VERSION);
1285 assert!(matches!(
1286 decode_message(&msg),
1287 Err(DecodeErr::UnknownProtocol)
1288 ));
1289 }
1290
1291 #[test]
1292 fn test_decode_rejects_wrong_discriminator() {
1293 let mut msg = vec![0x00]; encode_string(&mut msg, "t1");
1295 msg.push(TAG_HANDSHAKE_REQ);
1296 msg.push(0);
1297 msg.push(PROTOCOL_VERSION);
1298 assert!(matches!(
1299 decode_message(&msg),
1300 Err(DecodeErr::UnknownProtocol)
1301 ));
1302 }
1303
1304 #[test]
1305 fn test_decode_accepts_correct_discriminator() {
1306 let mut msg = vec![PROTOCOL_DISCRIMINATOR];
1307 encode_string(&mut msg, "t1");
1308 msg.push(TAG_HANDSHAKE_REQ);
1309 msg.push(0);
1310 msg.push(PROTOCOL_VERSION);
1311 let (req_id, tag, _) = decode_message(&msg).unwrap();
1312 assert_eq!(req_id, "t1");
1313 assert_eq!(tag, TAG_HANDSHAKE_REQ);
1314 }
1315
1316 #[test]
1317 fn test_is_host_sdk_message_true() {
1318 assert!(is_host_sdk_message(&[0x01, 0x08, b't', b'1', 0]));
1319 assert!(is_host_sdk_message(&[0x01])); }
1321
1322 #[test]
1323 fn test_is_host_sdk_message_false_empty() {
1324 assert!(!is_host_sdk_message(&[]));
1325 }
1326
1327 #[test]
1328 fn test_is_host_sdk_message_false_wrong_byte() {
1329 assert!(!is_host_sdk_message(&[0x00, 0x08]));
1330 assert!(!is_host_sdk_message(&[0x02, 0x08]));
1331 assert!(!is_host_sdk_message(&[0xFF]));
1332 }
1333
1334 #[test]
1335 fn test_all_encode_functions_start_with_discriminator() {
1336 let buf = encode_response("r", TAG_HANDSHAKE_REQ, &HostResponse::HandshakeOk);
1338 assert_eq!(buf[0], PROTOCOL_DISCRIMINATOR);
1339
1340 let buf = encode_response(
1342 "r",
1343 TAG_GET_NON_PRODUCT_ACCOUNTS_REQ,
1344 &HostResponse::AccountList(vec![]),
1345 );
1346 assert_eq!(buf[0], PROTOCOL_DISCRIMINATOR);
1347
1348 let buf = encode_response("r", TAG_HANDSHAKE_REQ, &HostResponse::Error("e".into()));
1350 assert_eq!(buf[0], PROTOCOL_DISCRIMINATOR);
1351
1352 assert_eq!(
1354 encode_feature_response("r", true)[0],
1355 PROTOCOL_DISCRIMINATOR
1356 );
1357 assert_eq!(
1358 encode_feature_response("r", false)[0],
1359 PROTOCOL_DISCRIMINATOR
1360 );
1361
1362 assert_eq!(encode_account_status("r", true)[0], PROTOCOL_DISCRIMINATOR);
1364
1365 assert_eq!(
1367 encode_storage_read_response("r", None)[0],
1368 PROTOCOL_DISCRIMINATOR
1369 );
1370 assert_eq!(
1371 encode_storage_read_response("r", Some(b"v"))[0],
1372 PROTOCOL_DISCRIMINATOR
1373 );
1374
1375 assert_eq!(
1377 encode_storage_write_response("r", false)[0],
1378 PROTOCOL_DISCRIMINATOR
1379 );
1380 assert_eq!(
1381 encode_storage_write_response("r", true)[0],
1382 PROTOCOL_DISCRIMINATOR
1383 );
1384
1385 assert_eq!(encode_navigate_response("r")[0], PROTOCOL_DISCRIMINATOR);
1387
1388 assert_eq!(
1390 encode_push_notification_response("r")[0],
1391 PROTOCOL_DISCRIMINATOR
1392 );
1393
1394 assert_eq!(
1396 encode_sign_response("r", false, &[0; 64])[0],
1397 PROTOCOL_DISCRIMINATOR
1398 );
1399 assert_eq!(
1400 encode_sign_response("r", true, &[0; 64])[0],
1401 PROTOCOL_DISCRIMINATOR
1402 );
1403
1404 assert_eq!(
1406 encode_jsonrpc_send_response("r", "{}")[0],
1407 PROTOCOL_DISCRIMINATOR
1408 );
1409
1410 assert_eq!(encode_jsonrpc_send_error("r")[0], PROTOCOL_DISCRIMINATOR);
1412
1413 assert_eq!(
1415 encode_jsonrpc_sub_receive("r", "{}")[0],
1416 PROTOCOL_DISCRIMINATOR
1417 );
1418
1419 assert_eq!(encode_sign_error("r", false)[0], PROTOCOL_DISCRIMINATOR);
1421 assert_eq!(encode_sign_error("r", true)[0], PROTOCOL_DISCRIMINATOR);
1422 }
1423
1424 #[test]
1425 fn decode_push_notification_truncated_missing_deeplink() {
1426 let mut msg = Vec::new();
1427 msg.push(PROTOCOL_DISCRIMINATOR);
1428 encode_string(&mut msg, "pn-trunc");
1429 msg.push(TAG_PUSH_NOTIFICATION_REQ);
1430 msg.push(0); encode_string(&mut msg, "Hello");
1432 assert!(decode_message(&msg).is_err());
1435 }
1436}