1use std::mem::size_of;
2
3use borsh::{BorshDeserialize, BorshSerialize};
4
5use unc_crypto::PublicKey;
6
7use crate::hash::CryptoHash;
8use crate::types::AccountId;
9
10pub(crate) const ACCOUNT_DATA_SEPARATOR: u8 = b',';
11pub(crate) const ACCESS_KEY_SEPARATOR: u8 = col::ACCESS_KEY;
14
15pub(crate) const RSA2048_KEY_SEPARATOR: u8 = col::RSA2048_KEY;
16
17pub mod col {
19 pub const ACCOUNT: u8 = 0;
22 pub const CONTRACT_CODE: u8 = 1;
24 pub const ACCESS_KEY: u8 = 2;
27 pub const RECEIVED_DATA: u8 = 3;
31 pub const POSTPONED_RECEIPT_ID: u8 = 4;
34 pub const PENDING_DATA_COUNT: u8 = 5;
37 pub const POSTPONED_RECEIPT: u8 = 6;
39 pub const DELAYED_RECEIPT_OR_INDICES: u8 = 7;
46 pub const CONTRACT_DATA: u8 = 9;
48
49 pub const RSA2048_KEY: u8 = 10;
50 pub const NON_DELAYED_RECEIPT_COLUMNS: [(u8, &str); 8] = [
52 (ACCOUNT, "Account"),
53 (CONTRACT_CODE, "ContractCode"),
54 (ACCESS_KEY, "AccessKey"),
55 (RECEIVED_DATA, "ReceivedData"),
56 (POSTPONED_RECEIPT_ID, "PostponedReceiptId"),
57 (PENDING_DATA_COUNT, "PendingDataCount"),
58 (POSTPONED_RECEIPT, "PostponedReceipt"),
59 (CONTRACT_DATA, "ContractData"),
60 ];
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
65pub enum TrieKey {
66 Account { account_id: AccountId },
68 ContractCode { account_id: AccountId },
70 AccessKey { account_id: AccountId, public_key: PublicKey },
73 ReceivedData { receiver_id: AccountId, data_id: CryptoHash },
78 PostponedReceiptId { receiver_id: AccountId, data_id: CryptoHash },
83 PendingDataCount { receiver_id: AccountId, receipt_id: CryptoHash },
86 PostponedReceipt { receiver_id: AccountId, receipt_id: CryptoHash },
89 DelayedReceiptIndices,
92 DelayedReceipt { index: u64 },
95 ContractData { account_id: AccountId, key: Vec<u8> },
98
99 Rsa2048Keys { account_id: AccountId, public_key: PublicKey },
101}
102
103trait Byte {
109 fn len(self) -> usize;
110}
111
112impl Byte for u8 {
113 fn len(self) -> usize {
114 1
115 }
116}
117
118impl TrieKey {
119 pub fn len(&self) -> usize {
120 match self {
121 TrieKey::Account { account_id } => col::ACCOUNT.len() + account_id.len(),
122 TrieKey::ContractCode { account_id } => col::CONTRACT_CODE.len() + account_id.len(),
123 TrieKey::AccessKey { account_id, public_key } => {
124 col::ACCESS_KEY.len() * 2 + account_id.len() + public_key.len()
125 }
126 TrieKey::ReceivedData { receiver_id, data_id } => {
127 col::RECEIVED_DATA.len()
128 + receiver_id.len()
129 + ACCOUNT_DATA_SEPARATOR.len()
130 + data_id.as_ref().len()
131 }
132 TrieKey::PostponedReceiptId { receiver_id, data_id } => {
133 col::POSTPONED_RECEIPT_ID.len()
134 + receiver_id.len()
135 + ACCOUNT_DATA_SEPARATOR.len()
136 + data_id.as_ref().len()
137 }
138 TrieKey::PendingDataCount { receiver_id, receipt_id } => {
139 col::PENDING_DATA_COUNT.len()
140 + receiver_id.len()
141 + ACCOUNT_DATA_SEPARATOR.len()
142 + receipt_id.as_ref().len()
143 }
144 TrieKey::PostponedReceipt { receiver_id, receipt_id } => {
145 col::POSTPONED_RECEIPT.len()
146 + receiver_id.len()
147 + ACCOUNT_DATA_SEPARATOR.len()
148 + receipt_id.as_ref().len()
149 }
150 TrieKey::DelayedReceiptIndices => col::DELAYED_RECEIPT_OR_INDICES.len(),
151 TrieKey::DelayedReceipt { .. } => {
152 col::DELAYED_RECEIPT_OR_INDICES.len() + size_of::<u64>()
153 }
154 TrieKey::ContractData { account_id, key } => {
155 col::CONTRACT_DATA.len()
156 + account_id.len()
157 + ACCOUNT_DATA_SEPARATOR.len()
158 + key.len()
159 }
160 TrieKey::Rsa2048Keys { account_id, public_key } => {
161 col::RSA2048_KEY.len() * 2 + account_id.len() + public_key.len()
162 }
163 }
164 }
165
166 pub fn append_into(&self, buf: &mut Vec<u8>) {
167 let expected_len = self.len();
168 let start_len = buf.len();
169 buf.reserve(self.len());
170 match self {
171 TrieKey::Account { account_id } => {
172 buf.push(col::ACCOUNT);
173 buf.extend(account_id.as_bytes());
174 }
175 TrieKey::ContractCode { account_id } => {
176 buf.push(col::CONTRACT_CODE);
177 buf.extend(account_id.as_bytes());
178 }
179 TrieKey::AccessKey { account_id, public_key } => {
180 buf.push(col::ACCESS_KEY);
181 buf.extend(account_id.as_bytes());
182 buf.push(ACCESS_KEY_SEPARATOR);
183 buf.extend(borsh::to_vec(&public_key).unwrap());
184 }
185 TrieKey::ReceivedData { receiver_id, data_id } => {
186 buf.push(col::RECEIVED_DATA);
187 buf.extend(receiver_id.as_bytes());
188 buf.push(ACCOUNT_DATA_SEPARATOR);
189 buf.extend(data_id.as_ref());
190 }
191 TrieKey::PostponedReceiptId { receiver_id, data_id } => {
192 buf.push(col::POSTPONED_RECEIPT_ID);
193 buf.extend(receiver_id.as_bytes());
194 buf.push(ACCOUNT_DATA_SEPARATOR);
195 buf.extend(data_id.as_ref());
196 }
197 TrieKey::PendingDataCount { receiver_id, receipt_id } => {
198 buf.push(col::PENDING_DATA_COUNT);
199 buf.extend(receiver_id.as_bytes());
200 buf.push(ACCOUNT_DATA_SEPARATOR);
201 buf.extend(receipt_id.as_ref());
202 }
203 TrieKey::PostponedReceipt { receiver_id, receipt_id } => {
204 buf.push(col::POSTPONED_RECEIPT);
205 buf.extend(receiver_id.as_bytes());
206 buf.push(ACCOUNT_DATA_SEPARATOR);
207 buf.extend(receipt_id.as_ref());
208 }
209 TrieKey::DelayedReceiptIndices => {
210 buf.push(col::DELAYED_RECEIPT_OR_INDICES);
211 }
212 TrieKey::DelayedReceipt { index } => {
213 buf.push(col::DELAYED_RECEIPT_OR_INDICES);
214 buf.extend(&index.to_le_bytes());
215 }
216 TrieKey::ContractData { account_id, key } => {
217 buf.push(col::CONTRACT_DATA);
218 buf.extend(account_id.as_bytes());
219 buf.push(ACCOUNT_DATA_SEPARATOR);
220 buf.extend(key);
221 }
222 TrieKey::Rsa2048Keys { account_id, public_key } => {
223 buf.push(col::RSA2048_KEY);
224 buf.extend(account_id.as_bytes());
225 buf.push(RSA2048_KEY_SEPARATOR);
226 buf.extend(borsh::to_vec(&public_key).unwrap());
227 }
228 };
229 debug_assert_eq!(expected_len, buf.len() - start_len);
230 }
231
232 pub fn to_vec(&self) -> Vec<u8> {
233 let mut buf = Vec::with_capacity(self.len());
234 self.append_into(&mut buf);
235 buf
236 }
237
238 pub fn get_account_id(&self) -> Option<AccountId> {
240 match self {
241 TrieKey::Account { account_id, .. } => Some(account_id.clone()),
242 TrieKey::ContractCode { account_id, .. } => Some(account_id.clone()),
243 TrieKey::AccessKey { account_id, .. } => Some(account_id.clone()),
244 TrieKey::ReceivedData { receiver_id, .. } => Some(receiver_id.clone()),
245 TrieKey::PostponedReceiptId { receiver_id, .. } => Some(receiver_id.clone()),
246 TrieKey::PendingDataCount { receiver_id, .. } => Some(receiver_id.clone()),
247 TrieKey::PostponedReceipt { receiver_id, .. } => Some(receiver_id.clone()),
248 TrieKey::DelayedReceiptIndices => None,
249 TrieKey::DelayedReceipt { .. } => None,
250 TrieKey::ContractData { account_id, .. } => Some(account_id.clone()),
251 TrieKey::Rsa2048Keys { account_id, .. } => Some(account_id.clone()),
252 }
253 }
254}
255
256pub mod trie_key_parsers {
258 use super::*;
259
260 pub fn parse_public_key_from_access_key_key(
261 raw_key: &[u8],
262 account_id: &AccountId,
263 ) -> Result<PublicKey, std::io::Error> {
264 let prefix_len = col::ACCESS_KEY.len() * 2 + account_id.len();
265 if raw_key.len() < prefix_len {
266 return Err(std::io::Error::new(
267 std::io::ErrorKind::InvalidData,
268 "raw key is too short for TrieKey::AccessKey",
269 ));
270 }
271 PublicKey::try_from_slice(&raw_key[prefix_len..])
272 }
273
274 pub fn parse_data_key_from_contract_data_key<'a>(
275 raw_key: &'a [u8],
276 account_id: &AccountId,
277 ) -> Result<&'a [u8], std::io::Error> {
278 let prefix_len = col::CONTRACT_DATA.len() + account_id.len() + ACCOUNT_DATA_SEPARATOR.len();
279 if raw_key.len() < prefix_len {
280 return Err(std::io::Error::new(
281 std::io::ErrorKind::InvalidData,
282 "raw key is too short for TrieKey::ContractData",
283 ));
284 }
285 Ok(&raw_key[prefix_len..])
286 }
287
288 pub fn parse_account_id_prefix<'a>(
289 column: u8,
290 raw_key: &'a [u8],
291 ) -> Result<&'a [u8], std::io::Error> {
292 let prefix = std::slice::from_ref(&column);
293 if let Some(tail) = raw_key.strip_prefix(prefix) {
294 Ok(tail)
295 } else {
296 Err(std::io::Error::new(
297 std::io::ErrorKind::InvalidData,
298 "raw key is does not start with a proper column marker",
299 ))
300 }
301 }
302
303 fn parse_account_id_from_slice(
304 data: &[u8],
305 trie_key: &str,
306 ) -> Result<AccountId, std::io::Error> {
307 std::str::from_utf8(data)
308 .map_err(|_| {
309 std::io::Error::new(
310 std::io::ErrorKind::InvalidData,
311 format!(
312 "raw key AccountId has invalid UTF-8 format to be TrieKey::{}",
313 trie_key
314 ),
315 )
316 })?
317 .parse()
318 .map_err(|_| {
319 std::io::Error::new(
320 std::io::ErrorKind::InvalidData,
321 format!("raw key does not have a valid AccountId to be TrieKey::{}", trie_key),
322 )
323 })
324 }
325
326 fn next_token(data: &[u8], separator: u8) -> Option<&[u8]> {
332 data.iter().position(|&byte| byte == separator).map(|idx| &data[..idx])
333 }
334
335 pub fn parse_account_id_from_contract_data_key(
336 raw_key: &[u8],
337 ) -> Result<AccountId, std::io::Error> {
338 let account_id_prefix = parse_account_id_prefix(col::CONTRACT_DATA, raw_key)?;
339 if let Some(account_id) = next_token(account_id_prefix, ACCOUNT_DATA_SEPARATOR) {
340 parse_account_id_from_slice(account_id, "ContractData")
341 } else {
342 Err(std::io::Error::new(
343 std::io::ErrorKind::InvalidData,
344 "raw key does not have ACCOUNT_DATA_SEPARATOR to be TrieKey::ContractData",
345 ))
346 }
347 }
348
349 pub fn parse_account_id_from_account_key(raw_key: &[u8]) -> Result<AccountId, std::io::Error> {
350 let account_id = parse_account_id_prefix(col::ACCOUNT, raw_key)?;
351 parse_account_id_from_slice(account_id, "Account")
352 }
353
354 pub fn parse_account_id_from_access_key_key(
355 raw_key: &[u8],
356 ) -> Result<AccountId, std::io::Error> {
357 let account_id_prefix = parse_account_id_prefix(col::ACCESS_KEY, raw_key)?;
358 if let Some(account_id) = next_token(account_id_prefix, ACCESS_KEY_SEPARATOR) {
359 parse_account_id_from_slice(account_id, "AccessKey")
360 } else {
361 Err(std::io::Error::new(
362 std::io::ErrorKind::InvalidData,
363 "raw key does not have public key to be TrieKey::AccessKey",
364 ))
365 }
366 }
367
368 pub fn parse_account_id_from_contract_code_key(
369 raw_key: &[u8],
370 ) -> Result<AccountId, std::io::Error> {
371 let account_id = parse_account_id_prefix(col::CONTRACT_CODE, raw_key)?;
372 parse_account_id_from_slice(account_id, "ContractCode")
373 }
374
375 pub fn parse_trie_key_access_key_from_raw_key(
376 raw_key: &[u8],
377 ) -> Result<TrieKey, std::io::Error> {
378 let account_id = parse_account_id_from_access_key_key(raw_key)?;
379 let public_key = parse_public_key_from_access_key_key(raw_key, &account_id)?;
380 Ok(TrieKey::AccessKey { account_id, public_key })
381 }
382
383 pub fn parse_account_id_from_raw_key(
384 raw_key: &[u8],
385 ) -> Result<Option<AccountId>, std::io::Error> {
386 for (col, col_name) in col::NON_DELAYED_RECEIPT_COLUMNS {
387 if parse_account_id_prefix(col, raw_key).is_err() {
388 continue;
389 }
390 let account_id = match col {
391 col::ACCOUNT => parse_account_id_from_account_key(raw_key)?,
392 col::CONTRACT_CODE => parse_account_id_from_contract_code_key(raw_key)?,
393 col::ACCESS_KEY => parse_account_id_from_access_key_key(raw_key)?,
394 _ => parse_account_id_from_trie_key_with_separator(col, raw_key, col_name)?,
395 };
396 return Ok(Some(account_id));
397 }
398 Ok(None)
399 }
400
401 pub fn parse_account_id_from_trie_key_with_separator(
402 col: u8,
403 raw_key: &[u8],
404 col_name: &str,
405 ) -> Result<AccountId, std::io::Error> {
406 let account_id_prefix = parse_account_id_prefix(col, raw_key)?;
407 if let Some(account_id) = next_token(account_id_prefix, ACCOUNT_DATA_SEPARATOR) {
408 parse_account_id_from_slice(account_id, col_name)
409 } else {
410 Err(std::io::Error::new(
411 std::io::ErrorKind::InvalidData,
412 format!("raw key does not have ACCOUNT_DATA_SEPARATOR to be TrieKey::{}", col_name),
413 ))
414 }
415 }
416
417 pub fn parse_account_id_from_received_data_key(
418 raw_key: &[u8],
419 ) -> Result<AccountId, std::io::Error> {
420 parse_account_id_from_trie_key_with_separator(col::RECEIVED_DATA, raw_key, "ReceivedData")
421 }
422
423 pub fn parse_data_id_from_received_data_key(
424 raw_key: &[u8],
425 account_id: &AccountId,
426 ) -> Result<CryptoHash, std::io::Error> {
427 let prefix_len = col::ACCESS_KEY.len() * 2 + account_id.len();
428 if raw_key.len() < prefix_len {
429 return Err(std::io::Error::new(
430 std::io::ErrorKind::InvalidData,
431 "raw key is too short for TrieKey::ReceivedData",
432 ));
433 }
434 CryptoHash::try_from(&raw_key[prefix_len..]).map_err(|_| {
435 std::io::Error::new(
436 std::io::ErrorKind::InvalidData,
437 "Can't parse CryptoHash for TrieKey::ReceivedData",
438 )
439 })
440 }
441
442 pub fn get_raw_prefix_for_rsa_keys(account_id: &AccountId) -> Vec<u8> {
443 let mut res = Vec::with_capacity(col::RSA2048_KEY.len() * 2 + account_id.len());
444 res.push(col::RSA2048_KEY);
445 res.extend(account_id.as_bytes());
446 res.push(col::RSA2048_KEY);
447 res
448 }
449 pub fn get_raw_prefix_for_access_keys(account_id: &AccountId) -> Vec<u8> {
450 let mut res = Vec::with_capacity(col::ACCESS_KEY.len() * 2 + account_id.len());
451 res.push(col::ACCESS_KEY);
452 res.extend(account_id.as_bytes());
453 res.push(col::ACCESS_KEY);
454 res
455 }
456
457 pub fn get_raw_prefix_for_contract_data(account_id: &AccountId, prefix: &[u8]) -> Vec<u8> {
458 let mut res = Vec::with_capacity(
459 col::CONTRACT_DATA.len()
460 + account_id.len()
461 + ACCOUNT_DATA_SEPARATOR.len()
462 + prefix.len(),
463 );
464 res.push(col::CONTRACT_DATA);
465 res.extend(account_id.as_bytes());
466 res.push(ACCOUNT_DATA_SEPARATOR);
467 res.extend(prefix);
468 res
469 }
470
471 pub fn parse_public_key_from_rsa_key_key(
472 raw_key: &[u8],
473 account_id: &AccountId,
474 ) -> Result<PublicKey, std::io::Error> {
475 let prefix_len = col::RSA2048_KEY.len() * 2 + account_id.len();
476 if raw_key.len() < prefix_len {
477 return Err(std::io::Error::new(
478 std::io::ErrorKind::InvalidData,
479 "raw key is too short for TrieKey::Rsa2048Keys",
480 ));
481 }
482 PublicKey::try_from_slice(&raw_key[prefix_len..])
483 }
484
485 pub fn parse_account_id_from_rsa_key_key(raw_key: &[u8]) -> Result<AccountId, std::io::Error> {
486 let account_id_prefix = parse_account_id_prefix(col::RSA2048_KEY, raw_key)?;
487 if let Some(account_id) = next_token(account_id_prefix, RSA2048_KEY_SEPARATOR) {
488 parse_account_id_from_slice(account_id, "Rsa2048Keys")
489 } else {
490 Err(std::io::Error::new(
491 std::io::ErrorKind::InvalidData,
492 "raw key does not have public key to be TrieKey::Rsa2048Keys",
493 ))
494 }
495 }
496
497 pub fn parse_trie_key_rsa_key_from_raw_key(raw_key: &[u8]) -> Result<TrieKey, std::io::Error> {
498 let account_id = parse_account_id_from_rsa_key_key(raw_key)?;
499 let public_key = parse_public_key_from_rsa_key_key(raw_key, &account_id)?;
500 Ok(TrieKey::Rsa2048Keys { account_id, public_key })
501 }
502}
503
504#[cfg(test)]
505mod tests {
506 use unc_crypto::KeyType;
507
508 use super::*;
509
510 const OK_ACCOUNT_IDS: &[&str] = &[
511 "aa",
512 "a-a",
513 "a-aa",
514 "100",
515 "0o",
516 "com",
517 "unc",
518 "bowen",
519 "b-o_w_e-n",
520 "b.owen",
521 "bro.wen",
522 "a.ha",
523 "a.b-a.ra",
524 "system",
525 "over.9000",
526 "google.com",
527 "illia.cheapaccounts.unc",
528 "0o0ooo00oo00o",
529 "alex-skidanov",
530 "10-4.8-2",
531 "b-o_w_e-n",
532 "no_lols",
533 "0123456789012345678901234567890123456789012345678901234567890123",
534 "unc.a",
536 ];
537
538 #[test]
539 fn test_key_for_account_consistency() {
540 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
541 let key = TrieKey::Account { account_id: account_id.clone() };
542 let raw_key = key.to_vec();
543 assert_eq!(raw_key.len(), key.len());
544 assert_eq!(
545 trie_key_parsers::parse_account_id_from_account_key(&raw_key).unwrap(),
546 account_id
547 );
548 assert_eq!(
549 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
550 account_id
551 );
552 }
553 }
554
555 #[test]
556 fn test_key_for_access_key_consistency() {
557 let public_key = PublicKey::empty(KeyType::ED25519);
558 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
559 let key = TrieKey::AccessKey {
560 account_id: account_id.clone(),
561 public_key: public_key.clone(),
562 };
563 let raw_key = key.to_vec();
564 assert_eq!(raw_key.len(), key.len());
565 assert_eq!(
566 trie_key_parsers::parse_trie_key_access_key_from_raw_key(&raw_key).unwrap(),
567 key
568 );
569 assert_eq!(
570 trie_key_parsers::parse_account_id_from_access_key_key(&raw_key).unwrap(),
571 account_id
572 );
573 assert_eq!(
574 trie_key_parsers::parse_public_key_from_access_key_key(&raw_key, &account_id)
575 .unwrap(),
576 public_key
577 );
578 assert_eq!(
579 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
580 account_id
581 );
582 }
583 }
584
585 #[test]
586 fn test_key_for_data_consistency() {
587 let data_key = b"0123456789" as &[u8];
588 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
589 let key =
590 TrieKey::ContractData { account_id: account_id.clone(), key: data_key.to_vec() };
591 let raw_key = key.to_vec();
592 assert_eq!(raw_key.len(), key.len());
593 assert_eq!(
594 trie_key_parsers::parse_account_id_from_contract_data_key(&raw_key).unwrap(),
595 account_id
596 );
597 assert_eq!(
598 trie_key_parsers::parse_data_key_from_contract_data_key(&raw_key, &account_id)
599 .unwrap(),
600 data_key
601 );
602 assert_eq!(
603 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
604 account_id
605 );
606 }
607 }
608
609 #[test]
610 fn test_key_for_code_consistency() {
611 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
612 let key = TrieKey::ContractCode { account_id: account_id.clone() };
613 let raw_key = key.to_vec();
614 assert_eq!(raw_key.len(), key.len());
615 assert_eq!(
616 trie_key_parsers::parse_account_id_from_contract_code_key(&raw_key).unwrap(),
617 account_id
618 );
619 assert_eq!(
620 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
621 account_id
622 );
623 }
624 }
625
626 #[test]
627 fn test_key_for_received_data_consistency() {
628 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
629 let key = TrieKey::ReceivedData {
630 receiver_id: account_id.clone(),
631 data_id: CryptoHash::default(),
632 };
633 let raw_key = key.to_vec();
634 assert_eq!(raw_key.len(), key.len());
635 assert_eq!(
636 trie_key_parsers::parse_account_id_from_received_data_key(&raw_key).unwrap(),
637 account_id
638 );
639 assert_eq!(
640 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
641 account_id
642 );
643 assert_eq!(
644 trie_key_parsers::parse_data_id_from_received_data_key(&raw_key, &account_id)
645 .unwrap(),
646 CryptoHash::default(),
647 );
648 }
649 }
650
651 #[test]
652 fn test_key_for_postponed_receipt_consistency() {
653 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
654 let key = TrieKey::PostponedReceipt {
655 receiver_id: account_id.clone(),
656 receipt_id: CryptoHash::default(),
657 };
658 let raw_key = key.to_vec();
659 assert_eq!(raw_key.len(), key.len());
660 assert_eq!(
661 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
662 account_id
663 );
664 }
665 }
666
667 #[test]
668 fn test_key_for_postponed_receipt_id_consistency() {
669 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
670 let key = TrieKey::PostponedReceiptId {
671 receiver_id: account_id.clone(),
672 data_id: CryptoHash::default(),
673 };
674 let raw_key = key.to_vec();
675 assert_eq!(raw_key.len(), key.len());
676 assert_eq!(
677 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
678 account_id
679 );
680 }
681 }
682
683 #[test]
684 fn test_key_for_pending_data_count_consistency() {
685 for account_id in OK_ACCOUNT_IDS.iter().map(|x| x.parse::<AccountId>().unwrap()) {
686 let key = TrieKey::PendingDataCount {
687 receiver_id: account_id.clone(),
688 receipt_id: CryptoHash::default(),
689 };
690 let raw_key = key.to_vec();
691 assert_eq!(raw_key.len(), key.len());
692 assert_eq!(
693 trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().unwrap(),
694 account_id
695 );
696 }
697 }
698
699 #[test]
700 fn test_key_for_delayed_receipts_consistency() {
701 let key = TrieKey::DelayedReceiptIndices;
702 let raw_key = key.to_vec();
703 assert!(trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().is_none());
704 let key = TrieKey::DelayedReceipt { index: 0 };
705 let raw_key = key.to_vec();
706 assert!(trie_key_parsers::parse_account_id_from_raw_key(&raw_key).unwrap().is_none());
707 }
708
709 #[test]
710 fn test_account_id_from_trie_key() {
711 for account_id_str in OK_ACCOUNT_IDS {
712 let account_id = account_id_str.parse::<AccountId>().unwrap();
713
714 assert_eq!(
715 TrieKey::Account { account_id: account_id.clone() }.get_account_id(),
716 Some(account_id.clone())
717 );
718 assert_eq!(
719 TrieKey::ContractCode { account_id: account_id.clone() }.get_account_id(),
720 Some(account_id.clone())
721 );
722 assert_eq!(
723 TrieKey::AccessKey {
724 account_id: account_id.clone(),
725 public_key: PublicKey::empty(KeyType::ED25519)
726 }
727 .get_account_id(),
728 Some(account_id.clone())
729 );
730 assert_eq!(
731 TrieKey::ReceivedData {
732 receiver_id: account_id.clone(),
733 data_id: Default::default()
734 }
735 .get_account_id(),
736 Some(account_id.clone())
737 );
738 assert_eq!(
739 TrieKey::PostponedReceiptId {
740 receiver_id: account_id.clone(),
741 data_id: Default::default()
742 }
743 .get_account_id(),
744 Some(account_id.clone())
745 );
746 assert_eq!(
747 TrieKey::PendingDataCount {
748 receiver_id: account_id.clone(),
749 receipt_id: Default::default()
750 }
751 .get_account_id(),
752 Some(account_id.clone())
753 );
754 assert_eq!(
755 TrieKey::PostponedReceipt {
756 receiver_id: account_id.clone(),
757 receipt_id: Default::default()
758 }
759 .get_account_id(),
760 Some(account_id.clone())
761 );
762 assert_eq!(
763 TrieKey::DelayedReceipt { index: Default::default() }.get_account_id(),
764 None
765 );
766 assert_eq!(TrieKey::DelayedReceiptIndices.get_account_id(), None);
767 assert_eq!(
768 TrieKey::ContractData { account_id: account_id.clone(), key: Default::default() }
769 .get_account_id(),
770 Some(account_id)
771 );
772 }
773 }
774}