1use std::fmt::{Debug, Display, Formatter};
2
3use miden_node_utils::formatting::format_opt;
4use miden_objects::Word;
5use miden_objects::account::{
6 Account,
7 AccountHeader,
8 AccountId,
9 AccountStorageHeader,
10 StorageMap,
11 StorageSlotType,
12};
13use miden_objects::asset::{Asset, AssetVault};
14use miden_objects::block::{AccountWitness, BlockNumber};
15use miden_objects::crypto::merkle::SparseMerklePath;
16use miden_objects::note::{NoteExecutionMode, NoteTag};
17use miden_objects::utils::{Deserializable, DeserializationError, Serializable};
18use thiserror::Error;
19
20use super::try_convert;
21use crate::errors::{ConversionError, MissingFieldHelper};
22use crate::generated::{self as proto};
23
24impl Display for proto::account::AccountId {
28 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
29 write!(f, "0x")?;
30 for byte in &self.id {
31 write!(f, "{byte:02x}")?;
32 }
33 Ok(())
34 }
35}
36
37impl Debug for proto::account::AccountId {
38 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39 Display::fmt(self, f)
40 }
41}
42
43impl TryFrom<proto::account::AccountId> for AccountId {
47 type Error = ConversionError;
48
49 fn try_from(account_id: proto::account::AccountId) -> Result<Self, Self::Error> {
50 AccountId::read_from_bytes(&account_id.id).map_err(|_| ConversionError::NotAValidFelt)
51 }
52}
53
54impl From<&AccountId> for proto::account::AccountId {
58 fn from(account_id: &AccountId) -> Self {
59 (*account_id).into()
60 }
61}
62
63impl From<AccountId> for proto::account::AccountId {
64 fn from(account_id: AccountId) -> Self {
65 Self { id: account_id.to_bytes() }
66 }
67}
68
69#[derive(Debug, PartialEq)]
73pub struct AccountSummary {
74 pub account_id: AccountId,
75 pub account_commitment: Word,
76 pub block_num: BlockNumber,
77}
78
79impl From<&AccountSummary> for proto::account::AccountSummary {
80 fn from(update: &AccountSummary) -> Self {
81 Self {
82 account_id: Some(update.account_id.into()),
83 account_commitment: Some(update.account_commitment.into()),
84 block_num: update.block_num.as_u32(),
85 }
86 }
87}
88
89#[derive(Debug, PartialEq)]
90pub struct AccountInfo {
91 pub summary: AccountSummary,
92 pub details: Option<Account>,
93}
94
95impl From<&AccountInfo> for proto::account::AccountDetails {
96 fn from(AccountInfo { summary, details }: &AccountInfo) -> Self {
97 Self {
98 summary: Some(summary.into()),
99 details: details.as_ref().map(miden_objects::utils::Serializable::to_bytes),
100 }
101 }
102}
103
104pub struct AccountProofRequest {
109 pub account_id: AccountId,
110 pub block_num: Option<BlockNumber>,
112 pub details: Option<AccountDetailRequest>,
113}
114
115impl TryFrom<proto::rpc_store::AccountProofRequest> for AccountProofRequest {
116 type Error = ConversionError;
117
118 fn try_from(value: proto::rpc_store::AccountProofRequest) -> Result<Self, Self::Error> {
119 let proto::rpc_store::AccountProofRequest { account_id, block_num, details } = value;
120
121 let account_id = account_id
122 .ok_or(proto::rpc_store::AccountProofRequest::missing_field(stringify!(account_id)))?
123 .try_into()?;
124 let block_num = block_num.map(Into::into);
125
126 let details = details.map(TryFrom::try_from).transpose()?;
127
128 Ok(AccountProofRequest { account_id, block_num, details })
129 }
130}
131
132pub struct AccountDetailRequest {
134 pub code_commitment: Option<Word>,
135 pub asset_vault_commitment: Option<Word>,
136 pub storage_requests: Vec<StorageMapRequest>,
137}
138
139impl TryFrom<proto::rpc_store::account_proof_request::AccountDetailRequest>
140 for AccountDetailRequest
141{
142 type Error = ConversionError;
143
144 fn try_from(
145 value: proto::rpc_store::account_proof_request::AccountDetailRequest,
146 ) -> Result<Self, Self::Error> {
147 let proto::rpc_store::account_proof_request::AccountDetailRequest {
148 code_commitment,
149 asset_vault_commitment,
150 storage_maps,
151 } = value;
152
153 let code_commitment = code_commitment.map(TryFrom::try_from).transpose()?;
154 let asset_vault_commitment = asset_vault_commitment.map(TryFrom::try_from).transpose()?;
155 let storage_requests = try_convert(storage_maps).collect::<Result<_, _>>()?;
156
157 Ok(AccountDetailRequest {
158 code_commitment,
159 asset_vault_commitment,
160 storage_requests,
161 })
162 }
163}
164
165impl TryFrom<proto::account::AccountStorageHeader> for AccountStorageHeader {
166 type Error = ConversionError;
167
168 fn try_from(value: proto::account::AccountStorageHeader) -> Result<Self, Self::Error> {
169 let proto::account::AccountStorageHeader { slots } = value;
170
171 let items = slots
172 .into_iter()
173 .map(|slot| {
174 let slot_type = storage_slot_type_from_raw(slot.slot_type)?;
175 let commitment =
176 slot.commitment.ok_or(ConversionError::NotAValidFelt)?.try_into()?;
177 Ok((slot_type, commitment))
178 })
179 .collect::<Result<Vec<_>, ConversionError>>()?;
180
181 Ok(AccountStorageHeader::new(items))
182 }
183}
184
185impl TryFrom<proto::rpc_store::account_storage_details::AccountStorageMapDetails>
186 for AccountStorageMapDetails
187{
188 type Error = ConversionError;
189
190 fn try_from(
191 value: proto::rpc_store::account_storage_details::AccountStorageMapDetails,
192 ) -> Result<Self, Self::Error> {
193 let proto::rpc_store::account_storage_details::AccountStorageMapDetails {
194 slot_index,
195 too_many_entries,
196 entries,
197 } = value;
198
199 let slot_index = slot_index.try_into().map_err(ConversionError::TryFromIntError)?;
200
201 let map_entries = if let Some(entries) = entries {
203 entries
204 .entries
205 .into_iter()
206 .map(|entry| {
207 let key = entry
208 .key
209 .ok_or(proto::rpc_store::account_storage_details::account_storage_map_details::map_entries::StorageMapEntry::missing_field(
210 stringify!(key),
211 ))?
212 .try_into()?;
213 let value = entry
214 .value
215 .ok_or(proto::rpc_store::account_storage_details::account_storage_map_details::map_entries::StorageMapEntry::missing_field(
216 stringify!(value),
217 ))?
218 .try_into()?;
219 Ok((key, value))
220 })
221 .collect::<Result<Vec<_>, ConversionError>>()?
222 } else {
223 Vec::new()
224 };
225
226 Ok(Self {
227 slot_index,
228 too_many_entries,
229 map_entries,
230 })
231 }
232}
233
234#[derive(Debug, Clone, PartialEq, Eq)]
235pub struct StorageMapRequest {
236 pub slot_index: u8,
237 pub slot_data: SlotData,
238}
239
240impl
241 TryFrom<
242 proto::rpc_store::account_proof_request::account_detail_request::StorageMapDetailRequest,
243 > for StorageMapRequest
244{
245 type Error = ConversionError;
246
247 fn try_from(
248 value: proto::rpc_store::account_proof_request::account_detail_request::StorageMapDetailRequest,
249 ) -> Result<Self, Self::Error> {
250 let proto::rpc_store::account_proof_request::account_detail_request::StorageMapDetailRequest {
251 slot_index,
252 slot_data,
253 } = value;
254
255 let slot_index = slot_index.try_into()?;
256 let slot_data = slot_data.ok_or(proto::rpc_store::account_proof_request::account_detail_request::StorageMapDetailRequest::missing_field(stringify!(slot_data)))?.try_into()?;
257
258 Ok(StorageMapRequest { slot_index, slot_data })
259 }
260}
261
262#[derive(Debug, Clone, PartialEq, Eq)]
263pub enum SlotData {
264 All,
265 MapKeys(Vec<Word>),
266}
267
268impl TryFrom<proto::rpc_store::account_proof_request::account_detail_request::storage_map_detail_request::SlotData>
269 for SlotData
270{
271 type Error = ConversionError;
272
273 fn try_from(value: proto::rpc_store::account_proof_request::account_detail_request::storage_map_detail_request::SlotData) -> Result<Self, Self::Error> {
274 use proto::rpc_store::account_proof_request::account_detail_request::storage_map_detail_request::SlotData as ProtoSlotData;
275
276 Ok(match value {
277 ProtoSlotData::AllEntries(true) => SlotData::All,
278 ProtoSlotData::AllEntries(false) => return Err(ConversionError::EnumDiscriminantOutOfRange),
279 ProtoSlotData::MapKeys(keys) => {
280 let keys = try_convert(keys.map_keys).collect::<Result<Vec<_>, _>>()?;
281 SlotData::MapKeys(keys)
282 },
283 })
284 }
285}
286
287impl TryFrom<proto::account::AccountHeader> for AccountHeader {
291 type Error = ConversionError;
292
293 fn try_from(value: proto::account::AccountHeader) -> Result<Self, Self::Error> {
294 let proto::account::AccountHeader {
295 account_id,
296 vault_root,
297 storage_commitment,
298 code_commitment,
299 nonce,
300 } = value;
301
302 let account_id = account_id
303 .ok_or(proto::account::AccountHeader::missing_field(stringify!(account_id)))?
304 .try_into()?;
305 let vault_root = vault_root
306 .ok_or(proto::account::AccountHeader::missing_field(stringify!(vault_root)))?
307 .try_into()?;
308 let storage_commitment = storage_commitment
309 .ok_or(proto::account::AccountHeader::missing_field(stringify!(storage_commitment)))?
310 .try_into()?;
311 let code_commitment = code_commitment
312 .ok_or(proto::account::AccountHeader::missing_field(stringify!(code_commitment)))?
313 .try_into()?;
314 let nonce = nonce.try_into().map_err(|_e| ConversionError::NotAValidFelt)?;
315
316 Ok(AccountHeader::new(
317 account_id,
318 nonce,
319 vault_root,
320 storage_commitment,
321 code_commitment,
322 ))
323 }
324}
325
326impl From<AccountHeader> for proto::account::AccountHeader {
327 fn from(header: AccountHeader) -> Self {
328 proto::account::AccountHeader {
329 account_id: Some(header.id().into()),
330 vault_root: Some(header.vault_root().into()),
331 storage_commitment: Some(header.storage_commitment().into()),
332 code_commitment: Some(header.code_commitment().into()),
333 nonce: header.nonce().as_int(),
334 }
335 }
336}
337
338impl From<AccountStorageHeader> for proto::account::AccountStorageHeader {
339 fn from(value: AccountStorageHeader) -> Self {
340 let slots = value
341 .slots()
342 .map(|(slot_type, slot_value)| proto::account::account_storage_header::StorageSlot {
343 slot_type: storage_slot_type_to_raw(*slot_type),
344 commitment: Some(proto::primitives::Digest::from(*slot_value)),
345 })
346 .collect();
347
348 Self { slots }
349 }
350}
351
352#[derive(Debug, Clone, PartialEq, Eq)]
353pub struct AccountVaultDetails {
354 pub too_many_assets: bool,
355 pub assets: Vec<Asset>,
356}
357impl AccountVaultDetails {
358 const MAX_RETURN_ENTRIES: usize = 1000;
359
360 pub fn new(vault: &AssetVault) -> Self {
361 if vault.assets().nth(Self::MAX_RETURN_ENTRIES).is_some() {
362 Self::too_many()
363 } else {
364 Self {
365 too_many_assets: false,
366 assets: Vec::from_iter(vault.assets()),
367 }
368 }
369 }
370
371 pub fn empty() -> Self {
372 Self {
373 too_many_assets: false,
374 assets: Vec::new(),
375 }
376 }
377
378 fn too_many() -> Self {
379 Self {
380 too_many_assets: true,
381 assets: Vec::new(),
382 }
383 }
384}
385
386impl TryFrom<proto::rpc_store::AccountVaultDetails> for AccountVaultDetails {
387 type Error = ConversionError;
388
389 fn try_from(value: proto::rpc_store::AccountVaultDetails) -> Result<Self, Self::Error> {
390 let proto::rpc_store::AccountVaultDetails { too_many_assets, assets } = value;
391
392 let assets =
393 Result::<Vec<_>, ConversionError>::from_iter(assets.into_iter().map(|asset| {
394 let asset = asset
395 .asset
396 .ok_or(proto::primitives::Asset::missing_field(stringify!(asset)))?;
397 let asset = Word::try_from(asset)?;
398 Asset::try_from(asset).map_err(ConversionError::AssetError)
399 }))?;
400 Ok(Self { too_many_assets, assets })
401 }
402}
403
404impl From<AccountVaultDetails> for proto::rpc_store::AccountVaultDetails {
405 fn from(value: AccountVaultDetails) -> Self {
406 let AccountVaultDetails { too_many_assets, assets } = value;
407
408 Self {
409 too_many_assets,
410 assets: Vec::from_iter(assets.into_iter().map(|asset| proto::primitives::Asset {
411 asset: Some(proto::primitives::Digest::from(Word::from(asset))),
412 })),
413 }
414 }
415}
416
417#[derive(Debug, Clone, PartialEq, Eq)]
418pub struct AccountStorageMapDetails {
419 pub slot_index: u8,
420 pub too_many_entries: bool,
421 pub map_entries: Vec<(Word, Word)>,
422}
423
424impl AccountStorageMapDetails {
425 const MAX_RETURN_ENTRIES: usize = 1000;
426
427 pub fn new(slot_index: u8, slot_data: SlotData, storage_map: &StorageMap) -> Self {
428 match slot_data {
429 SlotData::All => Self::from_all_entries(slot_index, storage_map),
430 SlotData::MapKeys(keys) => Self::from_specific_keys(slot_index, &keys[..], storage_map),
431 }
432 }
433
434 fn from_all_entries(slot_index: u8, storage_map: &StorageMap) -> Self {
435 if storage_map.num_entries() > Self::MAX_RETURN_ENTRIES {
436 Self::too_many_entries(slot_index)
437 } else {
438 let map_entries = Vec::from_iter(storage_map.entries().map(|(k, v)| (*k, *v)));
439 Self {
440 slot_index,
441 too_many_entries: false,
442 map_entries,
443 }
444 }
445 }
446
447 fn from_specific_keys(slot_index: u8, keys: &[Word], storage_map: &StorageMap) -> Self {
448 if keys.len() > Self::MAX_RETURN_ENTRIES {
449 Self::too_many_entries(slot_index)
450 } else {
451 Self::from_all_entries(slot_index, storage_map)
453 }
454 }
455
456 pub fn too_many_entries(slot_index: u8) -> Self {
457 Self {
458 slot_index,
459 too_many_entries: true,
460 map_entries: Vec::new(),
461 }
462 }
463}
464
465#[derive(Debug, Clone, PartialEq, Eq)]
466pub struct AccountStorageDetails {
467 pub header: AccountStorageHeader,
468 pub map_details: Vec<AccountStorageMapDetails>,
469}
470
471impl TryFrom<proto::rpc_store::AccountStorageDetails> for AccountStorageDetails {
472 type Error = ConversionError;
473
474 fn try_from(value: proto::rpc_store::AccountStorageDetails) -> Result<Self, Self::Error> {
475 let proto::rpc_store::AccountStorageDetails { header, map_details } = value;
476
477 let header = header
478 .ok_or(proto::rpc_store::AccountStorageDetails::missing_field(stringify!(header)))?
479 .try_into()?;
480
481 let map_details = try_convert(map_details).collect::<Result<Vec<_>, _>>()?;
482
483 Ok(Self { header, map_details })
484 }
485}
486
487impl From<AccountStorageDetails> for proto::rpc_store::AccountStorageDetails {
488 fn from(value: AccountStorageDetails) -> Self {
489 let AccountStorageDetails { header, map_details } = value;
490
491 Self {
492 header: Some(header.into()),
493 map_details: map_details.into_iter().map(Into::into).collect(),
494 }
495 }
496}
497
498const fn storage_slot_type_from_raw(slot_type: u32) -> Result<StorageSlotType, ConversionError> {
499 Ok(match slot_type {
500 0 => StorageSlotType::Map,
501 1 => StorageSlotType::Value,
502 _ => return Err(ConversionError::EnumDiscriminantOutOfRange),
503 })
504}
505
506const fn storage_slot_type_to_raw(slot_type: StorageSlotType) -> u32 {
507 match slot_type {
508 StorageSlotType::Map => 0,
509 StorageSlotType::Value => 1,
510 }
511}
512
513pub struct AccountDetails {
515 pub account_header: AccountHeader,
516 pub account_code: Option<Vec<u8>>,
517 pub vault_details: AccountVaultDetails,
518 pub storage_details: AccountStorageDetails,
519}
520
521pub struct AccountProofResponse {
523 pub block_num: BlockNumber,
524 pub witness: AccountWitness,
525 pub details: Option<AccountDetails>,
526}
527
528impl TryFrom<proto::rpc_store::AccountProofResponse> for AccountProofResponse {
529 type Error = ConversionError;
530
531 fn try_from(value: proto::rpc_store::AccountProofResponse) -> Result<Self, Self::Error> {
532 let proto::rpc_store::AccountProofResponse { block_num, witness, details } = value;
533
534 let block_num = block_num
535 .ok_or(proto::rpc_store::AccountProofResponse::missing_field(stringify!(block_num)))?
536 .into();
537
538 let witness = witness
539 .ok_or(proto::rpc_store::AccountProofResponse::missing_field(stringify!(witness)))?
540 .try_into()?;
541
542 let details = details.map(TryFrom::try_from).transpose()?;
543
544 Ok(AccountProofResponse { block_num, witness, details })
545 }
546}
547
548impl From<AccountProofResponse> for proto::rpc_store::AccountProofResponse {
549 fn from(value: AccountProofResponse) -> Self {
550 let AccountProofResponse { block_num, witness, details } = value;
551
552 Self {
553 witness: Some(witness.into()),
554 details: details.map(Into::into),
555 block_num: Some(block_num.into()),
556 }
557 }
558}
559
560impl TryFrom<proto::rpc_store::account_proof_response::AccountDetails> for AccountDetails {
561 type Error = ConversionError;
562
563 fn try_from(
564 value: proto::rpc_store::account_proof_response::AccountDetails,
565 ) -> Result<Self, Self::Error> {
566 let proto::rpc_store::account_proof_response::AccountDetails {
567 header,
568 code,
569 vault_details,
570 storage_details,
571 } = value;
572
573 let account_header = header
574 .ok_or(proto::rpc_store::account_proof_response::AccountDetails::missing_field(
575 stringify!(header),
576 ))?
577 .try_into()?;
578
579 let storage_details = storage_details
580 .ok_or(proto::rpc_store::account_proof_response::AccountDetails::missing_field(
581 stringify!(storage_details),
582 ))?
583 .try_into()?;
584
585 let vault_details = vault_details
586 .ok_or(proto::rpc_store::account_proof_response::AccountDetails::missing_field(
587 stringify!(vault_details),
588 ))?
589 .try_into()?;
590 let account_code = code;
591
592 Ok(AccountDetails {
593 account_header,
594 account_code,
595 vault_details,
596 storage_details,
597 })
598 }
599}
600
601impl From<AccountDetails> for proto::rpc_store::account_proof_response::AccountDetails {
602 fn from(value: AccountDetails) -> Self {
603 let AccountDetails {
604 account_header,
605 storage_details,
606 account_code,
607 vault_details,
608 } = value;
609
610 let header = Some(proto::account::AccountHeader::from(account_header));
611 let storage_details = Some(storage_details.into());
612 let code = account_code;
613 let vault_details = Some(vault_details.into());
614
615 Self {
616 header,
617 storage_details,
618 code,
619 vault_details,
620 }
621 }
622}
623
624impl From<AccountStorageMapDetails>
625 for proto::rpc_store::account_storage_details::AccountStorageMapDetails
626{
627 fn from(value: AccountStorageMapDetails) -> Self {
628 use proto::rpc_store::account_storage_details::account_storage_map_details;
629
630 let AccountStorageMapDetails {
631 slot_index,
632 too_many_entries,
633 map_entries,
634 } = value;
635
636 let entries = Some(account_storage_map_details::MapEntries {
637 entries: Vec::from_iter(map_entries.into_iter().map(|(key, value)| {
638 account_storage_map_details::map_entries::StorageMapEntry {
639 key: Some(key.into()),
640 value: Some(value.into()),
641 }
642 })),
643 });
644
645 Self {
646 slot_index: u32::from(slot_index),
647 too_many_entries,
648 entries,
649 }
650 }
651}
652
653impl TryFrom<proto::account::AccountWitness> for AccountWitness {
657 type Error = ConversionError;
658
659 fn try_from(account_witness: proto::account::AccountWitness) -> Result<Self, Self::Error> {
660 let witness_id = account_witness
661 .witness_id
662 .ok_or(proto::account::AccountWitness::missing_field(stringify!(witness_id)))?
663 .try_into()?;
664 let commitment = account_witness
665 .commitment
666 .ok_or(proto::account::AccountWitness::missing_field(stringify!(commitment)))?
667 .try_into()?;
668 let path = account_witness
669 .path
670 .ok_or(proto::account::AccountWitness::missing_field(stringify!(path)))?
671 .try_into()?;
672
673 AccountWitness::new(witness_id, commitment, path).map_err(|err| {
674 ConversionError::deserialization_error(
675 "AccountWitness",
676 DeserializationError::InvalidValue(err.to_string()),
677 )
678 })
679 }
680}
681
682impl From<AccountWitness> for proto::account::AccountWitness {
683 fn from(witness: AccountWitness) -> Self {
684 Self {
685 account_id: Some(witness.id().into()),
686 witness_id: Some(witness.id().into()),
687 commitment: Some(witness.state_commitment().into()),
688 path: Some(witness.into_proof().into_parts().0.into()),
689 }
690 }
691}
692
693#[derive(Clone, Debug, PartialEq, Eq)]
697pub struct AccountWitnessRecord {
698 pub account_id: AccountId,
699 pub witness: AccountWitness,
700}
701
702impl TryFrom<proto::account::AccountWitness> for AccountWitnessRecord {
703 type Error = ConversionError;
704
705 fn try_from(
706 account_witness_record: proto::account::AccountWitness,
707 ) -> Result<Self, Self::Error> {
708 let witness_id = account_witness_record
709 .witness_id
710 .ok_or(proto::account::AccountWitness::missing_field(stringify!(witness_id)))?
711 .try_into()?;
712 let commitment = account_witness_record
713 .commitment
714 .ok_or(proto::account::AccountWitness::missing_field(stringify!(commitment)))?
715 .try_into()?;
716 let path: SparseMerklePath = account_witness_record
717 .path
718 .as_ref()
719 .ok_or(proto::account::AccountWitness::missing_field(stringify!(path)))?
720 .clone()
721 .try_into()?;
722
723 let witness = AccountWitness::new(witness_id, commitment, path).map_err(|err| {
724 ConversionError::deserialization_error(
725 "AccountWitness",
726 DeserializationError::InvalidValue(err.to_string()),
727 )
728 })?;
729
730 Ok(Self {
731 account_id: account_witness_record
732 .account_id
733 .ok_or(proto::account::AccountWitness::missing_field(stringify!(account_id)))?
734 .try_into()?,
735 witness,
736 })
737 }
738}
739
740impl From<AccountWitnessRecord> for proto::account::AccountWitness {
741 fn from(from: AccountWitnessRecord) -> Self {
742 Self {
743 account_id: Some(from.account_id.into()),
744 witness_id: Some(from.witness.id().into()),
745 commitment: Some(from.witness.state_commitment().into()),
746 path: Some(from.witness.path().clone().into()),
747 }
748 }
749}
750
751#[derive(Debug)]
756pub struct AccountState {
757 pub account_id: AccountId,
759 pub account_commitment: Option<Word>,
761}
762
763impl Display for AccountState {
764 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
765 f.write_fmt(format_args!(
766 "{{ account_id: {}, account_commitment: {} }}",
767 self.account_id,
768 format_opt(self.account_commitment.as_ref()),
769 ))
770 }
771}
772
773impl TryFrom<proto::block_producer_store::transaction_inputs::AccountTransactionInputRecord>
774 for AccountState
775{
776 type Error = ConversionError;
777
778 fn try_from(
779 from: proto::block_producer_store::transaction_inputs::AccountTransactionInputRecord,
780 ) -> Result<Self, Self::Error> {
781 let account_id = from
782 .account_id
783 .ok_or(proto::block_producer_store::transaction_inputs::AccountTransactionInputRecord::missing_field(
784 stringify!(account_id),
785 ))?
786 .try_into()?;
787
788 let account_commitment = from
789 .account_commitment
790 .ok_or(proto::block_producer_store::transaction_inputs::AccountTransactionInputRecord::missing_field(
791 stringify!(account_commitment),
792 ))?
793 .try_into()?;
794
795 let account_commitment = if account_commitment == Word::empty() {
798 None
799 } else {
800 Some(account_commitment)
801 };
802
803 Ok(Self { account_id, account_commitment })
804 }
805}
806
807impl From<AccountState>
808 for proto::block_producer_store::transaction_inputs::AccountTransactionInputRecord
809{
810 fn from(from: AccountState) -> Self {
811 Self {
812 account_id: Some(from.account_id.into()),
813 account_commitment: from.account_commitment.map(Into::into),
814 }
815 }
816}
817
818impl TryFrom<proto::primitives::Asset> for Asset {
822 type Error = ConversionError;
823
824 fn try_from(value: proto::primitives::Asset) -> Result<Self, Self::Error> {
825 let inner = value.asset.ok_or(proto::primitives::Asset::missing_field("asset"))?;
826 let word = Word::try_from(inner)?;
827
828 Asset::try_from(word).map_err(ConversionError::AssetError)
829 }
830}
831
832impl From<Asset> for proto::primitives::Asset {
833 fn from(asset_from: Asset) -> Self {
834 proto::primitives::Asset {
835 asset: Some(Word::from(asset_from).into()),
836 }
837 }
838}
839
840pub type AccountPrefix = u32;
844
845#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
848pub struct NetworkAccountPrefix(u32);
849
850impl std::fmt::Display for NetworkAccountPrefix {
851 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
852 std::fmt::Display::fmt(&self.0, f)
853 }
854}
855
856impl NetworkAccountPrefix {
857 pub fn inner(&self) -> u32 {
858 self.0
859 }
860}
861
862impl TryFrom<u32> for NetworkAccountPrefix {
863 type Error = NetworkAccountError;
864
865 fn try_from(value: u32) -> Result<Self, Self::Error> {
866 if value >> 30 != 0 {
867 return Err(NetworkAccountError::InvalidPrefix(value));
868 }
869 Ok(NetworkAccountPrefix(value))
870 }
871}
872
873impl TryFrom<AccountId> for NetworkAccountPrefix {
874 type Error = NetworkAccountError;
875
876 fn try_from(id: AccountId) -> Result<Self, Self::Error> {
877 if !id.is_network() {
878 return Err(NetworkAccountError::NotNetworkAccount(id));
879 }
880 let prefix = get_account_id_tag_prefix(id);
881 Ok(NetworkAccountPrefix(prefix))
882 }
883}
884
885impl TryFrom<NoteTag> for NetworkAccountPrefix {
886 type Error = NetworkAccountError;
887
888 fn try_from(tag: NoteTag) -> Result<Self, Self::Error> {
889 if tag.execution_mode() != NoteExecutionMode::Network || !tag.is_single_target() {
890 return Err(NetworkAccountError::InvalidExecutionMode(tag));
891 }
892
893 let tag_inner: u32 = tag.into();
894 assert!(tag_inner >> 30 == 0, "first 2 bits have to be 0");
895 Ok(NetworkAccountPrefix(tag_inner))
896 }
897}
898
899impl From<NetworkAccountPrefix> for u32 {
900 fn from(value: NetworkAccountPrefix) -> Self {
901 value.inner()
902 }
903}
904
905#[derive(Debug, Error)]
906pub enum NetworkAccountError {
907 #[error("account ID {0} is not a valid network account ID")]
908 NotNetworkAccount(AccountId),
909 #[error("note tag {0} is not valid for network account execution")]
910 InvalidExecutionMode(NoteTag),
911 #[error("note prefix should be 30-bit long ({0} has non-zero in the 2 most significant bits)")]
912 InvalidPrefix(u32),
913}
914
915fn get_account_id_tag_prefix(id: AccountId) -> AccountPrefix {
917 (id.prefix().as_u64() >> 34) as AccountPrefix
918}